RLlib - KEY CONCEPTS 文档内容翻译

RLlib中关键概念

Trainers

Trainers将所有 RLlib 组件组合在一起,使算法可以通过 RLlib 的 Python API 及其命令行界面 (CLI) 访问。他们管理算法配置、部署rollout workers、optimizer的设置以及训练指标的收集。培训师还实施了 Tune Trainable API 以简化实验管理。Trainers还实施了 Tune Trainable API 以简化实验管理。
您可以通过三种方式与培训师互动。您可以使用基本的 Python API 或命令行来训练它,也可以使用 Ray Tune 来调整强化学习算法的超参数。下面的例子展示了与 PPOTrainer 交互的三种等效方式,它实现了 RLlib 中的近端策略优化算法
①Basic RLlib Trainers 利用RLlib中的算法进行训练

trainer = PPOTrainer(env="CartPole-v0", config={"train_batch_size": 4000})
while True:
    print(trainer.train())

②RLlib tune Trainer 利用ray中自带的tune进行训练

from ray import tune
tune.run(PPOTrainer, config={"env": "CartPole-v0", "train_batch_size": 4000})

③RLlib command line 使用命令行进行训练

rllib train --run=PPO --env=CartPole-v0 --config='{"train_batch_size": 4000}'

RLlib Trainer 类协调运行部署和优化策略的分布式工作流程。 Trainer 类利用并行迭代器来实现所需的计算模式。 下图显示了同步采样(synchronous sampling),这是这些模式中最简单的一种:
在这里插入图片描述
RLlib 使用 Ray Actor 将训练从单个核心扩展到集群中的数千个核心。您可以通过更改 num_workers 参数来配置用于训练的并行度。(自己的理解:Rollout Workers相当于是在环境中执行策略的智能体,图中有四个Rollout Workers,也就是该策略会在四个智能体上执行,分别与他们自身的环境进行交互,得到经验,最终采集到Trainer中,进行批次训练,这样可以大大提高训练的效率,因为强化学习绝大部分时间都在与环境进行交互,所以可以设置多个智能体(num_workers )执行相同的策略进行环境交互)

Policies(策略)

Policies是 RLlib 的核心概念。简而言之,Policies是定义agent在环境中的行为方式的 Python 类。Rollout workers 查询策略以确定agent的动作。在gym环境中,只有一个agent和Policies。在vector环境中,Policies推断同时针对多个agent,而在Multi-agent环境中,可能有多个Policies,每个Policies控制一个或多个agent:
在这里插入图片描述
可以使用任何框架来实现Policies。但是,对于 TensorFlow 和 PyTorch,RLlib 具有 build_tf_policy 和 build_torch_policy 辅助函数,可让您使用函数式 API 定义可训练的Policies,例如:
(下测函数为官方给定,汉语注释为自己理解)

# PG 损失函数计算:-Gt * onehot(action) * log(model(s)) 
def policy_gradient_loss(policy, model, dist_class, train_batch):
    logits, _ = model.from_batch(train_batch)
    action_dist = dist_class(logits, model)
    return -tf.reduce_mean(action_dist.logp(train_batch["actions"]) * train_batch["rewards"])

# <class 'ray.rllib.policy.tf_policy_template.MyTFPolicy'>
MyTFPolicy = build_tf_policy(
    name="MyTFPolicy",
    loss_fn=policy_gradient_loss)

Policy Evaluation(政策评估)

给定环境和Policy,Policy Evaluation会产生一批批的经验。这是经典的“环境交互循环”。有效的Policy Evaluation可能很麻烦,尤其是在利用矢量化、RNN 或在多智能体环境中运行时。 RLlib 提供了一个 RolloutWorker 类来管理所有这些,并且这个类用于大多数 RLlib 算法。
您可以单独使用 rollout workers 来产生批量体验。这可以通过在工作实例上调用 worker.sample() 或在作为 Ray Actor 创建的工作实例上并行调用 worker.sample.remote() 来完成(参见 WorkerSet)。
这是一个创建一组 rollout workers 并使用它们并行收集经验的示例。将轨迹连接起来,策略在轨迹批次上学习,然后我们将策略权重广播给 rollout workers 以进行下一轮部署

