ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

多智能体强化学习实战:基于MAPPO的无人机对抗策略训练指南

多智能体强化学习实战:基于MAPPO的无人机对抗策略训练指南

搞多智能体强化学习的朋友,尤其是把算法往无人机对抗这类环境里塞的,大概率绕不过一个名字:MAPPO。这个项目标题“基于MAPPO的无人机双方对抗打击策略研究”,乍一看像是实验室里的课题,但拆开来看,它其实是多智能体强化学习从算法验证走向仿真应用一个非常典型的样板。我自己的体会是,这类项目最吸引人的地方不在于MAPPO本身有多新——它其实是PPO在多智能体环境下的一个适配版本——而在于“双方对抗”这四个字带来的博弈属性,以及“打击策略”背后那一整套状态空间、奖励函数、训练节奏的设计。这篇文章我会把整个研究过程掰开揉碎讲清楚,包括算法原理、环境搭建、训练调参、策略涌现,以及那些我在实测中踩过的坑。如果你正准备用MAPPO做对抗类仿真,或者想把多智能体强化学习落到实际场景里验证,这篇内容应该能给你一套可以直接参考的路线。

1. 项目整体设计与思路拆解

1.1 为什么选MAPPO而不是其他多智能体算法

MAPPO全称是Multi-Agent Proximal Policy Optimization,最早是由某大学团队在2021年前后系统验证并推广的算法思路。它的核心逻辑不复杂:把PPO在单智能体上的策略优化方式,扩展到多个智能体共享一套critic、各自保留actor的场景中,采用“集中训练、分散执行”(Centralized Training with Decentralized Execution,CTDE)的范式。

但你真要把无人机双方对抗这个任务做出来,你会发现算法选型其实是一次权衡。我整理了一张对比表,表里列的这几个算法在做对抗场景时各有各的问题:

算法适用场景在无人机对抗中的痛点
DQN及其变体离散动作、单智能体连续控制支持差,双方多机场景下样本效率低
MADDPG连续动作、多智能体对超参敏感,训练不稳定,奖励震荡严重
QMIX合作型任务只能处理纯合作关系,对抗场景里双方的博弈建模困难
MAPPO多智能体、可处理合作/对抗需要精心设置环境与奖励,但整体稳定性好,工程可落地性强

实际跑下来你会发现,MAPPO最明显的好处是它继承了PPO的clip机制,限制了策略更新的幅度,不太容易出现MADDPG那种“练着练着策略突然崩掉”的情况。在双方对抗这种非平稳性极强的环境里,这种稳定性比什么都重要。因为红蓝双方的策略都在变,环境对每一个智能体来说都在动态变化,如果你的策略更新步子迈太大,一个震荡就可能让整个训练回到原点。

1.2 项目目标与核心需求拆解

这个项目要解决的核心问题,可以用一句话概括:在红蓝双方无人机数量对称或不对称的仿真对抗环境中,训练出能够自主协同、完成攻防打击任务的多无人机策略。

把这句话拆开,至少包含三层目标:

第一层,是“自主协同”。每一方的多架无人机之间不是独立的个体,它们需要学会分散、包抄、集火这些战术动作,而不是各打各的。这对算法的多智能体协同能力提出了要求。

第二层,是“攻防对抗”。红方有进攻的意图,蓝方有防守和反击的意图。和单智能体打固定目标不同,这里对手是活生生的、也在不断进化的策略。你的奖励设计既要激励进攻,又不能让自己的无人机白送人头。

第三层,是“策略的鲁棒性”。训练出来的策略不能只在固定环境下有效,换一个红蓝初始位置、换一个无人机数量,策略还得能打。这需要训练时做好充分的场景随机化。

1.3 整体技术架构

我采用的训练框架是:仿真环境 + MAPPO算法 + 并行训练加速。

整体流程是这样的:无人机仿真环境负责模拟双方的动力学、感知、攻击判定,并给算法暴露出观察空间和动作接口;MAPPO算法从环境中采样、计算优势函数、更新策略;训练过程中会跑大量的并行环境保证样本量充足。评估阶段则是把训练好的策略加载回仿真环境里以不同的初始条件反复测试,统计胜率、击杀数、存活率这些指标。

