ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

基于A3C的无人机三维路径规划:MATLAB异步强化学习实战

基于A3C的无人机三维路径规划:MATLAB异步强化学习实战 简介面向熟悉MATLAB与强化学习基础、从事无人机路径规划或智能控制研发的工程师这份完整的A3C三维路径规划项目实例以异步优势演员-评论家算法为核心解决无人机在复杂动态三维环境中高维连续动作空间建模难、训练效率低和收敛不稳定等实际问题。内容不仅覆盖项目背景、目标挑战、模型架构与代码实现还详细给出多线程异步训练机制、连续动作空间策略建模、丰富状态空间和复合奖励函数的设计思路并整合了带数据选择、参数设置、训练评估和结果导出功能的GUI界面便于直接上手验证和二次开发。资源包含1个docx文档整体大小67KB文档采用目录化结构代码示例与注释详尽模块化设计也有助于后续功能扩展与算法优化。目前已有62人学习适合需要系统掌握A3C在无人机三维导航中的工程落地、调试与性能评估方法的读者。 做无人机路径规划大多数人第一反应想到的是A*、RRT*或者人工势场这类经典算法。我之前也在这上面折腾了不少时间直到有一次把任务从二维平面换到带地形起伏的三维空域发现原来的方法明显吃力障碍物一多、目标点一变、或者想加入动态威胁区域规划算法就得重新推倒重来。后来我决定把强化学习真正接进无人机路径规划的流程里折腾一圈后落地的是A3C——异步优势演员-评论家算法。整套系统用MATLAB实现包含三维环境建模、演员评论家网络搭建、异步并行训练、3D轨迹可视化以及一个能直接点击操作的GUI控制台。这篇文章是我实际搭建这个项目的过程记录不是论文复述主要想给正在做无人机路径规划、或者想用MATLAB写强化学习项目的朋友一个可以照着做的参照。1. 为什么是A3C在三维连续空域里值函数方法先遇到麻烦1.1 DQN在无人机路径规划上的两个痛点很多人入坑强化学习都是从DQN开始我一开始也试图用DQN做三维航迹决策。三维空域的状态是连续的无人机当前位置、目标方位、与障碍物的距离一组合就是十几个浮点数。要想用DQN最直接的做法是把状态离散化但三维网格一旦分细状态数量就是乘方级增长10×10×10的粗网格有1000个状态放到真实任务里还远远不够用即便状态离散出来动作空间也一样膨胀。DQN需要一张巨大的Q表或者一个近似Q表网络去拟合训练难度和样本需求量跟着暴涨这在仿真里还能忍放到真实任务上几乎没有可操作性。第二个痛点是经验回放。DQN依赖经验回放池来打破样本相关性但无人机路径规划本身就是一个马尔可夫决策过程轨迹前后强相关回放池里采样出来的旧经验可能早已不适用于当前策略。而且每次探索都从起点重新跑数据利用率并不高训练早期很容易因为奖励稀疏而陷入长时间不收敛。1.2 演员-评论家结构和异步并行带来的实际收益A3C走的是另一条路线——它直接用策略网络输出动作概率也就是“演员”再用一个“评论家”网络估计状态价值。演员负责和环境互动探索评论家负责评价当前状态到底“值多少”两者互补不需要维护一张庞大的Q表也不需要经历从离散动作映射到连续动作的尴尬。更关键的是异步并行机制。A3C开多个独立的环境副本每个副本由不同的线程并行跑各自带着本地参数执行若干步然后把累积的梯度交回全局网络统一更新更新完再从全局网络拉最新权重继续跑。这样一来同一时刻多个actor看到的是不同状态、不同轨迹天然完成了样本去相关比单个actor反复跑同一条走廊要稳定得多。对我这种没有超算资源的研究者来说这个特性非常友好——在MATLAB里开几个并行worker就能获得接近多智能体采样的多样性效果。当然它也有缺点异步带来的参数更新延迟比较大收敛曲线经常抖动并且对一些需要精细控制的场景A3C不如后来的PPO、SAC那样稳。关于这些问题怎么在实际项目中应对我在第7章会展开。2. 三维环境怎么建障碍物、禁飞区和目标点共同构成的状态空间2.1 地图参数与障碍物生成逻辑环境是整个项目的底座。我选用了一块500m×500m×200m的空域把坐标原点放在地图中心。障碍物我分了三类山体、建筑、禁飞区。山体用二维高斯函数叠出起伏地形山体表面标高随平面坐标变化建筑简化为圆柱体传入中心坐标、半径和高度禁飞区用矩形柱体表示无人机一旦进入就立刻判负。在MATLAB里我会用一个配置结构体统一管理这些参数例如envParams.mapSize [500 500 200]; envParams.mountain {[150 100 30 40], [-120 80 25 35]}; % 中心x, 中心y, 高度, 半径 envParams.cylinders {[100 -80 20 60], [-130 -100 25 50]}; % x, y, 半径, 高度 envParams.noFlyZone {[200 50 60 40 80]}; % x, y, 长, 宽, 高碰撞检测的逻辑不复杂对圆柱体判断无人机水平投影点是否落在底面圆内并且飞行高度是否低于圆柱高度对禁飞区判断点是否落在矩形范围里。为了后期可视化方便我会额外生成一张碰撞网格用isocaps或者fill3绘制表面训练时不依赖这些图形只调用碰撞检测函数即可。你会发现环境建模里最需要重视的不是几何画得多漂亮而是“检测函数的性能”。训练过程中actor每走一步就要调一次碰撞检测如果里面写了大量meshgrid和循环整个训练会被拖慢好几倍。所以我把碰撞检测全部向量化一次检查1000个候选航点也不吃力。2.2 一帧状态向量由几个部分组成智能体每一步能观察的状态我最终定为14维向量无人机当前坐标xyz归一化到[-1,1]目标点的相对坐标偏差ΔxΔyΔz同样归一化当前位置与目标的欧氏距离六个方向上的最近障碍距离分别为前、后、左、右、上、下超过探测范围就截断到固定值剩余“电量”比例或者直接叫任务时限剩余量。为什么不直接把原始坐标丢给网络因为坐标量级通常是几百米而距离是几十米混合训练会让梯度更新方向被大数主导。归一化之后每个维度都落在接近同一量级的范围训练稳定很多。这一步千万不能省后面第7章我会说省掉的代价。2.3 离散动作与连续动作我的选择与理由A3C本身可以支持连续动作但为了让初版系统能快速跑通我采用了离散动作空间并扩展到了12个动作水平八个方向正北、东北、正东……、上升、下降、悬停外加一个加速前进。每个动作对应一个单位步长步长取5米。这样做的理由是离散动作的训练难度远低于连续动作策略网络输出层直接接softmax就能用奖励反馈也更直观等实验跑通了再换成连续动作只需要修改输出层和采样逻辑。3. 奖励设计和网络结构决定训练收敛速度的隐藏因素3.1 奖励塑形的分量拆解强化学习的成败一半在奖励。我一开始只设置了“到达目标给100撞障碍给-100”结果训练很久都学不会稀疏奖励让智能体几乎没有任何中间反馈。后来我把奖励拆成五个部分r_goal到达目标区域200r_collision撞障碍或飞出边界-200并终止本回合r_step每一步固定-1促使智能体别绕远路r_distance到目标距离缩短则奖励公式为0.5 * (d_prev - d_curr)是密集奖励的主要来源r_smooth转弯动作变化过大时给一个小的惩罚例如-0.1 * |action_change|让轨迹更平顺。五部分相加后的总奖励数值范围控制在了[-10, 10]多数情况内很少出现动不动几百上千的极端值。这一点对后续网络训练的稳定非常关键。注意奖励尺度如果过大梯度更新时波动也会跟着放大奖励尺度太小则收敛极慢。我建议先做几轮实验统计奖励量级再决定是否乘一个缩放系数。3.2 演员网络与评论家网络的MATLAB定义网络结构我用的是双隐藏层全连接没有上很花哨的CNN因为状态本身是14维向量。演员网络输入14维中间256和128个神经元输出12个动作的softmax概率评论家网络输入同样14维输出一个标量价值估计。layersActor [ featureInputLayer(14, Normalization, none) fullyConnectedLayer(256) reluLayer fullyConnectedLayer(128) reluLayer fullyConnectedLayer(12) softmaxLayer]; actorNet dlnetwork(layersActor); layersCritic [ featureInputLayer(14, Normalization, none) fullyConnectedLayer(256) reluLayer fullyConnectedLayer(128) reluLayer fullyConnectedLayer(1)]; criticNet dlnetwork(layersCritic);定义网络只是第一步真正麻烦的是自定义损失。A3C的演员损失是带优势函数加权的策略交叉熵再减去熵正则项评论家损失是n步回报与价值估计的均方误差。在MATLAB里我用dlgradient和dlfeval计算梯度用optimizerUpdate做参数更新。一开始我直接套用了内置强化学习工具箱的rlActorCriticAgent但发现它不支持多个worker异步更新于是改成自定义训练循环——自由度更高也更好调试。3.3 为什么我要加熵正则项以及系数怎么调离散动作的策略网络很容易在训练初期锁死在某一个动作上只要这个动作偶尔带来一次正向反馈网络输出的概率分布就会向它倾斜之后智能体不再探索性能从此卡住。熵正则项就是为了对抗这种事。熵在信息论里衡量概率分布的随机程度。策略分布越平均熵越大越偏向单峰熵越小。我把熵乘以一个小系数β作为惩罚项加到总损失里优化器在最小化损失时就会在“追求高回报”和“保持一定随机性”之间做平衡。β取多少合适我实测下来0.01起步是安全的训练过程中如果发现策略过早收敛就把β调大到0.05如果动作太乱、绕路太多就减小到0.005。这属于典型的超参数经验单一固定值很难通吃所有场景建议写成可调参数放进GUI里。4. 异步训练逻辑用MATLAB并行计算工具箱实现多个Actor并行4.1 全局网络与本地Actor的同步方式A3C的核心是“全局一张网本地多个actor”。MATLAB的并行池parpool各worker之间内存相互隔离所以不能像C多线程那样直接共享全局变量。我采用了一个稍微麻烦但可靠的办法全局网络只存在主进程每个worker定期收到最新的全局网络参数跑完一段时间后把“梯度累计结果”传回主进程主进程负责更新全局网络。具体流程如下主进程初始化全局演员网络和评论家网络用parfeval向每个worker派发一个训练任务任务参数里带上global的参数快照worker加载参数在本地环境副本上执行n步计算n步回报和优势函数worker把计算好的梯度矩阵或更新量返回主进程主进程用返回的梯度更新全局网络然后继续派发新一轮任务。因为异步不同worker的更新任务到达主进程的时间有先后带回来的参数对应的是旧版本这种“陈旧梯度”在A3C里是可以接受的反而能增加探索多样性。但如果陈旧程度过严重训练会不稳定。我的做法是限制单worker连续运行步数在200步以内并及时同步。4.2 训练主循环的代码骨架下面是一段简化的训练主循环骨架省去了很多细节但足以说明结构pool parpool(4); globalLearnables getLearnables(actorNet); for ep 1:maxEpisodes % 派发异步任务给每个worker for w 1:numWorkers futures(w) parfeval(pool, runLocalActor, 2, globalLearnables, envParams); end % 收集梯度并更新全局参数 for w 1:numWorkers [idx, gradActor, gradCritic] fetchNext(futures); % 调整学习率后更新 [actorNet, criticNet] applyGradients(actorNet, criticNet, gradActor, gradCritic, lr); globalLearnables getLearnables(actorNet); end end需要说明的是fetchNext会让主进程阻塞等待第一个完成的worker但A3C本来就是异步的所以这种“每轮都收齐再派发”的实际是半同步版本。想让异步更彻底可以改为持续后台接收任务、有返回就立即更新。我对初版采用的是前者因为调试起来更直观后期再改成真正的无阻塞异步。4.3 A3C在MATLAB中不同于PPO的地方用MATLAB的时候容易把A3C和PPO搞混因为MATLAB强化学习工具箱原生提供了PPO而A3C需要自己写。两者的关键差异是PPO用了重要性采样和裁剪clip可以重复使用一批采样数据优化多个epoch所以在经验利用效率上更高A3C则完全依赖在线策略每个样本只用一次靠多个并行actor的异步采样来弥补样本效率。也正是因为A3C没有重复利用样本学习率得调得保守一些。我建议初始学习率设在3e-4不要一上来就1e-2否则全局网络很容易在几次更新后直接发散。顺带一提只要把actor数量减少到1、去掉异步逻辑A3C就退化成了A2C前者收敛通常比后者更容易跳出局部最优——这也是我坚持保留异步的原因。5. 轨迹的三维可视化训练结果怎么看、怎么判断好与坏5.1 用三维坐标系绘制飞行轨迹训练结束后我会把每个episode的航迹点保存成矩阵[N×3]然后用plot3画出来。为了把环境信息也放在同一个图里我会先绘制山地地形曲面和圆柱障碍物再叠加航迹。视觉上能直观看到路径是否绕过了障碍、是否朝目标方向行进。figure; plot3(traj(:,1), traj(:,2), traj(:,3), r-, LineWidth, 1.5); hold on; % 绘制山体曲面和圆柱体 [X, Y] meshgrid(-250:5:250, -250:5:250); Z mountainHeight(X, Y); surf(X, Y, Z, EdgeColor, none, FaceAlpha, 0.6);如果训练完全没收敛航迹会是一团乱麻经常在起点附近绕圈或者直接冲进障碍区。这时候别急着调网络先回看奖励曲线和状态分布大概率是奖励设计或者学习率的问题。5.2 航迹平滑后处理三次样条与路径点神经网络输出的路径必然是折线因为动作是离散网格移动。直接让无人机走这种折线会遇到转弯过大、速度方向突变的动力学问题。我的做法是先用三次样条插值对路径做平滑再检查每一点的爬升角是否超过无人机的极限值如果超过就在该点附近插入过渡路径点重新样条。最终输出的是包含经纬度、高度、航向角和时间戳的航迹表可以直接导出成CSV供后续仿真使用。这一步看起来是后处理实际上非常重要。路径规划算法得到的航迹必须能映射到真实无人机的飞行包络否则仿真里再漂亮也没法落地。5.3 性能对比A3C与人工势场法的初步结果我把训练好的A3C和传统人工势场法在同一个地图上做了对比结果有参考价值指标A3C人工势场法平均航程/m12401520碰撞率/%621单次规划耗时/ms158A3C的单次耗时略高胜在环境适应性和碰撞率。人工势场法在简单障碍面前很优雅一旦障碍呈凹形或者多个斥力场叠加就容易陷入局部极小点。A3C通过训练学到的是“绕开并结合目标方向”的策略不容易被局部陷阱锁死。6. GUI设计App Designer搭一个可交互的训练控制台6.1 界面布局与回调解耦为了让这个项目不只是脚本而是能直接给别人使用的工具我用MATLAB App Designer搭了一个控制台。界面主要分三个区域左侧参数面板地图尺寸、障碍物数量、最大训练回合数、学习率、熵系数中部三维显示区用uiaxes实时展示无人机位置和规划轨迹右侧状态区训练步数、当前奖励、损失值外加开始/暂停/导出路径三个按钮。我选择了App Designer而不是GUIDE原因很简单GUIDE已经不再维护新写的组件和回调方式在后续MATLAB版本里容易出兼容问题。App Designer的数据绑定和回调机制清晰很多图窗组件也更现代。6.2 把训练、可视化和结果导出串成一条线这里最大的坑是UI回调里如果直接跑一个长训练循环界面会一直转圈、点击无响应。我的解决办法是把训练主体写成一个独立的函数训练过程中不断往共享的结构体里写入最新的奖励和位置数据UI侧用一个定时器或者drawnow limitrate每隔一定毫秒刷新一次图表。训练完成后再启用“导出路径”按钮把航迹和评估指标写进csv文件。按钮回调之间要解耦“暂停训练”和“停止训练”这种功能一定要共用一个状态标志位训练函数每迭代一步去检查这个标志而不是用interrupt这类容易导致数据损坏的机制。6.3 实测中最容易卡住的回调问题我遇到过最磨人的一个问题App Designer里uiaxes的绘图速度比普通figure慢很多如果每步都更新三维图训练速度会被拖到没法看。最后我改成每10个episode刷新一次航迹奖励曲线每5步追加一个点界面流畅度立刻就上来了。另外如果训练函数使用了parfeval创建了并行任务而用户直接关闭了GUI窗口worker可能不会立刻退出导致进程残留。我在窗口关闭回调里加了一段清理代码显式调用delete(gcp(nocreate))这才彻底解决。7. 我在这个项目里踩过的坑和最终的调试建议7.1 训练崩溃日志长什么样、怎么定位这个项目的训练崩溃日志最有代表性的就是损失值变成NaN。最初我遇到时第一反应是学习率太大但调小后依然崩溃。后来定位到根因输入状态里有两个维度没有做归一化坐标值是几百的量级经过全连接层后乘积直接溢出。把状态归一化、再把网络权重初始化改成标准差更小的方案之后NaN就消失了。另一种常见情况是策略完全锁死。损失值不NaN但智能体从头到尾都输出同一个动作。这时候排查顺序是先看奖励是否是常数再看熵系数是否被设成了0最后看softmax输出里是不是出现了inf。这三个节点排查完百分之八十的情况都能定位。7.2 参数参考表一套能稳定收敛的A3C起始参数这里给出一组我调试后认为比较稳妥的初始参数供没经验的朋友直接起步参数推荐值说明学习率演员/评论家3e-4评论家网络可以略大1e-3折扣因子γ0.99长期奖励权重n步回报步数200单worker每次同步前的最大步数隐藏层256/128两层全连接熵系数β0.01按收敛情况调整奖励缩放1.0保证奖励量级在[-10,10]并行actor数4资源有限时2也可但收敛稍慢这套参数在500×500×200的地图上、12动作离散空间里跑大约3000个episode就能看到比较明显的进步。7.3 我个人的实操结论与后续扩展想法整个项目做下来我的核心体会是A3C不是那种“开箱即用”的算法但它对算力要求低、代码结构清晰特别适合作为理解强化学习路径规划的内部实现模板。如果你后续想过渡到连续控制可以把输出层换成高斯分布参数想把复杂度拉高也可以尝试多个无人机协同用MAPPO的思路改造现有框架。最后分享一个我自己的习惯每训练50个episode就把网络参数和奖励曲线自动存档一次。A3C训练过程抖动大你可能跑了一个小时发现效果不好但中间某个checkpoint其实已经学到了不错的策略。有这个存档就能回滚对比而不是从零再来一遍。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

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