# Setup policy and rollout workers.
env = gym.make("CartPole-v0")
policy = CustomPolicy(env.observation_space, env.action_space, {})
workers = WorkerSet(
    policy_class=CustomPolicy,
    env_creator=lambda c: gym.make("CartPole-v0"),
    num_workers=10)

while True:
    # Gather a batch of samples.
    T1 = SampleBatch.concat_samples(
        ray.get([w.sample.remote() for w in workers.remote_workers()]))

    # Improve the policy using the T1 batch.
    # 根据收集到的批次数据进行学习
    policy.learn_on_batch(T1)

    # The local worker acts as a "parameter server" here.
    # We put the weights of its `policy` into the Ray object store once (`ray.put`)...
    weights = ray.put({"default_policy": policy.get_weights()})
    for w in workers.remote_workers():
        # ... so that we can broacast these weights to all rollout-workers once.
        # 将更新后的权重复制给每一个worker,继续进行经验的提取
        w.set_weights.remote(weights)

Sample Batches(批次采样)

无论是在单个进程中运行还是在大型集群中运行,RLlib 中的所有数据都以Sample Batches的形式进行交换。Sample Batches对轨迹的一个或多个片段进行编码。通常,RLlib 从 rollout worker 收集大小为 rollout_fragment_length 的批次,并将这些批次中的一个或多个连接成一个大小为 train_batch_size 的批次,作为 SGD 的输入。
典型的批次采样如下所示。由于所有值都保存在字典中,这允许在网络上进行有效的编码和传输。

sample_batch = { 'action_logp': np.ndarray((200,), dtype=float32, min=-0.701, max=-0.685, mean=-0.694),
    'actions': np.ndarray((200,), dtype=int64, min=0.0, max=1.0, mean=0.495),
    'dones': np.ndarray((200,), dtype=bool, min=0.0, max=1.0, mean=0.055),
    'infos': np.ndarray((200,), dtype=object, head={}),
    'new_obs': np.ndarray((200, 4), dtype=float32, min=-2.46, max=2.259, mean=0.018),
    'obs': np.ndarray((200, 4), dtype=float32, min=-2.46, max=2.259, mean=0.016),
    'rewards': np.ndarray((200,), dtype=float32, min=1.0, max=1.0, mean=1.0),
    't': np.ndarray((200,), dtype=int64, min=0.0, max=34.0, mean=9.14)
}

在multi-agent下,会为每个单独的策略单独收集样本批次。这些批次一起包装在 MultiAgentBatch 中,作为单个代理样本批次的容器.

Execution Plans(执行计划)

Execution Plans让您可以轻松地将 RL 算法的执行表达为一系列步骤,这些步骤要么在学习器中按顺序发生,要么在许多参与者之间并行发生。在底层,RLlib 将这些计划转换为 Ray Actor 上的 ray.get() 和 ray.wait() 操作,因此您可以轻松编写高性能算法,而无需管理单个低级 Ray Actor 调用。
Execution Plans代表 RL 训练的数据流(dataflow of the RL training job)。例如,A2C 算法可以被认为是一系列重复步骤或数据流。

# 用rollout workers在多个环境中并行产生经验
ParallelRollouts: Generate experiences from many envs in parallel using rollout workers.
# 将经验连接成一个可以训练的批次进行训练
ConcatBatches: The experiences are concatenated into one batch for training.
# 对策略损失采取梯度步骤,并更新rollout workers的权重。
TrainOneStep: Take a gradient step with respect to the policy loss, and update the worker weights.