有一点要说清楚:这类项目本质上是“算法 + 环境”双轮驱动的。很多人一门心思扑在算法上,觉得调好MAPPO就能出好结果,但实际上环境设计的合理性决定了训练效果的上限。在无人机对抗任务里,状态空间怎么定义、攻击判定怎么建模、奖励怎么设计,每一样都比算法本身更影响最终效果。这一点在后面会详细展开。

2. 无人机对抗环境建模与关键技术细节

2.1 状态空间与观测空间设计

状态空间是整个项目的地基。做这一段的时候我花的时间最长,因为状态怎么定义,直接决定了智能体能不能学到有效的策略。

在这个项目里,每架无人机的观测信息我分成两块:自身的状态信息和战场态势信息。自身状态包括位置坐标(x,y,z)、速度矢量、飞行航向角、剩余弹药量、是否被锁定。战场态势信息包括己方其他无人机的相对位置、敌方无人机的相对位置、敌方无人机的速度朝向、敌方是否在射击范围等。

关键的一个设计细节是:信息要相对化,不能给绝对坐标。给全局绝对坐标看起来信息量更大,但实际训练中智能体很难泛化——换一个初始位置它就懵了。把敌我距离转换成本机的相对极坐标(距离、方位角),把敌机速度也转换成相对速度,这能显著提升策略的泛化能力。

另外,对抗场景有一个和纯合作场景不一样的难点:观测信息的不对称性。蓝方侦察到红方的信息,和红方侦察到蓝方的信息,在真实场景里往往是不对等的。在仿真项目里我们没有把这个问题做得过于复杂,只做了简单的“感知距离限制”——超过一定距离,敌机信息就不可见。这个设计其实对策略训练有正面作用,逼着无人机学会主动侦察和保持队形,而不是一开局就靠着上帝视角莽过去。

2.2 动作空间与攻击模型

动作空间的设计我会直接决定训练复杂度。如果用连续动作同时控制油门、转向、俯仰、射击,整个探索空间会大得吓人,训练出来大概率是一堆乱飞乱打的行为。我在这个项目里采用的是混合动作空间:

  • 水平转向:离散,包含左转30度、保持、右转30度三个选项
  • 速度调整:连续,范围是1.0到2.0马赫
  • 高度调整:离散,包含爬升、保持、俯冲三个选项
  • 攻击动作:离散,包含不开火、锁定并开火两个选项

这样一个混合动作空间既保留了连续的速度调整能力,又把探索空间压缩到了一个可控范围。实测下来,训练收敛速度比全连续动作空间快了至少一倍。

攻击判定这一块,项目里没有模拟真实的导弹飞行弹道,而是做了简化判定:如果本机进入攻击范围、指向角度满足条件,同时目标处于锁定状态,那么存在命中概率;如果命中,则目标血量降低,血量为零则目标被击毁并从环境中移除。这里的命中概率不是固定的,而是和攻击距离、目标机动状态相关。距离越近、目标机动越小,命中概率越高。

2.3 奖励函数设计的核心原则

奖励函数是多智能体对抗项目里最需要精雕细琢的部分,也是我踩坑最多的地方。先说说我走过的弯路。

第一版我设计了很“完整”的奖励:击毁敌方无人机给高分、被击毁给负分、发射导弹给微小的负奖励、靠近敌方给正奖励。看起来逻辑通顺,但训练出来完全不是那么回事。程序跑到最后,红蓝双方都学会了远远地对峙,谁也不敢进入对方的攻击范围。因为在训练早期,冲上去打的人大概率被对面集火秒掉,AI学到的经验是“进攻 = 送死”。

后来我重新梳理了奖励设计的逻辑,确定了几个原则:

第一个原则是稀疏不等于没有引导。击毁和阵亡作为主要奖励信号必须保留,但在此之前需要给稠密的小奖励引导智能体做出“正确的行为意图”。比如,将机头朝向指向敌方时给出小量奖励,进入攻击范围时再给一点奖励。这有点像一个进阶打怪的闯关游戏,每靠近一关给一点反馈,最终通关给大头奖励。但必须谨慎:引导奖励设置过强,智能体会学会刷引导奖励而不完成击杀。奖励永远是目标导向的,辅助信号只能是引导。

