<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Miguel Silva</title>
<link>https://migsilva.com/es/</link>
<atom:link href="https://migsilva.com/es/index.xml" rel="self" type="application/rss+xml"/>
<description>Notes on statistics and data science</description>
<generator>quarto-1.10.19</generator>
<lastBuildDate>Sat, 26 Sep 2020 00:00:00 GMT</lastBuildDate>
<item>
  <title>Aproximación de función de valor</title>
  <link>https://migsilva.com/es/posts/aproximacion-de-funcion-de-valor/</link>
  <description><![CDATA[ 





<p>En este capítulo aprenderemos cómo escalar RL hacia problemas en el mundo real y cómo resolverlos, es decir daremos un vistazo más realista a cómo se aplican estos algoritmos en la época actual, e incluso veremos un algoritmo que en su momento fue el estado del arte.</p>
<section id="introducción" class="level2">
<h2 class="anchored" data-anchor-id="introducción">Introducción</h2>
<p>El aprendizaje por refuerzo puede ser usado para resolver problemas que suelen tener MDPs de gran cantidad de estados que resolver de otra manera sería virtualmente imposible, a continuación unos ejemplos:</p>
<ul>
<li>Backgammon posee una cantidad de 10²⁰ estados.</li>
<li>Go posee una cantidad de 10¹⁷⁰ estados.</li>
<li>Pilotear un helicóptero funciona en un espacio continuo de estados.</li>
</ul>
<p>La primera pregunta con la cual nos podemos encontrar es ¿Cómo podemos escalar los métodos de predicción y control sin modelo que hemos visto?</p>
<p>Bueno al intentar lograrlo nos trae ciertos problemas como:</p>
<ul>
<li>MDPs que tienen muchos estados y no pueden representarse en una tabla o en una base como lo hemos estado haciendo hasta el momento, debido a que la cantidad que ocuparían en memoria no sería eficiente.</li>
<li>Cuando existen tantos estados resulta muy lento aprender cada uno de estos individualmente.</li>
</ul>
<p>Hasta ahora hemos representado la función de valor en una tabla donde podíamos elegir qué acción tomar, eso no nos permitiría crecer si es que estuviéramos lidiando con un ambiente que tenga incontables estados y acciones, por otro lado esto también representaría que necesitaríamos una cantidad muy grande de episodios para tener el valor de cada acción para cada estado, lo cual termina siendo inviable en tiempo y en almacenamiento.</p>
<p>Debido a eso buscamos que nuestra función de valor sea capaz de generalizar a través de todos los estados que pudiera encontrar en el ambiente en el que se encuentra, lo cual no nos asegura que el valor que se le asigne a una acción en un estado sea necesariamente el valor óptimo, pero lo que sí representa es una aproximación muy cercana. Para lograrlo nos basamos en una función de valor que se aproxime al valor real, la cual permita que los valores que se estimen para cada acción o estado sea lo más parecido posible a la función de valor real e incluso pueda tener en cuenta el valor de estados que todavía no se han visitado.</p>
<p>Utilizando este principio podemos obtener diferentes tipos de aproximación de función de valor:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/aproximacion-de-funcion-de-valor/img-01.png" class="img-fluid figure-img"></p>
<figcaption>Fuente: David Silver, curso de RL de la UCL, clase 6.</figcaption>
</figure>
</div>
<ul>
<li>En el primer ejemplo nos muestra cómo se puede obtener el valor de un estado, al introducirlo dentro de nuestro aproximador de función.</li>
<li>En el segundo ejemplo se puede observar que al introducir un estado y qué acción estaríamos dispuestos a tomar, la función nos retornaría qué tanto valor nos daría tomar dicha acción.</li>
<li>En el último caso, dado el estado donde nos encontramos podríamos determinar el valor para cada una de las acciones que podemos tomar desde dicho estado.</li>
</ul>
<p>Dado que estamos buscando cómo aproximar nuestra función puede existir muchas alternativas, entre ellas las más usadas son:</p>
<ul>
<li>Combinación lineal de Features.</li>
<li>Red Neuronal.</li>
<li>Árboles de decisión, etc.</li>
</ul>
<p>¿Si hay tantas opciones entonces cuál deberíamos elegir? En este caso debemos centrarnos en aproximadores de función que sean <strong>diferenciables</strong> ya que conocemos hacia dónde se va a dirigir la gradiente de nuestra función debido a que tenemos la recompensa real de cada acción para cada estado (que es lo que se experimenta en cada episodio).</p>
</section>
<section id="métodos-incrementales" class="level2">
<h2 class="anchored" data-anchor-id="métodos-incrementales">Métodos incrementales</h2>
<p>Revisaremos algunos métodos para actualizar incrementalmente nuestra función de valor, antes de esto, por motivos de practicidad vamos a considerar que tenemos el valor real de la función de valor y queremos llegar a aprenderla con alguno de los métodos presentados a continuación.</p>
<section id="aproximación-de-función-de-valor-con-stochastic-gradient-descent" class="level3">
<h3 class="anchored" data-anchor-id="aproximación-de-función-de-valor-con-stochastic-gradient-descent">Aproximación de Función de Valor con Stochastic Gradient Descent</h3>
<p><a href="https://turing.iimas.unam.mx/~ivanvladimir/posts/gradient_descent/">Gradient Descent</a> busca minimizar el <a href="https://es.wikipedia.org/wiki/Error_cuadr%C3%A1tico_medio">MSE</a> sobre el valor que se aproxima en la función y el valor verdadero.</p>
<p>Aquí J(w) es el error cuadrático medio entre el valor verdadero y el aproximado:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AJ(%5Cmathbf%7Bw%7D)%20=%20%5Cmathbb%7BE%7D_%5Cpi%20%5Cleft%5B%20%5Cleft(%20v_%5Cpi(S)%20-%20%5Chat%7Bv%7D(S,%20%5Cmathbf%7Bw%7D)%20%5Cright)%5E2%20%5Cright%5D%0A"></p>
<p>La gradiente de J(w) se define como:</p>
<!-- antes una imagen: img-02.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cnabla_%7B%5Cmathbf%7Bw%7D%7D%20J(%5Cmathbf%7Bw%7D)%20=%0A%5Cbegin%7Bpmatrix%7D%0A%5Cdfrac%7B%5Cpartial%20J(%5Cmathbf%7Bw%7D)%7D%7B%5Cpartial%20%5Cmathbf%7Bw%7D_1%7D%20%5C%5C%0A%5Cvdots%20%5C%5C%0A%5Cdfrac%7B%5Cpartial%20J(%5Cmathbf%7Bw%7D)%7D%7B%5Cpartial%20%5Cmathbf%7Bw%7D_n%7D%0A%5Cend%7Bpmatrix%7D%0A"></p>
<p>Para encontrar el mínimo local de J(w) se debe ajustar en dirección de la gradiente:</p>
<!-- antes una imagen: img-03.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CDelta%20%5Cmathbf%7Bw%7D%20=%20-%5Cfrac%7B1%7D%7B2%7D%20%5Calpha%20%5Cnabla_%7B%5Cmathbf%7Bw%7D%7D%20J(%5Cmathbf%7Bw%7D)%0A"></p>
<p>Donde α representa con qué magnitud nos moveremos en dicha dirección. Para esto tomaremos una muestra aleatoria sobre una acción dado que nos encontramos en un estado, y la compararemos con el valor verdadero, utilizaremos gradient descent para decidir en qué dirección y con qué magnitud vamos a corregir nuestro error, entonces con esto logramos acercarnos cada vez más a la función verdadera basado en los resultados que tenemos al interactuar directamente con el ambiente.</p>
</section>
<section id="aproximación-de-función-de-valor-lineal" class="level3">
<h3 class="anchored" data-anchor-id="aproximación-de-función-de-valor-lineal">Aproximación de Función de Valor Lineal</h3>
<p>Un método para aproximar la función de valor es el lineal, está basado en una representación del estado donde nos encontramos, esto se puede realizar por medio de un Vector de Características (Feature Vector) el cual podría estar representado por la configuración actual de un tablero de ajedrez, las tendencias en el mercado de valores, etc. Esta representación termina siendo fundamental debido a que si captura correctamente el ambiente en el que se encuentra hará el problema mucho más fácil de resolver.</p>
<p>¿Cómo podemos utilizar ese vector de características? La forma más práctica es formando una combinación lineal de cada uno de sus valores, esto nos permitirá estimar el valor para cada caso utilizando la suma ponderada de cada una de las características que recibirá nuestra función.</p>
<!-- antes una imagen: img-04.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7Bv%7D(S,%20%5Cmathbf%7Bw%7D)%20=%20%5Cmathbf%7Bx%7D(S)%5E%5Ctop%20%5Cmathbf%7Bw%7D%20=%20%5Csum_%7Bj=1%7D%5E%7Bn%7D%20%5Cmathbf%7Bx%7D_j(S)%20%5Cmathbf%7Bw%7D_j%0A"></p>
<p>Para actualizar nuestros pesos se seguiría la siguiente regla, básicamente veremos qué tanto se asemeja nuestro resultado a la realidad y nos moveremos ligeramente con magnitud de α hacia esa dirección:</p>
<!-- antes una imagen: img-05.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CDelta%20%5Cmathbf%7Bw%7D%20=%20%5Calpha%20%5Cleft(%20v_%5Cpi(S)%20-%20%5Chat%7Bv%7D(S,%20%5Cmathbf%7Bw%7D)%20%5Cright)%20%5Cmathbf%7Bx%7D(S)%0A"></p>
</section>
<section id="algoritmos-de-predicción-incremental" class="level3">
<h3 class="anchored" data-anchor-id="algoritmos-de-predicción-incremental">Algoritmos de predicción incremental</h3>
<p>Hasta ahora se ha asumido que tenemos la capacidad de ver la verdadera función de valor, como una especie de “oráculo”, pero esto no ocurre en la realidad. En la práctica podemos encontrar valores que nos permiten estimar la función directamente desde la experiencia que obtenemos en el ambiente y veremos que las técnicas que hemos venido leyendo también pueden funcionar para este caso.</p>
<p><strong>Monte-Carlo</strong></p>
<!-- antes una imagen: img-06.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0A%5CDelta%20%5Cmathbf%7Bw%7D%20&amp;=%20%5Calpha%20%5Cleft(%20%7B%5Ccolor%7Bred%7D%20G_t%7D%20-%20%5Chat%7Bv%7D(S_t,%20%5Cmathbf%7Bw%7D)%20%5Cright)%20%5Cnabla_%7B%5Cmathbf%7Bw%7D%7D%20%5Chat%7Bv%7D(S_t,%20%5Cmathbf%7Bw%7D)%20%5C%5C%0A&amp;=%20%5Calpha%20%5Cleft(%20G_t%20-%20%5Chat%7Bv%7D(S_t,%20%5Cmathbf%7Bw%7D)%20%5Cright)%20%5Cmathbf%7Bx%7D(S_t)%0A%5Cend%7Baligned%7D%0A"></p>
<p>Como podemos observar se va a remplazar el valor “correcto” que poseíamos antes por el retorno total de un episodio, esto funcionará como un objetivo un poco ruidoso, que lentamente, dado que cada actualización se dará al fin de un episodio, nos llevará a la verdadera función de valor.</p>
<p>En pocas palabras utilizaremos la información de cada episodio como datos de entrenamiento, como si fuera entrenamiento supervisado.</p>
<p><strong>TD(0):</strong></p>
<!-- antes una imagen: img-07.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CDelta%20%5Cmathbf%7Bw%7D%20=%20%5Calpha%20%5Cleft(%20%7B%5Ccolor%7Bred%7D%20R%20+%20%5Cgamma%20%5Chat%7Bv%7D(S',%20%5Cmathbf%7Bw%7D)%7D%20-%20%5Chat%7Bv%7D(S,%20%5Cmathbf%7Bw%7D)%20%5Cright)%20%5Cnabla_%7B%5Cmathbf%7Bw%7D%7D%20%5Chat%7Bv%7D(S,%20%5Cmathbf%7Bw%7D)%0A"></p>
<p><strong>TD(</strong>λ<strong>):</strong></p>
<!-- antes una imagen: img-08.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CDelta%20%5Cmathbf%7Bw%7D%20=%20%5Calpha%20%5Cleft(%20%7B%5Ccolor%7Bred%7D%20G_t%5E%5Clambda%7D%20-%20%5Chat%7Bv%7D(S_t,%20%5Cmathbf%7Bw%7D)%20%5Cright)%20%5Cnabla_%7B%5Cmathbf%7Bw%7D%7D%20%5Chat%7Bv%7D(S_t,%20%5Cmathbf%7Bw%7D)%0A"></p>
<p>Para el caso de TD estimará un valor sesgado, esto se da porque se le pide a la propia función que estime cuál será la recompensa total que recibiremos hasta el final de la trayectoria, eso nos puede generar un error de lo que nuestra función creía era correcto y lo que realmente pasa en el ambiente, esto puede traer consecuencias negativas, como que no necesariamente converja en la función de valor real.</p>
</section>
<section id="control-con-aproximación-de-valor" class="level3">
<h3 class="anchored" data-anchor-id="control-con-aproximación-de-valor">Control con Aproximación de Valor</h3>
<p>Esta vez como control utilizaremos una evaluación de política se basará en utilizar el aproximador de función de valor que diseñamos y la cual nos ayudará a encontrar, luego de algunas iteraciones la función de valor más indicada dado los parámetros que ingresamos. En pocas palabras utilizaremos el mismo concepto que hemos revisado en este post, con la excepción de que en vez de centrarnos en V(s) nos centraremos en Q(s,a), pero utilizaremos exactamente los mismos conceptos que revisamos con Monte-Carlo y TD.</p>
</section>
</section>
<section id="métodos-de-batch" class="level2">
<h2 class="anchored" data-anchor-id="métodos-de-batch">Métodos de Batch</h2>
<p>Hasta ahora hemos visto métodos para actualizar nuestra función de valor luego de cada experiencia, pero esto no termina siendo eficiente debido a que al actualizar nuestra función con la experiencia que acaba de desarrollar nuestro agente la solemos desechar y continuar con una siguiente interacción con el ambiente, esto genera que el uso de los datos no sea eficiente, ya que cada experiencia solo se termina usando una vez y no permite que el agente encuentre realmente <strong>la mejor función de valor para todos los episodios</strong>, en este caso un Batch representaría a un conjunto de experiencias del agente.</p>
<section id="predicción-basada-en-mínimos-cuadrados" class="level3">
<h3 class="anchored" data-anchor-id="predicción-basada-en-mínimos-cuadrados">Predicción basada en mínimos cuadrados</h3>
<p>Podemos definir nuestros datos de entrenamiento de la misma manera que lo hemos hecho, es decir un par entre estado y valor y mejoraremos los valores de nuestra función al reducir la <a href="https://es.wikipedia.org/wiki/M%C3%ADnimos_cuadrados">suma del error cuadrático</a> entre lo que predice nuestra función y (para ejemplos prácticos) la función de valor verdadera, dicha función puede ser remplazada por el valor que obtenemos siguiendo Monte-Carlo o TD. La función de mínimos cuadrados se define con la siguiente fórmula.</p>
<!-- antes una imagen: img-09.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0ALS(%5Cmathbf%7Bw%7D)%20=%20%5Csum_%7Bt=1%7D%5E%7BT%7D%20%5Cleft(%20v_t%5E%5Cpi%20-%20%5Chat%7Bv%7D(s_t,%20%5Cmathbf%7Bw%7D)%20%5Cright)%5E2%0A"></p>
</section>
<section id="experience-replay" class="level3">
<h3 class="anchored" data-anchor-id="experience-replay"><strong>Experience Replay</strong></h3>
<p>Para hacer un uso correcto de las muestras que obtendremos en la interacción con el ambiente utilizaremos la técnica llamada <strong>experience replay</strong>, la cual consiste en que cada interacción que se dé con el ambiente y recompensa que nos otorgue quedará registrada dentro de una estructura de datos, luego se elegirá aleatoriamente un número de “experiencias” las cuales utilizaremos para entrenar nuestro algoritmo, de esta manera se puede romper la correlación entre los datos y generar una función mucho más estable. Se entrenará el algoritmo una y otra vez hasta que converja a la solución de mínimos cuadrados (con una red neuronal no hay garantía de que sea el mínimo global).</p>
</section>
</section>
<section id="implementación" class="level2">
<h2 class="anchored" data-anchor-id="implementación">Implementación</h2>
<p>A continuación comparto una implementación de aproximación de valor utilizando una red neuronal, el código también se puede encontrar <a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/blob/master/RL-7-FuncionDeAproximacionDeValor/Aproximaci%C3%B3n%20de%20Valor%20-%20Deep%20Q%20Network.ipynb">aquí</a>.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> gymnasium <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> gym <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#ambiente de prueba</span></span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> math </span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> torch</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> random</span>
<span id="cb1-5"></span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> torch.nn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> nn</span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> torch.nn.functional <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> F</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> torch.optim <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> optim</span>
<span id="cb1-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-11"></span>
<span id="cb1-12"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> display</span>
<span id="cb1-13"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> itertools <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> count</span>
<span id="cb1-14"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> collections <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> namedtuple</span>
<span id="cb1-15"></span>
<span id="cb1-16"></span>
<span id="cb1-17"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb1-18"></span>
<span id="cb1-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># guardamos el comportamiento para que sea replicable</span></span>
<span id="cb1-20">RANDOM_SEED <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">666</span></span>
<span id="cb1-21">torch.manual_seed(RANDOM_SEED)</span>
<span id="cb1-22">random.seed(RANDOM_SEED)</span>
<span id="cb1-23">np.random.seed(RANDOM_SEED)</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># arquitectura de la red neuronal</span></span>
<span id="cb2-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Net(nn.Module):</span>
<span id="cb2-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">__init__</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>):</span>
<span id="cb2-4">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">super</span>(Net, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>).<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">__init__</span>()</span>
<span id="cb2-5">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.fc1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nn.Linear(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">128</span>)</span>
<span id="cb2-6">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.fc2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nn.Linear(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">128</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb2-7"></span>
<span id="cb2-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> forward(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, x):</span>
<span id="cb2-9">        x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> F.relu(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.fc1(x))</span>
<span id="cb2-10">        x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.fc2(x)</span>
<span id="cb2-11">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> x</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ambiente que utilizaremos</span></span>
<span id="cb3-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># la documentación del ambiente https://gymnasium.farama.org/environments/classic_control/mountain_car/</span></span>
<span id="cb3-3">env <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gym.make(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MountainCar-v0'</span>)</span>
<span id="cb3-4">env.reset(seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>RANDOM_SEED)</span>
<span id="cb3-5">env.action_space.seed(RANDOM_SEED)</span>
<span id="cb3-6"></span>
<span id="cb3-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># la posición va de -1.2 a 0.6 y la velocidad de -0.07 a 0.07: llevamos las dos a la escala [-1, 1]</span></span>
<span id="cb3-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># para que la red "vea" la velocidad tanto como la posición.</span></span>
<span id="cb3-9">minimo, maximo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.observation_space.low, env.observation_space.high</span>
<span id="cb3-10"></span>
<span id="cb3-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> escalar(observacion):</span>
<span id="cb3-12">    observacion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (observacion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> (minimo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> maximo) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> ((maximo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> minimo) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb3-13">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> torch.from_numpy(observacion.reshape((<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)).copy()).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>()</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># creamos una red que contendrá la politica y </span></span>
<span id="cb4-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># otra red que servirá como target, las dos </span></span>
<span id="cb4-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># son iguales en arquitectura pero varían en la velocidad con que serán actualizadas.</span></span>
<span id="cb4-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># la red policy será actualizada en cada paso, la otra red empieza como una copia</span></span>
<span id="cb4-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># y en cada paso se acerca solo un poco a la red policy (ver TAU).</span></span>
<span id="cb4-6">policy_net <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Net()</span>
<span id="cb4-7">target_net <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Net()</span>
<span id="cb4-8">_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> target_net.load_state_dict(policy_net.state_dict())</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">Transition <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> namedtuple(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Transition'</span>,</span>
<span id="cb5-2">                        (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'state'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'action'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'next_state'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'reward'</span>))</span>
<span id="cb5-3"></span>
<span id="cb5-4"></span>
<span id="cb5-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> ReplayMemory(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">object</span>):</span>
<span id="cb5-6">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">'''Esta es la estructura donde se almacenará los pasos</span></span>
<span id="cb5-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">       que se ejecuten en el ambiente.'''</span></span>
<span id="cb5-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">__init__</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, capacity):</span>
<span id="cb5-9">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.capacity <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> capacity</span>
<span id="cb5-10">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.memory <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb5-11">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.position <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb5-12"></span>
<span id="cb5-13">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> push(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>args):</span>
<span id="cb5-14">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.memory) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.capacity:</span>
<span id="cb5-15">            <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.memory.append(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>)</span>
<span id="cb5-16">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.memory[<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.position] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Transition(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>args)</span>
<span id="cb5-17">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.position <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.position <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.capacity</span>
<span id="cb5-18"></span>
<span id="cb5-19">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> sample(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, batch_size):</span>
<span id="cb5-20">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> random.sample(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.memory, batch_size)</span>
<span id="cb5-21"></span>
<span id="cb5-22">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">__len__</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>):</span>
<span id="cb5-23">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.memory)</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">learning_rate <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-3</span></span>
<span id="cb6-2">optimizer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> optim.Adam(policy_net.parameters(), lr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>learning_rate)</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">steps_done <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb7-2">n_actions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span></span>
<span id="cb7-3">episode_durations <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb7-4"></span>
<span id="cb7-5">BATCH_SIZE <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2048</span></span>
<span id="cb7-6">GAMMA <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.995</span></span>
<span id="cb7-7">EPS_START <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.99</span></span>
<span id="cb7-8">EPS_END <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span></span>
<span id="cb7-9">EPS_DECAY <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8000</span></span>
<span id="cb7-10">TAU <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.005</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#capacidad de la memoria</span></span>
<span id="cb8-2">memory <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ReplayMemory(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20000</span>)</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> seleccionar_accion(state):</span>
<span id="cb9-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">global</span> steps_done</span>
<span id="cb9-3">    sample <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> random.random()</span>
<span id="cb9-4">    eps_threshold <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> EPS_END <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (EPS_START <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> EPS_END) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb9-5">        math.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> steps_done <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> EPS_DECAY)</span>
<span id="cb9-6">    steps_done <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb9-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> sample <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> eps_threshold:</span>
<span id="cb9-8">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">with</span> torch.no_grad():</span>
<span id="cb9-9">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> policy_net(state).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].view(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb9-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb9-11">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> torch.tensor([[random.randrange(n_actions)]], dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>torch.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">long</span>)</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> optimize_model():</span>
<span id="cb10-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(memory) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> BATCH_SIZE:</span>
<span id="cb10-3">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span></span>
<span id="cb10-4">    transitions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> memory.sample(BATCH_SIZE)</span>
<span id="cb10-5">    batch <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Transition(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>transitions))</span>
<span id="cb10-6">    non_final_mask <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.tensor(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">tuple</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">map</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> s: s <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>,</span>
<span id="cb10-7">                                          batch.next_state)),dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>torch.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">bool</span>)</span>
<span id="cb10-8">    non_final_next_states <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.cat([s <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> s <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> batch.next_state</span>
<span id="cb10-9">                                                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> s <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>])</span>
<span id="cb10-10">    state_batch <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.cat(batch.state)</span>
<span id="cb10-11">    action_batch <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.cat(batch.action)</span>
<span id="cb10-12">    reward_batch <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.cat(batch.reward)</span>
<span id="cb10-13"></span>
<span id="cb10-14">    state_action_values <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> policy_net(state_batch).gather(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, action_batch)</span>
<span id="cb10-15"></span>
<span id="cb10-16">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calcula V(s_{t+1}) para todos los estados siguientes.</span></span>
<span id="cb10-17">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># mayor detalle de la implementación puede ser encontrado en:</span></span>
<span id="cb10-18">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># https://pytorch.org/tutorials/intermediate/reinforcement_q_learning.html</span></span>
<span id="cb10-19">    next_state_values <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.zeros(BATCH_SIZE)</span>
<span id="cb10-20">    next_state_values[non_final_mask] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> target_net(non_final_next_states).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].detach()</span>
<span id="cb10-21">    expected_state_action_values <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (next_state_values <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> GAMMA) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> reward_batch</span>
<span id="cb10-22"></span>
<span id="cb10-23">    loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> F.mse_loss(state_action_values, expected_state_action_values.unsqueeze(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb10-24"></span>
<span id="cb10-25">    optimizer.zero_grad()</span>
<span id="cb10-26">    loss.backward()</span>
<span id="cb10-27">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> param <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> policy_net.parameters():</span>
<span id="cb10-28">        param.grad.data.clamp_(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb10-29">    optimizer.step()</span>
<span id="cb10-30">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> loss.item()</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> plot_durations():</span>
<span id="cb11-2">    plt.figure(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb11-3">    plt.clf()</span>
<span id="cb11-4">    durations_t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.tensor(reward_t, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>torch.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb11-5">    plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Training...'</span>)</span>
<span id="cb11-6">    plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Episode'</span>)</span>
<span id="cb11-7">    plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Reward'</span>)</span>
<span id="cb11-8">    plt.plot(durations_t.numpy())</span>
<span id="cb11-9">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Se toma el promedio de la duración de los ultimos 100 episodios y se grafica.</span></span>
<span id="cb11-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(durations_t) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>:</span>
<span id="cb11-11">        means <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> durations_t.unfold(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>).mean(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>).view(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb11-12">        means <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.cat((torch.repeat_interleave(means[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">99</span>), means))</span>
<span id="cb11-13">        plt.plot(means.numpy())</span>
<span id="cb11-14">    plt.pause(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>) </span>
<span id="cb11-15">    display.clear_output(wait<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">num_episodes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span></span>
<span id="cb12-2">loss_t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb12-3">reward_t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb12-4">loss_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span></span>
<span id="cb12-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i_episode <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(num_episodes):</span>
<span id="cb12-6">    state, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.reset()</span>
<span id="cb12-7">    state <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> escalar(state)</span>
<span id="cb12-8">    reward_acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb12-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> t <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> count():</span>
<span id="cb12-10">        accion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> seleccionar_accion(state)</span>
<span id="cb12-11">        observacion, reward, terminado, truncado, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.step(accion.item())</span>
<span id="cb12-12">        done <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> terminado <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> truncado</span>
<span id="cb12-13">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># si llegó a la bandera no hay estado siguiente: ese final vale 0.</span></span>
<span id="cb12-14">        next_state <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> terminado <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> escalar(observacion)</span>
<span id="cb12-15">        reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.tensor([reward])</span>
<span id="cb12-16">        reward_acc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> reward.item()</span>
<span id="cb12-17">        memory.push(state, accion, next_state, reward)</span>
<span id="cb12-18">        state <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> next_state</span>
<span id="cb12-19">        loss_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> optimize_model()</span>
<span id="cb12-20">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># la red target sigue a la red policy un poco en cada paso.</span></span>
<span id="cb12-21">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> target_param, policy_param <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(target_net.parameters(), policy_net.parameters()):</span>
<span id="cb12-22">            target_param.data.copy_(TAU <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> policy_param.data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> TAU) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> target_param.data)</span>
<span id="cb12-23">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> done:</span>
<span id="cb12-24">            episode_durations.append(t <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb12-25">            loss_t.append(loss_)</span>
<span id="cb12-26">            reward_t.append(reward_acc)</span>
<span id="cb12-27">            plot_durations()</span>
<span id="cb12-28">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span></code></pre></div></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/aproximacion-de-funcion-de-valor/dqn-entrenamiento.png" class="img-fluid figure-img"></p>
<figcaption>Recompensa por episodio durante el entrenamiento; en naranja, el promedio de los últimos 100 episodios.</figcaption>
</figure>
</div>
<p>Actualicé este código en octubre de 2026 (Python 3.14, Gymnasium 1.4.0, PyTorch 2.14). Al volver a ejecutar la versión de 2020, el carro casi nunca llegaba a la bandera, así que hice cinco cambios: cuando llega a la bandera no hay estado siguiente y ese final vale 0; la red target se acerca un poco a la red policy en cada paso en vez de copiarla de golpe; la tasa de aprendizaje bajó de 0.05 a 0.001; la exploración baja más despacio y hasta el 2 %; y la posición y la velocidad entran a la red en la misma escala. En una prueba con 2000 episodios el mejor promedio llegó cerca del episodio 1000 y luego bajó poco a poco, por eso aquí entreno 1000.</p>
<p>Gracias por haberme seguido hasta aquí, si tienes alguna duda (o algo en lo que crees que podría mejorar) no dudes en hablarme.</p>
</section>
<section id="referencias" class="level2">
<h2 class="anchored" data-anchor-id="referencias">Referencias</h2>
<ul>
<li><a href="https://davidstarsilver.wordpress.com/wp-content/uploads/2025/04/lecture-6-value-function-approximation-.pdf">UCL Course on RL Lecture 6: Value Function Approximation</a></li>
<li><a href="https://pytorch.org/tutorials/intermediate/reinforcement_q_learning.html">DQN Implementation in PyTorch</a></li>
<li><a href="http://incompleteideas.net/book/RLbook2018.pdf">Richard Sutton’s Intro to Reinforcement Learning</a></li>
</ul>


</section>

 ]]></description>
  <category>aprendizaje por refuerzo</category>
  <guid>https://migsilva.com/es/posts/aproximacion-de-funcion-de-valor/</guid>
  <pubDate>Sat, 26 Sep 2020 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Control sin modelo</title>
  <link>https://migsilva.com/es/posts/control-libre-de-modelo/</link>
  <description><![CDATA[ 





<p>En este capítulo nos centraremos en entender cómo un agente sin experiencia previa en un ambiente desconocido (el cual puede o no tener final) decide qué acciones debe desempeñar para maximizar la recompensa, para lograr esto nos basaremos en lo visto en el capítulo anterior, el cual trató de cómo estimar una función de valor para un MDP desconocido, en este caso buscaremos optimizar esa función utilizando técnicas que hemos visto antes y algunas nuevas, para comenzar revisaremos qué tipos de políticas podemos utilizar para esta clase de problemas.</p>
<section id="tipos-de-política" class="level2">
<h2 class="anchored" data-anchor-id="tipos-de-política">Tipos de política</h2>
<section id="aprendizaje-usando-política" class="level3">
<h3 class="anchored" data-anchor-id="aprendizaje-usando-política">Aprendizaje usando política</h3>
<p>Se sigue la política π, y mientras esto se hace también se le evalúa realizando muestras sobre ellas.</p>
</section>
<section id="aprendizaje-sin-utilizar-la-política" class="level3">
<h3 class="anchored" data-anchor-id="aprendizaje-sin-utilizar-la-política">Aprendizaje sin utilizar la política</h3>
<p>Se aprende de una política π utilizando muestras realizadas por otro u otros agentes, el ejemplo más entendible sería quizás observar el ejemplo de otra persona (o pedirle consejo a alguien para tomar una decisión) y guiarse de eso para saber qué tan bueno sería tomar una decisión.</p>
</section>
</section>
<section id="iteración-de-política-generalizada" class="level2">
<h2 class="anchored" data-anchor-id="iteración-de-política-generalizada">Iteración de Política Generalizada</h2>
<p>Como habíamos visto en capítulos anteriores la iteración de política está basada en una función que evalúe la política π y otra que se encargue de mejorarla, así sucesivamente hasta encontrar la política que nos dé la mejor recompensa, la cual sería nuestra política final. Por otro lado, si quisiéramos iniciar explorando este ambiente sin tener conocimientos previos de sus estados, ¿Cómo lo haríamos?</p>
<p>Para esto debemos tener claro que debemos elegir dos algoritmos, uno para la evaluación y otro para el mejoramiento de política, para evaluación podríamos utilizar un algoritmo que ya venimos conociendo un tiempo atrás, <strong>Monte-Carlo</strong>, como paso inicial, y para el caso del mejoramiento podríamos utilizar mejoramiento voraz (consiste en siempre elegir los casos que nos aseguran la mejor recompensa), de esta manera Monte-Carlo podría darnos los valores para cada acción y cada estado que visitamos, a la vez que el mejoramiento voraz nos daría una dirección en la cual deberíamos seguir dirigiéndonos para mejorar esta política, para que esto funcione, el mejoramiento voraz necesita un modelo de MDP.</p>
<p>Como vamos a centrarnos en encontrar el mejor valor para cada acción nuestra política tiene que estar basada en las posibles acciones que se pueden tomar desde un estado <em>s</em>, en otras palabras, en este nuevo escenario nos centraríamos en usar la política π para encontrar el valor de cada acción que se tomaría en cada estado <em>s</em>, y con esto elegir la acción que genere mayor valor a través de cada estado, generando una nueva política π.</p>
<p>La desventaja de utilizar este modelo es que se vería limitado por el mejoramiento voraz debido a que siempre tomaría la elección que nos diera el mayor valor inmediato, sin contemplar opciones que podrían ser más provechosas a largo plazo, en otras palabras, tener opción de mantener:</p>
<ul>
<li>Exploración continua.</li>
<li>Todas las acciones han sido probadas con probabilidades mayores a cero.</li>
</ul>
<section id="exploración-ε-greedy" class="level3">
<h3 class="anchored" data-anchor-id="exploración-ε-greedy">Exploración ε-Greedy</h3>
<p>Es por esto que nace el concepto de exploración ε-greedy, la cual nos permite tener una probabilidad de 1 — ε de escoger la mejor acción para nuestra política y una probabilidad de ε para escoger una acción totalmente aleatoria, con este método tendremos la posibilidad de visitar estados que no serían posibles de visitar escogiendo siempre el mejor estado, y por otro lado esto nos asegura como mínimo tener una solución igual de buena que la política actual, si es que no mejor.</p>
</section>
</section>
<section id="cómo-podemos-seguir-mejorando-nuestro-modelo" class="level2">
<h2 class="anchored" data-anchor-id="cómo-podemos-seguir-mejorando-nuestro-modelo">¿Cómo podemos seguir mejorando nuestro modelo?</h2>
<p>Ahora que ya hemos encontrado un método que nos ayuda a explorar el ambiente y en general a tener una mejor política, deberíamos buscar cómo mejorar la evaluación de la misma, al utilizar Monte-Carlo nos asegura llegar al mejor resultado pero no necesariamente por un proceso veloz, dicho esto haría falta elegir una forma más eficiente de evaluar dichas políticas, quizá podríamos comenzar por no esperar hasta recorrer cierto número de episodios para evaluar nuestra política, en cambio bastaría con evaluarla al final de un solo episodio, lo cual daría suficiente información para guiarnos hacia una ligeramente mejor política π.</p>
<p>Sin embargo debemos encontrar un balance entre el tiempo que nos tomará encontrar la mejor política y la cantidad de acciones aleatorias que tomaremos, es por esto que nace el concepto de GLIE.</p>
</section>
<section id="glie" class="level2">
<h2 class="anchored" data-anchor-id="glie">GLIE</h2>
<p>GLIE (Greedy in the Limit with Infinite Exploration) parte de la necesidad de limitar la exploración luego de que se hayan cumplido sus dos pilares fundamentales:</p>
<ul>
<li>Todas las acciones por cada estado han sido exploradas una infinidad de veces.</li>
<li>La política al final convergerá en una política voraz.</li>
</ul>
<p>Una forma de llegar a eso es por medio de ε-greedy, la cual se podría convertir en una política voraz si ε tiende a 0 con el paso del tiempo, aquí dejo una <a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/blob/master/RL-6-ControlSinModelo/GLIE%20Monte-Carlo%20Control.ipynb">implementación en Python</a> para que veas detalladamente cómo funciona.</p>
<p>Una pregunta que nacería naturalmente con la experimentación sería la siguiente, ¿Cómo podríamos actualizar nuestra política si estamos hablando de un ambiente continuo (Online)? Qué acción deberíamos tomar si es que no podemos esperar hasta el final del episodio para actualizar nuestra política, por este motivo nos centraremos en una herramienta que habíamos visto en el capítulo pasado, <strong>TD Learning</strong> como método de evaluación de política, este algoritmo también posee otros beneficios aparte de ser un entrenamiento “Online”, como disminuir la varianza y actualizar nuestra política aunque las secuencias no sean completadas del todo.</p>
</section>
<section id="sarsa" class="level2">
<h2 class="anchored" data-anchor-id="sarsa">SARSA</h2>
<p>Al usar TD Learning como método de evaluación y ε-greedy como método de actualización llegamos al algoritmo SARSA, el cual significa:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/control-libre-de-modelo/img-02.jpeg" class="img-fluid figure-img"></p>
<figcaption>Estado S -&gt; Acción A -&gt; Recompensa R -&gt; Estado S’ -&gt; Acción A’. Fuente: David Silver, curso de RL de la UCL, clase 5.</figcaption>
</figure>
</div>
<p>Dicho algoritmo representa un patrón de actualización para nuestra política explicado por la siguiente fórmula:</p>
<!-- antes una imagen: img-03.jpeg -->
<p><img src="https://latex.codecogs.com/png.latex?%0AQ(S,%20A)%20%5Cleftarrow%20Q(S,%20A)%20+%20%5Calpha%20%5Cleft(%20R%20+%20%5Cgamma%20Q(S',%20A')%20-%20Q(S,%20A)%20%5Cright)%0A"></p>
<p>De esta manera se actualiza nuestro valor para cada par estado-acción dependiendo de las acciones que se podrán tomar desde ese punto.</p>
<p>SARSA se centra en actualizar nuestro valor inicial para el estado <em>s</em> y la acción <em>a</em> sumándole <a href="../../../es/posts/predicciones-sin-modelo/index.html#cómo-funciona-el-td">TD Target</a> menos nuestro valor de ese par original todo esto multiplicado por un valor α, que representa el impacto con el cual se actualizará los valores, como quedó claro esto se va a actualizar cada vez que se tome una acción en nuestro ambiente, eso significa que si volvemos a caer en un estado que ya ha sido visitado, vamos a tener un valor actualizado de ese estado con la última información que pudimos recabar.</p>
</section>
<section id="sarsa-λ" class="level2">
<h2 class="anchored" data-anchor-id="sarsa-λ">SARSA λ</h2>
<p>SARSA λ nos da lo mejor de los dos algoritmos que hemos visto anteriormente en este capítulo, SARSA λ nos permite variar qué tanto deseamos “recordar” (al igual que TD λ) los estados y acciones que hemos visitado, nos ayuda a decidir en qué medida valoramos estas acciones y estados ejecutados en el mismo episodio en pasos anteriores con respecto a nuestra actualización de valores, a continuación se muestra gráficamente cómo el valor de los estados visitados en el pasado se ven afectados por la constante λ, que en cada paso se multiplicará de nuevo por el mismo factor, para así decrecer el impacto de ese paso en el tiempo.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/control-libre-de-modelo/img-04.jpeg" class="img-fluid figure-img"></p>
<figcaption>Fuente: David Silver, curso de RL de la UCL, clase 5.</figcaption>
</figure>
</div>
<p>De esta manera se promedian todos los pasos realizados desde el inicio del episodio hasta ese momento en el tiempo para actualizar los valores de los estados y acciones visitados.<br>
En el algoritmo también tendremos en cuenta <a href="../../../es/posts/predicciones-sin-modelo/index.html#rastros-de-elegibilidad">rastros de elegibilidad</a>, en este caso representados por Et(<em>s, a</em>). Al ejecutarse la actualización tendremos en cuenta el TD-Error representado con δ, siempre todo multiplicado por un valor de α que representa la magnitud de actualización de nuestros valores como se muestra en la siguiente fórmula:</p>
<!-- antes una imagen: img-05.jpeg -->
<p><img src="https://latex.codecogs.com/png.latex?%0AE_t(s,%20a)%20=%20%5Cgamma%20%5Clambda%20E_%7Bt-1%7D(s,%20a)%20+%20%5Cmathbf%7B1%7D(S_t%20=%20s,%20A_t%20=%20a)%0A"></p>
<!-- antes una imagen: img-06.jpeg -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0A%5Cdelta_t%20&amp;=%20R_%7Bt+1%7D%20+%20%5Cgamma%20Q(S_%7Bt+1%7D,%20A_%7Bt+1%7D)%20-%20Q(S_t,%20A_t)%20%5C%5C%0AQ(s,%20a)%20&amp;%5Cleftarrow%20Q(s,%20a)%20+%20%5Calpha%20%5Cdelta_t%20E_t(s,%20a)%0A%5Cend%7Baligned%7D%0A"></p>
<p>A continuación una <a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/blob/master/RL-6-ControlSinModelo/SARSA%20Lambda.ipynb">implementación de SARSA λ en Python</a> para que el concepto quede más claro.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center collapsed" data-bs-toggle="collapse" data-bs-target=".callout-1-contents" aria-controls="callout-1" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Nota</span>Código: SARSA λ
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-1" class="callout-1-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p>Usa la función <code>e_greedy</code> de <code>utils.py</code>, que está en Implementación. El notebook completo está en <a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/blob/master/RL-6-ControlSinModelo/SARSA%20Lambda.ipynb">GitHub</a>.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> gymnasium <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> gym <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># para elegir el ambiente en el cual entrenaremos el agente.</span></span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb1-3"></span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># para disponer de la data de forma mas organizada.</span></span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># para mostrar gráficos.</span></span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#para el procesamiento de números.</span></span>
<span id="cb1-7"></span>
<span id="cb1-8">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">666</span>)</span>
<span id="cb1-9"></span>
<span id="cb1-10"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb1-11"></span>
<span id="cb1-12"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> collections <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> defaultdict <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#utilizaremos un defaultdict como base</span></span>
<span id="cb1-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># en la cual guardaremos el valor que tendrá cada una de nuestras acciones.</span></span>
<span id="cb1-14"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> utils <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> e_greedy</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">env <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gym.make(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'FrozenLake-v1'</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#este es el ambiente que utilizaremos,</span></span>
<span id="cb2-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># puedes buscar como funciona en la documentación.</span></span>
<span id="cb2-3">_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.reset(seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">666</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#fija la semilla del ambiente, para poder repetir el resultado</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">numero_de_acciones <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.action_space.n</span>
<span id="cb3-2">Q <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> defaultdict(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span>: np.zeros(numero_de_acciones)) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se define nuestra base como un diccionario anidado con cada acción </span></span>
<span id="cb3-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#que podría tomar el agente.</span></span>
<span id="cb3-4">decay <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0000042</span></span>
<span id="cb3-5">decay <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> decay <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#este valor será por el cual decaerá nuestro epsilon en cada episodio. </span></span>
<span id="cb3-6">alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0005</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#nuestro valor de "media movil" se verá afectado por esta variable. </span></span>
<span id="cb3-7">lambd <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable lambda de TD(lambda).</span></span>
<span id="cb3-8">gamma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable por la cual verá reducido la elegibilidad de cada estado.</span></span>
<span id="cb3-9"></span>
<span id="cb3-10">episode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb3-11">total_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb3-12">eps <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> epsilon <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># valor de epsilon inicial</span></span>
<span id="cb3-13">eps_list <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable que almacenará los valores de epsilon.</span></span>
<span id="cb3-14">reward_list <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [] <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable que almacenará los valores de recompensa.</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> numb_iter <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1200001</span>):</span>
<span id="cb4-2">    estado_anterior, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.reset()</span>
<span id="cb4-3">    epsilon<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> eps<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>decay<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span>episode  </span>
<span id="cb4-4">    reward_list.append(total_reward)</span>
<span id="cb4-5">    total_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb4-6">    episode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb4-7">    actions_prob <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> e_greedy(Q, epsilon, numero_de_acciones, estado_anterior) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable que almacenará la probabilidad de realizar cada acción. </span></span>
<span id="cb4-8">    selected_next_action <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argmax(np.random.multinomial(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, actions_prob)) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se elige la acción.</span></span>
<span id="cb4-9">    counter_state_actions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#esta variable almacenará cada que accion se realice por cada episodio.</span></span>
<span id="cb4-10">    elegibilidad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> defaultdict(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span>: np.zeros(numero_de_acciones)) </span>
<span id="cb4-11">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>:   </span>
<span id="cb4-12">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ob, ac <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> counter_state_actions:</span>
<span id="cb4-13">            elegibilidad[ob][ac]  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*=</span> lambd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> gamma </span>
<span id="cb4-14">        elegibilidad[estado_anterior][selected_next_action] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span></span>
<span id="cb4-15">        obs, temporal_reward, terminado, truncado, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.step(selected_next_action)</span>
<span id="cb4-16">        final <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> terminado <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> truncado <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#el episodio acaba por el ambiente (terminado) o por el límite de pasos (truncado)</span></span>
<span id="cb4-17">        counter_state_actions.add((estado_anterior, selected_next_action))</span>
<span id="cb4-18">        selected_action <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> selected_next_action</span>
<span id="cb4-19">        actions_prob <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> e_greedy(Q, epsilon, numero_de_acciones, obs) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable que almacenará la probabilidad de realizar cada acción. </span></span>
<span id="cb4-20">        selected_next_action <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argmax(np.random.multinomial(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, actions_prob)) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se elige la acción.   </span></span>
<span id="cb4-21">        td_error <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> temporal_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> gamma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> Q[obs][selected_next_action] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> Q[estado_anterior][selected_action]</span>
<span id="cb4-22">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ob, ac <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> counter_state_actions:</span>
<span id="cb4-23">            Q[ob][ac] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> td_error <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> elegibilidad[ob][ac]</span>
<span id="cb4-24">        estado_anterior <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> obs</span>
<span id="cb4-25">        total_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> temporal_reward</span>
<span id="cb4-26">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> final:</span>
<span id="cb4-27">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> episode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100000</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb4-28">                <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Número de Episodios Realizados: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>episode<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)           </span>
<span id="cb4-29">            eps_list.append(epsilon)</span>
<span id="cb4-30">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span></code></pre></div></div>
<div class="nb-output">
<pre><code>Número de Episodios Realizados: 100000
Número de Episodios Realizados: 200000
Número de Episodios Realizados: 300000
Número de Episodios Realizados: 400000
Número de Episodios Realizados: 500000
Número de Episodios Realizados: 600000
Número de Episodios Realizados: 700000
Número de Episodios Realizados: 800000
Número de Episodios Realizados: 900000
Número de Episodios Realizados: 1000000
Número de Episodios Realizados: 1100000
Número de Episodios Realizados: 1200000</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>)) </span>
<span id="cb6-2">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Valor de Epsilon atraves de Episodios'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, pad<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)</span>
<span id="cb6-3">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Episodios'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb6-4">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Epsilon'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb6-5"></span>
<span id="cb6-6">plt.plot(eps_list, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>)</span></code></pre></div></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/control-libre-de-modelo/sarsa-lambda-epsilon.png" class="img-fluid figure-img"></p>
<figcaption>SARSA λ: valor de epsilon a través de los episodios.</figcaption>
</figure>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Reward'</span>: reward_list})</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)) </span>
<span id="cb8-2">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Promedio de Recompensa cada 3000 Episodios'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, pad<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)</span>
<span id="cb8-3">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Episodios Agrupados'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb8-4">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Recompensa Promedio'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb8-5">plt.plot(df.groupby(df.index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3000</span>)[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Reward'</span>].mean(), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'g'</span>)</span></code></pre></div></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/control-libre-de-modelo/sarsa-lambda-recompensa.png" class="img-fluid figure-img"></p>
<figcaption>SARSA λ: promedio de recompensa cada 3000 episodios.</figcaption>
</figure>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1">Q</span></code></pre></div></div>
<div class="nb-output">
<pre><code>defaultdict(&lt;function __main__.&lt;lambda&gt;()&gt;,
            {0: array([0.16733262, 0.16103185, 0.16177678, 0.15851396]),
             4: array([0.19578473, 0.14968439, 0.13750081, 0.12255647]),
             8: array([0.14391385, 0.19412623, 0.18207562, 0.25883041]),
             9: array([0.23948054, 0.36279075, 0.27932647, 0.20617548]),
             10: array([0.38405777, 0.33235978, 0.26832376, 0.16180898]),
             11: array([0., 0., 0., 0.]),
             5: array([0., 0., 0., 0.]),
             1: array([0.08180946, 0.08496883, 0.07703245, 0.14855739]),
             12: array([0., 0., 0., 0.]),
             14: array([0.51119489, 0.71401638, 0.68548844, 0.61231512]),
             13: array([0.25990588, 0.37702804, 0.49237952, 0.34040207]),
             2: array([0.14554138, 0.12068572, 0.1232465 , 0.10899049]),
             6: array([0.156147  , 0.11502148, 0.16282666, 0.04060761]),
             3: array([0.03554855, 0.03659547, 0.03113266, 0.11893593]),
             7: array([0., 0., 0., 0.]),
             15: array([0., 0., 0., 0.])})</code></pre>
</div>
</div>
</div>
</div>
</section>
<section id="aprendizaje-fuera-de-política" class="level2">
<h2 class="anchored" data-anchor-id="aprendizaje-fuera-de-política">Aprendizaje Fuera de Política</h2>
<p>Hasta este punto dentro de todos los capítulos solo hemos observado la capacidad de aprender de la misma política que estamos evaluando pero esto no siempre es el caso, es aquí donde nace el concepto de aprendizaje fuera de política el cual se basa en evaluar una política objetivo mientras se sigue otra llamada de comportamiento, un ejemplo de esto sería tener una política exploratoria como política de comportamiento y tener una política objetivo que esté basada en la elección de la acción que nos dé mayor valor, esto nos puede ayudar a balancear el concepto de la <strong>exploración vs explotación</strong> uno de los problemas esenciales dentro del Aprendizaje por Refuerzo. Otro motivo por el cual podría interesarnos es que permite aprender múltiples políticas (teniéndolas como políticas objetivo) mientras se sigue la política de comportamiento.</p>
<p><strong>Q-Learning</strong></p>
<p>Es aquí donde nace el concepto de Q-Learning, con la aplicación del concepto de aprendizaje fuera de política hacia algoritmos que permitan disminuir la variación de la misma, como SARSA, el funcionamiento de estos conceptos juntos es el siguiente, se centra en que la política de comportamiento sea la que siempre elija qué acción tomar y a su vez se contempla qué valor puede tener una siguiente acción tomada de la política objetivo, de esta manera nos ayudaría a medir mejor el valor de la acción actual tomando en cuenta ambas políticas.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/control-libre-de-modelo/img-07.jpeg" class="img-fluid figure-img"></p>
<figcaption>Fuente: David Silver, curso de RL de la UCL, clase 5.</figcaption>
</figure>
</div>
<p>Dicho modelo tiene como objetivo mejorar la política objetivo y de comportamiento, y para lograr esto Q-Learning utiliza una política voraz como objetivo (para tener el valor de la mejor acción posible) y una política de comportamiento ε-greedy (para que tengamos la totalidad de estados y acciones explorados), esto nos lleva, por medio de la ecuación de Bellman a encontrar la política óptima.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center collapsed" data-bs-toggle="collapse" data-bs-target=".callout-2-contents" aria-controls="callout-2" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Nota</span>Código: Q-Learning
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-2" class="callout-2-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p>Usa la función <code>e_greedy</code> de <code>utils.py</code>, que está en Implementación. El notebook completo está en <a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/blob/master/RL-6-ControlSinModelo/Q-Learning.ipynb">GitHub</a>.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> gymnasium <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> gym <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># para elegir el ambiente en el cual entrenaremos el agente.</span></span>
<span id="cb11-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb11-3"></span>
<span id="cb11-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># para disponer de la data de forma mas organizada.</span></span>
<span id="cb11-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># para mostrar gráficos.</span></span>
<span id="cb11-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#para el procesamiento de números.</span></span>
<span id="cb11-7"></span>
<span id="cb11-8">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">666</span>)</span>
<span id="cb11-9"></span>
<span id="cb11-10"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb11-11"></span>
<span id="cb11-12"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> collections <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> defaultdict <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#utilizaremos un defaultdict como base</span></span>
<span id="cb11-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># en la cual guardaremos el valor que tendrá cada una de nuestras acciones.</span></span>
<span id="cb11-14"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> utils <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> e_greedy</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">env <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gym.make(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'FrozenLake-v1'</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#este es el ambiente que utilizaremos,</span></span>
<span id="cb12-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># puedes buscar como funciona en la documentación.</span></span>
<span id="cb12-3">_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.reset(seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">666</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#fija la semilla del ambiente, para poder repetir el resultado</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">numero_de_acciones <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.action_space.n</span>
<span id="cb13-2">Q <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> defaultdict(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span>: np.zeros(numero_de_acciones)) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se define nuestra base como un diccionario anidado con cada acción </span></span>
<span id="cb13-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#que podría tomar el agente.</span></span>
<span id="cb13-4">decay <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0000042</span></span>
<span id="cb13-5">decay <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> decay <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#este valor será por el cual decaerá nuestro epsilon en cada episodio. </span></span>
<span id="cb13-6">alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0005</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#nuestro valor de "media movil" se verá afectado por esta variable. </span></span>
<span id="cb13-7">gamma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.95</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#factor de descuento de las recompensas futuras.</span></span>
<span id="cb13-8"></span>
<span id="cb13-9">episode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb13-10">total_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb13-11">eps <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> epsilon <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># valor de epsilon inicial</span></span>
<span id="cb13-12">eps_list <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable que almacenará los valores de epsilon.</span></span>
<span id="cb13-13">reward_list <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [] <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable que almacenará los valores de recompensa.</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> numb_iter <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1200000</span>):</span>
<span id="cb14-2">    estado_anterior, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.reset()</span>
<span id="cb14-3">    epsilon<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> eps<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>decay<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span>episode  </span>
<span id="cb14-4">    reward_list.append(total_reward)</span>
<span id="cb14-5">    total_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb14-6">    episode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb14-7">    actions_prob <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> e_greedy(Q, epsilon, numero_de_acciones, estado_anterior) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable que almacenará la probabilidad de realizar cada acción. </span></span>
<span id="cb14-8">    selected_next_action <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argmax(np.random.multinomial(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, actions_prob)) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se elige la acción.</span></span>
<span id="cb14-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>:   </span>
<span id="cb14-10">        obs, temporal_reward, terminado, truncado, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.step(selected_next_action)</span>
<span id="cb14-11">        final <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> terminado <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> truncado <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#el episodio acaba por el ambiente (terminado) o por el límite de pasos (truncado)</span></span>
<span id="cb14-12">        selected_action <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> selected_next_action</span>
<span id="cb14-13">        actions_prob <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> e_greedy(Q, epsilon, numero_de_acciones, obs) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable que almacenará la probabilidad de realizar cada acción. </span></span>
<span id="cb14-14">        selected_next_action <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argmax(np.random.multinomial(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, actions_prob)) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se elige la acción.   </span></span>
<span id="cb14-15">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#solo se actualiza el valor del par (estado, acción) que se acaba de jugar.</span></span>
<span id="cb14-16">        Q[estado_anterior][selected_action] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (temporal_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> gamma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> Q[obs][np.argmax(Q[obs])] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> Q[estado_anterior][selected_action])</span>
<span id="cb14-17">        estado_anterior <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> obs</span>
<span id="cb14-18">        total_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> temporal_reward</span>
<span id="cb14-19">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> final:</span>
<span id="cb14-20">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> episode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100000</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb14-21">                <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Número de Episodios Realizados: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>episode<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)           </span>
<span id="cb14-22">            eps_list.append(epsilon)</span>
<span id="cb14-23">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span></code></pre></div></div>
<div class="nb-output">
<pre><code>Número de Episodios Realizados: 100000
Número de Episodios Realizados: 200000
Número de Episodios Realizados: 300000
Número de Episodios Realizados: 400000
Número de Episodios Realizados: 500000
Número de Episodios Realizados: 600000
Número de Episodios Realizados: 700000
Número de Episodios Realizados: 800000
Número de Episodios Realizados: 900000
Número de Episodios Realizados: 1000000
Número de Episodios Realizados: 1100000</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>)) </span>
<span id="cb16-2">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Valor de Epsilon atraves de Episodios'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, pad<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)</span>
<span id="cb16-3">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Episodios'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb16-4">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Epsilon'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb16-5"></span>
<span id="cb16-6">plt.plot(eps_list, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>)</span></code></pre></div></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/control-libre-de-modelo/q-learning-epsilon.png" class="img-fluid figure-img"></p>
<figcaption>Q-Learning: valor de epsilon a través de los episodios.</figcaption>
</figure>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Reward'</span>: reward_list})</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)) </span>
<span id="cb18-2">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Promedio de Recompensa cada 3000 Episodios'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, pad<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)</span>
<span id="cb18-3">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Episodios Agrupados'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb18-4">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Recompensa Promedio'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb18-5">plt.plot(df.groupby(df.index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3000</span>)[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Reward'</span>].mean(), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'g'</span>)</span></code></pre></div></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/control-libre-de-modelo/q-learning-recompensa.png" class="img-fluid figure-img"></p>
<figcaption>Q-Learning: promedio de recompensa cada 3000 episodios.</figcaption>
</figure>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1">Q</span></code></pre></div></div>
<div class="nb-output">
<pre><code>defaultdict(&lt;function __main__.&lt;lambda&gt;()&gt;,
            {0: array([0.17856144, 0.17272719, 0.17200595, 0.16327648]),
             4: array([0.20632593, 0.15377256, 0.14341815, 0.12079893]),
             8: array([0.15352161, 0.20156184, 0.17962873, 0.26638579]),
             9: array([0.24547571, 0.37216881, 0.28660106, 0.21416926]),
             10: array([0.39754283, 0.34687734, 0.28611501, 0.17309577]),
             11: array([0., 0., 0., 0.]),
             5: array([0., 0., 0., 0.]),
             1: array([0.10618972, 0.10638551, 0.0968513 , 0.15523046]),
             12: array([0., 0., 0., 0.]),
             14: array([0.51967362, 0.71992915, 0.68593507, 0.61697365]),
             13: array([0.28509968, 0.38470453, 0.50802292, 0.34783627]),
             2: array([0.15355193, 0.14461999, 0.14359513, 0.13668374]),
             6: array([0.17064613, 0.1312255 , 0.17391164, 0.04847348]),
             3: array([0.05037522, 0.04821116, 0.03926747, 0.13154451]),
             7: array([0., 0., 0., 0.]),
             15: array([0., 0., 0., 0.])})</code></pre>
</div>
</div>
</div>
</div>
</section>
<section id="implementación" class="level2">
<h2 class="anchored" data-anchor-id="implementación">Implementación</h2>
<p>A continuación comparto una implementación de Monte-Carlo, pero en <a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/tree/master/RL-6-ControlSinModelo"><strong>mi repositorio de GitHub tengo implementaciones de Q-Learning y SARSA.</strong></a></p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center collapsed" data-bs-toggle="collapse" data-bs-target=".callout-3-contents" aria-controls="callout-3" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Nota</span>Código de apoyo: <code>utils.py</code>
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-3" class="callout-3-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb21-2"></span>
<span id="cb21-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> e_greedy(Q, epsilon, nA, observation):</span>
<span id="cb21-4">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">'''Retorna la mejor acción dada la politica Q, esto </span></span>
<span id="cb21-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    siempre con la probabilidad epsilon de elegir una acción</span></span>
<span id="cb21-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    al azar'''</span></span>
<span id="cb21-7">    A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.ones(nA) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> epsilon <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> nA</span>
<span id="cb21-8">    best_action <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argmax(Q[observation])</span>
<span id="cb21-9">    A[best_action] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> (<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> epsilon)</span>
<span id="cb21-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> A</span></code></pre></div></div>
</div>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> gymnasium <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> gym <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># para elegir el ambiente en el cual entrenaremos el agente.</span></span>
<span id="cb22-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb22-3"></span>
<span id="cb22-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># para disponer de la data de forma mas organizada.</span></span>
<span id="cb22-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># para mostrar gráficos.</span></span>
<span id="cb22-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#para el procesamiento de números.</span></span>
<span id="cb22-7"></span>
<span id="cb22-8">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">777</span>)</span>
<span id="cb22-9"></span>
<span id="cb22-10"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span>matplotlib inline</span>
<span id="cb22-11"></span>
<span id="cb22-12"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> collections <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> defaultdict <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#utilizaremos un defaultdict como base</span></span>
<span id="cb22-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># en la cual guardaremos el valor que tendrá cada una de nuestras acciones. </span></span>
<span id="cb22-14"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> utils <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> e_greedy</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1">env <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gym.make(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'FrozenLake-v1'</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#este es el ambiente que utilizaremos,</span></span>
<span id="cb23-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># puedes buscar como funciona en la documentación.</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1">numero_de_acciones <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.action_space.n</span>
<span id="cb24-2">Q <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> defaultdict(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span>: np.zeros(numero_de_acciones)) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se define nuestra base como un diccionario anidado con cada acción </span></span>
<span id="cb24-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#que podría tomar el agente.</span></span>
<span id="cb24-4"></span>
<span id="cb24-5"></span>
<span id="cb24-6">decay <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0000042</span></span>
<span id="cb24-7">decay <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> decay <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#este valor será por el cual decaerá nuestro epsilon en cada episodio. </span></span>
<span id="cb24-8"></span>
<span id="cb24-9">alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#nuestro valor de "media movil" se verá afectado por esta variable. </span></span>
<span id="cb24-10"></span>
<span id="cb24-11">episode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb24-12">counter_state_actions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#esta variable almacenará cada que accion se realice por cada episodio.</span></span>
<span id="cb24-13">total_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb24-14">constante <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> epsilon <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># valor de epsilon inicial</span></span>
<span id="cb24-15">obs, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.reset(seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">777</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#inicia el ambiente (con semilla, para poder repetir el resultado)</span></span>
<span id="cb24-16">eps_list <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable que almacenará los valores de epsilon.</span></span>
<span id="cb24-17">reward_list <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [] <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable que almacenará los valores de recompensa.</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb25" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb25-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> numb_iter <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1200001</span>):</span>
<span id="cb25-2">    episode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb25-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>:   </span>
<span id="cb25-4">        actions_prob <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> e_greedy(Q, epsilon, numero_de_acciones, obs) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable que almacenará la probabilidad de realizar cada acción. </span></span>
<span id="cb25-5">        selected_action <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argmax(np.random.multinomial(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, actions_prob)) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se elige la acción de acuerdo a las probabilidades que ocurran.</span></span>
<span id="cb25-6">        counter_state_actions.add((obs, selected_action)) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se agrega la acción y el estado en donde se encuentra  </span></span>
<span id="cb25-7">        obs, temporal_reward, terminado, truncado, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.step(selected_action)</span>
<span id="cb25-8">        final <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> terminado <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> truncado <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#el episodio acaba por el ambiente (terminado) o por el límite de pasos (truncado)</span></span>
<span id="cb25-9">        total_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> temporal_reward</span>
<span id="cb25-10">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> final:</span>
<span id="cb25-11">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> episode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100000</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb25-12">                <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Número de Episodios Realizados: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>episode<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)         </span>
<span id="cb25-13">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> ob, ac <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> counter_state_actions:</span>
<span id="cb25-14">                Q[ob][ac] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (total_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> Q[ob][ac]) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se actualiza el valor de cada acción en cada estado que estuvo involucrado.</span></span>
<span id="cb25-15">            eps_list.append(epsilon)</span>
<span id="cb25-16">            epsilon<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> constante<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>decay<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span>episode <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#decae epsilon</span></span>
<span id="cb25-17">            obs, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> env.reset()</span>
<span id="cb25-18">            reward_list.append(total_reward)</span>
<span id="cb25-19">            total_reward <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb25-20">            counter_state_actions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>()</span>
<span id="cb25-21">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span></code></pre></div></div>
<div class="nb-output">
<pre><code>Número de Episodios Realizados: 100000
Número de Episodios Realizados: 200000
Número de Episodios Realizados: 300000
Número de Episodios Realizados: 400000
Número de Episodios Realizados: 500000
Número de Episodios Realizados: 600000
Número de Episodios Realizados: 700000
Número de Episodios Realizados: 800000
Número de Episodios Realizados: 900000
Número de Episodios Realizados: 1000000
Número de Episodios Realizados: 1100000
Número de Episodios Realizados: 1200000</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb27-1">plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>)) </span>
<span id="cb27-2">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Valor de Epsilon atraves de Episodios'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, pad<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)</span>
<span id="cb27-3">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Episodios'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb27-4">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Epsilon'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb27-5">plt.plot(eps_list, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>)</span></code></pre></div></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/control-libre-de-modelo/glie-epsilon.png" class="img-fluid figure-img"></p>
<figcaption>Valor de epsilon a través de los episodios.</figcaption>
</figure>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb28" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb28-1">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Reward'</span>: reward_list})</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb29" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb29-1">plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)) </span>
<span id="cb29-2">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Promedio de Recompensa cada 3000 Episodios'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, pad<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)</span>
<span id="cb29-3">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Episodios Agrupados'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb29-4">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Recompensa Promedio'</span>, fontsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb29-5">plt.plot(df.groupby(df.index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3000</span>)[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Reward'</span>].mean(), color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'g'</span>)</span></code></pre></div></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/control-libre-de-modelo/glie-recompensa.png" class="img-fluid figure-img"></p>
<figcaption>Promedio de recompensa cada 3000 episodios.</figcaption>
</figure>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb30" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb30-1">Q</span></code></pre></div></div>
<div class="nb-output">
<pre><code>defaultdict(&lt;function __main__.&lt;lambda&gt;()&gt;,
            {0: array([0.64872188, 0.55519318, 0.54045388, 0.57202126]),
             4: array([0.65117279, 0.45329994, 0.36016008, 0.3863543 ]),
             8: array([0.40491151, 0.36500373, 0.42262894, 0.65842282]),
             1: array([0.36167407, 0.29727266, 0.25546344, 0.47366043]),
             2: array([0.31830702, 0.32369242, 0.32672494, 0.45373966]),
             6: array([0.25790535, 0.23705466, 0.33795361, 0.14804296]),
             9: array([0.44831155, 0.66724437, 0.47154336, 0.42305228]),
             10: array([0.60447847, 0.52296887, 0.4014465 , 0.36710678]),
             13: array([0.45479967, 0.60880903, 0.73733508, 0.52526832]),
             14: array([0.71509948, 0.85752314, 0.80282114, 0.78027574]),
             3: array([0.20558106, 0.23756616, 0.25399436, 0.4225149 ])})</code></pre>
</div>
<p>El notebook completo está en <a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/blob/master/RL-6-ControlSinModelo/GLIE%20Monte-Carlo%20Control.ipynb">GitHub</a>. Probado en octubre de 2026 con Python 3.14, Gymnasium 1.4.0 y NumPy 2.5.4.</p>
<p>Esto es todo lo que veremos por este capítulo, espero que les sea de ayuda y cualquier duda por favor escribirme.</p>
<p>¡Muchas gracias!</p>
</section>
<section id="referencias" class="level2">
<h2 class="anchored" data-anchor-id="referencias">Referencias</h2>
<ul>
<li><a href="https://davidstarsilver.wordpress.com/wp-content/uploads/2025/04/lecture-5-model-free-control-.pdf">UCL Course on RL Lecture 5: Model-Free Control</a></li>
<li><a href="http://incompleteideas.net/book/RLbook2018.pdf">Richard Sutton’s Intro to Reinforcement Learning</a></li>
</ul>


</section>

 ]]></description>
  <category>aprendizaje por refuerzo</category>
  <guid>https://migsilva.com/es/posts/control-libre-de-modelo/</guid>
  <pubDate>Tue, 31 Mar 2020 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Predicciones sin modelo</title>
  <link>https://migsilva.com/es/posts/predicciones-sin-modelo/</link>
  <description><![CDATA[ 





<p>La predicción sin modelo se basa en tener un problema que se pueda expresar por medio de un MDP, pero no necesariamente conocemos la estructura de este, por lo tanto, no sabemos cómo funcionan realmente las mecánicas de este ambiente, siendo el objetivo estimar qué tan buena es una política dada, es decir su función de valor, en ese ambiente desconocido.</p>
<section id="introducción" class="level2">
<h2 class="anchored" data-anchor-id="introducción">Introducción</h2>
<p>En el anterior post vimos cómo resolver un MDP que se conocía por completo, en este post veremos cómo estimar la función de valor de un <strong><em>MDP desconocido</em></strong>.</p>
</section>
<section id="aprendizaje-de-monte-carlo" class="level2">
<h2 class="anchored" data-anchor-id="aprendizaje-de-monte-carlo">Aprendizaje de Monte-Carlo</h2>
<p>El algoritmo de aprendizaje de Monte-Carlo nos sirve para estimar la función de valor, toma muestras directamente de episodios realizados por un agente dada la política que elegimos, funciona mejor para ambientes que tienen las características de juegos, es decir, que siempre tienen un final.</p>
<section id="cómo-funciona-el-mc" class="level3">
<h3 class="anchored" data-anchor-id="cómo-funciona-el-mc">¿Cómo funciona el MC?</h3>
<p>MC estima la función de valor repitiendo una y otra vez la política elegida desde un estado <em>s</em> hasta el final del episodio, al terminar de realizar estas pruebas se promedia todo el retorno obtenido (El retorno representa el total de recompensa utilizando el factor de descuento) y de esta manera se encuentra la función de valor para dicha política, esta es la manera más “simple” de encontrar la función de valor, el aprendizaje de Monte-Carlo se puede ejecutar de dos maneras:</p>
<p><strong>Evaluación de Política de Primera Visita de Monte-Carlo</strong></p>
<p>Para evaluar la política π se inicia seleccionando un estado <em>s</em>:</p>
<ol type="1">
<li>Se genera una muestra ejecutando la política π sobre el ambiente.</li>
<li>Se iniciará un episodio si se visita el estado <em>s</em> en dicha muestra, solo se considera un episodio si por lo menos se pasa una vez por el estado <em>s</em>.</li>
<li>Se añadirá el valor de uno a un contador <em>n</em> por <strong>la primera vez que se visite el estado <em>s</em> por episodio</strong> (que llevará la cuenta de cuántas veces se ha visitado el estado <em>s</em> en el total de nuestros episodios).</li>
<li>Se contabilizará el valor del retorno final desde que se visite el estado s por primera vez por episodio hacia adelante, el cual luego se guardará junto al retorno de los siguientes episodios que también pasen por el estado s, el retorno se contabilizará desde el momento que se visita el estado s por primera vez hasta el final del episodio.</li>
<li>Luego de ejecutar el algoritmo hasta que se estabilicen los valores se hallará la media del retorno total dividiendo el retorno total entre el contador n, la cual nos dará como resultado la función de valor de la política π.<br>
Según <a href="https://es.wikipedia.org/wiki/Ley_de_los_grandes_n%C3%BAmeros">la ley de los grandes números</a>, si tomamos el promedio de un gran número de episodios eventualmente se acercará y convergerá en la función de valor de la política π, como requisito para que funcione esta evaluación de política se necesita que se visiten todos los estados que pueden ser alcanzados por la política π por lo menos una vez, y esto se logra al reproducir el experimento un gran número de veces.</li>
</ol>
<p><strong>Evaluación de Política de Cada Visita de Monte-Carlo</strong></p>
<p>Para evaluar la política π se iniciará de nuevo seleccionando un estado <em>s</em>:</p>
<ol type="1">
<li>Se genera una muestra ejecutando la política π sobre el ambiente.</li>
<li>Se iniciará un episodio si se visita el estado <em>s</em> en dicha muestra, <strong>se considera un episodio cada vez que se pasa por el estado <em>s</em></strong>.</li>
<li>Se añadirá el valor de uno a un contador <em>n</em> por cada vez que se visite el estado <em>s</em>.</li>
<li>Se contabilizará el valor del retorno final desde que se visite el estado <em>s</em> hasta el final del episodio, el cual luego se guardará junto al retorno de los siguientes episodios.</li>
<li>Luego de ejecutar el programa las veces que uno crea necesario se hallará la media del retorno total dividiendo el retorno total entre el contador <em>n</em>, la cual nos dará como resultado la función de valor de la política π.</li>
</ol>
<p>Como se ve, la diferencia con este método es que cada vez que se visita el estado <em>s</em>, se generará un nuevo episodio del cual se contabilizará el retorno desde el momento que visitan el estado, hasta el final.</p>
<p><strong>Media Incremental</strong></p>
<p>La media de una secuencia puede calcularse incrementalmente dándole forma a la ecuación de la siguiente manera:</p>
<!-- antes una imagen: img-02.jpeg -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0A%5Cmu_k%20&amp;=%20%5Cfrac%7B1%7D%7Bk%7D%20%5Csum_%7Bj=1%7D%5E%7Bk%7D%20x_j%20%5C%5C%0A&amp;=%20%5Cfrac%7B1%7D%7Bk%7D%20%5Cleft(%20x_k%20+%20%5Csum_%7Bj=1%7D%5E%7Bk-1%7D%20x_j%20%5Cright)%20%5C%5C%0A&amp;=%20%5Cfrac%7B1%7D%7Bk%7D%20%5Cleft(%20x_k%20+%20(k-1)%5Cmu_%7Bk-1%7D%20%5Cright)%20%5C%5C%0A&amp;=%20%5Cmu_%7Bk-1%7D%20+%20%5Cfrac%7B1%7D%7Bk%7D%20%5Cleft(%20x_k%20-%20%5Cmu_%7Bk-1%7D%20%5Cright)%0A%5Cend%7Baligned%7D%0A"></p>
<p>Esto permitiría que el algoritmo de aprendizaje de Monte-Carlo pueda ser actualizado al final de cada episodio, en este caso sería representado de la siguiente manera:</p>
<!-- antes una imagen: img-03.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0AN(S_t)%20&amp;%5Cleftarrow%20N(S_t)%20+%201%20%5C%5C%0AV(S_t)%20&amp;%5Cleftarrow%20V(S_t)%20+%20%5Cfrac%7B1%7D%7BN(S_t)%7D%20%5Cleft(%20G_t%20-%20V(S_t)%20%5Cright)%0A%5Cend%7Baligned%7D%0A"></p>
<p><em>N</em> representa el contador dentro del algoritmo de Monte-Carlo, <em>V</em> la función de valor, <em>G</em> el retorno y <em>S</em> el estado.</p>
<p><a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/blob/master/RL-5-PrediccionesSinModelo/Monte-Carlo.ipynb">Aquí una pequeña implementación de MC en Python</a>, para que el concepto quede más claro.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center collapsed" data-bs-toggle="collapse" data-bs-target=".callout-1-contents" aria-controls="callout-1" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Nota</span>Código: Monte-Carlo
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-1" class="callout-1-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p>Usa el ambiente de la cadena (<code>ambiente_cadena.py</code>), que se describe en Implementación. El notebook completo está en <a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/blob/master/RL-5-PrediccionesSinModelo/Monte-Carlo.ipynb">GitHub</a>.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> ambiente_cadena <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Cadena</span>
<span id="cb1-3"></span>
<span id="cb1-4">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">666</span>)</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> politica():</span>
<span id="cb2-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.random.choice([<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">numero_de_estados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#número de estados del ambiente.</span></span>
<span id="cb3-2"></span>
<span id="cb3-3">valores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros(numero_de_estados) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># se inicializará los valores de los estados en 0.</span></span>
<span id="cb3-4">estados_visitados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros(numero_de_estados)</span>
<span id="cb3-5"></span>
<span id="cb3-6">ambiente <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Cadena() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se inicializa el ambiente.</span></span>
<span id="cb3-7">episodios <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#número de episodios.</span></span>
<span id="cb3-8">contador <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb3-9">recompensa_total <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb3-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># variables del algoritmo</span></span>
<span id="cb3-11"></span>
<span id="cb3-12">alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable por la que se multiplica el error. </span></span>
<span id="cb3-13"></span>
<span id="cb3-14"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>:</span>
<span id="cb3-15">    accion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> politica() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se genera una acción.</span></span>
<span id="cb3-16">    estado_anterior <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ambiente.estado_actual()</span>
<span id="cb3-17">    estados_visitados[estado_anterior] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb3-18">    recompensa, nuevo_estado, _, final_episodio <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ambiente.movimiento(accion)</span>
<span id="cb3-19">    recompensa_total <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> recompensa</span>
<span id="cb3-20">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> final_episodio:</span>
<span id="cb3-21">        valores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (recompensa_total <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> valores)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>estados_visitados</span>
<span id="cb3-22">        ambiente <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Cadena() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#reiniciamos el ambiente</span></span>
<span id="cb3-23">        recompensa_total <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb3-24">        estados_visitados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros(numero_de_estados)</span>
<span id="cb3-25">        contador<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se suma un episodio mas terminado</span></span>
<span id="cb3-26">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> contador <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb3-27">            <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Episodio :'</span>, contador)</span>
<span id="cb3-28">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> contador <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> episodios:</span>
<span id="cb3-29">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span></code></pre></div></div>
<div class="nb-output">
<pre><code>Episodio : 400
Episodio : 800
Episodio : 1200
Episodio : 1600
Episodio : 2000</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">valores[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>] <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#valor final de cada estado.</span></span></code></pre></div></div>
<div class="nb-output">
<pre><code>array([0.14487967, 0.17365872, 0.33387811, 0.65040468, 0.74735077])</code></pre>
</div>
</div>
</div>
</div>
</section>
</section>
<section id="método-de-diferencia-temporal" class="level2">
<h2 class="anchored" data-anchor-id="método-de-diferencia-temporal">Método de Diferencia Temporal</h2>
<p>Este método aprende directamente de episodios de experiencias, también funciona sin modelo.</p>
<section id="cómo-funciona-el-td" class="level3">
<h3 class="anchored" data-anchor-id="cómo-funciona-el-td">¿Cómo funciona el TD?</h3>
<p>El método de diferencia temporal aprende de episodios incompletos por medio de <strong>bootstrapping</strong>, esta técnica consiste en tomar un camino parcialmente y estimar cuál sería el retorno de este sin recorrerlo en su totalidad, este retorno estimado se ve actualizado cuando el agente tome otro paso en dirección hacia este camino.</p>
<p>El objetivo es aprender la función de valor de manera <em>online</em>, bajo la política π:<br>
Como se había mostrado TD se encarga de encontrar el retorno estimado (también llamado TD target u Objetivo TD), el cual se representa con la siguiente fórmula:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AR_%7Bt+1%7D%20+%20%5Cgamma%20V(S_%7Bt+1%7D)%0A"></p>
<p>Esta fórmula nos muestra que el retorno estimado puede ser representado como la recompensa inmediata más el valor estimado (y descontado) del resto de la trayectoria. Ahora, partimos de la fórmula de Actualización <em>Online</em> de MC:</p>
<!-- antes una imagen: img-04.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0AV(S_t)%20%5Cleftarrow%20V(S_t)%20+%20%5Calpha%20%5Cleft(%20G_t%20-%20V(S_t)%20%5Cright)%0A"></p>
<p>y variaremos el retorno real <em>Gt</em>, por el retorno estimado, dejándonos la siguiente fórmula:</p>
<!-- antes una imagen: img-05.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0AV(S_t)%20%5Cleftarrow%20V(S_t)%20+%20%5Calpha%20%5Cleft(%20R_%7Bt+1%7D%20+%20%5Cgamma%20V(S_%7Bt+1%7D)%20-%20V(S_t)%20%5Cright)%0A"></p>
<p>La parte final de la fórmula que se encuentra entre paréntesis es llamada Error TD.</p>
</section>
</section>
<section id="mc-vs-td" class="level2">
<h2 class="anchored" data-anchor-id="mc-vs-td">MC vs TD</h2>
<section id="td" class="level3">
<h3 class="anchored" data-anchor-id="td">TD</h3>
<ul>
<li>Puede aprender antes de ver el resultado final, debido a que puede estimar cuál será el retorno de una situación dado el punto en donde se encuentra, esto quiere decir que TD puede ir aprendiendo durante cada paso dentro del camino.</li>
<li>Puede aprender de episodios incompletos, es decir de episodios donde no se llega nunca a un estado final.</li>
<li>TD busca la máxima verosimilitud para un modelo de Markov (intenta construir un MDP que encaje de mejor manera con los datos).</li>
<li>Aprovecha la propiedad de Markov, por lo que suele ser más eficiente en ambientes que la cumplen.</li>
</ul>
</section>
<section id="mc" class="level3">
<h3 class="anchored" data-anchor-id="mc">MC</h3>
<ul>
<li>Debe esperar hasta el final del episodio para saber el retorno.</li>
<li>Solo puede aprender de secuencias completas.</li>
<li>Busca la solución con menor error cuadrático medio (Se basa en el retorno obtenido).</li>
<li>No aprovecha la propiedad de Markov, por lo que suele funcionar mejor en ambientes que no la cumplen.</li>
</ul>
</section>
<section id="intercambio-entre-el-sesgo-y-la-varianza" class="level3">
<h3 class="anchored" data-anchor-id="intercambio-entre-el-sesgo-y-la-varianza">Intercambio entre el Sesgo y la Varianza</h3>
<ul>
<li>El retorno que da MC no tiene ningún sesgo.</li>
<li>El retorno estimado de TD (o TD target) se encuentra sesgado, debido a que podemos estimarlo equivocadamente.</li>
<li>El TD target tiene menor varianza, debido a que solo depende de una acción aleatoria, una transición y un retorno, en cambio el retorno real depende de varias acciones aleatorias, varias transiciones y varios retornos.</li>
</ul>
</section>
</section>
<section id="tdλ" class="level2">
<h2 class="anchored" data-anchor-id="tdλ">TD(λ)</h2>
<section id="predicción-de-n-pasos" class="level3">
<h3 class="anchored" data-anchor-id="predicción-de-n-pasos"><strong>Predicción de N-pasos</strong></h3>
<p>Ahora que sabemos cómo funciona MC y TD, sería válido pensar, ¿Por qué TD solo toma un paso antes de estimar la función de valor? ¿Por qué no tomar 2 o 3? Esta es la idea detrás de predicción de n-pasos. Hasta este punto hemos visto cómo funciona TD utilizando solo un paso, llamado TD(0) y también cómo funciona MC, algoritmo que recorre todos los estados antes de generar una estimación, pero en esta sección veremos qué se encuentra entre estos dos algoritmos.</p>
<p>Veremos cómo definir el retorno para n-pasos:</p>
<!-- antes una imagen: img-06.jpeg -->
<p><img src="https://latex.codecogs.com/png.latex?%0AG_t%5E%7B(n)%7D%20=%20R_%7Bt+1%7D%20+%20%5Cgamma%20R_%7Bt+2%7D%20+%20%5Cdots%20+%20%5Cgamma%5E%7Bn-1%7D%20R_%7Bt+n%7D%20+%20%5Cgamma%5En%20V(S_%7Bt+n%7D)%0A"></p>
<p>Para este caso, el retorno se define como el retorno para todos los pasos dados en el ambiente y una estimación del retorno que vendría hasta la terminación de este episodio.</p>
<p>Podríamos añadir esto, para generar la función TD para n-pasos:</p>
<!-- antes una imagen: img-07.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0AV(S_t)%20%5Cleftarrow%20V(S_t)%20+%20%5Calpha%20%5Cleft(%20G_t%5E%7B(n)%7D%20-%20V(S_t)%20%5Cright)%0A"></p>
<p>Dadas las posibilidades que se muestran ahora, ¿Cómo podríamos elegir un <em>n</em> que sea mejor para cualquier problema? ¿Podríamos promediar varios retornos?</p>
<p>Sí, en realidad se puede promediar varios retornos para obtener lo mejor de ellos, es decir, podríamos promediar el retorno de un <em>n = 4</em> y de un <em>n = 2</em> y utilizarlo como TD target, así obtendríamos lo mejor de ambos.</p>
</section>
<section id="retorno-λ" class="level3">
<h3 class="anchored" data-anchor-id="retorno-λ">Retorno λ</h3>
<p>El retorno λ combina el retorno de todos los n utilizando una media ponderada, el retorno cambia a la siguiente fórmula:</p>
<!-- antes una imagen: img-08.jpeg -->
<p><img src="https://latex.codecogs.com/png.latex?%0AG_t%5E%5Clambda%20=%20(1%20-%20%5Clambda)%20%5Csum_%7Bn=1%7D%5E%7B%5Cinfty%7D%20%5Clambda%5E%7Bn-1%7D%20G_t%5E%7B(n)%7D%0A"></p>
<p>Donde λ es un número entre 0 y 1.</p>
<p>Lo cual genera la siguiente fórmula para TD(λ) hacia adelante.</p>
<!-- antes una imagen: img-09.jpeg -->
<p><img src="https://latex.codecogs.com/png.latex?%0AV(S_t)%20%5Cleftarrow%20V(S_t)%20+%20%5Calpha%20%5Cleft(%20G_t%5E%5Clambda%20-%20V(S_t)%20%5Cright)%0A"></p>
<p>Esa vista de TD(λ) es más que nada teórica, si se desea poner en práctica TD(λ) se necesita utilizar TD(λ) hacia atrás, debido a que no podemos saber actualmente cuánto es el valor para cada estado que viene hacia delante en nuestro MDP, es por eso que nos basamos en TD(λ) hacia atrás que nos permite actualizar nuestro valor basado en las recompensas que recibimos y los estados que hemos visitado.</p>
</section>
<section id="rastros-de-elegibilidad" class="level3">
<h3 class="anchored" data-anchor-id="rastros-de-elegibilidad">Rastros de Elegibilidad</h3>
<p>Si quisiéramos actualizar nuestra función de valor; ¿A qué estado deberíamos asignarle más o menos “responsabilidad” por el descenso del retorno?</p>
<p>Es por esto que nace el concepto de rastros de elegibilidad, que mantiene un conteo de qué tan recientemente se visita cada estado y con qué frecuencia, esto nos da una idea de cómo penalizar más justamente a cada estado, y actualizar nuestra función de valor.</p>
<p>Esta fórmula es TD(λ) hacia atrás utilizando rastros de elegibilidad.</p>
<!-- antes una imagen: img-10.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0A%5Cdelta_t%20&amp;=%20R_%7Bt+1%7D%20+%20%5Cgamma%20V(S_%7Bt+1%7D)%20-%20V(S_t)%20%5C%5C%0AV(s)%20&amp;%5Cleftarrow%20V(s)%20+%20%5Calpha%20%5Cdelta_t%20E_t(s)%0A%5Cend%7Baligned%7D%0A"></p>
<p><em>Et(s)</em> representa los rastros de elegibilidad, que designará qué estado se actualizará en mayor medida que otro; δ representará el error de TD.</p>
</section>
</section>
<section id="implementación" class="level2">
<h2 class="anchored" data-anchor-id="implementación">Implementación</h2>
<p>A continuación comparto una implementación de TD(λ), si deseas ver el código completo y una implementación de Monte-Carlo visita <a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/tree/master/RL-5-PrediccionesSinModelo">mi página de GitHub</a>.</p>
<p>En este caso utilizaremos el siguiente ambiente:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/predicciones-sin-modelo/td-lambda-ambiente.jpg" class="img-fluid figure-img"></p>
<figcaption>Fuente: Sutton y Barto, <em>Reinforcement Learning: An Introduction</em>, ejemplo 6.2.</figcaption>
</figure>
</div>
<p>Para ejemplificar cómo funcionaría con una política aleatoria, en este caso la política decidirá con igual probabilidad moverse hacia la izquierda o derecha, la peculiaridad de este ambiente es que solo se recompensa cuando se llega al estado final de la derecha, para el estado de la izquierda no hay premio alguno.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center collapsed" data-bs-toggle="collapse" data-bs-target=".callout-2-contents" aria-controls="callout-2" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Nota</span>Código de apoyo: <code>ambiente_cadena.py</code>
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-2" class="callout-2-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Cadena:   </span>
<span id="cb7-2">    </span>
<span id="cb7-3">    nodos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"F1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"A"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"B"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"C"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"D"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"E"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"F2"</span>]</span>
<span id="cb7-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">__init__</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>):</span>
<span id="cb7-5">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.posicion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># posicion inicial</span></span>
<span id="cb7-6">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.terminado <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span></span>
<span id="cb7-7">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.nodo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.nodos[<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.posicion]</span>
<span id="cb7-8">    </span>
<span id="cb7-9">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> estado_actual(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>):</span>
<span id="cb7-10">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.posicion</span>
<span id="cb7-11">        </span>
<span id="cb7-12">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> movimiento(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, decision):</span>
<span id="cb7-13">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.terminado:</span>
<span id="cb7-14">            nueva_posicion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.posicion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> decision    </span>
<span id="cb7-15">            recompensa <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.obtener_recompensa(nueva_posicion)</span>
<span id="cb7-16">            <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.posicion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nueva_posicion</span>
<span id="cb7-17">            <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.nodo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.nodos[<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.posicion]</span>
<span id="cb7-18">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.nodo <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'F1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'F2'</span>]:</span>
<span id="cb7-19">                <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.terminado <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span></span>
<span id="cb7-20">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> recompensa, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.posicion, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.nodo, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.terminado</span>
<span id="cb7-21">        </span>
<span id="cb7-22">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> obtener_recompensa(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, nueva_posicion):</span>
<span id="cb7-23">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.nodos[nueva_posicion] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"F2"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span></span></code></pre></div></div>
</div>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb8-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> ambiente_cadena <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Cadena</span>
<span id="cb8-3"></span>
<span id="cb8-4">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">666</span>)</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> politica():</span>
<span id="cb9-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.random.choice([<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">numero_de_estados <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#número de estados del ambiente.</span></span>
<span id="cb10-2"></span>
<span id="cb10-3">valores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros(numero_de_estados) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># se inicializará los valores de los estados en 0.</span></span>
<span id="cb10-4">elegibilidad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros(numero_de_estados) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># con este vector se llevará la cuenta de los estados visitados.</span></span>
<span id="cb10-5"></span>
<span id="cb10-6">ambiente <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Cadena() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se inicializa el ambiente.</span></span>
<span id="cb10-7">episodios <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#número de episodios.</span></span>
<span id="cb10-8">contador <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb10-9"></span>
<span id="cb10-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># variables del algoritmo</span></span>
<span id="cb10-11"></span>
<span id="cb10-12">lambd <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable lambda de TD(lambda).</span></span>
<span id="cb10-13">alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable por la que se multiplica el error. </span></span>
<span id="cb10-14">gamma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#variable por la cual verá reducido la elegibilidad de cada estado.</span></span>
<span id="cb10-15"></span>
<span id="cb10-16"></span>
<span id="cb10-17"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>:</span>
<span id="cb10-18">    accion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> politica() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se genera una acción.</span></span>
<span id="cb10-19">    estado_anterior <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ambiente.estado_actual()</span>
<span id="cb10-20">    recompensa, nuevo_estado, _, final_episodio <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ambiente.movimiento(accion)</span>
<span id="cb10-21">    elegibilidad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*=</span> lambd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> gamma</span>
<span id="cb10-22">    elegibilidad[estado_anterior] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span></span>
<span id="cb10-23">    td_error <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> recompensa <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> gamma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> valores[nuevo_estado] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> valores[estado_anterior]</span>
<span id="cb10-24">    valores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> td_error <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> elegibilidad</span>
<span id="cb10-25">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> final_episodio:</span>
<span id="cb10-26">        elegibilidad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros(numero_de_estados)</span>
<span id="cb10-27">        ambiente <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Cadena() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#reiniciamos el ambiente</span></span>
<span id="cb10-28">        contador<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se suma un episodio mas terminado</span></span>
<span id="cb10-29">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> contador <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb10-30">            <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Episodio :'</span>, contador)</span>
<span id="cb10-31">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> contador <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> episodios:</span>
<span id="cb10-32">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span></code></pre></div></div>
<div class="nb-output">
<pre><code>Episodio : 400
Episodio : 800
Episodio : 1200
Episodio : 1600
Episodio : 2000</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">valores[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>] <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#valor final de cada estado.</span></span></code></pre></div></div>
<div class="nb-output">
<pre><code>array([0.01023519, 0.01805448, 0.0570654 , 0.18990032, 0.62445833])</code></pre>
</div>
<p>El notebook completo está en <a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/blob/master/RL-5-PrediccionesSinModelo/TD-Lambda.ipynb">GitHub</a>.</p>
<p>Esto es todo lo que veremos por este post, espero que les sea de ayuda y cualquier duda por favor escribirme.</p>
<p>¡Muchas gracias!</p>
</section>
<section id="referencias" class="level2">
<h2 class="anchored" data-anchor-id="referencias">Referencias</h2>
<ul>
<li><a href="https://davidstarsilver.wordpress.com/wp-content/uploads/2025/04/lecture-4-model-free-prediction-.pdf">UCL Course on RL Lecture 4: Model-Free Prediction</a></li>
<li><a href="http://incompleteideas.net/book/RLbook2018.pdf">Richard Sutton’s Intro to Reinforcement Learning</a></li>
</ul>


</section>

 ]]></description>
  <category>aprendizaje por refuerzo</category>
  <guid>https://migsilva.com/es/posts/predicciones-sin-modelo/</guid>
  <pubDate>Mon, 28 Oct 2019 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Planificando con programación dinámica</title>
  <link>https://migsilva.com/es/posts/planificando-con-programacion-dinamica/</link>
  <description><![CDATA[ 





<p>Ahora que ya hemos visto cómo formalizar el problema de RL dentro de la serie de <a href="../../../es/index.html">Aprendizaje por Refuerzo</a>, ahora el siguiente paso es resolverlo, para esto en este y los siguientes posts veremos diferentes técnicas y cómo aplicarlas para resolver dichos problemas.<br>
Una de las técnicas más antiguas y conocidas es la programación dinámica.</p>
<section id="introducción" class="level2">
<h2 class="anchored" data-anchor-id="introducción">Introducción</h2>
<p>Programación dinámica viene de las palabras “programación” que en matemáticas viene a significar “optimizar un programa”, y en este caso por un programa nos estamos refiriendo a una política, por otro lado la palabra dinámica significa que el problema tiene un componente secuencial o temporal. Entonces la definición de programación dinámica vendría a ser un <strong>método de optimización para problemas secuenciales</strong>.</p>
<section id="y-cómo-funciona" class="level3">
<h3 class="anchored" data-anchor-id="y-cómo-funciona">¿Y cómo funciona?</h3>
<p>Divide el problema en “sub-problemas” y los resuelve, luego vuelve a unir estos sub-problemas para encontrar la solución general.<br>
Para que la programación dinámica pueda ocurrir deben cumplirse dos propiedades muy importantes:</p>
<ul>
<li><strong>Sub-estructura óptima</strong><br>
Para que se cumpla esta propiedad debe cumplirse el principio de optimalidad, lo cual significa que el problema se puede resolver si se parte en 2 o más sub-problemas y las óptimas soluciones para esos sub-problemas al unirlas dan como resultado la solución óptima a todo el problema.</li>
<li><strong>Sub-problemas superpuestos</strong><br>
Significa que los sub-problemas se repiten muchas veces, de modo que sus soluciones se pueden guardar y reutilizar en vez de volver a calcularlas, y por lo tanto la solución es hallada más rápidamente.</li>
</ul>
</section>
<section id="los-procesos-de-decisión-de-markov-cumplen-estas-propiedades" class="level3">
<h3 class="anchored" data-anchor-id="los-procesos-de-decisión-de-markov-cumplen-estas-propiedades">¿Los Procesos de Decisión de Markov cumplen estas propiedades?</h3>
<p>Sí, las cumplen debido a la ecuación de Bellman, que permite descomponer el MDP, eso cumple la propiedad de sub-estructura óptima.<br>
Pero, ¿qué hay de sub-problemas superpuestos? Bueno, para esto existe la función de valor, la cual guarda los mejores valores y decisiones a tomar, para la cual ya no se necesita re-calcular si se llega a un estado en donde ya se tiene el máximo valor hallado previamente.</p>
</section>
</section>
<section id="planificación-con-programación-dinámica" class="level2">
<h2 class="anchored" data-anchor-id="planificación-con-programación-dinámica">Planificación con Programación Dinámica</h2>
<p>La programación dinámica no afecta al problema completo de RL, sino que asume que se conoce completamente el ambiente.<br>
Ahora la programación dinámica nos puede servir para dos casos especiales de planificación en un MDP.<br>
Primero podríamos tomarlo como un <strong>caso de predicción</strong>, que como entrada le daríamos un MDP&lt;S, A, P, R, γ&gt; y una política π o un MRP&lt;S, Pπ, Rπ, γ&gt; y como salida obtendremos una función de valor π, esta función de valor nos va a decir cuánta recompensa esperar en cada estado de este MDP, en otras palabras evaluará nuestra política.<br>
El otro <strong>caso sería como control</strong>, para obtener la mayor optimización de este MDP, para esto también tendríamos como entrada un MDP&lt;S, A, P, R, γ&gt; pero en este caso la salida sería la política óptima que deseamos encontrar y la función de valor óptima.</p>
<section id="evaluación-de-política" class="level3">
<h3 class="anchored" data-anchor-id="evaluación-de-política">Evaluación de Política</h3>
<p>Comenzaremos viendo el primero de los casos, el problema que resolveremos será evaluar la política π y lo vamos a hacer utilizando la ecuación de expectativa de Bellman, la cual vimos en el anterior post.<br>
Para este proceso iniciaremos con un vector de valores arbitrarios “v”, utilizando en el cual dentro de cada iteración se aplicará la ecuación de expectativa de Bellman para ir conociendo los valores de los otros estados raíces, este proceso irá variando utilizando los estados que previamente fueron utilizados como raíces para luego utilizarlos como nodos hijos y hallar el valor del estado raíz, así se seguirá iterando hasta finalmente llegar al valor de vπ, <strong>el utilizar todos los estados a la vez, en cada iteración es llamado Synchronous Backups</strong>. En otras palabras significa que volveremos la ecuación de expectativa de Bellman en actualizaciones iterativas.<br>
Para entender mejor este problema propondremos el ejemplo de un mundo cuadrícula de tamaño 4 x 4:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/planificando-con-programacion-dinamica/img-01.jpeg" class="img-fluid figure-img"></p>
<figcaption>Las figuras de este ejemplo están adaptadas de David Silver, curso de RL de la UCL, clase 3.</figcaption>
</figure>
</div>
<ul>
<li>El descuento será de 1</li>
<li>El estado 0 y el 15 serán los estados terminales de nuestro MDP.</li>
<li>Se podrá desempeñar 4 acciones, ir a la derecha, izquierda, arriba, abajo.</li>
<li>La recompensa es -1 hasta que se llega al estado terminal.</li>
<li>Movimientos que te llevan fuera del mundo te devuelven al mismo estado (con recompensa -1).</li>
<li>La política será que la probabilidad de tomar cualquier dirección será la misma, o sea 0.25, básicamente al azar.</li>
</ul>
<p><strong>Desarrollo</strong></p>
<p>Se iniciará con una función de valor arbitrarios, que en este caso serán ceros, en este caso, los ceros de la imagen de la izquierda representan cuántos pasos se necesitan en promedio para llegar a los estados finales.</p>
<p><img src="https://migsilva.com/es/posts/planificando-con-programacion-dinamica/img-02.jpeg" class="img-fluid"></p>
<p>Ahora aplicamos la función de expectativa de Bellman para cada uno de los estados, para hacer esto seleccionamos un estado como ejemplo, en este caso el estado (0, 1), vemos que cualquiera sea la dirección que tome se llevará como recompensa -1 y esto se le suma el valor que tiene el estado donde se encontraría, entonces tendríamos que el nuevo valor para el estado (0,1) sería (-1+0)(1/4)+(-1+0)(1/4)+(-1+0)(1/4)+(-1+0)(1/4) = -1.</p>
<p>El valor de los estados finales no cambian, porque ya no necesita cambiar de estado cuando llegan a este.</p>
<p><img src="https://migsilva.com/es/posts/planificando-con-programacion-dinamica/img-03.jpeg" class="img-fluid"></p>
<p>Ahora teniendo esta nueva función de valor aplicaremos de nuevo el mismo proceso iterativo, tomando como ejemplo el mismo estado (0, 1) ahora veremos cómo cambia su valor de la siguiente manera, dado que tiene la misma probabilidad de tomar cualquier dirección: (-1+-1)(1/4)+(-1+-1)(1/4)+(-1+-1)(1/4)+(-1+0)(1/4) = -1.75 (en la figura aparece como -1.7)</p>
<p><img src="https://migsilva.com/es/posts/planificando-con-programacion-dinamica/img-04.jpeg" class="img-fluid"></p>
<p>Ahora si seguimos iterando el proceso, se encontrará que llega a converger. En la parte derecha del gráfico se puede ver cómo sería una política voraz («codiciosa» en la figura) si se eligiera siempre el estado con mayor valor, lo cual demuestra que no es necesario iterar hasta la convergencia para encontrar la política óptima y que observar la función de valor puede servirnos para encontrar una mejor política.</p>
<p><img src="https://migsilva.com/es/posts/planificando-con-programacion-dinamica/img-05.jpeg" class="img-fluid"></p>
</section>
<section id="iteración-de-política" class="level3">
<h3 class="anchored" data-anchor-id="iteración-de-política">Iteración de Política</h3>
<p>Todo parte de la premisa: ¿Cómo podríamos encontrar una mejor política a la que ya tenemos?</p>
<p>Para lograr esto se partirá el proceso en dos, dada la política π:</p>
<ul>
<li>Evaluamos la política π y encontramos su función de valor.</li>
<li>Mejoras la política actuando de forma voraz (seleccionas el estado que da más valor en cada paso) con respecto a la función de valor.</li>
</ul>
<p>En el caso del mundo de cuadrícula solo se necesita una iteración sobre la política inicial para hallar la política óptima actuando de forma voraz sobre esa función de valor, pero para otros problemas más complejos se necesita muchas más iteraciones y evaluaciones para llegar a una solución final.</p>
<p>Este proceso se repite una y otra vez hasta que la política deja de mejorar, en este caso habrá convergido en la política óptima, en realidad es un proceso iterativo que resulta al juntar la evaluación de una política y luego sobre esta evaluación se actúa de forma voraz sobre su función de valor y luego se encuentra una mejor política (también llamada iteración de política), estas iteraciones se siguen dando hasta que se termina con la política óptima para ese problema.</p>
<p><strong>Principio de Optimalidad</strong></p>
<p>Cada política óptima puede dividirse en dos componentes:</p>
<ul>
<li>Elegir una primera acción óptima.</li>
<li>Seguida por una política óptima desde el estado sucesor S’.</li>
</ul>
<p>Esto se puede expresar en el teorema del principio de optimalidad: una política π alcanza el valor óptimo desde un estado s, <img src="https://latex.codecogs.com/png.latex?v_%5Cpi(s)%20=%20v_*(s)">, si y solo si, para cualquier estado s’ que pueda ser alcanzado desde s, π alcanza el valor óptimo desde s’, <img src="https://latex.codecogs.com/png.latex?v_%5Cpi(s')%20=%20v_*(s')">.</p>
</section>
<section id="iteración-de-valor" class="level3">
<h3 class="anchored" data-anchor-id="iteración-de-valor">Iteración de Valor</h3>
<p>Se basa en que si sabemos la solución para el subproblema v*(s’), podemos hallar la solución de v*(s), la idea se basa en iniciar desde la recompensa final e ir retrocediendo para encontrar el valor óptimo de cada uno de los estados anteriores.</p>
<p>A continuación se verá un ejemplo del mundo cuadrícula, el mismo que vimos en el ejemplo anterior, pero esta vez solo con una salida.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/planificando-con-programacion-dinamica/img-06.jpeg" class="img-fluid figure-img"></p>
<figcaption>Ejemplo del camino más corto. Las figuras de este ejemplo están adaptadas de David Silver, curso de RL de la UCL, clase 3.</figcaption>
</figure>
</div>
<p>Para resolver este ejemplo se seleccionará la acción que nos dé mayor valor, esto nos permitirá llegar a la función de valor óptima luego de iterar algunas veces. De nuevo iniciamos nuestro mundo cuadrícula con un valor arbitrario como se muestra en V1, en el siguiente paso se actualizan todos los estados, esta vez <strong>tomando la acción que maximice el valor</strong>, en este caso (V2) todas darían el mismo valor, para V3 la situación ya cambia, se puede notar los estados posicionados en (0,1) y (1,0) eligieron la acción de llegar al estado terminal, la cual termina siendo la acción más óptima.</p>
<p><img src="https://migsilva.com/es/posts/planificando-con-programacion-dinamica/img-07.jpeg" class="img-fluid"></p>
<p>En las siguientes iteraciones se puede notar cómo cada estado va tomando la acción que maximiza su valor hasta llegar a converger en la función de valor óptima.</p>
<p><img src="https://migsilva.com/es/posts/planificando-con-programacion-dinamica/img-08.jpeg" class="img-fluid"></p>
<p>Para aterrizar un poco el uso de la iteración por valor tenemos que el objetivo final de esta es encontrar la política óptima π por medio de la aplicación iterativa de la ecuación de optimalidad de Bellman, si se decide detener el algoritmo en alguna iteración no final, puede ser que la función de valor que se encuentre en el algoritmo no sea necesariamente representada por alguna política, ya que la iteración de valor no se basa en ir iterando políticas sino ir alterando la función de valor, pero al final del funcionamiento de este algoritmo sí tendremos claro que se ha encontrado la mejor función de valor que corresponde a la mejor política seleccionando cada vez la acción que genere mayor valor.</p>
</section>
<section id="algoritmos-de-programación-dinámica-síncrona" class="level3">
<h3 class="anchored" data-anchor-id="algoritmos-de-programación-dinámica-síncrona">Algoritmos de Programación Dinámica Síncrona</h3>
<p>Ahora un resumen de lo que hemos visto:</p>
<!-- antes una imagen: img-09.jpeg -->
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Problema</th>
<th>Ecuación de Bellman</th>
<th>Algoritmo</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Predicción</td>
<td>Ecuación de expectativa de Bellman</td>
<td>Evaluación de Política</td>
</tr>
<tr class="even">
<td>Control</td>
<td>Ecuación de expectativa de Bellman + Mejoramiento con Política Voraz</td>
<td>Iteración de Política</td>
</tr>
<tr class="odd">
<td>Control</td>
<td>Ecuación de optimalidad de Bellman</td>
<td>Iteración de Valor</td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="implementación" class="level2">
<h2 class="anchored" data-anchor-id="implementación">Implementación</h2>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>gridworld.py</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" data-filename="gridworld.py" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> actualizar(funcion_de_valor, politica, longitud_del_mundo, recompensa,</span>
<span id="cb1-4">               descuento<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>):</span>
<span id="cb1-5">    nueva_funcion_de_valor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros((longitud_del_mundo, longitud_del_mundo))</span>
<span id="cb1-6">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se genera una matriz con ceros, la cual remplazara a la funcion de valor</span></span>
<span id="cb1-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># existente</span></span>
<span id="cb1-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> posicion_en_el_mundo, valor <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> np.ndenumerate(funcion_de_valor):</span>
<span id="cb1-9">        posicion_en_el_mundo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(posicion_en_el_mundo)</span>
<span id="cb1-10">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> es_estado_terminal(posicion_en_el_mundo, longitud_del_mundo):</span>
<span id="cb1-11">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se confirma si el estado es terminal o no</span></span>
<span id="cb1-12">            nuevo_valor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb1-13">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _, accion_individual <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> politica.items():</span>
<span id="cb1-14">                <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se iterara por cada una de las acciones de nuestra politica</span></span>
<span id="cb1-15">                nueva_posicion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (posicion_en_el_mundo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-16">                                  accion_individual[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'accion'</span>])</span>
<span id="cb1-17">                x, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nueva_posicion.T</span>
<span id="cb1-18">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> longitud_del_mundo <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span></span>
<span id="cb1-19">                    longitud_del_mundo):                  </span>
<span id="cb1-20">                    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#nos fijamos si esta dentro del mundo, si no se le devuelve</span></span>
<span id="cb1-21">                    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#a la misma posicion</span></span>
<span id="cb1-22">                    nueva_posicion <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> posicion_en_el_mundo</span>
<span id="cb1-23">                nuevo_valor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> (accion_individual[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span></span>
<span id="cb1-24">                                (recompensa <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> descuento <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span></span>
<span id="cb1-25">                                 funcion_de_valor[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">tuple</span>(nueva_posicion)]))</span>
<span id="cb1-26">                    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se genera el nuevo valor que remplazara ese estado</span></span>
<span id="cb1-27">            nueva_funcion_de_valor[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">tuple</span>(posicion_en_el_mundo)] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nuevo_valor</span>
<span id="cb1-28">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> nueva_funcion_de_valor</span>
<span id="cb1-29"></span>
<span id="cb1-30"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> es_estado_terminal(posicion_en_el_mundo, longitud_del_mundo):</span>
<span id="cb1-31">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">'''esta funcion hara que la funcion de valor no sufra ningun cambio cuando</span></span>
<span id="cb1-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    se encuentre en los estados terminales'''</span></span>
<span id="cb1-33">    inicio <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-34">    final <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([longitud_del_mundo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, longitud_del_mundo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb1-35">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (np.array_equal(posicion_en_el_mundo, inicio) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span></span>
<span id="cb1-36">            np.array_equal(posicion_en_el_mundo, final))</span>
<span id="cb1-37"></span>
<span id="cb1-38"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> mundo_cuadricula(longitud_del_mundo, politica, recompensa, k<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>):</span>
<span id="cb1-39">    funcion_de_valor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros((longitud_del_mundo, longitud_del_mundo))</span>
<span id="cb1-40">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#la funcion inicial arbitraria inicializa con una matriz de ceros</span></span>
<span id="cb1-41">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> iteracion <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(k):</span>
<span id="cb1-42">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#se va a actualizar la funcion de valor basado en el valor de k</span></span>
<span id="cb1-43">        funcion_de_valor_nueva <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> actualizar(funcion_de_valor, politica,</span>
<span id="cb1-44">                                            longitud_del_mundo, recompensa)</span>
<span id="cb1-45">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> np.array_equal(funcion_de_valor_nueva, funcion_de_valor):</span>
<span id="cb1-46">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#si la politica deja de cambiar significa que se habra</span></span>
<span id="cb1-47">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#encontrado una solucion</span></span>
<span id="cb1-48">            <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"convergio! a la iteracion:"</span>, iteracion)</span>
<span id="cb1-49">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span>
<span id="cb1-50">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb1-51">            funcion_de_valor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> funcion_de_valor_nueva</span>
<span id="cb1-52">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(funcion_de_valor)</span>
<span id="cb1-53"></span>
<span id="cb1-54"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">__name__</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'__main__'</span>:</span>
<span id="cb1-55">    recompensa <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb1-56">    longitud_del_mundo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#el tamaño del mundo sera una cuadricula 4 x 4</span></span>
<span id="cb1-57">    politica <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {           <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#la politica es la misma que se explico en el post</span></span>
<span id="cb1-58">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'derecha'</span> : {</span>
<span id="cb1-59">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>: <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>,</span>
<span id="cb1-60">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'accion'</span>: np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb1-61">        },</span>
<span id="cb1-62">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'izquierda'</span> : {</span>
<span id="cb1-63">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>: <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>,</span>
<span id="cb1-64">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'accion'</span>: np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb1-65">        },</span>
<span id="cb1-66">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'arriba'</span> : {</span>
<span id="cb1-67">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>: <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>,</span>
<span id="cb1-68">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'accion'</span>: np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-69">        },</span>
<span id="cb1-70">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'abajo'</span> : {</span>
<span id="cb1-71">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'probabilidad'</span>: <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>,</span>
<span id="cb1-72">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'accion'</span>: np.array([<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb1-73">        }</span>
<span id="cb1-74">    }</span>
<span id="cb1-75">    mundo_cuadricula(longitud_del_mundo, politica, recompensa)</span></code></pre></div></div>
</div>
<p>Al ejecutarlo imprime la función de valor en cada iteración. Estas son las últimas líneas de la salida, que coinciden con la función de valor final de la figura 4.1 del libro de Sutton y Barto:</p>
<div class="nb-output">
<pre><code>[[  0. -14. -20. -22.]
 [-14. -18. -20. -20.]
 [-20. -20. -18. -14.]
 [-22. -20. -14.   0.]]
convergio! a la iteracion: 633</code></pre>
</div>
<p>El código está en <a href="https://github.com/miguelsilva15/Blog-AprendizajePorRefuerzo/blob/master/RL-4-GridWorld/gridworld.py">GitHub</a>.</p>
<p>Con esto concluimos el tema de programación dinámica, si hubiera alguna duda por favor déjala en los comentarios y espero haberte ayudado con este tema, sigue la serie de mis posts que pronto iré añadiendo más.</p>
<p>¡Muchas gracias!</p>
</section>
<section id="referencias" class="level2">
<h2 class="anchored" data-anchor-id="referencias">Referencias</h2>
<ul>
<li><a href="https://davidstarsilver.wordpress.com/wp-content/uploads/2025/04/lecture-3-planning-by-dynamic-programming-.pdf">UCL Course on RL Lecture 3: Planning by Dynamic Programming</a></li>
<li><a href="https://github.com/ShangtongZhang/reinforcement-learning-an-introduction/blob/master/chapter04/grid_world.py">Inspiración del ejemplo del mundo cuadrícula</a></li>
<li><a href="http://incompleteideas.net/book/RLbook2018.pdf">Richard Sutton’s Intro to Reinforcement Learning</a></li>
</ul>


</section>

 ]]></description>
  <category>aprendizaje por refuerzo</category>
  <guid>https://migsilva.com/es/posts/planificando-con-programacion-dinamica/</guid>
  <pubDate>Tue, 13 Aug 2019 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Procesos de decisión de Markov, parte 2</title>
  <link>https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-2/</link>
  <description><![CDATA[ 





<p>Continuaremos viendo procesos de decisión de Markov esta vez dejaremos de lado las introducciones y nos centraremos en el tema central, si deseas acceder a todos los posts sobre aprendizaje por refuerzo ingresa <a href="../../../es/index.html">aquí</a>, si deseas conocer el post de introducción a procesos de decisión de Markov ingresa <a href="../../../es/posts/procesos-de-decision-de-markov-parte-1/index.html">aquí</a>.</p>
<section id="procesos-de-decisión-de-markov" class="level2">
<h2 class="anchored" data-anchor-id="procesos-de-decisión-de-markov">Procesos de Decisión de Markov</h2>
<p>Los procesos de decisión de Markov poseen la misma forma que un proceso de recompensa de Markov pero en este caso se le agregan decisiones que van a ser tomadas por nuestro agente, es decir que ya no se moverá libremente en el sistema.</p>
<p>Ahora para adentrarnos en la definición agregaremos variables a la tupla ya antes explicada en la primera parte de este post &lt;<strong>S, A, P, R, γ</strong>&gt;</p>
<ul>
<li><strong>S</strong> es una lista de estados a los cuales puede pertenecer.</li>
<li><strong>A</strong> es una lista de acciones.</li>
<li><strong>P</strong> es una matriz de transición de estado.</li>
<li><strong>R</strong> es la función de recompensa.</li>
<li><strong>γ</strong> es el valor de descuento.</li>
</ul>
<p>En este caso se agregará una lista de acciones que se tomará, debido a que no será un problema en el cual el agente se moverá aleatoriamente en la cadena de Markov sino más bien será una serie de decisiones que nos llevarán a hallar la mayor recompensa.</p>
<p>Ahora que ya hemos definido lo que es un proceso de decisión de Markov actualizaremos nuestro ejemplo en base a estados y decisiones.</p>
<p><img src="https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-2/img-01.png" class="img-fluid"></p>
<p>En la parte inferior de la cadena de Markov se ve representada una decisión que puede transportarte aleatoriamente (según una probabilidad) a uno de los estados con los cuales está relacionado.</p>
<section id="políticas" class="level3">
<h3 class="anchored" data-anchor-id="políticas">Políticas</h3>
<p>Las políticas se pueden describir como una distribución π de acciones dado estados.</p>
<!-- antes una imagen: img-02.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cpi(a%20%5Cmid%20s)%20=%20%5Cmathbb%7BP%7D%5BA_t%20=%20a%20%5Cmid%20S_t%20=%20s%5D%0A"></p>
<p>La política depende del estado actual y no de los estados pasados.<br>
La política es independiente del tiempo, es decir son estacionarias.</p>
</section>
<section id="función-de-valor" class="level3">
<h3 class="anchored" data-anchor-id="función-de-valor">Función de Valor</h3>
<p>La función de valor se divide en dos conceptos separados, la función estado-valor, que representa qué tan bueno es un estado (o qué tanto valor tiene) y la función acción-valor que representa qué tan positivo es tomar cierta acción y qué tanto valor nos va a devolver.</p>
<p><strong>La función de estado-valor</strong> básicamente representa el retorno esperado desde un estado s siguiendo la política π</p>
<!-- antes una imagen: img-03.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0Av_%5Cpi(s)%20=%20%5Cmathbb%7BE%7D_%5Cpi%5BG_t%20%5Cmid%20S_t%20=%20s%5D%0A"></p>
<p>E representa la expectativa cuando se prueba todas las <strong>acciones</strong> dada la política π.</p>
<p><strong>La función de acción-valor</strong> iniciando desde el estado s, como la anterior pero tomando una acción a y luego siguiendo la política π para ver cuánto retorno nos trae.</p>
<!-- antes una imagen: img-04.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0Aq_%5Cpi(s,%20a)%20=%20%5Cmathbb%7BE%7D_%5Cpi%5BG_t%20%5Cmid%20S_t%20=%20s,%20A_t%20=%20a%5D%0A"></p>
</section>
<section id="ecuación-de-expectativa-de-bellman" class="level3">
<h3 class="anchored" data-anchor-id="ecuación-de-expectativa-de-bellman">Ecuación de expectativa de Bellman</h3>
<p>Esta vez volvemos a ver la ecuación de Bellman desde otro punto de vista:</p>
<p>Para la función de estado-valor puede ser descompuesta en la recompensa inmediata más el valor descontado del siguiente estado siguiendo la política π.</p>
<!-- antes una imagen: img-05.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0Av_%5Cpi(s)%20=%20%5Cmathbb%7BE%7D_%5Cpi%5BR_%7Bt+1%7D%20+%20%5Cgamma%20v_%5Cpi(S_%7Bt+1%7D)%20%5Cmid%20S_t%20=%20s%5D%0A"></p>
<p>Para la función de acción-valor puede también ser descompuesta en la expectativa por la recompensa actual y el valor de la acción que se eligió desde ese punto para adelante.</p>
<!-- antes una imagen: img-06.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0Aq_%5Cpi(s,%20a)%20=%20%5Cmathbb%7BE%7D_%5Cpi%5BR_%7Bt+1%7D%20+%20%5Cgamma%20q_%5Cpi(S_%7Bt+1%7D,%20A_%7Bt+1%7D)%20%5Cmid%20S_t%20=%20s,%20A_t%20=%20a%5D%0A"></p>
<p>Ahora a partir de los siguientes gráficos veremos cómo v y q se relacionan unos a otros y entraremos en mayor profundidad en la generalización de la ecuación de expectativa de Bellman.</p>
<p>En el siguiente gráfico muestra el estado “s” y las posibles acciones que puede tomar (siendo representado por los puntos negros). Si queremos saber cuál es el valor de “s” necesitamos promediar las acciones que se puedan tomar desde ese estado, en otras palabras lo que se debe hacer para saber el valor del estado “s” es observar cuál es el <strong>valor de las siguientes acciones que se pueden tomar dada la política</strong> π <strong>desde el estado “s” y promediarlas</strong>.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-2/img-07.png" class="img-fluid figure-img"></p>
<figcaption>Adaptado de David Silver, curso de RL de la UCL, clase 2.</figcaption>
</figure>
</div>
<!-- antes una imagen: img-08.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0Av_%5Cpi(s)%20=%20%5Csum_%7Ba%20%5Cin%20A%7D%20%5Cpi(a%20%5Cmid%20s)%5C,%20q_%5Cpi(s,%20a)%0A"></p>
<p>Ahora vamos a ver lo contrario, comenzaremos seleccionando una acción, dado el estado “s”, seleccionamos la acción “a” la cual dada la dinámica de nuestro Proceso de Decisión de Markov puede llevarlo hacia el estado de la derecha o el de la izquierda, entonces para hallar el valor de esta acción tendríamos que promediar el valor de los estados donde nos puede llevar esa acción junto a las probabilidades de la dinámica de nuestro Proceso de Decisión de Markov (la cual se denota en la fórmula por P), en otras palabras la probabilidad que nos pueda llevar al estado de la derecha y al de la izquierda.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-2/img-09.png" class="img-fluid figure-img"></p>
<figcaption>Adaptado de David Silver, curso de RL de la UCL, clase 2.</figcaption>
</figure>
</div>
<!-- antes una imagen: img-10.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0Aq_%5Cpi(s,%20a)%20=%20R_s%5Ea%20+%20%5Cgamma%20%5Csum_%7Bs'%20%5Cin%20S%7D%20P_%7Bss'%7D%5Ea%20v_%5Cpi(s')%0A"></p>
<p>Ambas propiedades se pueden mezclar de diferentes maneras para unificar ambas fórmulas en formas más complejas.</p>
<p>A continuación veremos cómo sería aplicada la Ecuación de Expectativa de Bellman en nuestro proceso de decisión de Markov de ejemplo.</p>
<p><img src="https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-2/img-11.png" class="img-fluid"></p>
<p>En este proceso hallaremos la función de estado-valor según la política que estamos utilizando (escoger cada uno de los caminos con igual probabilidad) iniciaremos en el segundo estado con igual probabilidad de escoger la acción de “ir a Buenos Aires” que nos traería una recompensa de -3 o “hacer turismo” con recompensa de -5, el hecho de haber escogido la acción de hacer turismo nos puede transportar, por dinámicas del proceso de decisión de Markov, hacia el primer estado, al segundo o al último (con probabilidades de 0.4, 0.4 y 0.2 respectivamente), entonces dado este caso al sumar todos los posibles resultados obtenemos cuánto sería el valor esperado de este estado.</p>
<p>Ahora, en este post hemos aprendido cómo hallar el valor para cada uno de los estados, utilizando la política de tener la misma probabilidad de caer en cualquier estado, pero todavía no tenemos claro cómo elegir el mejor camino que podría existir en nuestro proceso de decisión de Markov, es decir en cuál obtendríamos la mayor cantidad de recompensa, aquí es donde necesitamos la función de valor óptimo.</p>
</section>
<section id="función-de-valor-óptimo" class="level3">
<h3 class="anchored" data-anchor-id="función-de-valor-óptimo">Función de Valor Óptimo</h3>
<p>Como era en los casos anteriores, esta función de valor también se divide en valor estado y acción, cuyas definiciones pasaremos a revisar.</p>
<p>La función de estado-valor óptimo es la que posee el mayor valor sobre todas las políticas, en otras palabras se puede representar como el camino óptimo que traería mayor valor dentro de todo el sistema, y todas las políticas posibles.</p>
<!-- antes una imagen: img-12.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0Av_*(s)%20=%20%5Cmax_%5Cpi%20v_%5Cpi(s)%0A"></p>
<p>La función óptima de acción-valor es el máximo valor que se puede alcanzar luego de haber tomado una acción “a”, sobre todas las políticas. Este valor terminaría siendo el más importante, debido a que si se mapean todos los valores para cada opción ya se tendría resuelto el proceso de decisión de Markov, debido a que ya sabrías que si tomas cierto camino cuál es el valor de este, entonces teniendo los valores para cada acción seleccionarías los que te trajeran mayor valor, siempre.</p>
<!-- antes una imagen: img-13.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0Aq_*(s,%20a)%20=%20%5Cmax_%5Cpi%20q_%5Cpi(s,%20a)%0A"></p>
<p>En el siguiente ejemplo mostraremos cómo quedaría nuestro ejemplo si aplicáramos la función de valor óptimo.</p>
<p><img src="https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-2/img-14.png" class="img-fluid"></p>
<p>Los valores se hallan restando la recompensa por cada acción por ejemplo el penúltimo estado tiene un valor de 15 porque es la recompensa que puede ganar en el futuro, así se van hallando los diferentes valores de los estados basados en las acciones y las recompensas de estas, eso nos muestra qué tan bueno es estar en un estado y cuánto valor aporta, pero para saber cuál es el mejor camino para tomar debemos basarnos en el <strong>valor de <em>q</em></strong>, básicamente el valor de q nos demuestra qué acciones resultan con un mayor valor, y por tal motivo qué acción debemos tomar y podemos ver q visualmente por medio de los arcos que conectan a los estados en nuestro proceso de decisión de Markov.</p>
<p><strong>Política Óptima</strong></p>
<p>Para encontrar el mejor camino dentro de nuestro proceso de decisión de Markov es necesario encontrar la mejor política para este, a continuación veremos cómo definirla.</p>
<p>Para definir cuándo una política es mejor que otra se toma en cuenta que el valor de cada política sea mayor o igual que otra para cada uno de los estados, por lo tanto una política π no puede ser mejor que π’ si uno de sus estados tiene menor valor que π’.</p>
<p>Se puede concluir que:</p>
<ul>
<li>Siempre va a haber por lo menos una política óptima para cada proceso de decisión de Markov.</li>
<li>Si existe más de una política óptima, todas llegan a la misma función de valor.</li>
<li>Todas las políticas óptimas logran la óptima función de acción-valor.</li>
</ul>
</section>
<section id="ecuación-de-optimalidad-de-bellman" class="level3">
<h3 class="anchored" data-anchor-id="ecuación-de-optimalidad-de-bellman">Ecuación de Optimalidad de Bellman</h3>
<p>Por último veremos la aplicación de la ecuación de Bellman para encontrar las acciones más óptimas a tomar dentro del proceso de decisión de Markov.</p>
<p>Como se había visto previamente en la ecuación de expectativa de Bellman, iniciando desde un estado s, donde se tenían dos posibles acciones a tomar y se terminaba promediando el valor, a diferencia de ese caso, en la ecuación de optimalidad de Bellman se busca el mayor valor, por lo tanto, solo nos quedaríamos con la acción que tuviera el mayor valor de todas las posibles acciones.</p>
<!-- antes una imagen: img-15.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0Av_*(s)%20=%20%5Cmax_a%20q_*(s,%20a)%0A"></p>
<p>En el caso del mayor valor para nuestras acciones que son guiadas por las dinámicas de nuestro proceso de decisión de Markov no podríamos simplemente escoger la de mayor valor, porque en este caso es el sistema el que nos mueve de un estado al otro, luego de tomar una acción, así que la fórmula se mantendría exactamente igual como la vista en la ecuación de la expectativa de Bellman.</p>
<p>Espero que este post haya sido de ayuda para ustedes, cualquier duda estaré atento a resolverla en los comentarios, gracias por leer y asegúrate de seguir el resto de la serie de aprendizaje por refuerzo.</p>
<p>¡Muchas gracias!</p>
</section>
</section>
<section id="referencias" class="level2">
<h2 class="anchored" data-anchor-id="referencias">Referencias</h2>
<ul>
<li><a href="https://davidstarsilver.wordpress.com/wp-content/uploads/2025/04/lecture-2-mdp.pdf">UCL Course on RL Lecture 2: Markov Decisión Processes</a></li>
<li><a href="http://incompleteideas.net/book/RLbook2018.pdf">Richard Sutton’s Intro to Reinforcement Learning</a></li>
</ul>


</section>

 ]]></description>
  <category>aprendizaje por refuerzo</category>
  <guid>https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-2/</guid>
  <pubDate>Wed, 05 Jun 2019 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Procesos de decisión de Markov, parte 1</title>
  <link>https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-1/</link>
  <description><![CDATA[ 





<p>Siguiendo con la serie de <a href="../../../es/index.html">Aprendizaje por Refuerzo</a> en esta ocasión conoceremos más sobre procesos de decisión de Markov comenzando desde lo más básico y subiendo el nivel de complejidad de conceptos hasta explicar por completo todo el tema.</p>
<section id="procesos-de-markov" class="level2">
<h2 class="anchored" data-anchor-id="procesos-de-markov">Procesos de Markov</h2>
<section id="introducción" class="level3">
<h3 class="anchored" data-anchor-id="introducción">Introducción</h3>
<p>Los MDP (Procesos de Decisión de Markov) son la forma idealizada matemáticamente del problema de aprendizaje por refuerzo, para el cual se podría encontrar un enunciado teórico preciso que pueda describirla, en otras palabras los MDP describen formalmente el medio ambiente en el cual se desarrolla el RL, donde el medio ambiente es completamente observable, esto da como consecuencia que la mayoría de problemas dentro del RL se pueden formalizar como MDPs. Con los MDP se introducen varios elementos clave para la descripción matemática del problema, como el retorno, funciones de valor y <strong>las ecuaciones de Bellman</strong>.</p>
</section>
<section id="propiedad-de-markov" class="level3">
<h3 class="anchored" data-anchor-id="propiedad-de-markov">Propiedad de Markov</h3>
<p>La propiedad de Markov nos muestra que el futuro es independiente del pasado, dado el presente, lo cual se expresa en la siguiente fórmula:</p>
<!-- antes una imagen: img-01.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathbb%7BP%7D%5BS_%7Bt+1%7D%20%5Cmid%20S_t%5D%20=%20%5Cmathbb%7BP%7D%5BS_%7Bt+1%7D%20%5Cmid%20S_1,%20%5Cdots,%20S_t%5D%0A"></p>
<p>La cual significa que el estado actual (representado por Sₜ) contiene toda la información relevante de los estados pasados (S₁,….. Sₜ), por lo tanto ya no nos serviría tener mayor información de los estados pasados.</p>
</section>
<section id="matriz-de-transición-de-estados" class="level3">
<h3 class="anchored" data-anchor-id="matriz-de-transición-de-estados">Matriz de transición de estados</h3>
<p>Ahora pasaremos a ver la llamada matriz de transición de estados, la cual nos muestra cuál sería la probabilidad de transición desde un estado S a un estado S’ y en donde cada fila sumaría uno, se vería de la siguiente manera, estos conceptos serán mostrados en un ejemplo más adelante.</p>
<!-- antes una imagen: img-02.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Bbmatrix%7D%0AP_%7B11%7D%20&amp;%20%5Ccdots%20&amp;%20P_%7B1n%7D%20%5C%5C%0A%5Cvdots%20&amp;%20&amp;%20%5Cvdots%20%5C%5C%0AP_%7Bn1%7D%20&amp;%20%5Ccdots%20&amp;%20P_%7Bnn%7D%0A%5Cend%7Bbmatrix%7D%0A"></p>
</section>
<section id="definición" class="level3">
<h3 class="anchored" data-anchor-id="definición">Definición</h3>
<p>Simplificando, un proceso de Markov es un proceso sin memoria y aleatorio; en otras palabras es una <strong>secuencia de estados aleatorios que posee la propiedad de Markov</strong>.<br>
Se podría definir el proceso de Markov como una tupla &lt;S,P&gt;</p>
<ul>
<li>S es una lista de estados a los cuales puede pertenecer.</li>
<li>P es una matriz de transición de estado.</li>
</ul>
</section>
<section id="ejemplo" class="level3">
<h3 class="anchored" data-anchor-id="ejemplo">Ejemplo</h3>
<p>En este ejemplo se muestra el caso de un empleado del área de TI en una empresa de maquinarias que reside en México, se le ha encomendado la labor de visitar varias ciudades de Sudamérica donde conversará con varios consultores para encontrar la mejor oferta sobre una consultoría de optimización de procesos de producción, el objetivo de este empleado será escribir un informe en el cual dará su opinión de cada proveedor luego de visitar estas ciudades, en este viaje se verá tentado por hacer turismo en las bellas ciudades que visitará o en permanecer un tiempo en Lima, su ciudad natal, en la cual puede distraerse con amigos o con familia.</p>
<p><img src="https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-1/img-03.png" class="img-fluid"></p>
<p>Los números representan la probabilidad de ir al siguiente estado.</p>
<p>Ahora veremos cómo podemos sacar muestras de la cadena de Markov propuesta donde se iniciará desde nuestro primer destino, Caracas (S₁= Caracas).</p>
<ul>
<li>CARACAS, TURISMO, VIAJE DE RETORNO</li>
<li>CARACAS, BUENOS AIRES, LIMA, FIESTA CON AMIGOS, FIESTA CON AMIGOS, LIMA, LA PAZ, INFORME, VIAJE DE RETORNO</li>
<li>CARACAS, BUENOS AIRES, LIMA, VISITAR A MAMÁ, LIMA, LA PAZ, INFORME, VIAJE DE RETORNO</li>
<li>CARACAS, BUENOS AIRES, LIMA, LA PAZ, INFORME, VIAJE DE RETORNO</li>
</ul>
<p>Ahora observaremos la matriz de transición de estados para este caso:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 10%">
<col style="width: 10%">
<col style="width: 10%">
<col style="width: 10%">
<col style="width: 10%">
<col style="width: 10%">
<col style="width: 10%">
<col style="width: 10%">
<col style="width: 10%">
<col style="width: 10%">
</colgroup>
<thead>
<tr class="header">
<th></th>
<th>CARACAS</th>
<th>TURISMO</th>
<th>BUENOS AIRES</th>
<th>LIMA</th>
<th>VISITAR A MAMÁ</th>
<th>FIESTA CON AMIGOS</th>
<th>LA PAZ</th>
<th>INFORME</th>
<th>VIAJE DE RETORNO</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>CARACAS</td>
<td></td>
<td>0.2</td>
<td>0.8</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr class="even">
<td>TURISMO</td>
<td>0.4</td>
<td></td>
<td>0.4</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>0.2</td>
</tr>
<tr class="odd">
<td>BUENOS AIRES</td>
<td></td>
<td>0.3</td>
<td></td>
<td>0.7</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr class="even">
<td>LIMA</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>0.4</td>
<td>0.3</td>
<td>0.3</td>
<td></td>
<td></td>
</tr>
<tr class="odd">
<td>VISITAR A MAMÁ</td>
<td></td>
<td></td>
<td></td>
<td>1.0</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr class="even">
<td>FIESTA CON AMIGOS</td>
<td></td>
<td></td>
<td></td>
<td>0.3</td>
<td></td>
<td>0.7</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr class="odd">
<td>LA PAZ</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>1.0</td>
<td></td>
</tr>
<tr class="even">
<td>INFORME</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>1.0</td>
</tr>
<tr class="odd">
<td>VIAJE DE RETORNO</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>1</td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="procesos-de-recompensa-de-markov" class="level2">
<h2 class="anchored" data-anchor-id="procesos-de-recompensa-de-markov">Procesos de Recompensa de Markov</h2>
<p>Los procesos de recompensa de Markov se pueden ver como procesos de Markov normales con valores que juzgan qué tan positivo es estar en un estado, esto traería un cambio a la definición de procesos de Markov que tuvimos previamente agregándole dos nuevas variables.</p>
<p>Se podría definir el proceso de recompensa de Markov como una tupla &lt;S,P,R, γ&gt;</p>
<ul>
<li><strong>S</strong> es una lista de estados a los cuales puede pertenecer.</li>
<li><strong>P</strong> es una matriz de transición de estado.</li>
<li><strong>R</strong> es la recompensa inmediata en el estado donde nos encontraríamos, se puede expresar de la siguiente manera</li>
</ul>
<!-- antes una imagen: img-04.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0AR_s%20=%20%5Cmathbb%7BE%7D%5BR_%7Bt+1%7D%20%5Cmid%20S_t%20=%20s%5D%0A"></p>
<ul>
<li><strong>γ</strong> es un valor de descuento que va entre el 0 a 1</li>
</ul>
<p>Ahora al ejemplo le agregamos los valores de la recompensa en cada estado, que quede claro que para este y los siguientes ejemplos el valor de descuento será de 1 por motivos didácticos (salvo en el ejemplo de retorno de más abajo, que usa 1/3 para que se note su efecto):</p>
<p><img src="https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-1/img-05.png" class="img-fluid"></p>
<section id="retorno" class="level3">
<h3 class="anchored" data-anchor-id="retorno">Retorno</h3>
<p>El retorno Gₜ es el total de recompensa multiplicado por el valor de descuento en cada paso de tiempo.</p>
<!-- antes una imagen: img-06.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0AG_t%20=%20R_%7Bt+1%7D%20+%20%5Cgamma%20R_%7Bt+2%7D%20+%20%5Ccdots%20=%20%5Csum_%7Bk=0%7D%5E%7B%5Cinfty%7D%20%5Cgamma%5Ek%20R_%7Bt+k+1%7D%0A"></p>
<p>Si el valor del descuento es 0, significa que solo tomas en cuenta la primera recompensa, ya que los demás valores se harían 0; por otro lado si el valor del descuento es 1, significa que se tomará en cuenta todas las recompensas por igual.<br>
En otras palabras el valor de descuento te permite elegir qué tanto priorizar las recompensas más cercanas o más lejanas.</p>
</section>
<section id="pero-por-qué-es-conveniente-usar-descuento" class="level3">
<h3 class="anchored" data-anchor-id="pero-por-qué-es-conveniente-usar-descuento">¿Pero por qué es conveniente usar descuento?</h3>
<ul>
<li>Es matemáticamente conveniente usar descuentos.</li>
<li>Evita bucles infinitos en procesos de Markov cíclicos.</li>
<li>No siempre la incertidumbre del futuro puede ser representada.</li>
<li>El comportamiento animal muestra preferencia por recompensas inmediatas.</li>
</ul>
<p>También es posible usar procesos de Markov sin descuento, cuando todas las secuencias pueden terminar (por ejemplo el caso propuesto).</p>
</section>
<section id="función-de-valor" class="level3">
<h3 class="anchored" data-anchor-id="función-de-valor">Función de valor</h3>
<p>Se representa como v(s) y nos muestra cuál es la recompensa esperada desde ese estado hasta el final de la secuencia.</p>
<!-- antes una imagen: img-07.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0Av(s)%20=%20%5Cmathbb%7BE%7D%5BG_t%20%5Cmid%20S_t%20=%20s%5D%0A"></p>
</section>
<section id="ejemplo-de-retorno-de-la-cadena-de-markov" class="level3">
<h3 class="anchored" data-anchor-id="ejemplo-de-retorno-de-la-cadena-de-markov">Ejemplo de Retorno de la Cadena de Markov</h3>
<p>Comenzando el ejemplo de S₁ = Caracas, γ=1/3</p>
<!-- antes una imagen: img-08.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0AG_1%20=%20R_2%20+%20%5Cgamma%20R_3%20+%20%5Ccdots%20+%20%5Cgamma%5E%7BT-2%7D%20R_T%0A"></p>
<table class="caption-top table">
<colgroup>
<col style="width: 50%">
<col style="width: 50%">
</colgroup>
<thead>
<tr class="header">
<th>Ruta</th>
<th>Retorno</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>CARACAS, TURISMO, VIAJE DE RETORNO</td>
<td><img src="https://latex.codecogs.com/png.latex?v_1%20=%20-3%20-%205%20%5Ccdot%20%5Ctfrac%7B1%7D%7B3%7D%20+%200%20%5Ccdot%20%5Ctfrac%7B1%7D%7B9%7D%20=%20-4.67"></td>
</tr>
<tr class="even">
<td>CARACAS, BUENOS AIRES, LIMA, FIESTA CON AMIGOS, FIESTA CON AMIGOS, LIMA, LA PAZ, INFORME, VIAJE DE RETORNO</td>
<td><img src="https://latex.codecogs.com/png.latex?v_2%20=%20-3%20-%203%20%5Ccdot%20%5Ctfrac%7B1%7D%7B3%7D%20-%202%20%5Ccdot%20%5Ctfrac%7B1%7D%7B9%7D%20-%201%20%5Ccdot%20%5Ctfrac%7B1%7D%7B27%7D%20-%201%20%5Ccdot%20%5Ctfrac%7B1%7D%7B81%7D%20-%202%20%5Ccdot%20%5Ctfrac%7B1%7D%7B243%7D%20-%203%20%5Ccdot%20%5Ctfrac%7B1%7D%7B729%7D%20+%2015%20%5Ccdot%20%5Ctfrac%7B1%7D%7B2187%7D%20+%200%20%5Ccdot%20%5Ctfrac%7B1%7D%7B6561%7D%20=%20-4.28"></td>
</tr>
<tr class="odd">
<td>CARACAS, BUENOS AIRES, LIMA, VISITAR A MAMÁ, LIMA, LA PAZ, INFORME, VIAJE DE RETORNO</td>
<td><img src="https://latex.codecogs.com/png.latex?v_3%20=%20-3%20-%203%20%5Ccdot%20%5Ctfrac%7B1%7D%7B3%7D%20-%202%20%5Ccdot%20%5Ctfrac%7B1%7D%7B9%7D%20-%201%20%5Ccdot%20%5Ctfrac%7B1%7D%7B27%7D%20-%202%20%5Ccdot%20%5Ctfrac%7B1%7D%7B81%7D%20-%203%20%5Ccdot%20%5Ctfrac%7B1%7D%7B243%7D%20+%2015%20%5Ccdot%20%5Ctfrac%7B1%7D%7B729%7D%20+%200%20%5Ccdot%20%5Ctfrac%7B1%7D%7B2187%7D%20=%20-4.28"></td>
</tr>
<tr class="even">
<td>CARACAS, BUENOS AIRES, LIMA, LA PAZ, INFORME, VIAJE DE RETORNO</td>
<td><img src="https://latex.codecogs.com/png.latex?v_4%20=%20-3%20-%203%20%5Ccdot%20%5Ctfrac%7B1%7D%7B3%7D%20-%202%20%5Ccdot%20%5Ctfrac%7B1%7D%7B9%7D%20-%203%20%5Ccdot%20%5Ctfrac%7B1%7D%7B27%7D%20+%2015%20%5Ccdot%20%5Ctfrac%7B1%7D%7B81%7D%20+%200%20%5Ccdot%20%5Ctfrac%7B1%7D%7B243%7D%20=%20-4.15"></td>
</tr>
</tbody>
</table>
</section>
<section id="ecuación-de-bellman" class="level3">
<h3 class="anchored" data-anchor-id="ecuación-de-bellman">Ecuación de Bellman</h3>
<p>La ecuación de Bellman lo que hace es partir la función de valor en dos, en la recompensa inmediata de ese estado y el valor que vas a obtener luego de ese estado en adelante.</p>
<!-- antes una imagen: img-09.png -->
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0Av(s)%20&amp;=%20%5Cmathbb%7BE%7D%5BG_t%20%5Cmid%20S_t%20=%20s%5D%20%5C%5C%0A&amp;=%20%5Cmathbb%7BE%7D%5BR_%7Bt+1%7D%20+%20%5Cgamma%20R_%7Bt+2%7D%20+%20%5Cgamma%5E2%20R_%7Bt+3%7D%20+%20%5Ccdots%20%5Cmid%20S_t%20=%20s%5D%20%5C%5C%0A&amp;=%20%5Cmathbb%7BE%7D%5BR_%7Bt+1%7D%20+%20%5Cgamma%20(R_%7Bt+2%7D%20+%20%5Cgamma%20R_%7Bt+3%7D%20+%20%5Ccdots)%20%5Cmid%20S_t%20=%20s%5D%20%5C%5C%0A&amp;=%20%5Cmathbb%7BE%7D%5BR_%7Bt+1%7D%20+%20%5Cgamma%20G_%7Bt+1%7D%20%5Cmid%20S_t%20=%20s%5D%20%5C%5C%0A&amp;=%20%5Cmathbb%7BE%7D%5BR_%7Bt+1%7D%20+%20%5Cgamma%20v(S_%7Bt+1%7D)%20%5Cmid%20S_t%20=%20s%5D%0A%5Cend%7Baligned%7D%0A"></p>
<p>Básicamente para hallar el valor de un estado se mira en los siguientes y en el valor de cada uno de estos, luego se suman todos estos valores para representar el valor del estado inicial.</p>
<p>Ahora mostraremos la ecuación de Bellman aplicada al MRP de ejemplo, antes explicado.</p>
<p><img src="https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-1/img-10.png" class="img-fluid"></p>
<p>Como se ve en nuestro gráfico explicaremos el valor de un estado específico (el que se encuentra de color rojo), se toma los valores de los dos posibles estados en los que puede terminar el agente desde el estado inicial, estos dos estados tienen un valor y una probabilidad de terminar en cada uno, estos se multiplican y se suman para hallar el valor del estado inicial.</p>
</section>
<section id="resolviendo-la-ecuación-de-bellman" class="level3">
<h3 class="anchored" data-anchor-id="resolviendo-la-ecuación-de-bellman">Resolviendo la ecuación de Bellman</h3>
<p>La ecuación de Bellman es lineal y puede ser resuelta directamente aunque su complejidad es O(n³) para n estados, por lo tanto solo puede ser resuelta de esta manera para MRPs pequeños, para otros casos es recomendado otras técnicas como programación dinámica u otras técnicas.</p>
<p>En el siguiente post veremos el final de este tema explicando los procesos de decisión de Markov y los estados que lo conforman, puedes acceder al siguiente post en <a href="../../../es/posts/procesos-de-decision-de-markov-parte-2/index.html">Procesos de decisión de Markov, parte 2.</a></p>
</section>
</section>
<section id="referencias" class="level2">
<h2 class="anchored" data-anchor-id="referencias">Referencias</h2>
<ul>
<li><a href="https://davidstarsilver.wordpress.com/wp-content/uploads/2025/04/lecture-2-mdp.pdf">UCL Course on RL Lecture 2: Markov Decisión Processes</a></li>
<li><a href="http://incompleteideas.net/book/RLbook2018.pdf">Richard Sutton’s Intro to Reinforcement Learning</a></li>
</ul>


</section>

 ]]></description>
  <category>aprendizaje por refuerzo</category>
  <guid>https://migsilva.com/es/posts/procesos-de-decision-de-markov-parte-1/</guid>
  <pubDate>Thu, 30 May 2019 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Introducción al mundo del RL</title>
  <link>https://migsilva.com/es/posts/introduccion-al-mundo-del-rl/</link>
  <description><![CDATA[ 





<p>Hola a todos, esta será una serie de posts donde explicaré la teoría detrás del aprendizaje por refuerzo lo más simple y cautivadoramente que pueda, para juntos introducirnos en este mundo. Al final dejaré links donde se pueda investigar más profundamente.</p>
<p>Si deseas ver la serie de posts completa, accede <a href="../../../es/index.html">aquí</a>.<br>
Me centraré en hacerlo en español debido a que no he encontrado un recurso parecido sobre este tema en este idioma. Cualquier comentario y/o modificación que se proponga será bien recibido.</p>
<p><strong>Actualización:</strong> Estos posts son de 2019 y 2020. He trabajado en recuperarlos y poco a poco pienso terminar esta serie (como testimonio de perseverancia). Los códigos han sido actualizados, porque varios de ellos funcionaban en ese entonces, pero ahora no, por temas de paquetes, etc.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/introduccion-al-mundo-del-rl/img-01.gif" class="img-fluid figure-img"></p>
<figcaption>Pacman siendo jugado por un agente de aprendizaje por refuerzo. Pac-Man es una marca de Bandai Namco.</figcaption>
</figure>
</div>
<section id="qué-es-aprendizaje-por-refuerzo" class="level2">
<h2 class="anchored" data-anchor-id="qué-es-aprendizaje-por-refuerzo">¿Qué es aprendizaje por refuerzo?</h2>
<p>El aprendizaje por refuerzo es un área de la inteligencia artificial que está centrada en descubrir qué acciones se deben tomar para maximizar la señal de recompensa; en otras palabras, se centra en cómo mapear situaciones a acciones que se centren en encontrar dicha recompensa. Al agente no se le dice qué acciones tomar, sino que, al contrario, él debe experimentar para encontrar qué acciones lo llevan a una mayor recompensa. Los casos más desafiantes son aquellos en los que la recompensa no es inmediata, sino que llega en las siguientes situaciones.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://migsilva.com/es/posts/introduccion-al-mundo-del-rl/img-02.jpeg" class="img-fluid figure-img"></p>
<figcaption>Adaptado de Sutton y Barto (1998).</figcaption>
</figure>
</div>
<section id="diferencia-con-aprendizaje-supervisado" class="level3">
<h3 class="anchored" data-anchor-id="diferencia-con-aprendizaje-supervisado">Diferencia con aprendizaje supervisado</h3>
<p>El aprendizaje supervisado está basado en un set de ejemplos que han sido etiquetados previamente; en otras palabras, te muestra exactamente qué acción debes tomar en cada circunstancia, lo que mayormente consiste en identificar o categorizar la situación. Por eso, el objetivo de este tipo de aprendizaje es generalizar o extrapolar a situaciones que no estén presentes en los datos de entrenamiento. Esto, sin embargo, no es beneficioso para los problemas interactivos, debido a que, al saber qué acciones debe desempeñar el agente, esta técnica termina siendo inefectiva en territorio no explorado. Es ahí donde el agente debe aprender por su propia experiencia.</p>
</section>
<section id="diferencia-con-aprendizaje-no-supervisado" class="level3">
<h3 class="anchored" data-anchor-id="diferencia-con-aprendizaje-no-supervisado">Diferencia con aprendizaje no supervisado</h3>
<p>El aprendizaje no supervisado se centra en encontrar estructuras dentro de una colección de datos, mientras que el aprendizaje por refuerzo se enfoca en aumentar la señal de recompensa.</p>
<p>Debido a lo que hemos visto, el aprendizaje por refuerzo se considera un tercer paradigma de aprendizaje automático.<br>
Uno de los desafíos más grandes que existen en el aprendizaje por refuerzo es el intercambio entre <strong>explotación y exploración</strong>. Para que el agente pueda encontrar mayor recompensa, debe explotar lo que le ha funcionado en el pasado, pero para descubrir estas acciones debe explorar nuevas acciones. Tomar alguna de las dos acciones exclusivamente lleva al error, por lo cual deben ser balanceadas progresivamente; una acción se debe probar muchas veces para saber con mayor confianza cuánta recompensa esperar. Este dilema ha sido estudiado extensivamente sin encontrar una solución definitiva.</p>
<p>Otro aspecto clave del aprendizaje por refuerzo es el enfoque, el cual se centra en el problema de un agente orientado hacia un objetivo en un medio ambiente desconocido. Todos los agentes en aprendizaje por refuerzo tienen objetivos explícitos, pueden sentir los cambios en el ambiente y pueden tomar acciones que lo influencien. Como se trata de un enfoque que engloba todo el problema orientado hacia un objetivo, el agente no necesariamente es un organismo completo o un robot.</p>
</section>
</section>
<section id="ejemplos" class="level2">
<h2 class="anchored" data-anchor-id="ejemplos">Ejemplos</h2>
<section id="openai-dexterity" class="level3">
<h3 class="anchored" data-anchor-id="openai-dexterity">OpenAI Dexterity</h3>
<p>OpenAI desarrolló un sistema llamado Dactyl, el cual está completamente entrenado en simulaciones de computadora y transfiere el conocimiento aprendido hacia el mundo real. Este sistema aprende desde cero utilizando aprendizaje por refuerzo. Su objetivo es demostrar que el entrenamiento por refuerzo en simulaciones puede lograr un gran impacto en la vida real: incluso con lo “ruidoso” que es esto, por ejemplo, con sensores que no responden a tiempo y con datos parciales, igual logra manipular con destreza el objeto y lograr el objetivo propuesto (mostrar una cara específica del cubo).</p>
<iframe class="video-embed" src="https://www.youtube-nocookie.com/embed/DKe8FumoD4E" title="Learning Dexterity: Uncut (OpenAI)" loading="lazy" allowfullscreen="">
</iframe>
</section>
<section id="alphastar" class="level3">
<h3 class="anchored" data-anchor-id="alphastar">AlphaStar</h3>
<p>Los juegos se han usado por décadas como una manera de probar el desempeño de sistemas de inteligencia artificial. Como su capacidad ha aumentado, con el tiempo se han buscado juegos mucho más complejos y desafiantes que contengan elementos básicos de inteligencia que permitan resolver problemas científicos o de la vida real. Como ya ha ocurrido con otros juegos antes (Atari, Mario, Quake, Dota 2), en una serie de partidas de prueba AlphaStar venció al jugador profesional de StarCraft II Grzegorz “MaNa” Komincz por 5–0. Esto se dio en condiciones de partidas oficiales entre jugadores profesionales.<br>
AlphaStar fue entrenado inicialmente utilizando aprendizaje supervisado sobre partidas anónimas publicadas por Blizzard. Esto permitió que aprendiera micro y macro estrategias de jugadores reales; luego, el sistema comenzó a jugar contra sí mismo para mejorar sus estrategias por medio de aprendizaje por refuerzo.</p>
<video autoplay="" loop="" muted="" playsinline="" class="looping-clip" aria-label="AlphaStar vs MaNa">
<source src="alphastar-vs-mana.mp4" type="video/mp4">
</video>
<p>AlphaStar vs MaNa. Fuente: demostración de AlphaStar de DeepMind (StarCraft II es de Blizzard).</p>
</section>
<section id="navegación-de-robots" class="level3">
<h3 class="anchored" data-anchor-id="navegación-de-robots">Navegación de robots</h3>
<p>Cada día se encuentran nuevas aplicaciones del aprendizaje por refuerzo. Este tipo de aprendizaje resulta útil para mapear entradas de sensores, agarrar objetos y controlar movimientos de robots. Es por esto que se ha generado este sistema de prueba, el cual puede servir para gente que posee algún impedimento para moverse libremente. Estos robots pueden recorrer grandes distancias y traer las compras, medicinas y, en general, cualquier tipo de paquete. Es el futuro de los repartos y se está haciendo con aprendizaje por refuerzo.</p>
<iframe class="video-embed" src="https://www.youtube-nocookie.com/embed/Kq1nQAF4xeM" title="Robot navigation with AutoRL (Aleksandra Faust)" loading="lazy" allowfullscreen="">
</iframe>
</section>
</section>
<section id="elementos-del-aprendizaje-por-refuerzo" class="level2">
<h2 class="anchored" data-anchor-id="elementos-del-aprendizaje-por-refuerzo">Elementos del aprendizaje por refuerzo</h2>
<p>Aparte del agente y el medio ambiente, se pueden identificar cuatro subelementos de un sistema de aprendizaje por refuerzo: una <strong>política/policy, señal de recompensa/reward signal, función de valor/value function</strong>, y opcionalmente, un <strong>modelo</strong> del medio ambiente.</p>
<p>Una <strong>política</strong> define el modo en que el agente se comporta en un momento dado; una política vendría a mapear qué acciones se deberían llevar a cabo dados los estados que se han percibido del medio ambiente. Una política puede representar una función simple o una tabla de búsqueda, aunque en la mayoría de casos puede involucrar un cálculo extensivo. La política representa el núcleo del agente y es suficiente para determinar el comportamiento de este.</p>
<p>La <strong>señal de recompensa</strong> es lo que define el objetivo del problema que se quiere solucionar. En cada paso de tiempo, el ambiente retorna un número llamado <em>recompensa</em>, y el objetivo del agente es maximizar esta recompensa a largo plazo; en este caso, la señal de recompensa decide cuáles son buenos o malos eventos para el agente. La señal de recompensa termina siendo uno de los recursos más importantes para la política, debido a que, si la acción lleva a una recompensa baja, la política deberá variar para futuros eventos que involucren a esa acción en la misma situación.</p>
<p>Es aquí donde se genera la diferencia con la <strong>función de valor</strong>, ya que la señal de recompensa señala qué será lo mejor a corto plazo, pero a largo plazo la encargada es la función de valor.<br>
El <em>valor</em> representa la cantidad de recompensa que puede esperar el agente en el futuro, iniciando desde el estado actual. Es decir, la recompensa es lo que se debe buscar: sin recompensa no puede haber valor, y el valor solo sirve para encontrar una mayor recompensa. Las acciones se guían por los valores para encontrar una mayor recompensa; por eso se buscan acciones que puedan traer mayor valor, no mayor recompensa, porque dichas acciones son las que obtienen mayor recompensa a largo plazo.</p>
<p>Por último, está el <strong>modelo</strong> del medio ambiente. Este modelo imita el comportamiento del medio ambiente y generalmente ayuda a inferir cómo el medio ambiente se va a comportar; por ejemplo, dado un estado y una acción, el modelo puede predecir el siguiente estado y la siguiente recompensa. Normalmente estos modelos se utilizan para planificar qué acciones se llevarán a cabo. Los métodos que utilizan modelos para resolver problemas de aprendizaje por refuerzo se llaman <strong>métodos basados en modelos</strong> o <strong>model-based</strong>; por otro lado, también existe el método llamado <strong>model-free o sin modelo</strong>, el cual se basa en prueba y error, lo que es visto como lo contrario a la planificación.</p>
<p>Aparte de estos métodos, también existen los basados en el <strong>valor/value based</strong>, los basados en la <strong>política/policy based</strong> y el <strong>actor crítico/actor critic</strong>, que se basa en la política y el valor.</p>
</section>
<section id="problemas-dentro-del-aprendizaje-por-refuerzo" class="level2">
<h2 class="anchored" data-anchor-id="problemas-dentro-del-aprendizaje-por-refuerzo">Problemas dentro del aprendizaje por refuerzo</h2>
<p>Los principales problemas en la toma de decisiones secuenciales se pueden dividir en dos ramas:</p>
<p><strong>Aprendizaje por refuerzo</strong></p>
<ul>
<li>El medio ambiente es desconocido.</li>
<li>Los agentes interactúan con el medio ambiente.</li>
<li>Los agentes mejoran su política.</li>
</ul>
<p><strong>Planificación</strong></p>
<ul>
<li>Un modelo del medio ambiente es conocido.</li>
<li>El agente realiza cálculos con el modelo (sin ninguna interacción externa).</li>
<li>El agente mejora su política.</li>
<li>Búsqueda, deliberación, razonamiento, etc.</li>
</ul>
<p>Muchas gracias por leer este artículo. En los siguientes posts entraremos a conocer más de este mundo. Si deseas ver el siguiente, ingresa a <a href="../../../es/posts/procesos-de-decision-de-markov-parte-1/index.html">Procesos de decisión de Markov, parte 1</a>.</p>
</section>
<section id="referencias" class="level2">
<h2 class="anchored" data-anchor-id="referencias">Referencias</h2>
<ul>
<li><a href="https://davidstarsilver.wordpress.com/wp-content/uploads/2025/04/intro_rl.pdf">UCL Course on RL Lecture 1: Introduction to Reinforcement Learning</a></li>
<li><a href="http://incompleteideas.net/book/RLbook2018.pdf">Richard Sutton’s Intro to Reinforcement Learning</a></li>
<li><a href="https://openai.com/index/learning-dexterity/">Learning Dexterity (OpenAI)</a></li>
<li><a href="https://deepmind.google/discover/blog/alphastar-mastering-the-real-time-strategy-game-starcraft-ii/">AlphaStar: Mastering the real-time strategy game StarCraft II (DeepMind)</a></li>
<li><a href="https://research.google/blog/long-range-robotic-navigation-via-automated-reinforcement-learning/">Long-Range Robotic Navigation via Automated Reinforcement Learning (Google Research)</a></li>
</ul>


</section>

 ]]></description>
  <category>aprendizaje por refuerzo</category>
  <guid>https://migsilva.com/es/posts/introduccion-al-mundo-del-rl/</guid>
  <pubDate>Sun, 28 Apr 2019 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
