Documentación | Tensordicto | Características | Ejemplos, tutoriales y demostraciones | Cita | Instalación | Haciendo una pregunta | Que contribuye
Torchrl es una biblioteca de aprendizaje de refuerzo de código abierto (RL) para Pytorch.
Lea el documento completo para obtener una descripción más curada de la biblioteca.
¡Consulte nuestros tutoriales de inicio para obtener rápidamente las características básicas de la biblioteca!
La documentación de Torchrl se puede encontrar aquí. Contiene tutoriales y la referencia de API.
Torchrl también proporciona una base de conocimiento RL para ayudarlo a depurar su código, o simplemente aprender los conceptos básicos de RL. Compruébalo aquí.
Tenemos algunos videos introductorios para que conozcas mejor la biblioteca, échales un vistazo:
Torchrl AGNISTICO AGNATO, puede usarlo en muchos campos diferentes. Aquí hay algunos ejemplos:
TensorDict
Los algoritmos RL son muy heterogéneos, y puede ser difícil reciclar una base de código a través de la configuración (por ejemplo, desde en línea hasta fuera de línea, desde el aprendizaje basado en el estado hasta el aprendizaje basado en píxeles). TORCHRL resuelve este problema a través de TensorDict
, una estructura de datos conveniente (1) que puede usarse para optimizar la base de código RL de uno. ¡Con esta herramienta, uno puede escribir un script de entrenamiento PPO completo en menos de 100 líneas de código !
import torch
from tensordict . nn import TensorDictModule
from tensordict . nn . distributions import NormalParamExtractor
from torch import nn
from torchrl . collectors import SyncDataCollector
from torchrl . data . replay_buffers import TensorDictReplayBuffer ,
LazyTensorStorage , SamplerWithoutReplacement
from torchrl . envs . libs . gym import GymEnv
from torchrl . modules import ProbabilisticActor , ValueOperator , TanhNormal
from torchrl . objectives import ClipPPOLoss
from torchrl . objectives . value import GAE
env = GymEnv ( "Pendulum-v1" )
model = TensorDictModule (
nn . Sequential (
nn . Linear ( 3 , 128 ), nn . Tanh (),
nn . Linear ( 128 , 128 ), nn . Tanh (),
nn . Linear ( 128 , 128 ), nn . Tanh (),
nn . Linear ( 128 , 2 ),
NormalParamExtractor ()
),
in_keys = [ "observation" ],
out_keys = [ "loc" , "scale" ]
)
critic = ValueOperator (
nn . Sequential (
nn . Linear ( 3 , 128 ), nn . Tanh (),
nn . Linear ( 128 , 128 ), nn . Tanh (),
nn . Linear ( 128 , 128 ), nn . Tanh (),
nn . Linear ( 128 , 1 ),
),
in_keys = [ "observation" ],
)
actor = ProbabilisticActor (
model ,
in_keys = [ "loc" , "scale" ],
distribution_class = TanhNormal ,
distribution_kwargs = { "low" : - 1.0 , "high" : 1.0 },
return_log_prob = True
)
buffer = TensorDictReplayBuffer (
storage = LazyTensorStorage ( 1000 ),
sampler = SamplerWithoutReplacement (),
batch_size = 50 ,
)
collector = SyncDataCollector (
env ,
actor ,
frames_per_batch = 1000 ,
total_frames = 1_000_000 ,
)
loss_fn = ClipPPOLoss ( actor , critic )
adv_fn = GAE ( value_network = critic , average_gae = True , gamma = 0.99 , lmbda = 0.95 )
optim = torch . optim . Adam ( loss_fn . parameters (), lr = 2e-4 )
for data in collector : # collect data
for epoch in range ( 10 ):
adv_fn ( data ) # compute advantage
buffer . extend ( data )
for sample in buffer : # consume data
loss_vals = loss_fn ( sample )
loss_val = sum (
value for key , value in loss_vals . items () if
key . startswith ( "loss" )
)
loss_val . backward ()
optim . step ()
optim . zero_grad ()
print ( f"avg reward: { data [ 'next' , 'reward' ]. mean (). item (): 4.4f } " )
Aquí hay un ejemplo de cómo la API del entorno se basa en Tensordicto para llevar datos de una función a otra durante una ejecución de despliegue:
TensorDict
hace que sea fácil reutilizar piezas de código en entornos, modelos y algoritmos.
Por ejemplo, aquí le mostramos cómo codificar un despliegue en Torchrl:
- obs, done = env.reset()
+ tensordict = env.reset()
policy = SafeModule(
model,
in_keys=["observation_pixels", "observation_vector"],
out_keys=["action"],
)
out = []
for i in range(n_steps):
- action, log_prob = policy(obs)
- next_obs, reward, done, info = env.step(action)
- out.append((obs, next_obs, action, log_prob, reward, done))
- obs = next_obs
+ tensordict = policy(tensordict)
+ tensordict = env.step(tensordict)
+ out.append(tensordict)
+ tensordict = step_mdp(tensordict) # renames next_observation_* keys to observation_*
- obs, next_obs, action, log_prob, reward, done = [torch.stack(vals, 0) for vals in zip(*out)]
+ out = torch.stack(out, 0) # TensorDict supports multiple tensor operations
Usando esto, TorChrl abstrae las firmas de entrada / salida de los módulos, env, coleccionistas, buffers de repetición y pérdidas de la biblioteca, lo que permite que todas las primitivas se reciclen fácilmente a través de la configuración.
Aquí hay otro ejemplo de un bucle de entrenamiento fuera de política en TORCHRL (suponiendo que un recopilador de datos, un búfer de repetición, una pérdida y un optimizador se hayan instanciado):
- for i, (obs, next_obs, action, hidden_state, reward, done) in enumerate(collector):
+ for i, tensordict in enumerate(collector):
- replay_buffer.add((obs, next_obs, action, log_prob, reward, done))
+ replay_buffer.add(tensordict)
for j in range(num_optim_steps):
- obs, next_obs, action, hidden_state, reward, done = replay_buffer.sample(batch_size)
- loss = loss_fn(obs, next_obs, action, hidden_state, reward, done)
+ tensordict = replay_buffer.sample(batch_size)
+ loss = loss_fn(tensordict)
loss.backward()
optim.step()
optim.zero_grad()
Este bucle de entrenamiento se puede reutilizar en los algoritmos, ya que hace un número mínimo de suposiciones sobre la estructura de los datos.
Tensordicto admite múltiples operaciones de tensor en su dispositivo y forma (la forma de Tensordicto, o su tamaño por lotes, es el arbitrary N Primero Dimensiones común de todos sus tensores contenidos):
# stack and cat
tensordict = torch . stack ( list_of_tensordicts , 0 )
tensordict = torch . cat ( list_of_tensordicts , 0 )
# reshape
tensordict = tensordict . view ( - 1 )
tensordict = tensordict . permute ( 0 , 2 , 1 )
tensordict = tensordict . unsqueeze ( - 1 )
tensordict = tensordict . squeeze ( - 1 )
# indexing
tensordict = tensordict [: 2 ]
tensordict [:, 2 ] = sub_tensordict
# device and memory location
tensordict . cuda ()
tensordict . to ( "cuda:1" )
tensordict . share_memory_ ()
Tensordict viene con un módulo dedicado tensordict.nn
que contiene todo lo que puede necesitar para escribir su modelo con él. ¡Y es functorch
y torch.compile
compatible!
transformer_model = nn.Transformer(nhead=16, num_encoder_layers=12)
+ td_module = SafeModule(transformer_model, in_keys=["src", "tgt"], out_keys=["out"])
src = torch.rand((10, 32, 512))
tgt = torch.rand((20, 32, 512))
+ tensordict = TensorDict({"src": src, "tgt": tgt}, batch_size=[20, 32])
- out = transformer_model(src, tgt)
+ td_module(tensordict)
+ out = tensordict["out"]
La clase TensorDictSequential
permite ramificar secuencias de instancias nn.Module
de una manera altamente modular. Por ejemplo, aquí hay una implementación de un transformador utilizando el codificador y los bloques de decodificadores:
encoder_module = TransformerEncoder (...)
encoder = TensorDictSequential ( encoder_module , in_keys = [ "src" , "src_mask" ], out_keys = [ "memory" ])
decoder_module = TransformerDecoder (...)
decoder = TensorDictModule ( decoder_module , in_keys = [ "tgt" , "memory" ], out_keys = [ "output" ])
transformer = TensorDictSequential ( encoder , decoder )
assert transformer . in_keys == [ "src" , "src_mask" , "tgt" ]
assert transformer . out_keys == [ "memory" , "output" ]
TensorDictSequential
permite aislar subgrafos consultando un conjunto de teclas de entrada / salida deseadas:
transformer . select_subsequence ( out_keys = [ "memory" ]) # returns the encoder
transformer . select_subsequence ( in_keys = [ "tgt" , "memory" ]) # returns the decoder
¡Revise los tutoriales de Tensordict para obtener más información!
Una interfaz común para entornos que admiten bibliotecas comunes (OpenAI Gym, DeepMind Control Lab, etc.) (1) y ejecución sin estado (entornos de modelos por ejemplo). Los contenedores de entornos por lotes permiten la ejecución paralela (2) . También se proporciona una clase común Pytorch-First de clase de especificación de tensor. La API de entornos de Torchrl es simple pero estricto y específico. ¡Consulte la documentación y el tutorial para obtener más información!
env_make = lambda : GymEnv ( "Pendulum-v1" , from_pixels = True )
env_parallel = ParallelEnv ( 4 , env_make ) # creates 4 envs in parallel
tensordict = env_parallel . rollout ( max_steps = 20 , policy = None ) # random rollout (no policy given)
assert tensordict . shape == [ 4 , 20 ] # 4 envs, 20 steps rollout
env_parallel . action_spec . is_in ( tensordict [ "action" ]) # spec check returns True
coleccionistas de datos multiprocesos y distribuidos (2) que funcionan sincrónicamente o asincrónicamente. Mediante el uso de Tensordicto, los bucles de entrenamiento de Torchrl se hacen muy similares a los bucles de entrenamiento regulares en el aprendizaje supervisado (aunque el "DataLoader"-Leer recolector de datos-se modifica en la marcha):
env_make = lambda : GymEnv ( "Pendulum-v1" , from_pixels = True )
collector = MultiaSyncDataCollector (
[ env_make , env_make ],
policy = policy ,
devices = [ "cuda:0" , "cuda:0" ],
total_frames = 10000 ,
frames_per_batch = 50 ,
...
)
for i , tensordict_data in enumerate ( collector ):
loss = loss_module ( tensordict_data )
loss . backward ()
optim . step ()
optim . zero_grad ()
collector . update_policy_weights_ ()
Consulte nuestros ejemplos de colección distribuidos para obtener más información sobre la recopilación de datos ultra rápido con TORCHRL.
Buffers de reproducción eficientes (2) y genéricos (1) con almacenamiento modularizado:
storage = LazyMemmapStorage ( # memory-mapped (physical) storage
cfg . buffer_size ,
scratch_dir = "/tmp/"
)
buffer = TensorDictPrioritizedReplayBuffer (
alpha = 0.7 ,
beta = 0.5 ,
collate_fn = lambda x : x ,
pin_memory = device != torch . device ( "cpu" ),
prefetch = 10 , # multi-threaded sampling
storage = storage
)
Los búferes de reproducción también se ofrecen como envoltorios en torno a conjuntos de datos comunes para RL fuera de línea :
from torchrl . data . replay_buffers import SamplerWithoutReplacement
from torchrl . data . datasets . d4rl import D4RLExperienceReplay
data = D4RLExperienceReplay (
"maze2d-open-v0" ,
split_trajs = True ,
batch_size = 128 ,
sampler = SamplerWithoutReplacement ( drop_last = True ),
)
for sample in data : # or alternatively sample = data.sample()
fun ( sample )
Transformaciones de entorno de biblioteca cruzada (1) , ejecutadas en el dispositivo y de manera vectorizada (2) , que procesan y preparan los datos que salen de los entornos que utilizarán el agente:
env_make = lambda : GymEnv ( "Pendulum-v1" , from_pixels = True )
env_base = ParallelEnv ( 4 , env_make , device = "cuda:0" ) # creates 4 envs in parallel
env = TransformedEnv (
env_base ,
Compose (
ToTensorImage (),
ObservationNorm ( loc = 0.5 , scale = 1.0 )), # executes the transforms once and on device
)
tensordict = env . reset ()
assert tensordict . device == torch . device ( "cuda:0" )
Otras transformaciones incluyen: escala de recompensas ( RewardScaling
), operaciones de forma (concatenación de tensores, insuficiencia, etc.), concatenación de operaciones sucesivas ( CatFrames
), cambio de tamaño ( Resize
) y muchos más.
A diferencia de otras bibliotecas, las transformaciones se apilan como una lista (y no se envuelven entre sí), lo que facilita agregarlas y eliminarlas a voluntad:
env . insert_transform ( 0 , NoopResetEnv ()) # inserts the NoopResetEnv transform at the index 0
Sin embargo, las transformaciones pueden acceder y ejecutar operaciones en el entorno principal:
transform = env . transform [ 1 ] # gathers the second transform of the list
parent_env = transform . parent # returns the base environment of the second transform, i.e. the base env + the first transform
varias herramientas para el aprendizaje distribuido (por ejemplo, tensores mapeados de memoria) (2) ;
Varias arquitecturas y modelos (por ejemplo, actor-crítico) (1) :
# create an nn.Module
common_module = ConvNet (
bias_last_layer = True ,
depth = None ,
num_cells = [ 32 , 64 , 64 ],
kernel_sizes = [ 8 , 4 , 3 ],
strides = [ 4 , 2 , 1 ],
)
# Wrap it in a SafeModule, indicating what key to read in and where to
# write out the output
common_module = SafeModule (
common_module ,
in_keys = [ "pixels" ],
out_keys = [ "hidden" ],
)
# Wrap the policy module in NormalParamsWrapper, such that the output
# tensor is split in loc and scale, and scale is mapped onto a positive space
policy_module = SafeModule (
NormalParamsWrapper (
MLP ( num_cells = [ 64 , 64 ], out_features = 32 , activation = nn . ELU )
),
in_keys = [ "hidden" ],
out_keys = [ "loc" , "scale" ],
)
# Use a SafeProbabilisticTensorDictSequential to combine the SafeModule with a
# SafeProbabilisticModule, indicating how to build the
# torch.distribution.Distribution object and what to do with it
policy_module = SafeProbabilisticTensorDictSequential ( # stochastic policy
policy_module ,
SafeProbabilisticModule (
in_keys = [ "loc" , "scale" ],
out_keys = "action" ,
distribution_class = TanhNormal ,
),
)
value_module = MLP (
num_cells = [ 64 , 64 ],
out_features = 1 ,
activation = nn . ELU ,
)
# Wrap the policy and value funciton in a common module
actor_value = ActorValueOperator ( common_module , policy_module , value_module )
# standalone policy from this
standalone_policy = actor_value . get_policy_operator ()
envoltorios de exploración y módulos para intercambiar fácilmente entre exploración y explotación (1) :
policy_explore = EGreedyWrapper ( policy )
with set_exploration_type ( ExplorationType . RANDOM ):
tensordict = policy_explore ( tensordict ) # will use eps-greedy
with set_exploration_type ( ExplorationType . DETERMINISTIC ):
tensordict = policy_explore ( tensordict ) # will not use eps-greedy
Una serie de módulos de pérdida eficientes y rendimiento funcional altamente vectorial y cálculo de ventaja.
from torchrl . objectives import DQNLoss
loss_module = DQNLoss ( value_network = value_network , gamma = 0.99 )
tensordict = replay_buffer . sample ( batch_size )
loss = loss_module ( tensordict )
from torchrl . objectives . value . functional import vec_td_lambda_return_estimate
advantage = vec_td_lambda_return_estimate ( gamma , lmbda , next_state_value , reward , done , terminated )
Una clase de entrenador genérico (1) que ejecuta el ciclo de entrenamiento antes mencionado. A través de un mecanismo de enganche, también admite cualquier operación de registro o transformación de datos en un momento dado.
Varias recetas para construir modelos que corresponden al entorno que se implementa.
Si cree que falta una función en la biblioteca, ¡envíe un problema! Si desea contribuir a nuevas funciones, consulte nuestra llamada de contribuciones y nuestra página de contribución.
Una serie de implementaciones de vanguardia se proporcionan con un propósito ilustrativo:
Algoritmo | Compilar soporte ** | API sin tensordicto | Pérdidas modulares | Continuo y discreto |
Dqn | 1.9x | + + | N / A | + (a través de la transformación de ActionDisCretizer) |
Ddpg | 1.87x | + + | + + | - (solo continuo) |
IQL | 3.22x | + + | + + | + + |
CQL | 2.68x | + + | + + | + + |
TD3 | 2.27x | + + | + + | - (solo continuo) |
TD3+BC | no probado | + + | + + | - (solo continuo) |
A2C | 2.67x | + + | - | + + |
PPO | 2.42x | + + | - | + + |
SACO | 2.62x | + + | - | + + |
Rojizo | 2.28x | + + | - | - (solo continuo) |
Soñador v1 | no probado | + + | + (diferentes clases) | - (solo continuo) |
Transformadores de decisión | no probado | + + | N / A | - (solo continuo) |
Crossq | no probado | + + | + + | - (solo continuo) |
Gail | no probado | + + | N / A | + + |
Impala | no probado | + + | - | + + |
IQL (Marl) | no probado | + + | + + | + + |
DDPG (marga) | no probado | + + | + + | - (solo continuo) |
PPO (marga) | no probado | + + | - | + + |
QMIX-VDN (Marl) | no probado | + + | N / A | + + |
SAC (marga) | no probado | + + | - | + + |
RLHF | N / A | + + | N / A | N / A |
** El número indica aceleración esperada en comparación con el modo ansioso cuando se ejecuta en CPU. Los números pueden variar según la arquitectura y el dispositivo.
¡Y muchos más por venir!
Ejemplos de código que muestran fragmentos de código de juguete y scripts de entrenamiento también están disponibles
Consulte el directorio de ejemplos para obtener más detalles sobre el manejo de las diversas configuraciones de configuración.
También proporcionamos tutoriales y demostraciones que dan una idea de lo que la biblioteca puede hacer.
Si está utilizando TORCHRL, consulte esta entrada de Bibtex para citar este trabajo:
@misc{bou2023torchrl,
title={TorchRL: A data-driven decision-making library for PyTorch},
author={Albert Bou and Matteo Bettini and Sebastian Dittert and Vikash Kumar and Shagun Sodhani and Xiaomeng Yang and Gianni De Fabritiis and Vincent Moens},
year={2023},
eprint={2306.00577},
archivePrefix={arXiv},
primaryClass={cs.LG}
}
Cree un entorno de condena donde se instalen los paquetes.
conda create --name torch_rl python=3.9
conda activate torch_rl
Pytorch
Dependiendo del uso de Functorch que desee hacer, es posible que desee instalar el último lanzamiento de Pytorch (nocturno) o la última versión estable de Pytorch. Consulte aquí para obtener una lista detallada de comandos, incluido pip3
u otras instrucciones especiales de instalación.
Torcer
Puede instalar la última versión estable utilizando
pip3 install torchrl
Esto debería funcionar en Linux, Windows 10 y OSX (Intel o chips de silicio). En ciertas máquinas de Windows (Windows 11), uno debe instalar la biblioteca localmente (ver más abajo).
La construcción nocturna se puede instalar a través de
pip3 install torchrl-nightly
que actualmente solo enviamos para máquinas Linux y OSX (Intel). Es importante destacar que las construcciones nocturnas también requieren las construcciones nocturnas de Pytorch.
Para instalar dependencias adicionales, llame
pip3 install " torchrl[atari,dm_control,gym_continuous,rendering,tests,utils,marl,open_spiel,checkpointing] "
o un subconjunto de estos.
También se puede desear instalar la biblioteca localmente. Tres razones principales pueden motivar esto:
Para instalar la biblioteca localmente, comience clonando el repositorio:
git clone https://github.com/pytorch/rl
Y no olvide ver la rama o la etiqueta que desea usar para la compilación:
git checkout v0.4.0
Vaya al directorio donde ha clonado el repositorio de Torchrl e instálelo (después de instalar ninja
)
cd /path/to/torchrl/
pip3 install ninja -U
python setup.py develop
También se puede construir las ruedas para distribuir a los compañeros de trabajo que usan
python setup.py bdist_wheel
Sus ruedas se almacenarán allí ./dist/torchrl<name>.whl
e instalable a través de
pip install torchrl < name > .whl
ADVERTENCIA : Desafortunadamente, pip3 install -e .
Actualmente no funciona. ¡Las contribuciones para ayudar a solucionar esto son bienvenidos!
En las máquinas M1, esto debería funcionar fuera de la caja con la construcción nocturna de Pytorch. Si la generación de este artefacto en MacOS M1 no funciona correctamente o en la ejecución, aparece el mensaje (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64e'))
, luego intente
ARCHFLAGS="-arch arm64" python setup.py develop
Para ejecutar una verificación rápida de cordura, deje ese directorio (por ejemplo, ejecutando cd ~/
) e intente importar la biblioteca.
python -c "import torchrl"
Esto no debe devolver ninguna advertencia o error.
Dependencias opcionales
Las siguientes bibliotecas se pueden instalar dependiendo del uso que se desee hacer de Torchrl:
# diverse
pip3 install tqdm tensorboard "hydra-core>=1.1" hydra-submitit-launcher
# rendering
pip3 install moviepy
# deepmind control suite
pip3 install dm_control
# gym, atari games
pip3 install "gym[atari]" "gym[accept-rom-license]" pygame
# tests
pip3 install pytest pyyaml pytest-instafail
# tensorboard
pip3 install tensorboard
# wandb
pip3 install wandb
Solución de problemas
Si se producen un ModuleNotFoundError: No module named 'torchrl._torchrl
(o una advertencia que indica que los binarios C ++ no se pueden cargar), significa que las extensiones de C ++ no se instalaron o no se encontraron.
develop
: cd ~/path/to/rl/repo
python -c 'from torchrl.envs.libs.gym import GymEnv'
python setup.py develop
. Una causa común es una discrepancia de la versión G ++/C ++ y/o un problema con la biblioteca ninja
. wget https://raw.githubusercontent.com/pytorch/pytorch/master/torch/utils/collect_env.py
python collect_env.py
OS: macOS *** (arm64)
OS: macOS **** (x86_64)
Los problemas de versiones pueden causar un mensaje de error del tipo undefined symbol
y tal. Para estos, consulte el documento de temas de versiones para obtener una explicación completa y las soluciones propuestas.
Si ve un error en la biblioteca, plantee un problema en este repositorio.
Si tiene una pregunta más genérica con respecto a RL en Pytorch, publíquela en el foro de Pytorch.
¡Las colaboraciones internas a Torchrl son bienvenidas! Siéntase libre de bifurcar, enviar problemas y PRS. Puede consultar la guía de contribución detallada aquí. Como se mencionó anteriormente, se puede encontrar una lista de contribuciones abiertas aquí.
Se recomienda que los contribuyentes instalaran ganchos previos al comercio (utilizando pre-commit install
). Precomitar verificará los problemas relacionados con las pelusas cuando el código se comete localmente. Puede deshabilitar la comprobación de la adición -n
a su comando de confirmación: git commit -m <commit message> -n
Esta biblioteca se lanzó como una función beta de Pytorch. Es probable que ocurran cambios en la ruptura de BC, pero se introducirán con una garantía de deprecación después de algunos ciclos de liberación.
Torchrl tiene licencia bajo la licencia MIT. Vea la licencia para más detalles.