第二个原则是对抗环境的奖励要公平。红蓝双方的奖励函数结构应该相同,只是权重做镜像。如果设置得不公平,某一方会在训练初期形成碾压优势,另一方完全没有学习的机会。

第三个原则是奖励要符合战斗逻辑。这里的战斗逻辑包括:多打一的时候应该有优势,侧后方攻击比迎头对射有优势,保持高度和能量优势应该有正向价值。可以把这些逻辑通过奖励函数“埋”进去,让策略涌现出来的行为更接近真实战术。

我最终使用的奖励函数主要由以下部分构成:

  • 击杀敌方无人机:+50
  • 被敌方击毁:-50
  • 参数奖励:当本机在敌方无人机的攻击包线之外,同时将机头指向敌方方向时,逐步给予+0.01到+0.05的正奖励
  • 攻击包线内的位置奖励:进入本机攻击包线内,给+0.1正奖励
  • 被敌方锁定:持续给-0.008惩罚,
  • 发射导弹:-0.02
  • 时间步惩罚:每一仿真步给-0.01,用于鼓励尽快完成战斗

2.4 场景随机化与训练集设置

为了让策略有一定鲁棒性,训练时不能只在一个固定初始条件下练。我会把初始条件随机化:双方的位置在设定区域内随机分布,速度方向和初始高度也有随机扰动。每次回合episode开始,环境重新生成一次初始条件。

另外一个重要设置是回合长度限制。一个回合最多跑600个仿真步,约合两分钟的模拟时间。超过时长强制结算。这个设置有两个作用:一是防止双方无限拖时间玩消耗战;二是给训练过程一个自然的终止信号,让智能体学会在有限时间内推进战局。

配置训练集的时候还要注意一个问题:如果随机范围太大,比如红方开局位置分布离散度极大,双方距离可能会远到第一回合连彼此都发现不了,训练效率会急剧下降。所以应根据无人机的速度来设计合理的开局距离范围。我实测的经验是开局的双方感知距离大约应该设置在“能发现对方但不能立刻攻击”的区间,这样既能逼出机动决策,又不至于开局即终局。

3. MAPPO训练流程与实操记录

3.1 MAPPO算法核心机制解读

在写训练流程之前,有必要把MAPPO的三个核心机制讲透,因为很多人在跑代码的时候只是套库,遇到问题根本不知道从哪里排查。

第一个机制是Actor-Critic架构。在MAPPO里,每个智能体有一个actor网络负责输出动作,所有智能体共享一个中心化critic网络(或者每个智能体基于全局观测构建各自critic,不同实现有区别)负责评估当前状态的全局价值。这个架构的巧妙之处在于:actor只用局部观测做决策,保留了执行时的独立性;critic能看到全局信息,训练时的价值评估更准确。用生活的话说:每个士兵自己看地图做判断,但背后有一个能看到整片战场的参谋部在打分指导。

第二个机制是近端策略优化。PPO的clip比率限制了新策略和旧策略的差异程度,防止更新步长过大导致策略崩溃,这个特性在多智能体环境里尤其关键。因为对抗场景里环境是非平稳的——对手也在变——策略更新如果太过激进,很快你就会发现自己的智能体适应不了对手新策略的节奏。

第三个机制是广义优势估计GAE。GAE负责平衡偏差和方差来估计当前动作相对基线的优势。我在实现时用的是GAE lambda = 0.95,当需要更平稳的梯度时,可以适当调高lambda。优势估计做不好,策略更新就是盲目的。直观理解:如果这一步飞得比平均水平好,优势就是正;飞得比平均烂,优势就是负。训练的目标就是让优势为正的动作概率越来越大。

3.2 训练流程与关键步骤

整个训练流程可以概括为一个循环:采样 → 计算优势 → 更新策略 → 更新价值函数 → 重复。

在项目里的具体实现是这样的:

初始化:创建N个并行仿真环境,初始化MAPPO的actor和critic网络 循环训练(共M个episode批次): 对每个并行环境: 重置环境,获取初始观测 运行当前策略,收集一个回合的完整轨迹(状态、动作、奖励、状态值) 当episode结束或达到最大步长,终止采样 汇总所有并行环境的轨迹数据到经验池 计算GAE优势估计 对actor和critic执行多轮小批量梯度更新(PPO clip) 定期保存模型权重 定期在评估模式下运行若干回合,记录胜率等指标

