简介:PyMARL是一套面向深度多智能体强化学习研究的开源框架,基于PyTorch实现,并以《星际争霸II》及其SMAC环境作为实验平台,适合具备一定强化学习基础、希望复现或扩展多智能体算法的研究生与算法工程师。资源包共52个文件,以32个Python源码为主体,涵盖算法实现、控制器、学习器、运行器与环境封装等核心模块,另含11个yaml配置、4个shell脚本及Dockerfile、README、LICENSE等辅助文件,压缩包约47KB,结构清晰便于按模块阅读与二次开发。需注意SC2版本差异会影响性能对比,SMAC论文结果基于SC2.4.6.2.69232而非SC2.4.10,安装时可通过build.sh构建镜像、install_sc2.sh配置游戏环境。目前已有1763人学习下载,适合作为多智能体强化学习入门与算法复现的参考工程。
1. 从一份 pymarl 源码包说起:多智能体强化学习到底怎么跑起来
如果你正在找一份能直接跑通的多智能体强化学习(MARL)代码,大概率绕不开 pymarl 这个名字。它是一套基于 Python 和 PyTorch 的多智能体强化学习框架,最早配合 QMIX、VDN、COMA 这类值分解与策略梯度算法一起出现,后来被大量论文当作实验基线。你拿到的这份资源,就是 pymarl 的完整源码包,里面包含算法实现、环境封装、训练入口和配置文件,不是那种只给几个 notebook 的演示仓库。
它解决的核心问题是:多智能体环境里,每个 agent 只能看到局部观测,但团队要学一个联合策略,这个「局部观测 → 联合动作」的映射怎么用一套统一接口写出来、换算法时不用重写环境、换环境时不用重写算法。适合谁?做 MARL 方向的研究生、需要复现 QMIX/VDN 对比实验的工程师、以及想拿一个成熟框架改自己算法的开发者。下面我按「先跑通、再改参数、最后避坑」的顺序拆一遍。
2. 环境与依赖:把 pymarl 跑起来的第一步
2.1 为什么 pymarl 的依赖比普通 RL 项目麻烦
单智能体 RL 项目通常一个 gym 加一个 PyTorch 就能跑,但 pymarl 多了一层「环境与算法的解耦」。它把环境抽象成 StarCraft II、Multi-Agent Particle Environment(MPE)等具体实现,算法侧只认统一的 batch 数据结构。这意味着你装依赖时,除了 Python 和 PyTorch,还要处理环境本身的依赖,比如 StarCraft II 的 Linux 客户端、MPE 的 pygame 渲染库。
常见做法是先用 MPE 跑通,因为 MPE 纯 Python,不需要额外下载游戏客户端,适合验证框架本身是否正常。等 MPE 能出训练曲线了,再换 SMAC(StarCraft Multi-Agent Challenge)。这个顺序能帮你把「框架问题」和「环境问题」分开排查,不然一上来就报错,你根本不知道是 pymarl 配置错了还是星际客户端没装好。
2.2 依赖安装与目录结构确认
先确认 Python 版本。pymarl 原始代码对 Python 3.6~3.8 兼容较好,如果你用 3.10 以上,部分旧版 PyTorch API 会报torch.nn.functional相关警告,但不影响训练。我一般用 conda 建一个独立环境,避免和系统里的包打架。
# 创建独立环境,Python 版本建议 3.8 conda create -n pymarl python=3.8 -y conda activate pymarl # 安装 PyTorch,按你的 CUDA 版本选,这里以 CUDA 11.3 为例 pip install torch==1.10.0+cu113 torchvision==0.11.1+cu113 -f https://download.pytorch.org/whl/torch_stable.html # 安装 pymarl 基础依赖 pip install numpy scipy tensorboardx pygame matplotlib装完后进到源码根目录,先看结构。典型 pymarl 目录下有src/(算法与训练逻辑)、config/(YAML 配置)、envs/(环境封装)、results/(训练输出)。src/main.py是入口,src/learners/下每个算法一个文件,比如q_learner.py对应 QMIX/VDN,coma_learner.py对应 COMA。
# 查看目录结构,确认关键文件存在 ls src/ # 应看到 main.py, learners/, modules/, controllers/, envs/, runners/ 等 ls src/config/ # 应看到 default.yaml, alg/ 下的 qmix.yaml, vdn.yaml, coma.yaml 等逻辑说明:main.py负责解析命令行参数、加载 YAML 配置、实例化环境和 learner,然后进run()循环。config/default.yaml是全局默认参数,config/alg/*.yaml是算法级覆盖。参数说明:--config指定算法配置名,--env-config指定环境配置名,这两个是启动训练必须传的。
提示:如果你拿到的是压缩包,解压后先确认
src/main.py存在。有些二次打包的版本会把src改名成pymarl,这时启动命令里的路径要相应调整。
2.3 用 MPE 做第一次冒烟测试
MPE 里最简单的场景是simple_spread,N 个 agent 要覆盖 N 个地标,奖励是负的距离和。它观测维度低、回合短,适合确认训练循环是否正常。
# 在源码根目录执行,用 QMIX 跑 MPE 的 simple_spread python src/main.py --config=qmix --env-config=mpe \ with env_args.map_name=simple_spread \ t_max=20000 \ test_interval=5000逻辑说明:--config=qmix加载config/alg/qmix.yaml,--env-config=mpe加载config/envs/mpe.yaml。with后面是覆盖参数,env_args.map_name指定具体地图,t_max是总训练步数,test_interval是每多少步跑一次测试。参数说明:t_max设小一点(比如 20000)先看能不能跑完,正式训练再调到 200 万步级别。跑起来后终端会打印timestep、episode reward、test return,results/下会生成sacred/日志和 TensorBoard 文件。
如果这一步报ModuleNotFoundError: No module named 'envs',说明你不在源码根目录,或者src没被加入PYTHONPATH。解决方法是回到根目录执行,或者临时export PYTHONPATH=$PYTHONPATH:$(pwd)/src。
3. 算法配置与参数调优:QMIX、VDN、COMA 怎么选
3.1 值分解类算法:QMIX 与 VDN 的配置差异
QMIX 和 VDN 都属于值分解,核心区别在混合网络。VDN 直接把各 agent 的 Q 值相加,QMIX 用一个超网络生成混合权重,保证单调性约束。在 pymarl 里,两者共用q_learner.py,靠config/alg/下的 YAML 区分。
# config/alg/qmix.yaml 关键字段 learner: "q_learner" mixer: "qmix" # VDN 改成 "vdn" mixing_embed_dim: 32 # 混合网络隐层维度 hypernet_layers: 2 # 超网络层数 hypernet_embed: 64 # 超网络隐层维度 lr: 0.0005 # 学习率 optim_alpha: 0.99 optim_eps: 0.00001逻辑说明:mixer字段决定用哪种混合方式,改成vdn就是 VDN。mixing_embed_dim和hypernet_embed影响模型容量,小地图(如simple_spread)用默认值就够,大地图(如 SMAC 的MMM2)可以适当加大。参数说明:lr是 Adam 学习率,QMIX 原论文用 0.0005,如果你发现训练震荡,先降到 0.0001 试。optim_alpha和optim_eps是 RMSProp 的,但 pymarl 默认用 Adam,这两个字段实际不生效,属于历史遗留。
启动 QMIX 训练 SMAC 的典型命令:
python src/main.py --config=qmix --env-config=sc2 \ with env_args.map_name=MMM2 \ t_max=2000000 \ batch_size=32 \ buffer_size=5000逻辑说明:--env-config=sc2加载星际环境配置,map_name=MMM2是具体地图。batch_size和buffer_size是经验回放相关,SMAC 地图大,buffer_size设 5000 是常见起点。参数说明:t_max=2000000是原论文级别步数,跑完大概需要几小时到一天,取决于 GPU。如果你只有 CPU,建议先用 MPE 验证,SMAC 训练会非常慢。
3.2 策略梯度类算法:COMA 的适用边界
COMA 用反事实基线做信用分配,适合动作空间离散但 agent 数量不多的场景。在 pymarl 里它对应coma_learner.py,配置字段和 QMIX 差别较大。
# config/alg/coma.yaml 关键字段 learner: "coma_learner" critic_lr: 0.0005 actor_lr: 0.0005 td_lambda: 0.8 entropy_coef: 0.01逻辑说明:COMA 是 actor-critic 结构,所以有critic_lr和actor_lr两个学习率。td_lambda控制 TD(λ) 的 λ,越大越偏向蒙特卡洛,方差大但偏差小。entropy_coef是熵正则系数,鼓励探索。参数说明:COMA 在 SMAC 上表现通常不如 QMIX,但在 MPE 的simple_tag这类需要精细信用分配的场景有优势。如果你要复现 COMA 论文,注意它原版用的是集中式 critic,pymarl 实现基本一致。
3.3 参数覆盖的优先级与调试技巧
pymarl 用 Sacred 做配置管理,优先级是:命令行with> 算法 YAML > 环境 YAML >default.yaml。这意味着你可以在命令行临时改任何参数,不用动文件。
# 临时把学习率改成 0.0001,并打开 TensorBoard 日志 python src/main.py --config=qmix --env-config=mpe \ with env_args.map_name=simple_spread \ lr=0.0001 \ use_tensorboard=True逻辑说明:lr=0.0001会覆盖qmix.yaml里的lr。use_tensorboard=True让 Sacred 额外输出 TensorBoard 格式,方便看曲线。参数说明:如果你不确定某个参数名,可以在src/config/下 grep,比如grep -r "buffer_size" src/config/。调试时我习惯先把t_max设小、test_interval设小,快速看几轮测试回报,确认没有 NaN 再放大。
注意:SMAC 环境需要设置
SC2PATH环境变量指向星际客户端目录,否则会报StarCraft II not found。MPE 不需要这个变量。
4. 避坑与排查:pymarl 跑不通时先看这几条
4.1 现象:训练启动后立刻报KeyError: 'map_name'
原因:--env-config指定的环境 YAML 里没有map_name字段,或者你传的env_args.map_name拼写不对。MPE 和 SMAC 的env_args结构不同,MPE 用map_name,SMAC 也用map_name,但部分旧版 MPE 配置用scenario_name。
解决:打开src/config/envs/mpe.yaml和sc2.yaml,确认字段名。如果 MPE 里是scenario_name,命令行就改成env_args.scenario_name=simple_spread。或者直接在 YAML 里把字段名统一成map_name。
4.2 现象:训练能跑,但test return一直是 0 或负数不上升
原因:常见有三种。一是t_max太小,模型还没学到东西就停了;二是epsilon探索参数没衰减,一直随机动作;三是环境奖励设置和算法不匹配,比如 QMIX 需要单调性,但环境奖励是非单调的。
解决:先把t_max调到 50 万以上,epsilon_start设 1.0、epsilon_finish设 0.05、epsilon_anneal_time设 50000,让探索充分衰减。如果还不涨,换 VDN 试,VDN 约束更弱,有时反而能跑。最后检查环境 reward 函数,确认不是全零。
4.3 现象:SMAC 训练报StarCraft II not found或版本不匹配
原因:SC2PATH没设,或者星际客户端版本和 pymarl 要求的版本不一致。SMAC 对星际版本敏感,4.10 和 4.8 的 API 有差异。
解决:下载对应版本的 Linux 客户端,解压后export SC2PATH=/path/to/StarCraftII。然后在src/config/envs/sc2.yaml里确认sc2_version字段和客户端版本一致。如果还是报错,用python -c "from smac.env import StarCraft2Env; env=StarCraft2Env(map_name='MMM2'); print(env)"单独测环境,把框架和环境问题分开。
4.4 现象:GPU 显存够但训练速度极慢
原因:pymarl 默认可能跑在 CPU 上,或者batch_size太小导致 GPU 利用率低。另外 SMAC 的环境步进在 CPU 上,如果 agent 数量多,环境本身会成为瓶颈。
解决:确认torch.cuda.is_available()为 True,并在default.yaml里设use_cuda=True。batch_size从 32 提到 64 或 128,看显存占用。如果环境是瓶颈,可以开多个环境实例并行采样,但 pymarl 原生不支持,需要改runner.py。
4.5 现象:换了自己的环境后,观测维度对不上
原因:pymarl 的envs/封装要求环境返回obs、state、avail_actions、reward、done、info这几个字段,且obs形状是(n_agents, obs_dim)。如果你的环境返回的是(n_agents, n_agents, obs_dim)或者字典,就会在controllers/里报维度错误。
解决:在envs/下新建一个 wrapper,把观测 reshape 成 pymarl 要求的格式。参考envs/mpe.py的get_obs()实现,确保avail_actions是 one-hot 或全 1 的数组。改完后用python src/main.py --config=qmix --env-config=你的环境 --dry_run做一次 dry run,不训练只走前向,确认维度通过。
5. 进阶技巧:用 pymarl 做消融实验与自定义算法
5.1 用 Sacred 的命名实验管理多组参数
pymarl 底层用 Sacred,每次运行会生成一个唯一 ID,存在results/sacred/下。做消融时,我习惯用--seed和with覆盖参数,然后靠 Sacred 的 ID 区分。
# 跑三组不同 mixing_embed_dim 的消融 for dim in 16 32 64; do python src/main.py --config=qmix --env-config=mpe \ with env_args.map_name=simple_spread \ mixing_embed_dim=$dim \ t_max=100000 \ seed=1 done逻辑说明:mixing_embed_dim分别取 16、32、64,其他参数固定,seed=1保证可复现。跑完后在results/sacred/下每个运行一个目录,里面有config.json和metrics.json。参数说明:seed控制随机种子,消融实验建议至少跑 3 个 seed 取平均,不然单次结果波动可能盖过参数差异。
5.2 自定义 learner 的接入点
如果你想加自己的算法,最省事的方式是复制q_learner.py改成my_learner.py,然后在config/alg/下新建my_alg.yaml,把learner字段指向你的类名。pymarl 的learners/__init__.py里有一个注册字典,需要把你的类加进去。
# src/learners/__init__.py 片段 from .q_learner import QLearner from .coma_learner import COMALearner from .my_learner import MyLearner # 新增 REGISTRY = { "q_learner": QLearner, "coma_learner": COMALearner, "my_learner": MyLearner, # 新增 }逻辑说明:REGISTRY是字符串到类的映射,main.py根据 YAML 里的learner字段查这个字典。参数说明:你的 learner 类需要实现train()和get_actions()两个方法,train()接收一个 batch 返回 loss 字典,get_actions()接收观测返回动作。具体接口参考q_learner.py的train方法签名。
5.3 验证训练是否真的在学:看三个指标
不要只看最终 return,训练过程中我固定看三个东西。第一是td_error或critic_loss,如果一直不降,说明 critic 没学好。第二是epsilon或熵,确认探索在衰减。第三是test_return的滑动平均,单次测试波动大,看 5 次平均更稳。
# 用 tensorboard 看曲线 tensorboard --logdir results/sacred/逻辑说明:Sacred 输出的 TensorBoard 日志在results/sacred/<run_id>/tensorboard/下,--logdir指向results/sacred/会自动聚合所有运行。参数说明:如果曲线抖动厉害,把test_interval调大,或者对test_return做窗口平滑。我一般会跑一个t_max=20000的短实验,确认三条曲线趋势正常,再开正式训练。
从那以后我每次拿到新的 MARL 代码包,都强制先跑一个 MPE 的simple_spread冒烟测试,确认训练循环、日志、测试三个环节都通,再碰 SMAC 或自定义环境。这个习惯帮我省掉了大量「以为是算法问题、其实是环境没配对」的排查时间。希望帮到你。
本文还有配套的精品资源,点击获取