大家还记得“在 MATLAB & Simulink环境中开发机器狗控制算法”这篇文章吗?其中已经介绍了基于步态设计算法的四足机器人的建模和控制。 本期文章中,我们将一起来看看,借助强化学习为机器狗开发智能控制算法过程中踩过的坑,以及怎样避免 GPU 燃烧导致电费飙涨(不要问我怎么知道的 T_T)。 ◆ ◆ ◆ ◆ 1. 设计基础:使用 Simscape Multibody 进行机器人动力学建模; 2. 运动设计:模拟猫狗走路方式设计初级步态,从而定义终端足部的运动轨迹,根据逆向运动学求解各个关节位置,在由逆动力学分析求解关节受力状态,作为驱动电机选型的指标; 3. 正向动力学仿真:搭建电机模型,给定关节力矩指令,输出关节位置,查看机器人控制效果; 4. 算法简化:由于求逆过程大量迭代限制了运行速度,将逆向动力学用查表模型替换,加快生成步态部分算法效率。 ◆ ◆ ◆ ◆ 如果你希望将以上方法扩展到更多使用场景,需要进一步深化步态设计,实现过程中,查表模型的维度也会不断增大。 而维度爆炸,是我们无论开发什么算法都希望避免的,通过深度强化学习自动开发算法,实现四足机器人平衡和行走控制,在一定程度上能够帮助我们降低开发阶段的脑力投入,并更易于进行部署(自动代码生成了解一下 >> MATLAB Coder/GPU Coder)。 强化学习,区别于监督式学习和无监督学习,是指在既没有数据,也没有标签的情况下,通过智能体与外部环境交互获取数据,不断试错来学习策略。 其中,智能体是被训练的对象。智能体中的策略部分,将在与环境交互的过程中,根据观测值选择动作输出。 观测值的集合,可以描述环境的状态。与此同时,环境则评估智能体的行为,给予正向或负向的激励信号 —— 奖励(及惩罚)。 智能体内置的强化学习算法,会相应地调整策略以尽可能地最大化积累的奖励。 MATLAB 从 R2019a 起推出强化学习工具箱(Reinforcement Learning Toolbox),你可以结合深度学习工具箱与 Simulink,实现深度强化学习在复杂系统控制设计方面的完整工作流,包括环境创建、奖励定义、智能体创建和训练,以及最终策略的验证和部署。 其中,四足机器人的建模,你可以参考前面提到的文章,预留观测值、奖励值、仿真终止判定等信号接口,再与强化学习工具箱提供的强化学习智能体模块(RL Agent)连接,该模块将指向待定义的智能体对象agent(此时RL Agent模块自带一圈红色的光晕)。智能体输出的动作值,即为需要作用在各个关节上的电机扭矩控制信号。 同时,使用以下指令构造环境对象 env: env = rlSimulinkEnv(mdl,[mdl '/RL Agent'],obsInfo,actInfo); env 将被用于在 MATLAB 中设定后续的训练和仿真过程,此处, obsInfo 和 actInfo 定义了观测值和动作的信息(维度、上下限等)。 接下来,我们需要重点考虑工作流中的其他步骤。 ◆ ◆ ◆ ◆ 1 奖励函数定义 区别于步态设计,我们并不直接指导智能体如何选择输出的动作/控制指令,而是反馈给智能体“奖励”这样一个数值信号,如图所示,让智能体学习自动更新策略。 关于如何设置和分配奖励,可移步文末 FAQ 部分了解。 ◆ ◆ ◆ ◆ 2 智能体创建 智能体由两个部分组成,策略和强化学习算法。 强化学习工具箱内置了一系列智能体,包括 DQN,SARSA,DDPG,PPO,SAC 等,你也可以自定义强化学习算法。 接下来我们将首先尝试使用 DDPG 智能体进行机器狗运动控制。 Deep Deterministic Policy Gradient (DDPG),是一种基于 Actor-Critic 结构的智能体,其中 Actor 和 Critic 均为神经网络,Actor 根据观测值决定输出,Critic 则由观测值和动作值,估计动作的价值。 关于策略的表达方式、强化学习算法实现以及 DDPG 智能体的基本原理,可移步文末 FAQ 部分了解。 深度强化学习智能体的创建通常分为以下 3 个步骤,你可以参考强化学习工具箱文档查看更多细节。 步骤1:定义网络 利用 MATLAB 中的深度学习工具箱,你可以在 Deep Network Designer 中,以点击拖拽的方式,构建一个神经网络后导出到工作区,也可以直接编写 MATLAB 代码创建网络。 例如,Actor 接收观测值作为输入,输出动作值,其网络定义如下: 步骤2:定义 Actor 和 Critic 这一步对于基于神经网络的强化学习智能体是通用的,通过 rlRepresentationOptions 可定义网络权重和偏置的学习率、优化器等,并声明输入(观测值)和输出(动作): actorOptions = rlRepresentationOptions('LearnRate',5e-04,... 'GradientThreshold',1,'UseDevice','gpu'); actor = rlDeterministicActorRepresentation(actorNetwork,obsInfo,actInfo,... 'Observation',{'observation'},'Action',{'ActorTanh1'},actorOptions); 步骤3:定义智能体 指定智能体中的 actor 和 critic,通过 rlDDPGAgentOptions 可定义强化学习算法中的折扣因子、采样时间、经验缓存长度和噪声模型参数等: agentOptions = rlDDPGAgentOptions; agentOptions.ExperienceBufferLength= 1e6; [友情提示] 如果你是第一次开始训练智能体,请设置保存经验缓存: agentOptions.SaveExperienceBufferWithAgent= true; agentOptions.ResetExperienceBufferBeforeTraining= false; 注意:存在高维观测数据(图像像素)等数据量大的情况下,可能会出现内存不足的情况。 然后就可以定义智能体了,还记得刚才提到的 RL Agent 模块需要指向一个 agent 对象吗? agent =rlDDPGAgent(actor,critic,agentOptions); ◆ ◆ ◆ ◆ 3 智能体训练与验证 使用 train 函数,指定环境 env 以训练智能体 agent,并通过 rlTrainingOptions 函数设定训练中止条件,是否自动保存智能体,最大仿真次数,是否使用并行等条件。 trainOpts = rlTrainingOptions; trainOpts.MaxEpisodes = 20000; trainOpts.UseParallel = true; 使用 GPU 能够提高策略部分神经网络的训练速度,而通过使用多核计算机将仿真并行化,可以进一步节约训练时间,如果有集群计算资源就再好不过了。 如果你希望在训练过程中,通过 Mechanics Explorers 多体仿真查看训练效果,必须在训练串行的模式下进行(提示:256 倍速观看效果更佳哦)。 训练启动后,将会打开 Episode Manager 图窗,用于可视化训练进度。 trainingStats =train(agent,env,trainingOptions); [友情提示] 训练启动前,记得在 Simulink 模型中停止记录所有所选信号,避免训练期间,产生过多不需要记录的数据。注意训练开始后,无法修改模型。 调用 sim 函数,按设定条件运行仿真以验证控制效果: simOptions =rlSimulationOptions('MaxSteps',1500); experience =sim(env,agent,simOptions); 你可能已经开始构想机器狗迈着灵活敏捷的步伐走来的模样,不过,假如你有空翻看 DDPG 的原论文,会发现作者有写道:除了 cheetah(猎豹机器人)以外,测试过的其他场景中,动作值都是驱动关节处的扭矩。 在这个示例中,使用 DDPG 实现力矩控制的收敛效果并不理想,Critic 很容易出现对 Q 值(黄线)的过度估计,从而出现这过山车一般的训练曲线: 经过漫长的训练,机器狗仍难以保持平衡,导致仿真提前终止: 让我们复盘一下,奖励函数的设定,模型参数等众多因素都会导致训练效果差强人意,一般以上步骤往往需要持续迭代修正。 另一种思路是,附加约束进行训练,缩小需要探索的动作空间,例如机器狗的 12 个关节中,髋关节控制效果很不理想,出现绕圈转的现象,可以考虑在模型中将髋关节的运动范围限制在合理区间。 为了节约 GPU 燃烧费用,更好的选择是尝试另一种策略:TD3 (Twin-Delayed DDPG ),其中 Actor 和 Critic 结构和 DDPG 相同,但在算法上进行了优化,通过使用 2 个 Critic 网络估计 Q 值,选取其中较低的结果作为参考,并延迟 Actor 网络更新,使估计误差有更多的时间减小,从而抑制对 Q 值的高估倾向。 以下是训练过程: 乍一眼看上去,第一次训练中,奖励上升幅度很缓慢,训练 20000 个 Episode 后,每个仿真周期能够获得的奖励值总和才开始升高,好在之前设置了保存经验缓存,我们可以继续训练。 在第二次训练中,经过 6000 个 Episode 后,奖励回报升高趋势越来越明显,在进一步迭代优化后,已经能够稳定地行走,当然,你还可以继续训练,直到机器狗健步如飞。 下一步: 在 MATLAB 中结合使用其他工具箱,你还可以:
◆ ◆ ◆ ◆ 想要了解更多,欢迎留言联系我们,或扫码填写问卷获取代码下载链接。 (继续下拉阅读 FAQ 常见问题问答) ◆ ◆ ◆ ◆ FAQ-1:应该以怎样的频率分配奖励? A: 奖励的分配方式比较灵活,即可以在整个任务完成后给一个奖励信号,也可以在策略与环境交互的每个时间步长中计算奖励值,本例中,采用在每个仿真步长计算奖励值的方式。 FAQ-2:奖励函数定义有没有规则可循? A: 定义一个有效的奖励函数,需要结合领域知识,并没有通用的方法。奖励函数通常可以包括系数为正的奖励项和系数为负的惩罚项。 惩罚项可以理解为一个需要最小化的目标(参考 RMSE,损失函数),定义方式与控制系统中的代价函数相似,当目标是减小多个物理量的跟踪误差,例如本例中,希望最小化机器狗偏离x轴的距离,躯干俯仰角度,以及重心关于初始高度的偏移量,可以将对应的误差项平方后加和。 在设定各项系数时,如果没有提前对数据进行归一化,需要综合考虑对应的取值范围和目标跟踪的重要性。同时,由于物理系统中的各变量的调整往往是牵一发而动全身,依据相应的物理准则,一个物理量的取值会影响到另一个,因此次要目标的系数权重可以选的小一些,留出一定弹性空间,以最小化主要目标。合理构建环境模型,包括定义奖励函数,是有效设置智能体任务的关键。 FAQ-3:怎样表征策略? A: 简单的决策问题,例如井字棋、网格世界游戏,对应的观测值、动作值取值离散,智能体需要探索的状态和动作空间有限,可以通过查找表描述策略。相比之下,控制系统的输入和输出量一般为连续值,本例中,电机的驱动力矩为[-25Nm,25Nm]之间的任意值,所以状态和动作空间是无限的,无论是通过仿真还是实物测试,学习的过程中,能够探索的空间大小有限,因此,一个关键问题在于,策略的泛化能力,即能不能根据有限的经验积累,推断在没有经历过的场景下,怎样作出决策。 另外,在需要处理图像、雷达和激光雷达数据输入时,由于信息量非常丰富,状态空间是高维度的,策略的输入可能是上万个像素点,使用表格或者一般函数的表达功能有限,无法处理这种应用场景,此时就需要借助于深度神经网络: 神经网络擅长处理高维度的输入数据,例如通过卷积层自动提取图像中的低级特征,包括颜色、边缘、明暗等,并且融合得到一些通用的抽象特征,而这些特征在很多数据中都有类似的表达,所以,即使在训练神经网络时,无法遍历整个状态空间,也能够得到较好的泛化能力,应对新数据。虽然,训练神经网络涉及大量学习参数的优化,但是参数空间远小于状态空间,因此相较于使用查表法定义策略,对内存的要求更低也更贴近于实际的可行范围。 神经网络可作为一个通用函数近似器,将任意输入映射到任意输出,从而实现对连续动作空间的支持。 这种将深度神经网络用于强化学习的方式,被称为深度强化学习。 FAQ-4:强化学习算法如何实现? A: 智能体在与环境交互的过程中,获取数据或积累经验,经验是指执行策略得到的一系列“状态-动作-奖励-下一状态”,即(s,a,r,s')的序列数据。强化学习算法基于经验数据,调整策略。其中,一个重要问题是,如何在动作空间的探索和利用之间权衡。所谓探索,是指对于未知奖励的动作进行尝试,看看是否有可能获取更高的奖励。而利用则是,在已知奖励的动作空间中,选择能够立即获得更高奖励的动作。常用的一种训练方法是 ε-贪心算法,在每个控制时间间隔,智能体随机选择动作空间中的任意动作(探索)的概率为ε,而利用已知的动作空间(贪心)的概率为1-ε。 具体每种强化学习算法的实现有所区别,例如深度确定性策略梯度,Deep Deterministic Policy Gradient (DDPG),是一种基于 Actor-Critic 结构的智能体,其中 Actor 和 Critic 均为神经网络,Actor 根据观测值决定输出,Critic 则由观测值和动作值,估计动作的价值,即未来一段时间内能够获得的长期回报的期望值,通过评估价值,而不是即时奖励,以作出更好的决策。训练过程中,在每个时间步长,智能体将从经验缓存中随机采样,通过优化器更新两个神经网络的学习参数。 训练早期,智能体探索的动作空间比较有限,学习效果离预期的差距比较大,但随着迭代次数增加,参数优化后,Critic 能够更加准确地估计价值,而智能体在一次仿真中累积的奖励值也将提高。 |