核心概念#

注意

Ray 2.40 默认使用 RLlib 的新 API 栈。Ray 团队已基本完成将算法、示例脚本和文档迁移到新的代码库。

如果您仍在使用旧的 API 栈,请参阅新 API 栈迁移指南了解如何迁移的详细信息。

为了帮助您对该库的工作原理有一个高层次的了解,本页将介绍 RLlib 的核心概念和总体架构。

../_images/rllib_key_concepts.svg

RLlib 概述:RLlib 的核心组件是Algorithm类,它充当执行您的 RL 实验的运行时。使用算法的入口是AlgorithmConfig青色)类,它允许您管理可用的配置设置,例如学习率或模型架构。大多数Algorithm对象都拥有EnvRunneractor蓝色)用于从RL 环境收集训练样本,以及Learneractor黄色)用于计算梯度和更新您的模型。算法在更新后会同步模型权重。#

AlgorithmConfig 和 Algorithm#

提示

以下是关于 RLlib AlgorithmConfig 和 Algorithm 的快速概述。有关 Algorithm 类的详细描述,请参见此处。

RLlib 的Algorithm类作为您的 RL 实验的运行时,汇集了学习RL 环境最优解所需的所有组件。它公开了强大的 Python API,用于控制您的实验运行。

使用各种 RLlib Algorithm 类型的入口是各自的 AlgorithmConfig 类,允许您以检查和类型安全的方式配置可用设置。例如,要配置 PPO(“近端策略优化”)算法实例,您可以使用 PPOConfig 类。

在构建过程中,Algorithm 首先设置其 EnvRunnerGroup,其中包含 nEnvRunner actor,以及其 LearnerGroup,其中包含 mLearner actor。通过这种方式,您可以分别从单个核心扩展到集群中的数千个核心,以扩展样本收集和训练。

有关更多详细信息,请参阅此扩展指南

您有两种方式与 Algorithm 交互并运行它

  • 您可以直接通过 Python API 创建和管理它的实例。

  • 由于 Algorithm 类是 Tune Trainable API 的子类,因此您可以使用 Ray Tune 更轻松地管理您的实验并调优超参数。

以下示例演示了如何在 RLlib 的 PPO(“近端策略优化”)算法上实现这一点

from ray.rllib.algorithms.ppo import PPOConfig

# Configure.
config = (
    PPOConfig()
    .environment("CartPole-v1")
    .training(
        train_batch_size_per_learner=2000,
        lr=0.0004,
    )
)

# Build the Algorithm.
algo = config.build()

# Train for one iteration, which is 2000 timesteps (1 train batch).
print(algo.train())
from ray import tune
from ray.rllib.algorithms.ppo import PPOConfig

# Configure.
config = (
    PPOConfig()
    .environment("CartPole-v1")
    .training(
        train_batch_size_per_learner=2000,
        lr=0.0004,
    )
)

# Train through Ray Tune.
results = tune.Tuner(
    "PPO",
    param_space=config,
    # Train for 4000 timesteps (2 iterations).
    run_config=tune.RunConfig(stop={"num_env_steps_sampled_lifetime": 4000}),
).fit()

RL 环境#

提示

以下是关于 RL 环境 的快速概述。有关 如何在 RLlib 中使用 RL 环境的详细描述,请参见此处

强化学习 (RL) 环境是一个结构化空间,例如模拟器或真实世界的受控部分,其中一个或多个智能体进行交互并学习以实现特定目标。环境定义了观察空间(每个时间步可观察张量的结构和形状)、动作空间(定义了智能体在每个时间步可用的动作)、奖励函数,以及应用动作时控制环境转换的规则。

../_images/env_loop_concept.svg

一个简单的 RL 环境,其中智能体以 reset() 方法返回的初始观察开始。智能体(可能由神经网络策略控制)将动作(例如 rightjump)发送到环境的 step() 方法,该方法返回奖励。在此,达到目标的奖励值为 +5,否则为 0。环境还会返回一个布尔标志,指示回合是否完成。#

环境的复杂性各不相同,从简单的任务(例如在网格世界中导航)到高度复杂的系统(例如自动驾驶模拟器、机器人控制环境或多智能体游戏)。

RLlib 通过在训练迭代期间进行许多回合来与环境交互,以收集数据,例如进行的观察、采取的动作、收到的奖励和 done 标志(参见前图)。然后,它将这些回合数据转换为用于模型更新的训练批次。这些模型更新的目标是改变智能体的行为,使其在其生命周期内获得最大总奖励。

