Como vimos en la presentación de aprendizaje por refuerzo, el algoritmo Q utiliza una matriz de estados-acciones. Si el número de estados/acciones es muy grande, el algoritmo tardará en converger y no será útil.
En este caso, lo que nos permiten las redes neuronales es reducir la dimensionalidad del espacio, y encontrar la solución aplicando la técnica de descenso de gradiente.
Imagina un juego por ordenador, clásico, por simplificar, como el breakout, el número de estados posibles es enorme. Intentar aplicar el algoritmo Q es estos caso es inviable.
La idea es estos casos es reducir el número de parámetros (estados en el caso del algoritmo Q) que el algoritmo debe aprender, y utilizar una buena representación del problema.
Podemos utilizar una red neuronal para trabajar las ideas anteriores:
Una de las primeras aproximaciones de aplicación de redes neuronales profundas a soluciones de aprendizaje por refuerzo apareció publicada como: Playing Atari with Deep Reinforcement Learning
Recordemos la expresión de la actualización de Q:
\[ Q(S_t,A_t) \leftarrow Q(S_t,A_t) + \alpha[ \boxed{R_{t+1} + \gamma \max_{a \in A} Q(S_{t+1},a)} - Q(S_t,A_t) ] \]
Lo que queremos es que nuestra red neuronal aprenda (aproxime) la parte encuadrada de la función \(Q\).
La idea es relativamente sencilla: como no contamos con un conjunto de entrenamiento para entrenar la red, las muestras de entrenamiento los tomo del propio juego y con ellas calculo:
\[ y_t = R_{t+1} + \gamma \max_{a \in A} Q(S_{t+1},a) \]
Que es la parte de actualización si el learning rate lo tomo como \(1\).
El entrenamiento procede del siguiente modo:
Defino la función de pérdidas de la red como:
\[\mathcal{L}(\theta) = \left[ y_i - Q(\theta)\right]^2\]
Afortunadamente, estas técnicas están implementadas en paquetes de Python. Uno de estos paquetes es stable-baseline3
Instalamos el paquete:
Importamos los paquetes necesarios:
Y este es el código que crea el entorno y entrena una DQN:
env = gym.make("LunarLander-v2", enable_wind=False, gravity=-10.0,
wind_power=15.0, turbulence_power=1.5)
env.reset()
model = DQN("MlpPolicy", env, verbose=1,
gamma=0.99, learning_rate=5e-4, batch_size=128, buffer_size=50_000,
target_update_interval=250, train_freq=4, gradient_steps=-1,
learning_starts=0, exploration_fraction=0.12, exploration_final_eps=0.1,
policy_kwargs={'net_arch': [256, 256]})
model.learn(total_timesteps=200_000)
env.close()
Fíjate en el elevado número de iteraciones que tenemos que hacer para que el resultado sea bueno.
Y este es el resultado
Aterrizaje conseguido!!!
Aprendizaje Automático (IR2130) - Óscar Belmonte Fernández