首页 / 资讯中心 / 文章详情

DDPG与TD3在连续控制任务中的MATLAB实现与对比

DDPG与TD3在连续控制任务中的MATLAB实现与对比 ★ FEATURED ARTICLE
简介这套基于MATLAB 2021a的深度强化学习仿真资源以小球弹射控制系统为研究场景完整展示了DDPG与TD3两种连续动作空间算法的实现与对比。压缩包共十八个文件包含十一份.m源码分别负责网络结构定义、智能体训练、环境模拟与结果可视化四张.png图片清晰呈现了两种算法在七状态和八状态环境下的奖励变化曲线两份.mat数据文件保存了训练完成的智能体参数另有一份txt文档探讨了FPGA与MATLAB接口部署问题整个资源包仅二点零三兆字节结构紧凑便于快速查阅。目前已有1468人学习下载适合强化学习初学者、控制仿真方向的学生以及需要选型算法的工程师。通过对照源码与仿真图可以深入理解Actor-Critic框架、经验回放、目标网络等DDPG核心机制并结合TD3的双Q学习、延迟更新和噪声抖动掌握抑制价值过估计的改进思路不同状态数量下的测试结果也为评估算法收敛速度和稳定性提供了直观依据是一份兼具教学与工程参考价值的完整案例。1. 小球弹射控制为什么值得交给DDPG和TD3做对比小球弹射控制系统听起来像一个物理实验台但把它当成一个连续动作控制问题来看它恰好是深度强化学习算法对比的绝佳载体。系统本身一句话就能说清一个小球在水平轨道上弹射器给它一个初速度球在阻尼作用下滑行控制目标是让它准确停在目标位置。传统PID最怕这种带延迟和不确定性的对象而DDPG和TD3正好是深度强化学习里处理连续动作空间的两大基线算法。用MATLAB 2021a自带的强化学习工具箱实现这套环境跑完对比实验你能直观看到经验回放、目标网络、策略平滑这些机制在同一个物理环境中各自贡献了多少。这件事适合两类人一是要做算法对比实验的学生二是想评估DRL在自己控制任务上是否可行的工程师MATLAB版本不需要搭PyTorch或TensorFlow环境几分钟就能把基线跑起来。2. 环境与MDP建模小球弹射系统的状态、动作和奖励设计2.1 状态空间和动作空间一次弹射对应一个决策把小球弹射问题写成马尔可夫决策过程第一步是定义状态、动作和奖励。这里有一个值得先想清楚的设计决策一次完整的弹射过程算一个回合还是把弹射后的滑行过程拆成多个控制步常见做法是拆成多个控制步。弹射器给出初速度后小球在轨道上滑行每一步控制器都可以施加一个辅助力来修正速度而不是发射之后完全不管。这样问题就从“单步参数优化”变成了“序列决策”深度强化学习才有用武之地。如果只让算法一次性输出弹射初速度然后等小球滑到终点看误差那本质上是参数搜索不是强化学习。所以我把状态定义成三维% 状态向量位置x速度v目标位置x_target % 全部用连续值范围经过归一化 obsInfo rlNumericSpec([3 1], ... LowerLimit, [-2 -2 -2], ... UpperLimit, [2 2 2]); obsInfo.Name ballState;动作则定义为弹射时刻的初速度以及后续每一步可以施加的修正加速度这样动作空间是一维连续量% 动作施加在小球上的加速度修正量范围[-1, 1] actInfo rlNumericSpec([1 1], ... LowerLimit, -1, ... UpperLimit, 1); actInfo.Name controlAccel;归一化是这一步必须做的事。MATLAB的强化学习工具箱要求预先声明每个状态和动作的上下界这个上下界会直接影响探索噪声的尺度。如果动作范围写得比物理上能接受的大很多训练早期随机策略会把小球推出轨道边界环境返回的终止条件让算法学到一堆无效经验后面再想纠正就难了。2.2 奖励函数设计稀疏奖励还是密集奖励奖励函数是强化学习里最影响收敛速度的设计决策。我第一版用的是稀疏奖励小球停在目标位置附近就给1否则给0。结果跑了300个回合平均回报纹丝不动。原因很好理解在连续动作空间里随机策略能精确停在目标位置的概率几乎为零agent从头到尾收不到一次正向反馈策略梯度无从更新。后来换成密集奖励把每一步的欧氏距离和速度作为惩罚function [reward, isDone] computeReward(x, v, x_target, step) distance abs(x - x_target); reward -distance - 0.1 * abs(v) - 0.01 * step; if distance 0.01 reward reward 10; % 到达目标位置的额外奖励 isDone true; elseif abs(x) 2 reward reward - 5; % 越界惩罚 isDone true; else isDone false; end end这段代码里有三个值得注意的参数。第一个是距离惩罚系数它决定了agent有多大的动力去靠近目标第二步数惩罚系数0.01作用是鼓励agent少走弯路但这东西不能设太大否则agent会为了早结束而选择直接越界第三是越界惩罚-5必须比一回合正常累积的负回报更重才能让agent真正回避越界。还有一个容易被忽略的细节距离阈值0.01对应的是物理单位还是归一化单位这直接决定任务难度。2.3 环境动力学方程与离散化欧拉积分还是ode45小球在水平轨道上的动力学用一阶阻尼模型就够用了。质量m阻尼系数b外力u运动方程为m * dv/dt -b * v u dx/dt vMATLAB里实现环境有两种路径一是自己写离散欧拉积分二是用ode45解微分方程。对于这种简单线性系统固定步长欧拉积分完全够用而且更可控。用ode45虽然精度高但每一步的仿真时间不固定强化学习的环境步进需要稳定间隔否则连续状态下训练出来的策略在部署时会出现时序偏差。function [nextObs, reward, isDone, loggedSignals] envStep(action, obs) % 固定步长欧拉积分 m 1.0; % 小球质量 b 0.5; % 阻尼系数 dt 0.05; % 控制步长 x obs(1); v obs(2); x_target obs(3); % 动力学更新 a (-b * v action) / m; v v a * dt; x x v * dt; % 计算奖励与终止条件 [reward, isDone] computeReward(x, v, x_target, 0); nextObs [x; v; x_target]; loggedSignals struct(reward, reward); enddt取0.05秒意味着一个2秒的回合有40个控制步这个粒度刚好能让DDPG这样的actor-critic算法在1000个回合内看到足够多的时间差分信号。步长太大会导致动力学失真步长太小则单回合步数太多训练效率骤降。后面在避坑章节里我会展开讲这个参数的敏感性。3. DDPG与TD3的差异为什么TD3要改这三点3.1 从DQN到DDPG连续动作空间是硬需求小球弹射系统的动作是连续的加速度值DQN这种基于动作价值表的算法天然不适用。DQN输出的是每个离散动作的Q值动作空间稍大一点就会指数爆炸。DDPG把策略网络从Q-learning里解耦出来引入了确定性策略梯度的思路actor网络直接输出连续动作critic网络评估这个动作的Q值。DDPG的核心机制是经验回放加目标网络。经验回放把环境交互得到的四元组(s, a, r, s)存进缓冲区训练时随机采样打破样本之间的时间相关性。目标网络则用软更新的方式缓慢跟踪在线网络让TD误差的计算目标不至于剧烈变化。这两点是DDPG能在连续控制任务上站稳脚跟的基础。实现DDPG时有个容易踩的坑actor和critic的网络结构如果设得太深训练初期收敛极慢。小球弹射这种低维状态问题两层全连接网络各128个神经元已经足够没必要堆到三四层。3.2 TD3的三个关键改进TD3论文里说得很直白它是在DDPG基础上修了三个问题。第一个是clipped double Q-learning用两个critic网络分别估算Q值取较小值作为TD目标抑制Q值过估计。DDPG的monotonic overestimation会让critic对很多不该做的动作给出虚高的评价策略跟着跑偏。第二个改进是延迟更新actor网络。actor的更新频率比critic低让critic先稳定下来再更新策略。实践中常见设置是critic每步更新actor每两步更新一次。第三个改进是目标策略平滑在计算TD目标时给目标动作加上一个小噪声相当于对Q函数做正则化避免策略利用Q函数的尖锐峰值。这三个改动对小球弹射系统的影响可以直观感受到。DDPG学到的策略往往动作噪声大速度曲线抖动明显TD3学到的策略更平滑收敛后速度曲线接近理论最优。不过TD3的超参数比DDPG多调起来也更麻烦。3.3 关键超参数对照表从这些值起步做对比实验最重要的原则是两个算法站在同一起跑线上。我常用的做法是共享经验回放缓冲区大小、批大小、学习率、折扣因子这些公共超参数只保留算法特有的设置差异。下面这张表是经过多轮调试后比较稳的一组起始值超参数DDPGTD3说明Actor学习率1e-31e-3太小收敛慢太大训练震荡Critic学习率1e-31e-3两个算法保持一致批大小128128影响样本利用率折扣因子0.990.99衡量未来奖励的权重经验池容量1e61e6超过这个值后旧样本被覆盖软更新系数τ0.0050.005目标网络更新速率Actor延迟更新频率12TD3每两步更新一次actor目标策略平滑噪声无N(0, 0.2)TD3独有裁剪到±0.5动作探索噪声N(0, 0.1)N(0, 0.1)训练时叠加在动作上超参数表的实际意义在于如果两个算法用了完全不同的学习率收敛速度的对比就不公平。我在做对比实验时严格固定公共参数改一个变量就只改一个变量这样最终曲线差异才能归因到算法机制本身。4. MATLAB 2021a实现环境接口与agent创建代码4.1 自定义环境接口rlFunctionEnv绑定reset和stepMATLAB 2021a的强化学习工具箱提供了多种环境接口方式。最简单的是用rlFunctionEnv把reset和step函数绑定进去不需要写完整的类定义。这一步特别适合快速验证算法环境逻辑全部写在函数里修改起来直观。% 环境初始化函数 function initialState envReset() x0 0; % 小球起点 v0 0; % 初始速度为零 x_target 1.0; % 目标位置 initialState [x0; v0; x_target]; end % 绑定到rlFunctionEnv env rlFunctionEnv(obsInfo, actInfo, envStep, envReset);envReset负责每个回合开始时返回初始状态。这里有个设计细节目标位置x_target在重置时可以随机化让agent学会对不同目标距离都适用。如果固定目标位置agent可能学到的是针对这个特定点的记忆而不是通用的控制策略。我在实验中有一半回合随机化目标位置另一半固定这样既保证任务难度可控又迫使策略具备泛化能力。rlFunctionEnv接受的状态和动作规格必须和前面定义的obsInfo、actInfo一致维度不对会在训练开始时报错。这个错误很常见调试时要先检查规格定义。4.2 创建DDPG与TD3 agentactor和critic网络结构接下来是创建agent网络。MATLAB用网络层数组定义actor和critic最终通过rlDDPGAgent和rlTD3Agent封装。这里有一个MATLAB特有的注意事项actor的输出层必须用tanh激活函数把动作限制在[-1, 1]范围内再通过动作规格的缩放映射到实际范围。如果输出层用了purelin动作值可能超出声明范围训练过程直接崩溃。% 定义actor网络 actorNet [ featureInputLayer(3, Name, obs) fullyConnectedLayer(128, Name, fc1) reluLayer(Name, relu1) fullyConnectedLayer(128, Name, fc2) reluLayer(Name, relu2) fullyConnectedLayer(1, Name, action) tanhLayer(Name, tanh) % 输出限制在[-1,1] ]; actor rlDeterministicActor(actorNet, obsInfo, actInfo); % 定义critic网络输入是状态和动作的连接 criticNet [ featureInputLayer(3, Name, obs) fullyConnectedLayer(128, Name, fc1) reluLayer(Name, relu1) concatenationLayer(1, 2, Name, concat) % 合并动作输入 fullyConnectedLayer(128, Name, fc2) reluLayer(Name, relu2) fullyConnectedLayer(1, Name, qvalue) ]; critic rlQValueFunction(criticNet, obsInfo, actInfo);critic网络的结构里使用concatenationLayer把状态特征和动作特征合并这是MATLAB强化学习工具箱的标准做法。需要注意的是动作输入分支没有经过任何非线性变换直接与状态特征拼接这样Q函数的梯度能直接回传到actor网络不会被中间层扭曲。TD3需要两个critic网络MATLAB的rlTD3Agent构造函数内部会自动复制一份critic结构不需要手动创建两个。但这样也带来一个问题两个critic网络如果初始化为完全相同的参数训练初期两条Q曲线完全重合clipped double Q的效果会被削弱。工具箱在创建时会做一次参数扰动所以不用太担心。% 创建DDPG agent ddpgOpts rlDDPGAgentOptions; ddpgOpts.TargetSmoothFactor 0.005; ddpgOpts.ExperienceBufferLength 1e6; ddpgOpts.MiniBatchSize 128; ddpgAgent rlDDPGAgent(actor, critic, ddpgOpts); % 创建TD3 agent td3Opts rlTD3AgentOptions; td3Opts.TargetSmoothFactor 0.005; td3Opts.ExperienceBufferLength 1e6; td3Opts.MiniBatchSize 128; td3Opts.TargetPolicySmoothNoiseStd 0.2; td3Opts.TargetPolicySmoothNoiseBound 0.5; td3Opts.PolicyUpdateFrequency 2; td3Agent rlTD3Agent(actor, critic, td3Opts);rlTD3AgentOptions里四个参数是TD3性能的关键。TargetPolicySmoothNoiseStd是目标策略平滑噪声的标准差太大让目标Q值失真太小失去正则化效果TargetPolicySmoothNoiseBound是噪声裁剪边界PolicyUpdateFrequency控制actor延迟更新的步数。这些参数和PyTorch版本的TD3代码一样改一个都会明显影响收敛曲线建议每轮只动一个参数。4.3 训练循环配置收敛判断与可视化训练配置决定了实验何时停止、如何判断收敛。MATLAB的rlTrainingOptions提供了丰富的停止条件设置。我一般用AverageReward作为主停止条件同时设置最大回合数兜底防止策略确实无法收敛时训练一直跑下去。trainOpts rlTrainingOptions; trainOpts.MaxEpisodes 1000; trainOpts.MaxStepsPerEpisode 80; trainOpts.ScoreAverageWindowLength 20; trainOpts.StopTrainingCriteria AverageReward; trainOpts.StopTrainingValue -5; trainOpts.Verbose true; trainOpts.Plots training-progress; % 训练 trainingStats train(td3Agent, env, trainOpts);ScoreAverageWindowLength设20表示最近20个回合的平均回报超过StopTrainingValue就停止训练。这个窗口太短个别高回报回合会误报收敛太长则需要跑很多回合才能触发停止。MaxStepsPerEpisode设80对应每个回合4秒仿真时长小球从起点滑到目标位置并停稳正常情况下40步内就能完成预留80步是给探索阶段留余量。train函数的输出trainingStats里记录了每个回合的回报、平均回报和采样步数。保存这个结构体后续画对比图要用。我见过很多人直接在命令行里跑训练关掉窗口数据就丢了必须显式保存。5. DDPG与TD3调试避坑指南五个常见的翻车现场5.1 动作范围与物理边界不匹配训练发散现象是训练早期奖励曲线剧烈震荡偶尔出现巨大的负回报然后策略彻底崩溃。罪魁祸首通常是动作范围声明得比物理系统能承受的范围大。比如把action的UpperLimit设为10但模型里小球加速度超过2就会飞出轨道的边界。随机探索时动作值一直在2以上徘徊每次都以越界终止agent无论如何调整策略都得不到有效反馈。解决方法是先跑一个开环脚本随机采样动作统计状态变量实际能达到的范围再根据这个范围去声明观测和动作的上下界。这一步看起来不起眼但能省掉一整天的无效训练。经验法则是动作范围设置为物理极限的70%留出探索空间同时保证大部分随机动作不越界。5.2 奖励尺度太大导致Q值爆炸奖励函数里到达目标给10这个值看起来合理但如果训练早期偶尔蒙中一次目标TD误差会被放大到很大值Q网络的参数更新步长瞬间过大损失直接跳到NaN。我遇到过训练到第200回合时critic loss从个位数跳到几千之后曲线一直有毛刺。解决方法是把奖励整体缩放让单步奖励保持在[-1, 1]区间。距离惩罚除以一个归一化系数到达奖励降为2。另一个选择是使用reward normalization层但MATLAB 2021a的rlQValueFunction里没有内置这个功能手动缩放更直接。调奖励函数的原则是先让早期偶然的成功不至于引发Q值振荡再逐步提高末态奖励权重。5.3 TD3默认参数跑出来还不如DDPGTD3有四个独有超参数如果直接照搬论文里的值在小球弹射这种简单任务上经常表现不佳。TargetPolicySmoothNoiseStd设0.2在复杂机械臂任务上没问题但在这个一维控制任务上0.2的噪声相对于动作范围已经是20%的干扰导致目标Q值过于模糊。调整方法分两步。先把PolicyUpdateFrequency从2改为4让actor更新更慢critic有更多时间收敛再把平滑噪声标准差从0.2降到0.1噪声裁剪边界设为0.3。这两个改动会让TD3收敛曲线追平DDPG再往后td3的优势才逐渐浮现。如果一上来就拿着默认参数很容易得出“TD3不如DDPG”的错误结论。5.4 控制步长不当导致环境不稳定dt0.05可以从一开始就稳定运行但如果你为了加快仿真把dt改成0.2会出现一个问题每一步的位移变化太大小球可能在一个控制步里从目标位置左侧直接飞到右侧distance从正变成负密集奖励完全失效。更严重的是过大步长让离散化误差累积系统的阻尼效应被扭曲agent学到的策略在更细的步长下部署时完全失效。判断步长是否合适的标准在零输入的情况下小球从初速度1.0自然滑行到停止至少要经过20个控制步。只有在这个前提下强化学习的时间差分信号才足够细粒度QCritic能学到真实的Q函数形状。5.5 探索噪声过大或过小DDPG和TD3在训练时都需要给动作叠加高斯噪声做探索。噪声方差设0.1比较中庸。我做过一组测试噪声为0.5时训练前期几乎无法收敛因为动作被噪声淹没策略的确定性部分完全学不到东西噪声为0.001时前100回合收敛慢但后期策略更精确。用小方差噪声后如果发现agent陷入了局部最优可以手动提高噪声方差做退火先探索再收敛。TD3的exploration noise和target policy smooth noise是两回事这个需要分清楚。调的时候先固定target smoothing单独调exploration noise两个维度同时动很难定位问题。6. 对比实验怎么设计收敛曲线、鲁棒性与参数灵敏度6.1 同一起跑线共享环境与随机种子算法对比要让人信服关键是控制变量。环境、观测规格、动作规格、最大训练回合数、经验池容量这些公共配置必须完全一致。另一个容易忽略的干扰项是随机种子MATLAB的rng函数控制全局随机数生成不设种子的话两次训练之间的经验采样和网络初始化都不一样对比曲线没有说服力。我在每次训练前执行rng(42)保证结果可复现。同时需要做多组实验取平均。单次训练曲线噪声太大两个算法的差异可能淹没在随机性里。我自己会把每种算法跑5次不同种子保存每次的avgReward向量最后画mean和std band。这个做法虽然多花时间但图表呈现出的差异才是真实可信的。6.2 对比结果怎么解读三个维度收敛速度看曲线首次达到停止阈值的回合数。下图是我跑的一组代表性结果说明性描述非真实数据DDPG通常在第280回合首次触达阈值TD3在第240回合左右触达。TD3的曲线更平滑DDPG的曲线后期仍有小幅震荡原因是DDPG的Q值过估计让策略偶尔偏离最优方向。最终策略质量用收敛后的平均单回合回报衡量。TD3因为有目标策略平滑机制收敛后动作抖动小速度曲线更平滑DDPG收敛后仍然有轻微抖动。用小球的终点误差来衡量TD3稳态误差能到0.005以内DDPG在0.01左右。鲁棒性测试的方法是把目标位置随机化训练时只在0.5到1.5之间随机测试时外推到2.0的位置。这类外推测试能暴露agent是否学会了通用控制规律还是仅仅背下了训练分布。TD3在这个任务上外推表现明显更好这跟策略平滑机制有一定关系——Q函数被正则化得更平滑决策边界不会随着状态改变而剧烈变化。6.3 训练完成后的三个验证动作训练结束不等于实验结束我在提交结果前会做三个验证。第一是sim函数回放策略看实际控制曲线和状态轨迹确认没有明显的抖动和越界第二是保存agent到MAT文件确认加载后能复现同样的行为第三是做一次参数灵敏度扫描把学习率从1e-3改到3e-3和1e-4观察两个算法是否表现出相同的趋势。这一步能帮你回答“这个结论是不是只在特定超参数下成立”的关键问题。整个实验做下来我最深的体会是DDPG和TD3在小球弹射这类简单连续控制任务上差距远没有论文里展示的那么大但TD3的鲁棒性优势是真实存在的尤其当目标位置分布变化时。而DDPG的价值在于结构简单、参数少适合作为baseline快速验证环境建模是否正确。这也是这套对比实验的真正目的——先确认环境没有bug再评判算法优劣。如果你是刚开始做这个方向建议先从DDPG跑通全流程再把TD3加进去。按本文的配置和避坑清单一步步来半天时间出第一版对比结果不成问题。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站