在代码中,这个数据流可以表示为下面的执行计划,这是一个简单的函数,可以传递给 build_trainer 来定义一个新的算法。它接受 WorkerSet 和配置,并返回训练结果的迭代器:

def execution_plan(workers: WorkerSet, config: TrainerConfigDict):
    # type: LocalIterator[SampleBatchType]
    # 建立并行的rollouts workers
    rollouts = ParallelRollouts(workers, mode="bulk_sync")

    # type: LocalIterator[(SampleBatchType, List[LearnerStatsDict])]
    # rollouts.combine(ConcatBatches(min_batch_size=config["train_batch_size"])) 将从rollout workers中得到的经验组合起来,变成可以训练的批次
    # TrainOneStep(workers) 训练,并且更新
    train_op = rollouts.combine(ConcatBatches(min_batch_size=config["train_batch_size"])).for_each(TrainOneStep(workers))
    # 记录过程中的一些参数
    # type: LocalIterator[ResultDict]
    return StandardMetricsReporting(train_op, workers, config)

如您所见,每一步都返回一个对象迭代器(如果您不熟悉分布式迭代器,请参阅 Ray 的并行迭代器实现)。它是 LocalIterator 的原因是,虽然它是基于并行计算的,但迭代器已经变成了一个可以被程序按顺序在本地使用的迭代器。还有几点需要注意

  • 该计划在训练结果上返回迭代器的原因是 trainer.train() 正在从该迭代器中提取结果以作为 train 调用的结果返回
  • rollout worker 已经在 WorkerSet 中提前创建好了,所以执行计划函数只是定义了对 rollout 结果的一系列操作

这些迭代器表示可以从数据流中生成的无限数据项流。每个算子(例如 ConcatBatches、TrainOneStep)对每个项目执行一个操作并返回一个转换后的项目(例如,连接的批次(ConcatBatches)、来自训练的学习者统计数据(TrainOneStep))。最后,诸如 TrainOneStep 之类的一些运算符还具有更新 rollout worker 权重的作用(这就是TrainOneStep为什么将 workers作为参数的原因(TrainOneStep(workers)))

Understanding and Debugging Execution Plans(理解和调试执行计划)

执行计划基于 Ray 并行迭代器(parallel iterators),可以类似地检查。例如,假设您想在训练期间打印出中间数据项。这可以通过在数据流中插入打印功能来完成,例如,对于 A2C:

def debug_print(item):
    print("I saw", type(item))
    return item
# for_each(debug_print) 打印输出参数
train_op = rollouts \
    .combine(ConcatBatches(
        min_batch_size=config["train_batch_size"])) \
    .for_each(debug_print) \
    .for_each(TrainOneStep(workers))

你会在控制台上看到这样的输出

(pid=6555) I saw <class 'ray.rllib.policy.sample_batch.SampleBatch'>
(pid=6555) I saw <class 'ray.rllib.policy.sample_batch.SampleBatch'>
(pid=6555) I saw <class 'ray.rllib.policy.sample_batch.SampleBatch'>
(pid=6555) I saw <class 'ray.rllib.policy.sample_batch.SampleBatch'>

重要的是要理解执行计划的迭代器是惰性求值的。这意味着在训练器尝试从迭代器中读取下一项之前不会发生计算(即获取 Trainer.train() 调用的下一个训练结果)

Execution Plan Concepts(执行计划概念)

RLlib 提供了一个可用于执行计划的运算符库(GitHub 链接)。您当然可以编写自己的运算符(它们只是普通的 Python 函数)。提醒一下,运算符只是可以链接在迭代器上的函数(或有状态的函数对象)(例如,上面的 debug_print 运算符)。下面总结了几类运算符:
Rollout ops (rollout_ops.py):这些是用于生成和处理体验的函数,包括 ParallelRollouts(用于同步或异步生成体验)、ConcatBatches(用于将批次组合在一起)、SelectExperiences(用于在多代理设置中选择相关体验)和 AsyncGradients(用于计算梯度动态的、异步的新体验,就像在 A3C 中一样)。