有一个工程细节值得特别说明:不是每收集一小段数据就立即更新,而是先把所有并行环境的完整回合数据收集完,放进经验池,再统一做更新。这个设置能有效降低样本之间的相关性。

3.3 超参数配置参考

超参数配置是我反复调了很久才定下来的。这里直接给出我实测下来相对好用的配置:

超参数配置值说明
Actor学习率3e-4使用Adam优化器,配合线性衰减
Critic学习率1e-3比actor略高,让价值函数更快收敛
Clip比率0.2控制策略更新幅度
GAE lambda0.95平衡优势估计的偏差和方差
Gamma(折扣因子)0.99关注长期回报,鼓励策略有前瞻性
并行环境数16单机训练时16个环境是比较好的性价比选择
每批轨迹长度2048步每个环境最多采集128步,16个环境合起来构成一个batch
每batch更新轮数10在旧数据上迭代优化,轮数太少欠拟合,太多可能过拟合
Mini-batch大小2048与batch一致,保持简单
熵系数0.02鼓励探索,系数太大会导致策略跳变明显
最大值归一化使用对团队奖励做适当归一化,避免数值过大

3.4 训练资源与并行加速

训练速度和环境交互效率直接相关。我一开始用4个并行环境跑,训练效果极其缓慢,一晚上run了300个episode,曲线基本没有起色。后来把并行环境加到16个,采样效率翻了约4倍,训练曲线的学习迹象很快就出来了。

这里还要提一个细节:并行环境不是简单起16个Python进程就行。因为PyTorch的训练过程本身是CPU+GPU计算密集型的,而仿真环境的物理计算也是CPU密集的,两者混在一起会互相抢资源。建议的做法是分成两个部分:一部分进程跑环境采样,另一个进程跑GPU训练,两者之间用共享内存队列进行数据传输。如果只有一台机器,也尽量把环境进程绑定到不同CPU核心,避免采样和训练互相干扰。

我自己实测的情况是:在一块中高端的消费级GPU上,单卡训练16个并行环境,每个环境的物理仿真频率大约能跑到40到60帧每秒。一个完整的训练过程大约需要8到14个小时才能收敛到稳定策略,具体和奖励函数的设计质量强相关。奖励信号设计得越好,收敛越快。

4. 训练结果与策略行为分析

4.1 训练曲线解读

跑完训练之后,我做的第一件事不是直接看胜率,而是把训练曲线打印出来。有经验的人都知道,RL训练曲线藏着大量信息。

这个项目里我用到的曲线指标包括:团队回合平均奖励(team average return)、胜率(win rate)、策略熵(entropy)、平均击杀数(average kills)、平均存活时间(average survival time)。

我观察到的曲线变化是典型的三阶段过程:

第一阶段(约前100个episode,占总量5%-10%):奖励小幅爬坡,胜率在50%附近波动,策略熵逐渐下降。这一阶段的飞行状态基本是四散奔逃,偶尔有无人机接近敌方但很快被击落。

第二阶段(约300到800个episode之间):策略熵加速下降,团队奖励快速上升,胜率开始出现明显优势区间。这个时候观察仿真画面,能看到非常有趣的现象——红方无人机开始学会协同:一架无人机从正面“引诱”蓝方注意力,另外两架绕侧翼包抄。

第三阶段(约1000episode以后):曲线进入平台期,奖励和胜率都趋于稳定,策略熵已经很低,说明策略基本确定,在给定的场景配置下很难再有大的改观。如果这时候还想继续提升,就需要增加场景难度或者调高奖励函数的分辨率。

4.2 涌现的典型战术行为

训练结束后,我把模型跑到仿真里回放了大量对局,总结出了几个特别有代表性的行为模式。

第一个是“钳形夹击”。当红方有两架甚至三架无人机存活时,它们会自发地分头机动,从两个方向逼近蓝方单机,迫使蓝方只能应对一面,另一面直接被集火击落。这个战术我看到的时候挺意外的,因为训练时完全没有给过任何队形相关的显式指令,纯靠奖励函数的引导就涌现出来了。

