Cómo se crea TensorForce
Cómo se creó TensorForce
Este artículo se centrará en un problema práctico: cómo la comunidad que aplica el aprendizaje por refuerzo puede ir un paso más allá de la recopilación de scripts y casos únicos para implementar un API de aprendizaje por refuerzo: ¿tf-learn o skikit-learn para el aprendizaje por refuerzo? Antes de discutir el marco de TensorForce, hablaremos sobre las observaciones e ideas que inspiraron este proyecto. Si solo desea obtener información sobre la API, puede omitir esta parte. Nos gustaría enfatizar que este artículo no contiene una introducción al aprendizaje por refuerzo profundo en sí, ni propone ningún modelo nuevo ni habla sobre los mejores algoritmos más recientes, por lo que para los investigadores puros, este artículo puede no ser tan interesante.
Inicie el motor
Suponiendo que sea un investigador en sistemas informáticos, procesamiento del lenguaje natural u otros campos de aplicación, debe tener algunos conocimientos básicos del aprendizaje por refuerzo y estar interesado en aplicarlo en profundidad. El refuerzo del aprendizaje (RL profundo) se utiliza para controlar ciertos aspectos de su sistema.
Hay muchos artículos introductorios sobre aprendizaje por refuerzo profundo, DQN, gradiente de políticas estándar, A3C, etc. Por ejemplo, el artículo de Karpathy ofrece una buena descripción de las ideas intuitivas detrás del método de gradiente de políticas. Además, también puede encontrar una gran cantidad de código que lo ayudará a comenzar, como agentes de introducción a OpenAI, rllab y muchos algoritmos específicos en GitHub.
Sin embargo, descubrimos que todavía existe una enorme brecha entre el desarrollo de marcos de investigación y las aplicaciones prácticas del aprendizaje por refuerzo. En aplicaciones prácticas, podemos enfrentar los siguientes problemas: Estrecho acoplamiento entre la lógica de aprendizaje por refuerzo y los controles de simulación: las API del entorno de simulación son muy convenientes, por ejemplo, nos permiten crear un objeto de entorno y luego usarlo en un bucle for. también gestionando su lógica de actualización interna (por ejemplo, recopilando características de salida). Esto tiene sentido si nuestro objetivo es evaluar una idea de aprendizaje por refuerzo, pero separar el código de aprendizaje por refuerzo y los entornos de simulación es mucho más difícil. También implica la cuestión del control de flujo: cuando el entorno esté listo, ¿puede llamarlo el código de aprendizaje por refuerzo? ¿O invocará un agente de aprendizaje por refuerzo cuando el entorno requiera una decisión? Para las bibliotecas de aprendizaje por refuerzo aplicadas implementadas en muchos dominios, a menudo necesitamos lo último. Arquitectura de red fija: la mayoría de las implementaciones incluyen arquitecturas de redes neuronales codificadas. Por lo general, esto no es un gran problema, ya que es sencillo agregar o eliminar diferentes capas de red según sea necesario. Aún así, sería mucho mejor si hubiera una biblioteca de aprendizaje por refuerzo que proporcionara la funcionalidad de una interfaz declarativa sin tener que modificar el código de la biblioteca. Además, hay casos en los que es (sorprendentemente) mucho más difícil modificar la arquitectura, como cuando es necesario gestionar el estado interno (ver más abajo). Interfaz de estado/acción incompatible: gran parte del código fuente abierto inicial utilizaba el popular entorno OpenAI Gym, una interfaz simple con entradas de estado planas y una única salida de acción discreta o continua. Pero DeepMind Lab utiliza un formato de diccionario, normalmente con múltiples estados y acciones. OpenAI Universe utiliza eventos clave con nombre. Idealmente, nos gustaría tener un agente de aprendizaje por refuerzo que pueda manejar cualquier cantidad de estados y acciones, con tipos y formas potencialmente diferentes. Por ejemplo, uno de los autores de TensorForce estaba utilizando el aprendizaje por refuerzo en PNL y quería manejar entradas multimodales, donde un estado consta conceptualmente de dos entradas: una imagen y una descripción correspondiente. Configuraciones de ejecución opacas y problemas de rendimiento: al escribir código de TensorFlow, naturalmente nos centramos primero en la lógica. Esto puede dar lugar a muchas operaciones repetidas/innecesarias o valores intermedios innecesarios. Además, los objetivos del aprendizaje de refuerzo distribuido/asincrónico/paralelo son algo fluidos, y TensorFlow distribuido requiere cierto grado de ajuste manual para configuraciones de hardware específicas. Del mismo modo, sería bueno tener eventualmente una configuración de ejecución que simplemente declare dispositivos o máquinas disponibles y luego maneje todo lo demás internamente, como dos máquinas con diferentes IP ejecutando un VPG asíncrono.
Para ser claros, estas preguntas no pretenden criticar el código escrito por los investigadores, porque el código originalmente no estaba destinado a ser utilizado como API ni para otras aplicaciones. Aquí presentamos las perspectivas de investigadores que quieren aplicar el aprendizaje por refuerzo a diferentes campos.
API de TensorForce
TensorForce proporciona una interfaz declarativa que es una implementación sólida de algoritmos de aprendizaje por refuerzo profundo. En aplicaciones que quieran utilizar el aprendizaje por refuerzo profundo, se puede utilizar como biblioteca, lo que permite a los usuarios experimentar con diferentes configuraciones y arquitecturas de red sin tener que preocuparse por todo el diseño subyacente. Entendemos perfectamente que los métodos actuales de aprendizaje por refuerzo profundo tienden a ser frágiles y requieren muchos ajustes, pero eso no significa que todavía no podamos construir una infraestructura de software común para soluciones de aprendizaje por refuerzo.
TensorForce no es una colección de resultados de implementación originales, porque no es una simulación de investigación y se necesita mucho trabajo para utilizar la implementación original en aplicaciones del mundo real. Cualquier marco de este tipo contendrá inevitablemente algunas decisiones estructurales que harán que las cosas no estándar sean aún más molestas (abstracciones con fugas). Esta es la razón por la que los investigadores incondicionales del aprendizaje por refuerzo pueden preferir construir sus modelos desde cero. Con TensorForce, nuestro objetivo es capturar una visión holística de las mejores investigaciones actuales, incluidos los conocimientos y estándares emergentes que contienen.
A continuación, profundizaremos en los aspectos fundamentales de la API de TensorForce y discutiremos nuestras opciones de diseño.
Creación y configuración de agentes
Los estados y acciones en este ejemplo son formas abreviadas del estado/acción más general. Por ejemplo, una entrada multimodal que consta de una imagen y una descripción se define de la siguiente manera. De manera similar, también se pueden definir múltiples acciones de salida. Tenga en cuenta que a lo largo del código, se deben utilizar continuamente formas breves de estados/acciones individuales para comunicarse con el agente.
Los parámetros de configuración dependen del agente base y modelo utilizado.
Actualmente, TensorForce proporciona los siguientes algoritmos de aprendizaje por refuerzo: Línea base de agente aleatorio (RandomAgent) gradiente de política básico con estimación de ventaja generalizada (VPGAgent) optimización de política de región confiable (TRPOAgent) aprendizaje Q profundo/aprendizaje Q doble profundo (DQNAgent) Función de ventaja normalizada (NAFAgent) Aprendizaje Q profundo en demostraciones de expertos (DQFDAgent) Ventaja asincrónica Actor-crítico (A3C) (se puede usar implícitamente a través de distribuido)
El último elemento significa Se dice que no existe tal algo como A3CAgent, porque A3C en realidad describe un mecanismo de actualización asincrónico en lugar de un agente específico. Por lo tanto, el uso del mecanismo de actualización asincrónica distribuida de TensorFlow es parte de la clase base del modelo común de la que derivan todos los agentes. Como se describe en el artículo "Métodos asincrónicos para el aprendizaje por refuerzo profundo", A3C se implementa implícitamente configurando el indicador distribuido para VPGAgent. Cabe señalar que A3C no es la estrategia de actualización distribuida óptima para todos los modelos (puede que incluso no tenga ningún sentido para algunos modelos), y discutiremos la implementación de otros métodos (como PAAC) al final de este artículo. Es importante separar conceptualmente las cuestiones de los agentes y actualizar la semántica de la semántica de ejecución.
También queremos hablar de la diferencia entre un modelo y un agente. La clase Agente define una interfaz para utilizar el aprendizaje por refuerzo como API, que puede gestionar diversas tareas, como datos de observación entrantes, preprocesamiento y exploración. Dos de los métodos clave son agent.act(state) y agent.observe(reward, terminal).
agent.act(state) devuelve una acción, mientras que agent.observe(reward, terminal) actualiza el modelo de acuerdo con el mecanismo del agente, como la reproducción de memoria fuera de la política (MemoryAgent) o el procesamiento por lotes dentro de la política (BatchAgent). Tenga en cuenta que para que los mecanismos internos del agente funcionen correctamente, estas funciones deben llamarse alternativamente. La clase Modelo implementa el algoritmo central de aprendizaje por refuerzo y proporciona la interfaz necesaria a través de los métodos get_action y update que el agente puede llamar intrínsecamente en puntos relevantes. Por ejemplo, DQNAgent es un agente MemoryAgent con un DQNModel y una fila adicional (para actualizaciones de la red de destino).
Configuración de la red neuronal
Una cuestión clave en el aprendizaje por refuerzo es diseñar una función de valor efectiva. Conceptualmente, pensamos en un modelo como una descripción de un mecanismo de actualización, a diferencia de lo que realmente se actualiza; en el caso del aprendizaje por refuerzo profundo, una red neuronal (o redes neuronales). Por lo tanto, la red no está codificada en el modelo, sino que se crea una instancia de manera diferente según la configuración.
En el ejemplo anterior, creamos mediante programación una configuración de red como una lista de diccionarios que describen cada capa. Esta configuración también se puede proporcionar a través de JSON y luego convertirla en un constructor de red mediante una función de utilidad.
La capa de activación predeterminada es relu, pero hay otras funciones de activación disponibles (actualmente elu, selu, softmax, tanh y sigmoid). Además, se pueden modificar otras propiedades de las capas.
Elegimos no utilizar implementaciones de capas existentes (como las de tf.layers) para ejercer un control explícito sobre las operaciones internas y garantizar que funcionen con TensorForce. El resto de piezas encajan correctamente. Queremos evitar la dependencia de bibliotecas contenedoras dinámicas y, por lo tanto, confiar únicamente en operaciones de TensorFlow de nivel inferior.
Nuestra biblioteca de capas actualmente solo proporciona muy pocos tipos de capas básicas, pero se ampliará en el futuro.
Hasta ahora, hemos presentado las capacidades de TensorForce para crear redes jerárquicas, es decir, una red que toma un único tensor de estado de entrada, con una secuencia de capas que conduce a un tensor de salida. Sin embargo, en algunos casos puede ser necesario o más apropiado desviarse de una estructura de apilamiento de capas de este tipo. El caso más notable es cuando esto es necesario cuando se deben procesar múltiples estados de entrada, una tarea que no se puede lograr de forma natural utilizando una única secuencia de capas de procesamiento.
Actualmente no proporcionamos una interfaz de configuración de nivel superior para crear automáticamente los constructores de red correspondientes. Por lo tanto, para tal caso, debe definir su función de generador de red mediante programación y agregarla a la configuración del agente como antes.
Gestión de episodios y estados internos
A diferencia de las configuraciones clásicas de aprendizaje supervisado (donde las instancias y las llamadas de redes neuronales se consideran independientes), el aprendizaje por refuerzo depende del paso de tiempo en un episodio. la acción anterior y también afectará el estado posterior. Entonces, además de sus entradas de estado y salidas de acción en cada paso de tiempo, es concebible que la red neuronal pueda tener estados internos dentro del episodio correspondientes a la entrada/salida en cada paso de tiempo. El siguiente diagrama muestra cómo funciona dicha red a lo largo del tiempo:
La gestión de estos estados internos (es decir, propagarlos entre pasos de tiempo y restablecerlos al iniciar un nuevo episodio) puede ser completamente controlado por TensorForce. y las clases de modelo lo manejan. Tenga en cuenta que esto maneja todos los casos de uso relevantes (un episodio dentro de un lote, múltiples episodios dentro de un lote, episodios sin terminales dentro de un lote).
En esta arquitectura de ejemplo, la salida de la capa densa se introduce en una celda LSTM, que luego deriva la salida final para ese paso de tiempo. Cuando este LSTM avanza un paso hacia adelante, su estado interno se actualiza y proporciona la salida del estado interno aquí.
Para el siguiente paso de tiempo, la red obtendrá la nueva entrada de estado y este estado interno, luego empujará el LSTM un paso más y generará la salida real y el nuevo estado interno de LSTM, y así sucesivamente...
Para la red con una implementación personalizada interna de la capa de estado. Esta función debe devolver no solo la salida de la capa, sino también una lista de marcadores de posición de entrada de estado interno, el tensor de salida de estado interno correspondiente y una lista de inicialización de estado interno. tensores (todos tienen la misma longitud y en este orden).
Estados de preprocesamiento
Podemos definir pasos de preprocesamiento que se aplican a estos estados (posiblemente múltiples estados si se especifican como un diccionario de listas).
Cada preprocesador en esta pila tiene un tipo y, opcionalmente, una lista de argumentos y/o un diccionario kwargs. Por ejemplo, el preprocesador de secuencia tomará los cuatro estados más recientes (es decir, fotogramas) y los apilará para simular las propiedades de Markov. Solo un breve comentario: obviamente, esto no es necesario cuando se usa, por ejemplo, la capa LSTM mencionada anteriormente, ya que la capa LSTM puede modelar y comunicar dependencias temporales a través de estados internos.
Exploración
La exploración se puede definir en un objeto de configuración, que el agente puede aplicar a la acción donde se determina su modelo (manejar múltiples acciones, nuevamente, dará un diccionario normativo). Por ejemplo, para utilizar la exploración de Ornstein-Uhlenbeck para obtener resultados de acción continua, se agregaría la siguiente especificación a la configuración.
Uso de agentes con funciones de utilidad Runner
Usemos un agente, este código es un agente que se ejecuta en nuestro entorno de prueba y lo usaremos para una integración continua: —Un entorno mínimo que Valida los mecanismos de acción, observación y actualización de cómo funciona un determinado agente/modelo. Tenga en cuenta que todas las implementaciones de nuestro entorno (OpenAI Gym, OpenAI Universe, DeepMind Lab) utilizan la misma interfaz, por lo que es sencillo ejecutar pruebas utilizando otro entorno.
La función de utilidad Runner puede facilitar el proceso de ejecución de un agente en un entorno. Dada cualquier instancia de agente y entorno, puede gestionar el número de episodios, la duración máxima de cada episodio, condiciones de terminación, etc. Runner también puede aceptar el parámetro cluster_spec; si está presente, puede gestionar la ejecución distribuida (supervisores/sesiones/etc. de TensorFlow). Con el parámetro opcional episodio_finalizado, también puede informar los resultados periódicamente y proporcionar una métrica para detener la ejecución antes del número máximo de episodios.
Como se mencionó en la introducción, el uso de la clase de corredor en un escenario de aplicación determinado depende del control de flujo. Si el uso del aprendizaje por refuerzo nos permite consultar razonablemente a TensorForce para obtener información de estado (como a través de una cola o servicio de red) y devolver acciones (a otra cola o servicio), entonces se puede usar para implementar la interfaz del entorno y, por lo tanto, se puede usar. (o extensión) función de utilidad del corredor.
Una situación más común puede ser utilizar TensorForce como una biblioteca de aplicación externa para el control del controlador y, por lo tanto, no puede proporcionar un identificador del entorno. Para los investigadores, esto puede no importar, pero en campos como los sistemas informáticos, este es un problema de implementación típico. Esta es la razón fundamental por la que la mayoría de los scripts de investigación solo se pueden usar para simulaciones y no en aplicaciones reales.
Otro punto que vale la pena mencionar es que el objeto de configuración central declarativo nos permite utilizar directamente la optimización de hiperparámetros para configurar interfaces para todos los componentes del modelo de aprendizaje por refuerzo, especialmente la arquitectura de red.
Pensamientos adicionales
Esperamos que TensorForce le resulte útil. Hasta ahora, nuestro enfoque se ha centrado en implementar primero la arquitectura, lo que creemos que nos permitirá implementar de manera más consistente diferentes conceptos de aprendizaje por refuerzo y nuevos métodos, y evitar el inconveniente de explorar casos de uso de aprendizaje por refuerzo profundo en nuevos dominios.
En un campo que evoluciona tan rápidamente, puede resultar difícil decidir qué funciones incluir en una biblioteca real.
Hay tantos algoritmos y conceptos hoy en día, y parece que cada semana hay nuevas ideas para obtener mejores resultados en un subconjunto del entorno Arcade Learning Environment (ALE). Pero hay un problema: muchas ideas sólo funcionan en entornos que son fáciles de paralelizar o que tienen una estructura de episodios específica; todavía no tenemos una idea precisa de las propiedades del entorno y cómo se relacionan con los diferentes métodos. Sin embargo, podemos ver algunas tendencias claras: gradiente de políticas híbridas y métodos de Q-learning para mejorar la eficiencia de la muestra (PGQ, Q-Prop, etc.): esto es algo lógico, aunque no está claro qué estrategia híbrida prevalecerá, pero Creemos que éste se convertirá en el próximo "enfoque estándar". Estamos muy interesados en comprender la utilidad de estos métodos en diferentes dominios de aplicación (datos ricos/datos escasos). Una opinión nuestra muy subjetiva es que la mayoría de los investigadores aplicados tienden a utilizar variantes de gradientes de políticas estándar porque son fáciles de entender, implementar y, lo que es más importante, más robustos que los algoritmos más nuevos que pueden requerir amplios ajustes para manejar posibles inestabilidades numéricas. Una opinión diferente es que los investigadores del aprendizaje sin refuerzo pueden simplemente desconocer los nuevos métodos relevantes o no estar dispuestos a tomarse la molestia de implementarlos. Y esto inspiró el desarrollo de TensorForce. Finalmente, vale la pena considerar que el mecanismo de actualización del dominio de la aplicación suele ser menos importante que el modelado de estados, acciones y recompensas, y la arquitectura de red. Mejor utilización de las GPU y otros dispositivos disponibles para enfoques paralelos/de un solo paso/distribuidos (PAAC, GA3C, etc.): un problema con los enfoques en esta área son las suposiciones implícitas sobre el tiempo que lleva recopilar datos versus actualizarlos. En ámbitos que no son de simulación, estas suposiciones pueden no ser ciertas, y comprender cómo las propiedades ambientales afectan la semántica de ejecución del dispositivo requiere más investigación. Todavía utilizamos feed_dicts, pero también buscamos mejorar el rendimiento del procesamiento de entrada. Modos de exploración (por ejemplo, exploración basada en recuentos, ruido espacial de parámetros, etc.) Grandes espacios de acción discretos, modelos jerárquicos y descomposición de subobjetivos. Por ejemplo, el artículo "Aprendizaje por refuerzo profundo en grandes espacios de acción discretos" de Dulac-Arnold et al. Los espacios discretos complejos (como muchas subopciones dependientes del estado) son muy relevantes en los dominios de aplicaciones, pero actualmente son difíciles de usar a través de API. Esperamos muchos resultados en los próximos años. Módulos internos para predicción de estados y nuevos métodos basados en modelos: como el artículo "The Predictron: End-To-End Learning and Planning". Aprendizaje bayesiano por refuerzo profundo y razonamiento bajo incertidumbre
En general, estamos siguiendo estos desarrollos e incorporaremos técnicas existentes que hemos pasado por alto antes (y debería haber muchas). También incorporaremos una nueva idea una vez que creamos; tiene el potencial de convertirse en un enfoque estándar sólido. En este sentido, no constituimos una competencia explícita con el marco de investigación, sino más bien un mayor grado de cobertura.