Train ops (train_ops.py) :这些是改进策略和更新Rollout workers的功能。最基本的算子 TrainOneStep 将一批经验作为输入,并将指标作为输出。这里的重要算子包括 TrainOneStep、TrainTFMultiGPU(用于多 GPU 优化)、ComputeGradients(在不更新策略的情况下计算梯度)和 ApplyGradients(将计算的梯度应用于策略)。
Replay ops (replay_ops.py): 这里提供的主要操作符是 StoreToReplayBuffer,它可以将经验批次保存到本地重播缓冲区或一组分布式重播演员。它有一个对应的 Replay,它产生从上述重放缓冲区之一重放的新体验流。使用 StoreToReplayBuffer 和 Replay 的算法必然由多个子数据流(不同的迭代器)组成,这些子数据流与并发操作相结合。
Concurrency ops (concurrency_ops.py): 这里提供的主要操作符是 Concurrently,它通过以交错方式执行多个迭代器(数据流)来将它们组合成一个数据流。输出可以定义为两个数据流的混合,或过滤为子数据流之一的输出。它有两种模式:
round_robin 从每个输入数据流中交替获取项目。这确保了例如经验生成和经验回放之间的固定计算比率。可以通过设置 round_robin_weights 来调整比率
async 在不阻塞的情况下尽快执行每个输入数据流。例如,当您希望回放尽可能快地进行时,您可能想要使用它,而不管生成的体验有多快。
Metric ops (metric_ops.py) 最后,我们提供了一个 StandardMetricsReporting 运算符,它以统一的方式从 rollout Worker 收集训练指标,并返回训练结果字典流。执行计划应始终以该运算符结尾。此指标操作还报告由其他操作员存储在可通过 _get_shared_metrics() 访问的共享指标上下文中的各种内部性能指标。
EXAMPLE:
假设我们想让上面的 A2C 示例异步(即 A3C)。我们将使用 AsyncGradients 切换同步 ParallelRollouts 运算符,并使用 ApplyGradients 以尽可能快地应用梯度更新。 AsyncGradients 运算符将并行执行 rollout,计算远程工作人员上新批次(大小为 rollout_fragment_length)的策略梯度,然后返回计算梯度流:

def execution_plan(workers: WorkerSet, config: TrainerConfigDict):
    # type: LocalIterator[(ModelGradients, int)]
    grads = AsyncGradients(workers)

    # type: LocalIterator[_]
    train_op = grads.for_each(ApplyGradients(workers, update_all=False))

    # type: LocalIterator[ResultDict]
    return StandardMetricsReporting(train_op, workers, config)

让我们尝试向 A2C 添加一个回放缓冲区。这可以通过插入存储/重播操作并使用 Concurrently 将它们组合在一起来完成

def execution_plan(workers: WorkerSet, config: TrainerConfigDict):
    # Construct a replay buffer.
    replay_buffer = LocalReplayBuffer(...)

    # type: LocalIterator[_]
    store_op = ParallelRollouts(workers, mode="bulk_sync") \
        .for_each(StoreToReplayBuffer(local_buffer=replay_buffer))

    # type: LocalIterator[(SampleBatchType, List[LearnerStatsDict])]
    replay_op = Replay(local_buffer=replay_buffer) \
        .for_each(TrainOneStep(workers))

    # type: LocalIterator[(SampleBatchType, List[LearnerStatsDict])]
    train_op = Concurrently(
        [store_op, replay_op], mode="round_robin", output_indexes=[1])

    # type: LocalIterator[ResultDict]
    return StandardMetricsReporting(train_op, workers, config)

请注意,这里我们为 Concurrently 运算符设置了 output_indexes=[1],这使得它只返回重放操作的结果。另请参阅重放的 DQN 实现以获取完整示例,包括训练强度等选项的实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值