RLModule#

提示

以下是关于 RLlib RLModule 的快速概述。有关 RLModule 类的详细描述,请参见此处

RLModule 是深度学习框架特定的神经网络包装器。RLlib 的EnvRunner 在遍历 RL 环境时使用它们来计算动作,而 RLlib 的Learner 在更新模型之前使用 RLModule 实例来计算损失和梯度。

../_images/rl_module_overview.svg

RLModule 概述(左)一个最小的RLModule包含一个神经网络,并定义其前向探索、推理和训练逻辑。(右)在更复杂的设置中,一个MultiRLModule包含许多子模块,每个子模块本身都是一个RLModule实例,并通过ModuleID标识,允许您实现任意复杂的多模型和多智能体算法。#

简而言之,RLModule 承载神经网络模型,并定义在其 RL 生命周期中的三个阶段如何使用它们:探索(用于收集训练数据)、推理(在计算用于评估或生产环境中的动作时)和训练(用于计算损失函数输入)。

您可以选择使用RLlib 的内置默认模型并根据需要配置它们,例如更改层数或激活函数,或者在 PyTorch 中编写您自己的自定义模型,从而实现任何架构和计算逻辑。

../_images/rl_module_in_env_runner.svg

EnvRunner actor 中的 RLModuleEnvRunner 操作其自身的仅推理版本的 RLModule 副本,仅用于计算动作。#

每个 EnvRunner actor 由 Algorithm 的 EnvRunnerGroup 管理,都拥有用户 RLModule 的副本。同样,每个 Learner actor 由 Algorithm 的 LearnerGroup 管理,都拥有 RLModule 的副本。

阻止 EnvRunner 副本通常是其 inference_only 版本,这意味着计算纯动作不需要的组件(例如值函数估计)会被省略以节省内存。

../_images/rl_module_in_learner.svg

Learner actor 中的 RLModuleLearner 操作其自身的 RLModule 副本,计算损失函数输入、损失本身以及模型的梯度,然后通过 Learner 的优化器更新 RLModule#

回合 (Episode)#

提示

以下是关于 Episode 的快速概述。有关 Episode 类的详细描述,请参见此处

RLlib 以回合 (Episode) 的形式传输所有训练数据。

SingleAgentEpisode 类描述单智能体轨迹。MultiAgentEpisode 类包含多个此类单智能体回合,并描述了单个智能体相对于彼此的步进时间模式。

两个 Episode 类都存储了在遍历 RL 环境时生成的完整轨迹数据。这些数据包括观察、info 字典、动作、奖励、终止信号,以及沿途进行的任何模型计算,例如循环状态、动作 logits 或动作对数概率。

提示

有关 RLlib 的标准化列名,请参见此处。

请注意,回合(episode)方便地无需存储任何 next obs 信息,因为它总是与 obs 下的信息重叠。这种设计节省了近 50% 的内存,因为观察通常是轨迹中最大的部分。对于有状态网络,state_instate_out 信息也是如此。RLlib 在回合中仅保留 state_out 键。

通常,RLlib 通过 Algorithm 的 EnvRunnerGroup 中的 EnvRunner actor 生成大小为 config.rollout_fragment_length 的回合块,并向每个 Learner actor 发送所需的回合块数量,以构建一个大小恰好为 config.train_batch_size_per_learner 的训练批次。

一个典型的 SingleAgentEpisode 对象大致如下所示

# A SingleAgentEpisode of length 20 has roughly the following schematic structure.
# Note that after these 20 steps, you have 20 actions and rewards, but 21 observations and info dicts
# due to the initial "reset" observation/infos.
episode = {
    'obs': np.ndarray((21, 4), dtype=float32),  # 21 due to additional reset obs
    'infos': [{}, {}, {}, {}, .., {}, {}],  # infos are always lists of dicts
    'actions': np.ndarray((20,), dtype=int64),  # Discrete(4) action space
    'rewards': np.ndarray((20,), dtype=float32),
    'extra_model_outputs': {
        'action_dist_inputs': np.ndarray((20, 4), dtype=float32),  # Discrete(4) action space
    },
    'is_terminated': False,  # <- single bool
    'is_truncated': True,  # <- single bool
}

对于复杂的观察,例如 gym.spaces.Dict,回合(episode)将所有观察存储在一个与观察空间完全相似的结构中,该字典的叶节点是 NumPy 数组。例如