第二个是“能量优势保持”。无人机在接近敌机的过程中不会傻乎乎地保持平飞,而是会先爬升获得高度势能,然后在攻击前快速俯冲。虽然我们的仿真模型对高度优势的物理建模并不复杂,但智能体依然学到了这种看起来很有战术意识的策略。

第三个是“一击脱离”。当面对蓝方机群时,红方无人机往往会高速冲入、瞄准并开火,然后立刻大机动脱离,不让对方形成反打锁定。这个行为在奖励函数里没有直接对应项,完全是智能体为了最大化自身存活率而学会的“保命战术”。

第四个也值得一提:被锁定后的机动规避。在训练后期,无人机会在感知到被敌方锁定的第一时间做大幅度转向和高度变化,因为被锁定的惩罚信号很稠密,智能体很容易就学到了规避行为。这恰好印证了稠密惩罚信号在对抗训练中的引导价值。

4.3 对抗双方策略的演化与均衡

双人对抗里最有趣的分析维度是博弈均衡的演化。我做了不同训练阶段红蓝方的对其他策略的对抗测试,用来评估策略的相对强度。

具体做法是:分别保存不同训练阶段checkpoint的红方模型和蓝方模型,两两交叉匹配打比赛。结果发现了一个明显的现象:当红方处于较晚阶段、蓝方处于较早阶段时,红方胜率高得惊人,这说明策略的“进化代差”在对抗环境中体现得很清晰。反过来也一样,蓝方后期策略对红方早期策略也有碾压优势。

当前期红方对后期蓝方时,也经常出现胜率超过50%的情况,这让我一开始很困惑。后来查看回放才明白原因:早期红方策略有一个特点——它不会主动去缠斗,动作模式更“莽撞”,这种不可预测的乱动反而对晚期蓝方建立在“对手会按规律行动”基础上的策略形成了干扰。对抗博弈就是这样,一旦某一方的策略形成了固定套路,面对反套路的对手时反而容易被针对和突破。

4.4 不同初始条件下的泛化测试

训练完成之后,我做了几组泛化测试。第一组是增加交战双方无人机数量,从双方各三架变成四乘四甚至五乘五。结果出乎意料又在情理之中:三架训练出来的策略直接拿到四架场景里,胜率还维持在55%左右,没有断崖式下跌;但五架就开始吃力。原因不复杂——三架时形成的协同模式是“一对一盯防+一个自由人”,扩到四架以上,自由人的调度逻辑就有点不够用了。这也说明CTDE架构里的中心化critic确实学到了部分的再分配能力,但规模的跨越式增长仍然需要重新训练。

第二组是改变初始相对位置。我把红蓝距离拉远了一些,结果策略胜率依然保持稳定。这说明相对坐标的观测设计起到了预期作用。

第三组是测试单一策略的防御能力:蓝方使用最优的非学习型脚本策略(比如直线冲脸、永远开火),红方学习型策略对它有明显的优势,胜率稳定在85%以上。这至少说明我们的策略学习的不是环境漏洞,它确实远超固定脚本逻辑。

5. 常见问题与排查技巧实录

5.1 奖励震荡不收敛

这个几乎每个做多智能体强化学习项目的人都会遇到,我之前在这个项目里也遇到过一次比较严重的。具体表现是:奖励曲线像心电图一样上下狂跳,训练了500个episode完全没有上升趋势。

排查思路是这样一层层剥开的:先用最简单的脚本策略去环境中验证奖励是否合理。如果脚本策略能拿到稳定正分,说明环境判定逻辑没有bug。接着检查critic loss曲线,如果critic loss居高不下,可能是价值函数的学习没跟上策略的变化。再排查熵系数设置,某个阶段熵系数下降到接近零时,策略会变得极端,也很容易造成震荡。

最后定位到的问题是并行环境里有一个环境的初始条件设置了极端值,导致那一支采样的奖励数值特别离谱,拉高了整个batch的方差。把初始条件的抽样范围重新调整后,震荡问题明显缓解。这个案例给我的教训是:别一遇到震荡就怀疑算法,先查环境里有没有脏数据。

5.2 策略早熟与局部最优

这个问题在无人机对抗里很典型。我训练时发现,有一版模型在早期就学会了“远距离绕着对手盘旋,永远不进入攻击范围”。因为刚开始训练模型容易怯战,这个保守策略在奖励上至少不会赔太多,于是模型就固守在局部最优里了。

