**Métodos Aproximados** SVRAI
Fernando Sancho Caparrini --- ## Objetivos * Hasta ahora hemos supuesto que la función de valor se puede representar como una tabla. * Pero esto es solo útil para problemas pequeños y discretos. * Si el espacio de estados es grande, puede requerir una cantidad inviable de memoria, y los métodos exactos requieren una cantidad excesivamente grande de recursos de computación (en tiempo y en espacio). * Entonces, no queda más remedio que recurrir a métodos aproximados, donde la solución puede no ser exacta. * Vamos a ofrecer varios enfoques para aproximar la función de valor y cómo incorporar la programación dinámica para derivar políticas aproximadamente óptimas. --- ## Representaciones paramétricas * $U_\theta(s)$ denota una representación paramétrica de $U$, donde $\theta$ es el vector de parámetros. * Si tenemos una aproximación $U_\theta$, entonces: $\pi(s) = \arg \max_a \Big( R(s, a) + \gamma \sum_{s'} T(s' | s, a)U_\theta(s')\Big)$ * Si el espacio de estados es continuo, la suma anterior puede sustituirse por una integral, y esta integral puede aproximarse utilizando muestras del modelo de transición. * Otra opción: aproximar $Q(s, a)$. * Si $Q_\theta(s, a)$ es una aproximación paramétrica, entonces: $\pi(s) = \arg \max_a Q_\theta(s, a)$. * Aplicamos programación dinámica a $S = s_{1:m}$ para aproximar $U_\theta$ sobre el espacio de estados completo. * Si el espacio de estados es de dimensión relativamente baja, podemos definir una cuadrícula/malla. * Utilizar un muestreo aleatorio del espacio de estados (sesgando el muestreo hacia los estados más importantes realizando simulaciones con alguna política). * Enfoque iterativo: Alternar entre la mejora de las estimaciones de $U$ en $S$ mediante programación dinámica (con backup) y el reajuste de la aproximación en esos estados (con una función genérica). --- ## Representaciones paramétricas !!!alg:Algoritmo 1. ~~~~ struct ApproximateValueIteration Uθ # initial parameterized value function that supports fit! S # set of discrete states for performing backups k_max # maximum number of iterations end function solve(M::ApproximateValueIteration, 𝒫::MDP) Uθ, S, k_max = M.Uθ, M.S, M.k_max for k in 1:k_max U = [backup(𝒫, Uθ, s) for s in S] fit!(Uθ, S, U) end return ValueFunctionPolicy(𝒫, Uθ) end ~~~~ Las representaciones paramétricas que veremos siguen la estructura de este algoritmo: puede cambiar la evaluación de $U_\theta$ y la función de ajuste de $U_\theta$ (`fit!`). --- ## Representaciones paramétricas Podemos agrupar las representaciones paramétricas en dos categorías: 1. **Métodos de aproximación local**: $\theta=\{U(s):\ s\in S\}$. $U_\theta(s)$ usa una suma ponderada de los valores almacenados en $S$. 2. **Métodos de aproximación global**: $\theta$ no directamente relacionada $U$ en $S$. En general: $U_\theta(s) = \theta^⊤ \beta(s)$, donde la diferencia está en cómo se define la función vectorial $\beta$: * Aproximación local: $\beta(s)$ determina cómo ponderar las utilidades de los estados en $S$ para aproximar la utilidad en el estado $s$. Las ponderaciones son generalmente no negativas y suman $1$. * Aproximación global: $\beta(s)$ se ve como un conjunto de funciones base que se combinan de forma lineal para obtener una aproximación para un $s$ arbitrario. También es válido para $Q$: $Q_\theta(s, a) = \theta^⊤ \beta(s, a)$: * Aproximaciones local: se pueden dar aproximaciones sobre $\mathscr{A}$ continuos eligiendo un conjunto finito $A \subseteq \mathscr{A}$. $\theta$ consiste entonces en $|S| \times |A|$ componentes, para cada uno de los pares estado-acción. --- ## Vecinos más cercanos ![](../img/knn.jpg align=right width=25%)El enfoque más sencillo: para cada $s$ utilizar el valor del **vecino más cercano**. * Si $d(s, s')$ denota la distancia entre $s$ y $s'$, entonces $U_\theta(s) = \theta_i$, donde: $$i = \arg \min_{j\in 1:m} d(s_j, s)$$ * $U$ constante a trozos. * Generalización: promediar los valores de los **$k$ vecinos más cercanos**. * $U$ constante a trozos, pero con más *definición*. --- ## Vecinos más cercanos !!!alg: Nearest Neighbor Value Function ~~~~ mutable struct NearestNeighborValueFunction k # number of neighbors d # distance function d(s, s') S # set of discrete states θ # vector of values at states in S end function (Uθ::NearestNeighborValueFunction)(s) dists = [Uθ.d(s,s') for s' in Uθ.S] ind = sortperm(dists)[1:Uθ.k] return mean(Uθ.θ[i] for i in ind) end function fit!(Uθ::NearestNeighborValueFunction, S, U) Uθ.θ = U return Uθ end ~~~~ --- ## Kernel de suavizado * ![](../img/kernel.jpg align=right width=25%)$k(s, s')$ es la similaridad ente pares de estados $s$ y $s'$. * $k(s, s')$ es mayor para los estados que están más cerca entre sí porque esos valores nos indican cómo ponderar juntas las utilidades asociadas a los estados en $S$. * $U_\theta(s) = \sum_{i=1}^m \theta_i \beta_i(s) = \theta^⊤ \beta(s)$, donde $\beta_i(s) = \frac{k(s, s_i)}{\sum_{j=1}^m k(s, s_j)}$ * Opciones comunes de kernel: * $k(s, s') = max(d(s, s'), \epsilon)^{-1}$, donde $\epsilon > 0$. * $k(s, s') = exp \Big(-\frac{d(s, s')^2}{2\sigma^2} \Big)$, donde $\sigma$ controla el grado de suavidad. --- ## Kernel de suavizado !!!alg:Locally Weighted Value Function ~~~~C mutable struct LocallyWeightedValueFunction k # kernel function k(s, s') S # set of discrete states θ # vector of values at states in S end function (Uθ::LocallyWeightedValueFunction)(s) w = normalize([Uθ.k(s,s') for s' in Uθ.S], 1) return Uθ.θ ⋅ w end function fit!(Uθ::LocallyWeightedValueFunction, S, U) Uθ.θ = U return Uθ end ~~~~ --- ## Interpolación lineal ![](../img/lineal.jpg align=right width=20%) * El caso unidimensional interpola 2 vértices: $U\theta(s) = \alpha \theta_1 + (1 -\alpha)\theta_2$, con $\alpha = \frac{(s_2 - s)}{(s_2 - s_1)}$. * Puede extenderse a una malla multidimensional. * Caso bidimensional (**interpolación bilineal**) interpolamos entre cuatro vértices: Dados $s_i = [x_i, y_i]$ y $s = [x, y]$ $$ \begin{aligned} U\theta(s) &= \alpha\theta_{12} + (1 -\alpha)\theta_{34}\\ &= \frac{x_2 - x}{x_2 - x_1} \theta_{12} + \frac{x - x_1}{x-2 - x_1} \theta_{34}\\ &= \frac{x_2 - x}{x_2-x_1} (\alpha\theta_1 + (1 -\alpha)\theta_2) + \frac{x - x_1}{x_2 - x_1} (\alpha\theta_3 + (1-\alpha)\theta_4)\\ &= \frac{x_2 - x}{x_2 - x_1}\Big(\frac{y_2 - y}{y_2-y_1} \theta_1 + \frac{y - y_1}{y_2 - y_1} \theta_2\Big) + \frac{x - x_1}{x_2 - x_1}\Big(\frac{y_2 - y}{y_2- y_1} \theta_3 +\frac{y - y_1}{y_2 - y_1} \theta_4\Big)\\ &= \frac{(x_2 - x)(y_2 - y)}{(x_2 - x_1)(y_2 - y_1)}\theta_1 + \frac{(x_2 - x)(y - y_1)}{(x_2 - x_1)(y_2 - y_1)}\theta_2 + \frac{(x - x_1)(y_2 - y)}{(x_2 - x_1)(y_2 - y_1)}\theta_3 + \frac{(x - x_1)(y - y_1)}{(x_2 - x_1)(y_2 - y_1)}\theta_4 \end{aligned} $$ --- ## Interpolación lineal La interpolación resultante pondera cada vértice en función del área de su cuadrante opuesto: ![](../img/bilineal1.jpg width=20%) ![](../img/bilineal2.jpg width=20%) ![](../img/bilineal3.jpg width=20%) La **interpolación multilineal** en $d$ dimensiones se consigue interpolando linealmente a lo largo de cada eje, lo que requiere $2^d$ vértices. !!!note: Interpolación simplicial La interpolación multilineal es ineficiente en dimensiones elevadas. La **interpolación simplicial** considera sólo $d + 1$ puntos en la vecindad de un estado dado para producir una superficie continua que coincida con los puntos de muestra conocidos. --- ## Interpolación lineal !!!alg: Multilinear Value Function ~~~~ mutable struct MultilinearValueFunction o # position of lower-left corner δ # vector of widths θ # vector of values at states in S end function (Uθ::MultilinearValueFunction)(s) o, δ, θ = Uθ.o, Uθ.δ, Uθ.θ, Δ = (s - o)./δ, i = min.(floor.(Int, Δ) .+ 1, size(θ) .- 1) vertex_index = similar(i), d = length(s), u = 0.0 for vertex in 0:2^d-1 weight = 1.0 for j in 1:d if vertex & (1 << (j-1)) > 0 vertex_index[j] = i[j] + 1 weight *= Δ[j] - i[j] + 1 else vertex_index[j] = i[j] weight *= i[j] - Δ[j] end end u += θ[vertex_index...]*weight end return u end function fit!(Uθ::MultilinearValueFunction, S, U) Uθ.θ = U return Uθ end ~~~~ --- ## Regresión Lineal * $U_\theta(s)$ es una combinación lineal de funciones base (**características**), generalmente funciones no lineales de $s$ que se combinan en una función vectorial $\beta(s)$ (o $\beta(s, a)$), dando lugar a las aproximaciones: $$U_\theta(s) = \theta^⊤ \beta(s)\quad\quad Q_\theta(s, a) = \theta^⊤ \beta(s, a)$$ * Añadir más funciones base generalmente mejora la capacidad de igualar $U$ en los estados en $S$, pero demasiadas funciones base pueden llevar a aproximaciones pobres en otros estados (lo que se conoce como **sobreajuste**). Existen metodologías para elegir un conjunto adecuado de funciones de base para nuestro modelo de regresión. * Ajustar un modelos lineales implica determinar el vector $\theta$ que minimiza el error cuadrático de las predicciones en los estados de $S = s_{1:m}$. Si denotamos $u_i=U(s_i)$, entonces queremos encontrar la $\theta$ que minimiza $$\sum_{i=1}^m ( \hat{U}_\theta(s_i) - u_i)^2 = \sum_{i=1}^m (\theta^⊤ \beta(s_i) - u_i)^2$$ * La $\theta$ óptima puede calcularse mediante algunas operaciones matriciales sencillas. --- ## Regresión Lineal ![](../img/funcionesbase.jpg width=50% align=right)La figura muestra cómo se ajustan las utilidades de los estados en $S$ con varias familias de funciones base. Diferentes elecciones de funciones base dan lugar a diferentes errores. !!!alg:Linear Regression Value Function ~~~~ mutable struct LinearRegressionValueFunction β # basis vector function θ # vector of parameters end function (Uθ::LinearRegressionValueFunction)(s) return Uθ.β(s) ⋅ Uθ.θ end function fit!(Uθ::LinearRegressionValueFunction, S, U) X = hcat([Uθ.β(s) for s in S]...)' Uθ.θ = X / U # pinv(X)*U return Uθ end ~~~~ --- ## Regresión por redes neuronales * Nos libera de tener que construir un conjunto adecuado de funciones base. * Se utiliza una red neuronal para representar la función de valor: * La entrada de la red neuronal serían las variables de estado, * La salida sería la estimación de la utilidad. * Los parámetros $\theta$ corresponden a los pesos de la red neuronal. * Podemos optimizar los pesos de la red para conseguir un objetivo concreto: * En el contexto de la programación dinámica aproximada: minimizar el error de las predicciones. * Ahora la minimización del error cuadrático no puede hacerse mediante simples operaciones matriciales. * Uso de técnicas de optimización como el **descenso del gradiente** (el cálculo del gradiente de las redes neuronales puede hacerse exactamente mediante la aplicación directa de la regla de la cadena de derivadas).