episode_w_complex_observations = {
    'obs': {
        "camera": np.ndarray((21, 64, 64, 3), dtype=float32),  # RGB images
        "sensors": {
            "front": np.ndarray((21, 15), dtype=float32),  # 1D tensors
            "rear": np.ndarray((21, 5), dtype=float32),  # another batch of 1D tensors
        },
    },
    ...

因为 RLlib 将所有值存储在 NumPy 数组中,这使得跨网络的编码和传输非常高效。

多智能体模式下,EnvRunnerGroup 生成 MultiAgentEpisode 实例。

注意

Ray 团队正在编写 MultiAgentEpisode 类的详细描述。

EnvRunner:结合 RL 环境和 RLModule#

给定 RL 环境和一个 RLModule,一个 EnvRunner 会生成回合列表。

它通过执行经典的环境交互循环来完成此任务。高效的样本收集可能很难正确实现,尤其是在利用环境向量化、有状态循环神经网络或在多智能体设置中操作时。

RLlib 提供了两个内置的 EnvRunner 类,SingleAgentEnvRunnerMultiAgentEnvRunner,它们会自动处理这些复杂性。RLlib 根据您的配置选择正确的类型,特别是 config.environment()config.multi_agent() 设置。

提示

调用 is_multi_agent() 方法来判断您的配置是否是多智能体。

RLlib 通过 EnvRunnerGroup API 将多个 EnvRunner actor 捆绑在一起。

您也可以单独使用一个 EnvRunner,通过调用其 sample() 方法来生成回合列表。

以下是创建一组远程 EnvRunner actor 并使用它们并行收集经验的示例

import tree  # pip install dm_tree
import ray
from ray.rllib.algorithms.ppo import PPOConfig
from ray.rllib.env.single_agent_env_runner import SingleAgentEnvRunner

# Configure the EnvRunners.
config = (
    PPOConfig()
    .environment("Acrobot-v1")
    .env_runners(num_env_runners=2, num_envs_per_env_runner=1)
)
# Create the EnvRunner actors.
env_runners = [
    ray.remote(SingleAgentEnvRunner).remote(config=config)
    for _ in range(config.num_env_runners)
]

# Gather lists of `SingleAgentEpisode`s (each EnvRunner actor returns one
# such list with exactly two episodes in it).
episodes = ray.get([
    er.sample.remote(num_episodes=3)
    for er in env_runners
])
# Two remote EnvRunners used.
assert len(episodes) == 2
# Each EnvRunner returns three episodes
assert all(len(eps_list) == 3 for eps_list in episodes)

# Report the returns of all episodes collected
for episode in tree.flatten(episodes):
    print("R=", episode.get_return())

Learner:结合 RLModule、损失函数和优化器#

提示

以下是关于 RLlib Learner 的快速概述。有关 Learner 类的详细描述,请参见此处

给定 RLModule 以及一个或多个优化器和损失函数,Learner 计算损失和梯度,然后更新 RLModule

此类更新步骤的输入数据是回合列表的形式,Learner 自身的连接器管道或外部管道会将其转换为最终的训练批次。

注意

ConnectorV2 文档正在开发中。Ray 团队将在完成后在此处链接到正确的文档页面。

Learner 实例与算法特定,这主要是由于不同 RL 算法使用了各种损失函数。

RLlib 总是通过 LearnerGroup API 捆绑多个 Learner actor,自动在训练数据上应用分布式数据并行 (DDP)。您也可以单独使用一个 Learner,用回合列表更新您的 RLModule。

以下是创建远程 Learner actor 并调用其 update() 方法的示例。

import gymnasium as gym
import ray
from ray.rllib.algorithms.ppo import PPOConfig
from ray.rllib.core.rl_module.default_model_config import DefaultModelConfig

# Configure the Learner.
config = (
    PPOConfig()
    .environment("Acrobot-v1")
    .training(lr=0.0001)
    .rl_module(model_config=DefaultModelConfig(fcnet_hiddens=[64, 32]))
)
# Get the Learner class.
ppo_learner_class = config.get_default_learner_class()

# Create the Learner actor.
learner_actor = ray.remote(ppo_learner_class).remote(
    config=config,
    module_spec=config.get_multi_rl_module_spec(env=gym.make("Acrobot-v1")),
)
# Build the Learner.
ray.get(learner_actor.build.remote())

# Perform an update from the list of episodes we got from the `EnvRunners` above.
learner_results = ray.get(learner_actor.update.remote(
    episodes=tree.flatten(episodes)
))
print(learner_results["default_policy"]["policy_loss"])