基于 tf-agents 的多智能体 PPO 训练框架:social_rl multiagent_tfagents 源码级解析
【免费下载链接】google-research
Google Research
导读
本文聚焦 Google Research 开源仓库 social_rl/multiagent_tfagents 这一多智能体强化学习训练模块:它以 tf-agents 为基础,通过一个"集中式元智能体(meta-agent)"统一管理多个独立 PPO 子智能体,实现字典式聚合观测的拆分、多动作的聚合输出以及向量奖励的独立学习。读完本文,你将掌握该框架的整体架构、核心源码调用链、完整训练命令与 Gin 配置参数,并了解如何将多智能体训练扩展到单智能体、固定智能体与联合注意力(joint attention)等变体。
一、框架定位与整体设计
该模块实现了在 tf-agents)之上的多智能体 RL 训练代码。其设计核心是一个集中式元智能体(meta-agent),它负责持有并初始化若干独立的 PPO 智能体。整个数据流如下:
- 环境(MultiGrid 网格世界)向元智能体返回一个聚合的字典观测,其中包含所有智能体的观测;
- 元智能体将观测按智能体 ID 拆分并分别传递给各子智能体(sub-agent);
- 各子智能体返回各自的动作,元智能体将动作聚合后交还环境;
- 环境计算出包含所有智能体个体奖励的向量奖励(shape 为
(n_agents,)),供各子智能体独立训练。
这一"集中控制、独立学习"的范式在 multiagent_ppo.py 中通过 @gin.configurable 的 MultiagentPPO(tf_agent.TFAgent) 类实现。模块内各文件分工如下:
| 文件 | 职责 |
|---|---|
| multiagent_ppo.py | 元智能体 MultiagentPPO,创建并协调多个 PPO 子智能体 |
| multiagent_ppo_policy.py | 元策略 MultiagentPPOPolicy,负责观测分发与动作/状态聚合 |
| multigrid_networks.py | 面向 MultiGrid 的 actor/critic 网络构造器 |
| multiagent_gym_env.py | Gym 环境的多智能体适配包装器 |
| multiagent_gym_suite.py | Gym 环境加载 Suite |
| multiagent_metrics.py | 多智能体指标(聚合回报 + 各智能体个体回报) |
| multiagent_train_eval.py | 训练与评估主入口 |
| test_multiagent.py | 多智能体训练冒烟测试 |
二、Meta-agent 实现:多智能体 PPO 的核心机制
2.1 子智能体的创建与单智能体 Spec 推导
MultiagentPPO.__init__(multiagent_ppo.py)接收完整的 time_step_spec 与 action_spec,首先通过 get_single_agent_specs(multiagent_ppo.py)把多智能体 spec 降维为单智能体 spec:观测的 shape 从带智能体维的形式裁剪为单智能体版本,动作 spec 取 action_spec[0],奖励 spec 退化为标量。随后为每个智能体 agent_id 分别创建:
tf.compat.v1.train.AdamOptimizer(learning_rate)独立优化器;- 由
network_build_fn(默认为multigrid_networks.construct_multigrid_networks)构造的 actor / value 网络; - 由
agent_class(默认为ppo_clip_agent.PPOClipAgent,即 tf-agents 的 clipped PPO 智能体)创建的独立 PPO 智能体。
值得注意的是,子智能体内部硬编码了 importance_ratio_clipping=0.2、use_gae=True、normalize_observations=False、normalize_rewards=False、compute_value_and_advantage_in_train=True(multiagent_ppo.py)——即正常的 PPO 剪裁与 GAE 在子智能体层面生效,而观测/奖励归一化交由上层参数控制。
2.2 元策略的观测分发与状态聚合
MultiagentPPOPolicy(multiagent_ppo_policy.py)是集中式策略,负责把观测分发给对应智能体并聚合所有智能体的动作与网络状态。核心路径为:
_apply_actor_network(multiagent_ppo_policy.py):遍历每个子策略,对非激活智能体返回固定的 no-op 动作(tf.ones_like(...) * 6),否则调用_get_obs_for_agent切出该智能体的观测,并沿批次维[:, agent_id]取出其 LSTM 状态,最后用tf.stack(..., axis=1)把各智能体状态重新拼回(B, N, ...)形状;_get_obs_for_agent(multiagent_ppo_policy.py):对二维观测(B, N, ...)沿智能体维切片,必要时expand_dims补维;_distribution(multiagent_ppo_policy.py):在 collect 模式下输出各智能体的分布参数(policy_info),在 eval 模式下用dist.mode()实现贪心动作。
由于使用了 RNN/LSTM,策略要求调用方分别维护 actor 网络状态与 value 网络状态,所有智能体的状态被拼接后统一分发——这是该实现中状态管理的关键约定(multiagent_ppo_policy.py)。
2.3 训练时的轨迹拆分
_train(multiagent_ppo.py)把整批经验按智能体拆分:跳过 inactive_agent_ids(不训练也不行动)与 non_learning_agents(行动但不训练,loss 记 0),其余智能体经 extract_single_agent_trajectory(multiagent_ppo.py)从聚合轨迹中取出本智能体的观测、动作(trajectory.action[agent_id])、奖励(trajectory.reward[:, :, agent_id])与 policy_info,再各自调用 self.agents[a].train(...),最终把各子智能体 loss 求和作为元智能体总 loss 返回。
三、面向 MultiGrid 的网络架构
construct_multigrid_networks(multigrid_networks.py)为每个智能体构造适配 MultiGrid 的 actor / critic 网络,其输入处理管线(preprocessing layers)包括:
- image:
cast_and_scale()将像素值转为 float32 并除以 10 缩放,经Conv2D(conv_filters, conv_kernel)+ ReLU + Flatten; - direction(朝向标量):
one_hot_layer(scalar_dim)转为 one-hot 后经Dense(scalar_fc)稠密层(multigrid_networks.py); - position(可选):缩放后接稠密层;
- random_z / x / y(可选):分别支持随机向量输入与坐标 one-hot 输入。
所有分支经 Concatenate(axis=-1) 合并后,在 use_rnns=True 时送入 ActorDistributionRnnNetwork 与 ValueRnnNetwork(含 lstm_size),否则使用带 tanh 激活的普通 ActorDistributionNetwork / ValueNetwork。模块顶部注释提示了 social influence 实验的推荐超参:卷积核 3、卷积输出通道 6、LSTM 128(multigrid_networks.py)。
四、多智能体环境的适配
环境适配分为两层:
MultiagentGymWrapper(multiagent_gym_env.py):继承gym_wrapper.GymWrapper,把单智能体 action spec 平铺为(single_action_spec,) * n_agents,并根据n_agents生成向量奖励 spec——非 minigrid 模式下奖励 shape 为(self.n_agents,)(multiagent_gym_env.py);_step中还会把 tf-agents 的 ListWrapper 动作解包为底层环境可用的形式;multiagent_gym_suite.load(multiagent_gym_suite.py):通过gym.spec(env_id).make()加载注册的环境,并从 spec 提取max_episode_steps施加TimeLimit包装(避免 OpenAI TimeLimit 包装器无法区分"时间耗尽"与"负向行为"导致末步折扣设置失真的问题,见 multiagent_gym_suite.py)。
环境本体在 social_rl/gym_multigrid 中实现(详见 social_rl/README.md),例如随机化 Cluttered 场景定义于 cluttered.py:默认 15×15 网格、3 个智能体、25 个随机障碍物、随机化目标位置、5×5 局部视野、最多 250 步。
五、训练与评估
5.1 多智能体训练
在随机化的 Cluttered 环境(实现于 gym_multigrid/envs/cluttered.py)中训练多个 PPO 智能体:
python -m multiagent_train_eval.py --debug --root_dir=/tmp/cluttered/ \
--env_name='MultiGrid-Cluttered-v0'
5.2 单智能体训练
python -m single_agent_train_eval.py --debug --root_dir=/tmp/single_cluttered/ \
--env_name='MultiGrid-Cluttered-Single-6x6-v0'
其中 MultiGrid-Cluttered-Single-6x6-v0 对应 ClutteredMultiGridSingle6x6(6×6 网格、单智能体、5 个障碍物、50 步上限,见 cluttered.py),其注册位于 cluttered.py。需要说明的是,仓库当前目录下并未提供 single_agent_train_eval.py 源文件(README 中命令保留了该入口),若需要单智能体对照实验,可参考 MultiGrid-Cluttered-Single-v0 配置与 multiagent_ppo_cluttered_single.gin。
5.3 训练主入口的行为
multiagent_train_eval.py 是训练与评估的完整实现,其 train_eval 函数(multiagent_train_eval.py)完成:环境加载(训练用 ParallelPyEnvironment 并行多环境,评估用独立 TFPyEnvironment)→ 元智能体构建 → TFUniformReplayBuffer 分配 → 收集驱动(TFDriver)→ 训练循环。循环内每 eval_interval 步做一次评估,每轮训练后清空回放缓冲区,并按 log_interval / summary_interval / train_checkpoint_interval / policy_checkpoint_interval 输出日志、摘要与检查点。
几个值得注意的工程细节:
- 内置loss 发散保护:当 total_loss 为 NaN/Inf 或超过
MAX_LOSS=1e9且持续超过TERMINATE_AFTER_DIVERGED_LOSS_STEPS=100步时自动终止训练(multiagent_train_eval.py); --debug会关闭tf.function以方便调试(multiagent_train_eval.py);- 支持
--inactive_agent_ids(固定某些智能体不训练也不行动,输出 no-op 动作)与--reinit_checkpoint_dir(从检查点重初始化除最后一个外的所有智能体,并把其余智能体标为non_learning_agents,用于"专家-新手"设置,multiagent_train_eval.py); - 结束训练前会再执行一次最终评估。
5.4 命令行参数速查
multiagent_train_eval.py 中定义的常用 flag:
| Flag | 默认值 | 说明 |
|---|---|---|
--root_dir | TEST_UNDECLARED_OUTPUTS_DIR | 日志/摘要/检查点输出根目录(必需) |
--env_name | MultiGrid-DoorKey-16x16-v0 | 环境名 |
--replay_buffer_capacity | 3001 | 每个环境的回放缓冲区容量 |
--num_parallel_environments | 4 | 并行环境数(大规模实验原为 30) |
--num_environment_steps | 25000000 | 总环境步数上限 |
--num_epochs | 25 | 每次更新迭代的 epoch 数 |
--collect_episodes_per_iteration | 8 | 每次更新前收集的 episode 数(跨所有并行环境) |
--num_eval_episodes | 2 | 评估 episode 数(大规模实验原为 30) |
--train_checkpoint_interval | 500 | 训练检查点间隔 |
--policy_checkpoint_interval | 500 | 策略检查点间隔 |
--log_interval | 15 | 日志间隔 |
--summary_interval | 50 | 摘要间隔 |
--conv_filters / --conv_kernel | 16 / 3 | 卷积层配置 |
--direction_fc | 5 | 朝向 one-hot 到 LSTM 的连接神经元数 |
--actor_fc_layers_size / --value_fc_layers_size | 32 | actor / value 全连接层宽 |
--lstm_size | 256 | LSTM 单元数 |
--debug | False | 调试模式(关闭 tf.function) |
--inactive_agent_ids | None | 固定且不训练的智能体 ID 列表 |
--random_seed | 0 | 策略与环境随机种子 |
--reinit_checkpoint_dir | None | 重初始化检查点目录 |
六、Gin 配置文件实战
仓库在 configs 下为多种场景提供 Gin 配置,例如 multiagent_ppo_cluttered.gin:
# Run function
xm_train.train_eval = @multiagent_train_eval.train_eval
# Environment
multiagent_train_eval.train_eval.env_name = 'MultiGrid-Cluttered-v0'
# Training params
multiagent_train_eval.train_eval.num_environment_steps=1000000000
multiagent_train_eval.train_eval.replay_buffer_capacity = 4001
multiagent_train_eval.train_eval.collect_episodes_per_iteration = 30
multiagent_train_eval.train_eval.train_checkpoint_interval = 500
multiagent_train_eval.train_eval.policy_checkpoint_interval = 500
multiagent_train_eval.train_eval.log_interval = 15
multiagent_train_eval.train_eval.summary_interval = 50
multiagent_train_eval.train_eval.num_parallel_environments = 30
multiagent_train_eval.train_eval.num_eval_episodes = 10
multiagent_train_eval.train_eval.debug = False
# Architecture params
multiagent_train_eval.train_eval.actor_fc_layers = (32, 32)
multiagent_train_eval.train_eval.value_fc_layers=(32, 32)
multiagent_train_eval.train_eval.lstm_size=(256,)
multiagent_train_eval.train_eval.conv_filters=16
multiagent_train_eval.train_eval.conv_kernel=3
multiagent_train_eval.train_eval.direction_fc=5
# Agent params
ppo_agent.PPOAgent.discount_factor = 0.995
multiagent_train_eval.train_eval.entropy_regularization = .05
要点解读:
train_eval函数与MultiagentPPO等均为@gin.configurable,因此几乎所有超参都可在.gin文件中覆盖;- 全连接层以元组形式给出层宽,
lstm_size=(256,)表示单层 256 单元 LSTM; discount_factor=0.995与entropy_regularization=.05作用于 tf-agents 的PPOAgent;- multiagent_ppo_cluttered_fixed_agent.gin 展示了固定智能体用法(
fixed_agent_ids = [1],配合代码中的inactive_agent_ids逻辑);multiagent_ppo_cluttered_single.gin 则对应单智能体环境MultiGrid-Cluttered-Single-v0。
七、多智能体指标:聚合回报与个体回报
multiagent_metrics.py 对 tf-agents 指标做了多智能体改造,核心是 AverageReturnMetric(multiagent_metrics.py):
- 维护一个集体回报累加器(对
trajectory.reward沿 agent 轴取均值累加)与 n_agents 个个体回报累加器(trajectory.reward[:, a]); - 每个 episode 结束时把累加值写入各自的
TFDeque缓冲; result()返回集体平均回报,result_for_agent(agent_id)返回指定智能体的个体平均回报;tf_summaries除集体摘要外,还会为每个智能体生成..._agent{id}摘要(multiagent_metrics.py)。
配套的 MultiagentScalar 用于统计简单标量(如障碍物数量),eager_compute 与 MultiagentMetricsGroup 分别支持评估指标计算与指标分组检查点,log_metrics 则在日志中同时打印集体值与每个智能体的个体值(multiagent_metrics.py)。MultiagentMetricsGroup 使训练检查点可以同时保存这批多智能体指标(见 multiagent_train_eval.py)。
八、工程化验证与测试
- test_multiagent.py 提供端到端冒烟测试:在
MultiGrid-DoorKey-6x6-v0上以极小配置(num_environment_steps=1、lstm_size=(2,)等)运行train_eval,随后断言train/目录存在且policy_saved_model下至少保存了一个策略; - social_rl/run.sh 展示了完整的可复现环境准备流程:创建 virtualenv → 安装
tensorflow与social_rl/requirements.txt(含tf-agents==0.9.0、gym-minigrid==1.0.1、gfootball==2.10.1等,见 social_rl/requirements.txt)→ 依次运行多智能体、联合注意力、对抗环境三组测试。
九、扩展:联合注意力变体
multiagent_tfagents 还包含一个联合注意力(joint attention)扩展(见 joint_attention/README.md),对应论文 "Joint Attention for Multi-Agent Coordination and Social Learning"。它在 multiagent_train_eval.train_eval 中通过 use_attention_networks=True 启用:为智能体架构增加对图像输入的注意力图,并通过比较各智能体的注意力图计算联合注意力奖励,从而鼓励智能体共同关注环境中的同一区域以提升协作效率(实现在 joint_attention/attention_networks.py 与 joint_attention/attention_ppo_agent.py)。训练命令:
python -m joint_attention_train_eval.py --debug --root_dir=/tmp/meetup/ \
--env_name='MultiGrid-Meetup-Empty-12x12-v0'
注意该变体需要上一时间步的策略状态来计算注意力权重,因此收集驱动改用 drivers.StateTFDriver,并在观测中注入 policy_state(见 multiagent_train_eval.py)。
结语
social_rl/multiagent_tfagents 以"集中元智能体 + 独立子策略"的架构,在 tf-agents 之上提供了一套完整可运行的多智能体 PPO 训练方案:从环境适配、网络构造、策略分发、轨迹拆分到多智能体指标与 Gin 配置一应俱全,并可通过 inactive_agent_ids、non_learning_agents 与联合注意力扩展灵活构造固定智能体、专家-新手等多样化实验设定。对于希望在 MultiGrid 类部分可观测网格世界中进行多智能体协作研究的开发者,这是一个可以直接基于源码复现与扩展的可靠起点。
【免费下载链接】google-research
Google Research
更多推荐


所有评论(0)