**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
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
* $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

* 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:



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
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).