sobre los problemas del mundo real es difícil
El aprendizaje por refuerzo parece sencillo en entornos controlados: estados bien definidos, recompensas densas, dinámica estacionaria, simulación ilimitada. La mayoría de los resultados de referencia se producen bajo esos supuestos. El mundo real los viola casi todos.
Las observaciones son parciales y ruidosas, las recompensas se retrasan o son ambiguas, los entornos varían con el tiempo, la recopilación de datos es lenta y costosa y los errores conllevan un costo real. Las políticas deben operar bajo restricciones de seguridad, exploración limitada y distribuciones no estacionarias. Los datos ajenos a las políticas acumulan sesgos. La depuración es opaca. Los pequeños errores de modelado se combinan con un comportamiento inestable.
Una vez más, el aprendizaje reforzado sobre problemas del mundo real es realmente difícil.
Aparte de los simuladores controlados como Atari, que se encuentran en el mundo académico, hay muy poca orientación práctica sobre cómo diseñar, entrenar o depurar. Si se eliminan los supuestos que hacen que los puntos de referencia sean manejables, lo que queda es un espacio de problemas que parece casi imposible de resolver.
Pero luego tienes estos ejemplos y recuperas la esperanza:
OpenAI Five derrotó a los actuales campeones del mundo en Dota 2 en partidas completas de 5 contra 5. Entrenado utilizando aprendizaje por refuerzo profundo. AlphaStar de DeepMind alcanzó el rango de Gran Maestro en StarCraft II, superando al 99,8% de los jugadores humanos y derrotando consistentemente a competidores profesionales. Entrenado utilizando aprendizaje por refuerzo profundo. Atlas de Boston Dynamic entrena una arquitectura basada en un transformador de difusión de parámetros de 450M utilizando una combinación de datos simulados y del mundo real. Entrenado utilizando aprendizaje por refuerzo profundo.
En este artículo, voy a presentar enfoques prácticos del mundo real para entrenar agentes de aprendizaje por refuerzo con paralelismo, empleando muchas, si no exactamente las mismas, técnicas que impulsan los sistemas de inteligencia artificial sobrehumanos actuales. Esta es una selección deliberada de técnicas académicas + experiencia ganada con esfuerzo obtenida de la construcción de agentes que trabajan en dominios estocásticos y no estacionarios.
Si tiene la intención de abordar un problema del mundo real simplemente aplicando un punto de referencia no ajustado de una biblioteca RL en una sola máquina, es probable que falle.
Hay que entender lo siguiente:
Replantear el problema para que encaje dentro del marco de la teoría RL Las técnicas para la optimización de políticas que realmente funcionan fuera del ámbito académico Los matices de la “escala” con respecto al aprendizaje por refuerzo
Empecemos.
Requisitos previos
Si nunca antes te has acercado al aprendizaje por refuerzo, intentar construir una IA sobrehumana (o incluso un agente medianamente decente) es como tratar de enseñarle a un gato a hacer malabarismos con antorchas encendidas: en su mayor parte te ignora, ocasionalmente prende fuego a algo y de alguna manera aún se espera que lo llames "progreso". Debes estar bien versado en los siguientes temas:
Procesos de decisión de Markov (MDP) y procesos de decisión de Markov parcialmente observables (POMDP): proporcionan la base matemática de cómo los agentes de IA modernos interactúan con el mundo. Optimización de políticas (también conocido como aprendizaje espejo) Detalles sobre cómo una red neuronal se aproxima a una política óptima mediante el ascenso de gradiente. Seguimiento hasta 2) Métodos de actor crítico y optimización de políticas próximas (PPO), que son dos métodos ampliamente utilizados para la optimización de políticas.
Cada uno de estos requiere algo de tiempo para comprenderlo y digerirlo completamente. Desafortunadamente, la RL es un espacio problemático tan difícil que la simple ampliación no resolverá malentendidos fundamentales o aplicaciones incorrectas de los pasos previos, como ocurre a veces en el aprendizaje profundo tradicional.
Un problema de aprendizaje por refuerzo del mundo real
Para proporcionar un ejemplo coherente del mundo real, utilizamos una simulación de conducción autónoma simplificada como tarea de optimización. Digo "simplificado" porque los detalles exactos son menos importantes para el propósito del artículo. Sin embargo, para la vida real en el mundo real, asegúrese de tener una comprensión completa del entorno, las entradas, las salidas y cómo se genera realmente la recompensa. Esta comprensión le ayudará a enmarcar su problema del mundo real en el espacio de los MDP.
Nuestro simulador genera de manera procesal escenarios de conducción estocásticos, incluidos peatones, otros vehículos y diferentes condiciones del terreno y de la carretera que se han modelado a partir de datos de conducción registrados. Cada escenario está segmentado en un episodio de duración variable.
Aunque muchos problemas del mundo real no son verdaderos procesos de decisión de Markov, generalmente se aumentan para que el estado efectivo sea aproximadamente de Markov, lo que permite que las garantías de convergencia RL estándar se mantengan aproximadamente en la práctica.
Estados
El agente observa las entradas de la cámara y LiDAR junto con señales como la velocidad y orientación del vehículo. Las características adicionales pueden incluir las posiciones de vehículos y peatones cercanos. Estas observaciones se codifican como uno o más tensores, opcionalmente apilados en el tiempo para proporcionar un historial a corto plazo.
Comportamiento
El espacio de acción consta de controles continuos del vehículo (dirección, acelerador, freno) y controles discretos opcionales (por ejemplo, selección de marcha, señales de giro). Cada acción se representa como un vector multidimensional que especifica los comandos de control aplicados en cada paso de tiempo.
Recompensas
La recompensa fomenta una conducción segura, eficiente y orientada a objetivos. Combina múltiples objetivos Oi, incluidos términos positivos para el avance hacia el destino y sanciones por colisiones, infracciones de tránsito o maniobras inestables. La recompensa por paso de tiempo es una suma ponderada:
Hemos creado nuestro entorno de simulación para que se ajuste a la interfaz de 4 tuplas popularizada por Brockman et al., OpenAI Gym, 2016.
env = DrivingEnv() agente = Agente() para episodio en rango(N): # obs es un tensor multidimensional que representa el estado obs = env.reset() hecho = falso mientras no está hecho: # actuar es la aplicación de nuestra política actual π # π(obs) devuelve una acción multidimensional acción = agente.act(obs) # enviamos la acción al entorno para recibir # el siguiente paso y recompensamos hasta completar next_obs, recompensa, hecho, información = env.step(acción) obs = siguiente_obs
El entorno en sí debe ser fácilmente paralelizado, de modo que uno de muchos actores pueda aplicar simultáneamente su propia copia de la política sin la necesidad de interacciones complejas o sincronizaciones entre agentes. Esta API, desarrollada por OpenAI y utilizada en sus entornos de gimnasio, se ha convertido en el estándar de facto.
Si está creando su propio entorno, valdría la pena hacerlo con esta interfaz, ya que simplifica muchas cosas.
Agente
Utilizamos un actor-agente crítico profundo, siguiendo el enfoque popularizado en el artículo A3C de DeepMind (Mnih et al., 2016). El pseudocódigo de nuestro agente se encuentra a continuación:
clase Agente: def __init__(self, state_dim, action_dim): # — Actor — self.actor = Sequential( Linear(state_dim, 128), ReLU(), Linear(128, 128), ReLU(), Linear(128, action_dim) ) # — Crítico — self.critic = Sequential( Linear(state_dim, 128), ReLU(), Linear(128, 128), ReLU(), Linear(128, 1) ) def _dist(self, estado): logits = self.actor(estado) return Categorical(logits=logits) def act(self, estado): """ Devuelve: acción log_prob (política de comportamiento) valor """ dist = self._dist(estado) acción = dist.sample() log_prob = dist.log_prob(acción) valor = self.critic(estado) devolver acción, log_prob, valor def log_prob(self, estados, acciones): dist = self._dist(estados) devolver dist.log_prob(acciones) def entropía(self, estados): devolver self._dist(estados).entropy() def valor(self, estado): devolver self.critic(estado) def actualizar(self, state_dict): self.actor.load_state_dict(state_dict['actor']) self.critic.load_state_dict(state_dict['crítico'])
Es posible que esté un poco desconcertado por los métodos adicionales. Más explicaciones a seguir.
Nota muy importante: las arquitecturas mal elegidas pueden descarrilar fácilmente la capacitación. Asegúrese de comprender el espacio de acción y verificar que las capas de entrada, ocultas y de salida de su red tengan el tamaño adecuado y utilicen activaciones adecuadas.
Optimización de políticas
Para actualizar el agente, seguimos el marco de Optimización de Política Próxima (PPO) (Schulman et al., 2017), que utiliza el objetivo sustituto recortado para actualizar al actor de manera estable y al mismo tiempo actualizar al crítico. Esto permite al agente mejorar su política gradualmente en función de la experiencia recopilada mientras mantiene las actualizaciones dentro de una región de confianza, evitando cambios de política grandes y desestabilizadores.
Nota: PPO es uno de los métodos de optimización de políticas más utilizados y se utiliza para desarrollar OpenAI Five, Alphastar y muchos otros sistemas de control robótico del mundo real.
El agente primero interactúa con el entorno, registrando sus acciones, las recompensas que recibe y sus propias estimaciones de valor. Esta secuencia de experiencia se denomina comúnmente lanzamiento o, en la literatura, trayectoria. La experiencia se puede recopilar hasta el final del episodio o, más comúnmente, antes de que finalice el episodio durante un número fijo de pasos. Esto es especialmente útil en problemas de horizonte infinito sin inicio ni fin predefinidos, ya que permite lotes de experiencia de tamaño equivalente de cada actor.
A continuación se muestra un búfer de implementación de muestra. Independientemente de cómo elija diseñar su búfer, es muy importante que este búfer de implementación sea serializable para que pueda enviarse a través de la red.
Lanzamiento de clase: def __init__(self): self.states =[]auto.acciones =[]# ¡almacena el registro de prueba de acción! self.logprobs =[]auto.recompensas =[]valores.propios =[]auto.hechos =[]# Agregar la experiencia de un solo paso de tiempo def add(self, state, action, logprob, recompensa, valor, hecho): self.states.append(state) self.actions.append(action) self.logprobs.append(logprob) self.rewards.append(reward) self.values.append(value) self.dones.append(done) # Limpiar el búfer después de las actualizaciones def reset(self): self.states =[]auto.acciones =[]self.logprobs =[]auto.recompensas =[]valores.propios =[]auto.hechos =[]
Durante esta implementación, el agente registra estados, acciones, recompensas y estados siguientes en una secuencia de pasos de tiempo. Una vez que se completa el lanzamiento, esta experiencia se utiliza para calcular las funciones de pérdida tanto para el actor como para el crítico.
Aquí, aumentamos el ciclo de interacción del entorno del agente con nuestro búfer de implementación.
env = DrivingEnv() agente = Agente() buffer = Rollout() entrenador = Entrenador(agente) rollout_steps = 256 para episodio en rango(N): # obs es un tensor multidimensional que representa el estado obs = env.reset() hecho = pasos falsos = 0 mientras no está hecho: pasos += 1 # acto es la aplicación de nuestra política actual π # π(obs) devuelve una acción multidimensional acción, logprob, valor = agente.act(obs) # enviamos la acción al entorno para recibir # el siguiente paso y recompensamos hasta completar next_obs, recompensa, hecho, info = env.step(action) # agregamos la experiencia al búfer buffer.add(state=obs, action=action, logprob=logprob, recompensa=recompensa, value=value, done=done) if pasos % rollout_steps == 0: # agregaremos más detalles aquí state_dict = trainer.train(buffer) agente.actualización(state_dict) obs = next_obs
Voy a presentar la función objetivo tal como se usa en PPO; sin embargo, recomiendo leer el documento deliciosamente breve para comprender completamente los matices.
Para el actor, optimizamos un objetivo sustituto basado en la función de ventaja, que mide cuánto mejor se realizó una acción en comparación con el valor esperado predicho por el crítico.
El objetivo sustituto utilizado para actualizar la red de actores:
Tenga en cuenta que la ventaja, A, se puede estimar de varias maneras, como la Estimación de Ventaja Generalizada (GAE), o simplemente usando el error de diferencia temporal de un paso, dependiendo del equilibrio deseado entre sesgo y varianza (Schulman et al., 2017).
El crítico se actualiza minimizando el error cuadrático medio entre su valor predicho V(s_t) y el retorno observado R_t en cada paso de tiempo. Esto entrena al crítico para estimar con precisión el rendimiento esperado de cada estado, que luego se utiliza para calcular la ventaja para la actualización del actor.
En PPO, la pérdida también incluye un componente de entropía, que recompensa las políticas que tienen mayor entropía. La razón es que una política con mayor entropía es más aleatoria, lo que anima al agente a explorar una gama más amplia de acciones en lugar de converger prematuramente a un comportamiento determinista. El término de entropía normalmente se escala mediante un coeficiente, β, que controla el equilibrio entre exploración y explotación.
La pérdida total para PPO pasa a ser:
Nuevamente, en la práctica, simplemente usar los parámetros predeterminados establecidos en las líneas de base lo dejará descontento y posiblemente psicótico después de meses de tedioso ajuste de hiperparámetros. Para ahorrarle costosas visitas al psiquiatra, mire esta conferencia muy informativa del creador de PPO, John Schulman. En él, describe detalles muy importantes, como la normalización de la función de valor, las penalizaciones de KL, la normalización de ventajas y cómo las técnicas comúnmente utilizadas, como el abandono y la caída de peso, envenenarán su proyecto.
[insertar]https://www.youtube.com/watch?v=8EcdaCk9KaQ[/embed]
Estos detalles de esta conferencia, que no se especifican en ningún artículo, son fundamentales para construir un agente funcional. Nuevamente, como advertencia cautelosa: si simplemente intenta utilizar los valores predeterminados sin comprender lo que realmente está sucediendo con la optimización de políticas, fracasará o perderá mucho tiempo.
Nuestro agente ahora puede actualizarse. Tenga en cuenta que, dado que nuestro optimizador está minimizando un objetivo, es necesario invertir los signos del objetivo de PPO como se describe en el documento.
También tenga en cuenta que aquí es donde las funciones de nuestro agente serán útiles.
def Compute_advantages(recompensas, valores, gamma, lambda): # calcula las ventajas que desees def compute_returns(rewards, gamma): # calc devuelve los resultados que desees def get_batches(buffer): # aleatoriza y devuelve tuplas que producen clases por lotes Entrenador: def __init__(self, agent, config): self.agent = agente # Instancia ActorCriticAgent self.lr = config.get("lr", 3e-4) self.num_epochs = config.get("num_epochs", 4) self.eps = config.get("clip_epsilon", 0.2) self.entropy_coeff = config.get("entropy_coeff", 0.01) self.value_loss_coeff = config.get("value_loss_coeff", 0.5) self.gamma = config.get("gamma", 0.99) self.lambda_gae = config.get("lambda", 0.95) # Optimizador único que actualiza tanto al actor como al crítico self.optimizer = Optimizer(params=list(agent.actor.parameters()) + list(agent.critic.parameters()), lr=self.lr) def train(self, buffer): # — 1. Calcular ventajas y retornos — ventajas = Compute_advantages(buffer.rewards, buffer.values, self.gamma, self.lambda_gae) return = Compute_returns(buffer.rewards, self.gamma) # — 2. Actualizaciones de PPO — para época en rango (self.num_epochs): para lote en get_batches(buffer): estados, acciones, adv, ret = lote # — Relación de probabilidad — ratio = actor_prob(estados, acciones) / actor_prob_old(estados, acciones) # — Pérdida de actor (sustituto recortado) — surrogate1 = ratio * adv surrogate2 = clip(ratio, 1 – self.eps, 1 + self.eps) * adv actor_loss = -mean(min(surrogate1, surrogate2)) # — Bonificación de entropía — entropía = mean(policy_entropy(states)) actor_loss -= self.entropy_coeff * entropy # — Critic loss — critic_loss = mean((critic_value(states) – ret) ** 2) # — Pérdida total de PPO — total_loss = actor_loss + self.value_loss_coeff * critic_loss # — Aplicar gradientes — self.optimizer.zero_grad() total_loss.backward() self.optimizer.step() devuelve self.agent.state_dict()
Los tres pasos, definir nuestro entorno, definir nuestro agente y su modelo, así como definir nuestro procedimiento de optimización de políticas, están completos y ahora se pueden usar para construir un agente con una sola máquina.
Nada de lo descrito anteriormente te llevará a ser "sobrehumano".
Esperemos 2 meses para que su Macbook Pro con el costoso chip M4 comience a mostrar una mejora del 1% en el rendimiento (no es broma).
La arquitectura distribuida actor-aprendiz
La arquitectura actor-alumno separa la interacción ambiental de la optimización de políticas. Cada actor opera de forma independiente, interactuando con su propio entorno utilizando una copia local de la política, que se refleja en todos los actores. El alumno no interactúa directamente con el entorno; en cambio, sirve como un centro centralizado que actualiza las redes de políticas y valores de acuerdo con el objetivo de optimización y distribuye los modelos actualizados a los actores.
Esta separación permite que múltiples actores interactúen con el entorno en paralelo, mejorando la eficiencia de la muestra y estabilizando la capacitación mediante la descorrelación de actualizaciones. Esta arquitectura fue popularizada por el artículo A3C de DeepMind (Mnih et al., 2016), que demostró que las configuraciones asincrónicas actor-alumno podrían entrenar agentes de aprendizaje por refuerzo a gran escala de manera eficiente.
Actor
El actor es el componente del sistema que interactúa directamente con el entorno. Sus responsabilidades incluyen:
Recibir una copia de la política actual y las redes de valores del alumno. Acciones de muestreo según la política para el estado actual del medio ambiente. Recopilar experiencia en una secuencia de pasos de tiempo Enviar la experiencia recopilada al alumno de forma asincrónica.
Aprendiz
El alumno es el componente centralizado responsable de actualizar los parámetros del modelo. Sus responsabilidades incluyen:
Recibir experiencia de múltiples actores, ya sea en implementaciones completas o en minilotes. Calcular funciones de pérdida. Aplicar actualizaciones de gradiente a las redes de políticas y valores. Distribuir el modelo actualizado a los actores, cerrando el ciclo.
Esta separación entre actor y alumno no se incluye en las líneas de base estándar, como las líneas de base de OpenAI o las líneas de base estables. Si bien existen implementaciones distribuidas entre actor y alumno, para problemas del mundo real la personalización requerida puede hacer que la deuda técnica de adaptar estos marcos supere los beneficios de su uso.
Ahora las cosas empiezan a ponerse interesantes.
Con actores que se ejecutan de forma asincrónica, ya sea en diferentes partes del mismo episodio o en episodios completamente separados, nuestra optimización de políticas obtiene una gran cantidad de experiencias diversas. En una sola máquina, esto también significa que podemos acelerar drásticamente la recopilación de experiencias, reduciendo el tiempo de capacitación proporcionalmente a la cantidad de actores que se ejecutan en paralelo.
Sin embargo, ni siquiera la arquitectura actor-alumno nos llevará a la escala que necesitamos debido a un problema importante: la sincronización.
Para que los actores comiencen a procesar el siguiente lote de experiencia, todos deben esperar a que el alumno centralizado finalice el paso de optimización de políticas para que el algoritmo permanezca "en la política". Esto significa que cada actor está inactivo mientras el alumno actualiza el modelo utilizando el lote de experiencia anterior, lo que crea un cuello de botella que limita el rendimiento e impide la recopilación de datos completamente paralelizada.
¿Por qué no utilizar simplemente lotes antiguos de una política que se actualizó hace más de un paso?
El uso de datos ajenos a las políticas para actualizar el modelo ha demostrado ser destructivo. En la práctica, incluso un pequeño retraso en las políticas introduce un sesgo en la estimación del gradiente y, con la aproximación de funciones, este sesgo puede acumularse y causar inestabilidad o divergencia absoluta. Este problema se observó temprano en el aprendizaje de diferencias temporales fuera de políticas, donde el arranque más la aproximación de funciones causaron que las estimaciones de valor divergieran en lugar de converger, haciendo que la reutilización ingenua de experiencias obsoletas no fuera confiable a escala.
Por suerte, existe una solución a este problema.
IMPALA: Deep-RL distribuido y escalable con arquitecturas de actor-aprendiz ponderadas por importancia
Inventado en DeepMind, IMPALA (y su predecesor, SEED-RL) introdujo un concepto llamado V-Trace, que nos permite actualizar algoritmos de políticas con implementaciones que se generaron a partir de políticas.
Esto significa que la utilización de todo el sistema permanece constante, en lugar de tener bloques de espera de sincronización (los actores deben esperar la última actualización del modelo como es el caso en A3C). Sin embargo, esto tiene un costo: debido a que los actores utilizan parámetros ligeramente obsoletos, las trayectorias son generadas por políticas más antiguas, no por la política de aprendizaje actual. La aplicación ingenua de métodos basados en políticas (por ejemplo, gradiente de políticas estándar o A2C) se vuelve sesgada e inestable.
Para corregir esto, presentamos V-Trace. V-Trace utiliza una corrección basada en muestreo de importancia que ajusta los rendimientos para tener en cuenta el desajuste entre la política de comportamiento (actor) y la política objetivo (aprendiz).
En los métodos basados en políticas, la proporción inicial (al comienzo de cada miniépoca como es el caso en PPO) es ~ 1. Esto significa que la política de comportamiento es igual a la política objetivo.
En IMPALA, sin embargo, los actores generan continuamente experiencia utilizando parámetros ligeramente obsoletos, por lo que las trayectorias se muestrean a partir de una política de comportamiento μ que puede diferir de manera no trivial de la política actual π del alumno. En pocas palabras, la proporción inicial! = 1. Esta ponderación de importancia nos permite aproximarnos a qué tan obsoleta está la política que generó la experiencia.
Sólo necesitamos un cálculo más para corregir esta desviación fuera de la política, que es calcular la relación del comportamiento de la política μ, en comparación con la política actual, π al inicio de la actualización de la política. Luego podemos recalcular las pérdidas de la política y los objetivos de valor utilizando versiones recortadas de estas ponderaciones de importancia: rho para la política y c para los objetivos de valor.
Luego recalculamos nuestro error td (delta):
Luego, use este valor para calcular nuestros valores ponderados de importancia.
Ahora que tenemos valores de muestra corregidos, necesitamos recalcular nuestras ventajas.
De manera intuitiva, V-trace compara la probabilidad de cada acción muestreada según la política actual con la política anterior que la generó.
Si la acción aún es probable bajo la nueva política, la proporción es cercana a uno y la muestra es confiable.
Si la acción ahora es improbable, la proporción es pequeña y su influencia se reduce.
Debido a que la proporción se recorta en uno, las muestras nunca pueden aumentar su ponderación (sólo disminuir su ponderación), por lo que las trayectorias obsoletas o no coincidentes pierden impacto gradualmente mientras que las implementaciones cercanas a las políticas dominan la señal de aprendizaje.
Este conjunto muy importante de métodos nos permite extraer toda la potencia de nuestra infraestructura de entrenamiento y elimina por completo el cuello de botella de la sincronización. Ya no necesitamos esperar a que todos los actores terminen sus implementaciones, desperdiciando costoso tiempo de GPU y CPU.
Dado este método, debemos realizar algunas modificaciones en nuestra arquitectura de actor-alumno para aprovecharlo.
Arquitectura de actor-aprendiz distribuida masivamente
Como se describió anteriormente, aún podemos usar nuestra arquitectura Distributed Actor-Learner; sin embargo, necesitamos agregar algunos componentes y usar algunas técnicas de NVIDIA para permitir que se reciban trayectorias y pesos sin necesidad de primitivas de sincronización o un administrador central.
Base de datos de valores clave (KV)
Aquí, agregamos una base de datos KV simple como Redis para almacenar trayectorias. La adición requiere que serialicemos cada trayectoria después de que un actor complete la recopilación de experiencia, luego cada actor puede simplemente agregarla a una lista de Redis. Redis es seguro para subprocesos, por lo que no debemos preocuparnos por la sincronización de cada actor.
Cuando el alumno esté listo para una nueva actualización, simplemente puede sacar las trayectorias más recientes de esta lista, fusionarlas y realizar el procedimiento de optimización de políticas.
# modificando los pasos de nuestro actor r = redis.Redis(…)Py … if pasos % rollout_steps == 0: # en lugar de entrenar, simplemente serializa y envía a un búfer buffer_data = pickle.dumps(buffer) r.rpush("trayectorias", buffer_data) El alumno puede simplemente tomar trayectorias en un lote según sea necesario de esta lista, lo que actualiza los pesos. # en las trayectorias del alumno =[]while len(trajectories) <= trajectory_batch_size: trajectory = pickle.loads(r.lpop("trajectories")) trajectories.append(trajectory) # podemos fusionarlos en un único buffer para propósitos de entrenamiento buffer = merge_trajectories(trajectories) # continuar entrenando
Múltiples alumnos (opcional)
Cuando tienes cientos de trabajadores, una sola GPU en el alumno puede convertirse en un cuello de botella. Esto puede hacer que las trayectorias estén muy fuera de las políticas, lo que degrada el rendimiento del aprendizaje. Sin embargo, siempre que cada alumno ejecute el mismo código (los mismos pases hacia atrás), cada uno puede procesar trayectorias completamente diferentes de forma independiente.
En el fondo, si está utilizando PyTorch, la biblioteca NCCL de NVIDIA maneja las operaciones de reducción total necesarias para sincronizar los gradientes. Esto garantiza que las ponderaciones del modelo sigan siendo consistentes entre todos los alumnos. Puede iniciar cada proceso de aprendizaje utilizando torchrun, que gestiona automáticamente la ejecución distribuida y la coordinación de las actualizaciones de gradiente.
import torch.distributed as dist r = redis.Redis(..) def setup(rank, world_size): # Inicializa el grupo de procesos predeterminado dist.init_process_group( backend="nccl", init_method=os.environ["MASTER_ADDR"], # se establecerá en el comando de lanzamiento rango=rank, world_size=world_size ) torch.cuda.set_device(rank % torch.cuda.device_count()) # aplica el entrenamiento como arriba … total_loss = actor_loss + self.value_loss_coeff * critic_loss # aplica nuestro paso de entrenamiento anterior self.optimizer.zero_grad() total_loss.backward() # necesitamos usar una operación dist para p en agent.parameters(): dist.all_reduce(p.grad.data) p.grad.data /= world_size optimizador.step() if rango == 0: # actualizar parámetros del maestro r.rpush("params", agent.get_state_dict())
Estoy simplificando dramáticamente la aplicación de NCCL. Lea la documentación de PyTorch sobre la capacitación distribuida
Suponiendo que utilizamos 2 nodos, cada uno con 2 alumnos:
En el nodo 1:
MASTER_ADDR={usa tu ip} MASTER_PORT={elige un puerto no utilizado} WORLD_SIZE=4 RANK=0 torchrun –nnodes=2 –nproc_per_node=2 –rdzv_backend=c10d –rdzv_endpoint={tu DIRECCIÓN}:{tu puerto} learner.py
y en el nodo 2:
MASTER_ADDR={usa tu ip} MASTER_PORT={elige un puerto no utilizado} WORLD_SIZE=4 RANK=2 torchrun –nnodes=2 –nproc_per_node=2 –rdzv_backend=c10d –rdzv_endpoint={tu DIRECCIÓN}:{tu puerto} learner.py
Concluyendo
En resumen, escalar el aprendizaje por refuerzo desde experimentos de un solo nodo a configuraciones distribuidas de múltiples máquinas no es solo una optimización del rendimiento: es una necesidad para abordar tareas complejas del mundo real.
Cubrimos:
Cómo refactorizar espacios problemáticos en una arquitectura de agente MDP Métodos de optimización de políticas que realmente funcionan Ampliación de la recopilación de datos distribuidos y optimización de políticas
Al combinar múltiples actores para recopilar diversas trayectorias, sincronizar cuidadosamente a los alumnos con técnicas como V-trace y all-reduce, y coordinar eficientemente el cálculo entre GPU y nodos, podemos capacitar agentes que se acerquen o superen el rendimiento a nivel humano en entornos mucho más desafiantes que los puntos de referencia clásicos.
Dominar estas estrategias cierra la brecha entre la investigación sobre los problemas de los "juguetes" y la construcción de sistemas RL capaces de operar en dominios ricos y dinámicos, desde juegos avanzados hasta robótica y sistemas autónomos.
Referencias
Vinyals, O., Babuschkin, I., Czarnecki, WM, Mathieu, M., Dudzik, A., Chung, J.,… & Silver, D. (2019). Nivel Gran Maestro en StarCraft II utilizando el aprendizaje por refuerzo de múltiples agentes. Naturaleza. Berner, C., Brockman, G., Chan, B., Cheung, V., Dębiak, P., Dennison, C.,… y Salimans, T. (2019). Dota 2 con aprendizaje por refuerzo profundo a gran escala. arXiv:1912.06680 Mnih, V., Kavukcuoglu, K., Silver, D., Rusu, AA, Veness, J., Bellemare, MG,… & Hassabis, D. (2015). Control a nivel humano a través del aprendizaje por refuerzo profundo. Naturaleza, 518 (7540), 529–533. Schulman, J., Levine, S., Moritz, P., Jordan, M. y Abbeel, P. (2015). Optimización de la política de región de confianza. ICML 2015. Schulman, J., Wolski, F., Dhariwal, P., Radford, A. y Klimov, O. (2017). Algoritmos de optimización de políticas próximas. arXiv:1707.06347. Espeholt, L., Soyer, H., Munos, R., Simonyan, K., Mnih, V., Ward, T.,… y Kavukcuoglu, K. (2018). IMPALA: Deep-RL distribuido y escalable con arquitecturas de actor-aprendiz ponderadas por importancia. ICML 2018. Espeholt, L., Stooke, A., Ibarz, J., Leibo, JZ, Zambaldi, V., Song, F.,… & Silver, D. (2020). SEED RL: Deep-RL escalable y eficiente con aprendizaje centralizado acelerado. arXiv:1910.06591.