破解的办法我试过几种,最后组合使用效果最好。第一种调高击杀奖励对被动惩罚的比例,降低被击毁的惩罚权重,给进攻行为更大空间。第二种在早期训练阶段衰减熵系数更慢一些,保持一定探索水平。第三种最有效——把引导奖励做成“阶段性稀疏”:只在攻击包线边缘给一次引导奖励,一旦进入包线后就不再重复给。这个改动逼着智能体学会“趁着包线优势窗口完成击杀”,而不是满足于“进入包线就赶紧跑”。

5.3 训练时间过长与GPU利用率不足

很多人在本地做训练都有这个痛点:GPU利用率经常只有20%左右。问题往往不在于GPU本身,而在于数据流水线断了——环境采样速度太慢,GPU在等着数据送进来。

我的做法很固定:先把环境交互和训练解耦,环境交互进程用原生Python不跑太多额外开销;然后把obs、action、reward传回训练进程时一定走共享内存队列,不要在进程间拷贝大tensor;最后是预取数据缓冲,让训练进程永远有下一批数据可以拿。这些都做完之后,GPU利用率从20%左右提升到了60%靠上,整个训练周期缩短了将近三分之一。

另外还有一个容易被忽视的点:不要频繁做模型保存。每10个episode保存一次模型,看起来稳妥,但保存过程会引发IO阻塞进而打断训练。实际项目里可以每50到100个episode保存一次,并不会影响最终效果。

5.4 多机协同效果差

这批结果里最影响决策质量的就是多机协同做不出来。无人机经常挤在一起,阵型严重重叠。排查后发现,问题的根源在观测空间里缺少“我方其他无人机位置”这一项。智能体根本不知道队友在哪儿,自然谈不上配合。

加了“本机到己方最近两架无人机的距离与方位”这项观测之后,协同效果立刻改善,无人机开始自动拉开间距并形成可辨识的攻击阵型。这也从侧面说明:多智能体协作的前提是每个智能体对战场整体态势有足够的感知能力,判断与决策都需要信息支撑。

还有一个协作相关的细节:critic设计里,如果是每个智能体各维护一个基于自身观测的价值函数,协同能力往往较弱。我会倾向于用一个共享的全局critic把所有人观测拼接起来输入,价值估计更接近于一个团队评估官。牺牲一点点独立性,换回团队协同度,这笔账是值得的。

6. 项目总结与下一步扩展

做这个项目的整体体验,有一点我感触特别深:强化学习项目的迭代瓶颈往往不在算法代码本身,而在环境设计和奖励工程。MAPPO的代码本身已经足够成熟和稳定,你不需要去魔改它,真正能拉开效果差距的,是你的仿真环境是否还原了任务的核心矛盾、你的奖励函数是否在传达正确意图、你的观测设计是否给了智能体足够的信息去做出聪明决策。

如果后续继续扩展这个项目,我个人会比较关注两条技术线。一个方向是多层级的协同机制——比如把任务层(谁去绕后、谁去正面牵制)和执行层(如何机动、何时开火)拆分开,用分层强化学习去解决更大规模的编队对抗问题。另一个方向是智能体数量不对称的对抗场景——蓝方五架、红方三架,这种弱势方如何通过战术优势弥补数量劣势,会是一个非常精彩的研究问题。

还有一个小建议送给正在做类似项目的同学:开始训练之前,先花一两天时间写好沙盘中回放对局的可视化工具。没有画面的盯数据,很多问题藏得比你想象的深。有了可视化,策略行为的观察和调试都会顺手非常多。我自己在这上面吃过亏,早期的几版模型问题都是直到加上了回放工具之后才真正定位到的。

最后再分享一个实际经验:如果做的是无人机攻防这类对抗任务,奖励函数别怕改,但每次只改一个维度,并且保存好每个版本的配置和曲线。我维护了一个简单的实验记录表,记下每次改动、曲线变化、回放观察,这比任何代码注释都管用。调参的每一步到底起没起作用,一翻表格心里清清楚楚。对抗策略研究的价值不完全在最终那个模型,整个训练迭代中的数据和经验,反而是更值得保留的产出。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进