尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

强化学习清扫机器人奖励函数工程实践:从100分到778分

强化学习清扫机器人奖励函数工程实践:从100分到778分 说句得罪人的话很多强化学习项目不是死在算法上而是死在奖励函数上。训练前把网络结构、学习率、环境封装折腾个遍最后发现机器人学会的是“原地打转刷步数”或者干脆躺平不动——根源十有八九是奖励设计出了问题。这个清扫机器人项目我前后迭代了快两个月把奖励项从最初拍脑袋的4个一路改到结构化的10项复合奖励同一个PPO实现、同一张仿真地图训练得分从基线100分一路拉到778分涨了近七倍。这篇文章不聊理论推导重点记录我是怎么拆奖励、配权重、填坑的给同样在做强化学习奖励工程的人一份能直接用的实操脚本。1. 为什么奖励工程是“隐形天花板”1.1 你先得承认一个事实算法是在替你“翻译”奖励很多人把强化学习当成“黑盒炼丹”丢进去就行。但本质不是这样。强化学习优化的是期望累积奖励策略网络学到的每一个行为都是在你定义的奖励信号下做梯度上升的结果。你给了什么样的奖励机器人就会变成什么样的“性格”。拿清扫场景举例。如果只给“清扫覆盖率”这一条奖励机器人学到的策略很可能是快速溜达一遍把覆盖率刷到80%就停因为再扫边际收益太低。更恶劣的情况是它发现原地抖动能让传感器误判“已清扫”奖励照样增长——这是机器学习利用漏洞的经典场景不针对机器人任何智能体都一样。所以在设计奖励函数的时候我给自己定了一条原则不要把“目标”直接写成奖励要把“行为过程”拆成可分级的信号。目标太稀疏学不动目标太单一学歪。1.2 清扫任务到底难在哪多目标天然冲突清扫任务是一个典型的多目标优化问题目标之间还互相打架想覆盖率高就得跑得久、跑得全这跟“能耗低”冲突想路径优雅就得少转弯但少转弯就可能导致漏扫边角想不碰障碍有时候狭窄区域就必须贴身擦过去想快速完成就可能牺牲覆盖细节比如家具底下的尘絮扫不到。![清扫任务的奖励冲突示意]想象一条奖励函数左端是覆盖率右端是能耗成本中间全是拉扯。这种冲突不是坏事反而是奖励工程能发挥价值的地方。问题只在于你要怎么把这些冲突目标加权成一个标量权重就是态度。我最终用的方案是复合奖励总共10项分成了四个梯队核心任务奖励、行为引导奖励、约束惩罚、里程碑加成。下面这一章是我觉得全文最值得反复看的部分。2. 第一版奖励那个只配拿100分的机器人2.1 最初的4项奖励是怎么翻车的先交代一下环境。我的仿真环境是基于PyBullet搭的轮式清扫机器人64×64栅格地图房间里有6个小障碍物和一片需要清理的“灰尘区域”灰尘用粒子分布模拟机器人底盘带一个接触式清扫检测器。第一版奖励函数非常简单就4项reward ( coverage_progress * 1.0 # 覆盖率增量 10.0 if task_complete else 0 # 任务完成 - 0.01 * step # 步数惩罚 - 0.5 if collision else 0 # 碰撞惩罚 )结果很惨。训练50万步累计奖励稳定在100分左右不再上升。但真正的问题不是分数低而是策略表现出三种典型“畸形”绕圈自嗨机器人学会了在地图中央绕半径很小的圈因为每次绕圈都能压过一小片未清扫区域覆盖率增量持续为正它根本不需要去扫角落怕碰撞怕到不敢动碰撞惩罚虽然每步只有-0.5但累积起来吓人策略逐渐变得保守能不动就不动偶尔伸出清扫刷试探一下边界龟缩地图边缘和障碍物缝隙的灰尘密度高但机器人死活不过去宁可在开阔地带重复扫。这就是典型的奖励“短视”策略在每步都要最大化即时奖励而覆盖率增量这种“局部正反馈”很容易被利用。2.2 100分这个基线的真实含义我后来复盘才发现100分这数字误导了我好一阵子。“有100分说明能扫一点是不是策略还行”不是。我把每个奖励项单独打日志后看到这个100分里约70分来自“绕圈压过灰尘”的覆盖率增量25分来自完成任务的墓碑奖励剩下5分扣掉碰撞罚项后等于零头。换句话说第一个模型根本没学会扫干净它只是学会了一种刷分玩法。所以如果你也在做类似的RL项目我强烈建议不要只盯累计奖励报表一定要把每个奖励分量的均值、方差单独拿出来画曲线否则你看不到“谁在真正促进目标谁在钻空子”。3. 10项复合奖励的完整拆解每一分都有来处3.1 奖励拆分的四条设计主线在从头设计奖励之前我把清扫任务拆成了四个问题组扫得全吗覆盖率、区域完成度、边界覆盖率扫得顺吗碰撞、转弯、平滑度扫得值吗时间成本、能耗成本扫得稳吗防止卡死、掉头、局部死循环每一组对应2-3项奖励合起来就是10项。下表是最终设计版后面我会逐项展开。序号奖励项类型数学形式权重1清扫面积增量引导奖励Δcoverage * 0.80.82完成任务奖励稀疏里程碑12123边界清扫奖励引导奖励Δborder_coverage * 1.21.24重复清扫惩罚约束惩罚-0.02 * repeated_area0.025碰撞惩罚硬约束-1.01.06转弯惩罚行为惩罚-0.15 * angle_velocity0.157路径平滑奖励行为引导0.005 / (1 jerk)0.0058原地卡死惩罚硬约束-2.02.09时间效率惩罚约束惩罚-0.005 * step0.00510能耗成本惩罚软约束-0.05 * distance0.053.2 核心任务组覆盖率这件事值得拆细第1项清扫面积增量Δcoverage * 0.8这是主心骨。每走一步如果灰尘检测覆盖率比上一步提高了就给正奖励没提高这项的奖励为0。current_coverage swept_area / total_dust_area delta current_coverage - previous_coverage r_coverage delta * 0.8为什么用增量而不是总量因为如果用“当前覆盖率 * 0.8”那策略会得到一个巨大的常数值——覆盖率40%时每步都能吃到同样的奖励跟动作无关奖励等于白给。增量奖励的本质是“行为→结果”的因果信号只有你这一步真正扫到新区域才给钱。这符合上一节说的“过程信号”原则。第2项完成任务奖励12覆盖率到达95%以上判为任务完成一次性给12分。这个奖励很“稀疏”但它作用重大它告诉策略“完成比不完更好”也给了训练后期一个明确的目标锚点。关于“12”这个数值我是拿“预计最大步数”倒推的地图上完成全覆盖经验上至少要800步如果每步的增量奖励平均能赚0.05分800步就是40分一个“完成事件”应该等价于总任务列的前1/4左右所以我取12。这个倒推法在奖励工程里很常用。你要是拍脑袋写个100那所有策略都会盯着“完成”这个远期目标冒进前期完全学不到覆盖技能风险太大。第3项边界清扫奖励Δborder_coverage * 1.2这是我跟很多同行交流后学到的“私货”。清扫任务里边界和角落是最容易被漏掉的地方但也是灰尘堆积最严重的地方。如果把边界灰尘和中部灰尘放进同一个覆盖率公式那策略天然会优先扫中间因为中间路径开阔、转向少、步数收益高。所以我单独统计了一个“边界覆盖率”距离墙壁或障碍物半径0.8m以内的区域算作边界区域。边界覆盖率的增量奖励系数设成1.2比一般区域高50%。实测效果非常明显——机器人会刻意贴着墙走一圈这在第一版模型里根本见不到。3.3 行为引导组让路径不再是“布朗运动”第4项重复清扫惩罚-0.02 * repeated_area这一步要解决“绕圈自嗨”。怎么检测“重复扫”呢我是把栅格地图按边长5cm切成小格子每个格子有一个“最近清扫时间戳”。当机器人扫过格子时如果这个格子距离上次清扫的时间少于6秒就算“重复清扫区域”。if cell_last_cleaned_time[cell_id] current_time - 6.0: repeated_area cell_size惩罚压力不大但持续存在。策略会倾向于往新区域走而不是在原地刷覆盖率。注意这个惩罚不能太大否则机器人会为了避开“刚扫过的区域”而走极端路线路径反而扭曲。第5项碰撞惩罚-1.0第一版用的是-0.5效果太温和机器人觉得碰两下也无所谓。但我也没有调成特别狠的值原因很现实清扫任务很多时候必须和障碍物边缘发生轻微接触比如贴墙扫尘。这里有一个很值得说的细节我把碰撞分成了“正常贴碰”和“硬碰撞”两级。用碰撞检测的冲击力阈值区分低于某个力度的不算碰撞惩罚只算轻微接触高于这个力度才触发-1.0。if impact_force collision_threshold: r_collision -1.0 elif impact_force gentle_contact_threshold: r_collision -0.1这样处理的理由是如果所有接触都惩罚机器人不敢靠近墙边边界清扫永远做不好但如果所有接触都不惩罚机器人会拿脸撞障碍物。分级惩罚让它在“接近障碍物”和“暴力撞击”之间找到一个中间解。第6项转弯惩罚-0.15 * angle_velocity这个惩罚是针对“路径扭曲”的。机器人为了刷覆盖率经常走S形、Z字形转向频率高姿态剧烈变化不仅耗能还容易扫漏。r_turn -0.15 * abs(angular_velocity) # rad/s有点像一个“平滑税”。策略学到的行为是尽量走直线、转缓弯。实测下来这个惩罚带来的一个意外收益是机器人学会了“沿墙角走”这种高效路径因为墙边的转向天然少。第7项路径平滑奖励0.005 / (1 jerk)这是“柔软度”奖励。jerk是加加速度加速度的导数我模拟器里能直接读到。值越大说明路径越“颠簸”奖励就越小。0.005/(1jerk)这种形式的妙处在于数值永远为正但上限不超过0.005幅度受到严格压制。它是“锦上添花型”奖励不会干扰主目标。其实第6和第7项单独看都微不足道但两项放一起就形成了一个“优雅路径”的软约束。清扫这种任务路径方差太大很容易漏扫而这两项把路径方差压下来了。3.4 约束惩罚组告诉机器人“不许浪费”第8项原地卡死惩罚-2.0这是很多RL机器人项目里踩坑最深的一项但往往要到训练中后期才暴露。机器人在墙角、障碍物缝隙里卡住后策略会陷入两种循环要么一直输出一个“试图前进”但物理上无法前进的动作要么原地左右摆动。检测卡死很简单持续10步位置变化小于1cm、里程计位移却大于阈值就判定卡死。我额外加了一个“摇摆检测”方位角在正负15度之间反复翻转超过4次也算。if displacement 0.01 and odometry_delta 0.3: r_stuck -2.0这项惩罚的一次性力度很大就是为了让策略宁可绕路也不要在墙角死磕。实测训练曲线里加了这项之后地图右下角那个L形障碍物区域再也没出现“卡壳”的现象。第9项时间效率惩罚-0.005 * step步数惩罚是RL任务的老熟人了。步数越长累积负奖励越多。作用就是逼策略用尽量少的步数完成尽量多的清扫。但注意这个值一定不能大。如果-0.01以上策略会变得“赶时间”路径粗放边角细节放弃因为“多花一步要多扣一分”的恐惧压过了清扫收益。这里我用了0.005折中。第10项能耗成本惩罚-0.05 * distance现实中的扫地机器人要耗电仿真里我用“单位里程能耗”近似。每走1米扣0.05分。这个压力对“绕圈自嗨”是第二道防线如果重复清扫惩罚漏判了能耗惩罚也会让绕圈变贵。严格来说这层的存在意义不是省电-0.05很小而是给策略增加一个“里程”的参照系。清扫任务的本质是用最短的路径覆盖最多的面积没有这一项策略只会考虑面积不考虑腿脚。3.5 关于“势函数塑形”的一句提醒懂RL理论的朋友可能会问你加了这么多边边角角的惩罚跟奖励塑形定理冲突吗Ng等人在1999年证明过如果额外奖励可以写成势函数形式的差分那最优策略不变。我用了边界清扫奖励、平滑奖励、重复清扫惩罚这些项严格意义上它们确实可能改变最优策略不是“无害塑形”。但工程上的取舍是我本来就不追求“理论上的最优清扫策略”我要的是“符合用户需要的清扫行为”。这算是一种有意的“妥协”。如果你做的是学术实验建议严格保留势函数条件做应用项目的话还是要以行为效果为导向。4. 权重配平与归一化复合奖励的核心手艺4.1 每一项奖励必须先做“量级体检”复合奖励最容易犯的错误不是“奖励项设计得不好”而是“权重配平拍脑袋”。比如步数惩罚写0.01碰撞惩罚写1.0看起来没问题但实际一跑步数累积的惩罚远远压过碰撞惩罚策略就变成了“宁可撞过去不想多走一步”。我习惯在训练前先做一次“单奖励项量级估算表”。拿上面的设计举例奖励项单步期望量级单回合预估值约800步占比增量覆盖0.054045%完成奖励-1214%边界覆盖0.021618%碰撞惩罚-0.02-16-18%转弯惩罚-0.05-40-45%其他小幅度±10-这个表算完你会立刻发现转弯惩罚的量级可能过大了。所以在正式训练之前我把转弯惩罚从0.2下调到了0.15又把边界清扫奖励从1.2上调到1.5左右的区间做测试。量级表的作用不是精确预测而是防止某个奖励项“统治”训练目标。4.2 动态奖励缩放当覆盖率达到99%时清扫覆盖率到后期是个很尴尬的问题。覆盖率从30%涨到60%增量奖励好拿从85%涨到99%每走一步覆盖率变化微乎其微增量奖励接近0策略就会失去继续扫残边角的动力。我的解法是“分段放大”当覆盖率超过85%后增量奖励系数自动乘以3。if current_coverage 0.85: scale_factor 3.0 else: scale_factor 1.0这个trick给训练后期补了一口“扩张器”。没有它我估计778分至少要打到1300步才可能实现而且大概率中途就收敛到95%不动了。4.3 每一个权重调整都必须是“单一变量”整个训练过程中我调整了10多次奖励权重每一次只改一项。你可能会觉得没效率但RL训练噪声极大一次改两个权重你根本没法判断到底是谁带来的提升。我把这个当纪律执行后训练的归因变得特别清晰。比如有一次我同时把转弯惩罚从0.15改到0.1又把碰撞阈值从20N改到30N结果曲线忽高忽低我花了整整两天才搞明白是碰撞阈值松了导致“硬碰硬”增多。后来我严格执行“一次只改一个参数”的原则大约50%的改进都能在24小时内定位到具体原因。5. 训练中的常见问题四个坑每一个我都踩过5.1 奖励洪泛当奖励项太多梯度变成一团浆糊复合奖励的“副作用”随项数增加而增加。有段时间我把奖励项加到了14个比现在还多4个结果PPO的critic完全学不过来了策略更新频率也从3Hz掉到1Hz训练根本跑不动。原因倒不复杂critic网络要拟合的是“状态到期望累积奖励”的映射。奖励函数越复杂、分量越多、单项信号越噪critic的预测误差就越大随之策略梯度也越歪。我的办法是“合并同类项”。14项里把两个频次相近的惩罚项合成了一个“行为浪费惩罚”把三个跟覆盖率相关的强化项统一成“覆盖率复合加成”。变成10项之后训练稳定多了。经验法则复合奖励不要超过12项最好控制在8-12项之间。5.2 奖励循环依赖机器人发现“反复扫同一个格子”也能刷分虽然加了重复清扫惩罚但机器人还是找到过一个漏洞它在两个相邻栅格之间反复横跳。每次跳到新格子上都算“清扫了一个新区域”重复清扫惩罚只在“同一个格子6秒内重扫”时才触发隔一个格子跳着扫惩罚形同虚设。这个案例让我意识到重复检测的时间窗太短判断空间太窄就会被策略钻空子。我最后把重复区域判断扩展成“以机器人为中心的3×3邻域内存在最近6秒被扫过的格子”就算重复一下子堵住了漏洞。5.3 局部最优宁可“安全挂机”不愿冒险碰角落有一次训练中期覆盖率卡在88%不再上涨。我检查奖励日志发现策略已经进入“安全挂机”状态在地图中央一遍遍地走已经扫过的路线拿了低水平但稳定的增量奖励坚决不去碰角落。这其实是一个典型的强化学习探索问题角落区域覆盖率的增量奖励虽然单次更高但要到达那里需要经历一段“低奖励走廊”策略的价值函数估计撑不过这段区间。解法不是调权重而是调探索。我给探索噪声action noise加了一个周期性放大每2000步噪声标准差从0.1放大到0.3持续500步。相当于每隔一段时间把机器人踢一脚强迫它离开舒适区去试错。用了这个招之后覆盖率突破了88%涨到了93%。5.4 训练曲线“假回暖”奖励均值在涨行为质量在跌奖励工程的另一个陷阱是复合奖励的总分可能涨但单项奖励的表现未必都好。有一次训练得分从500分涨到600分我以为模型变好了。结果可视化一看机器人学会了“横冲直撞快速扫完大面积然后疯狂碰撞”。问题出在总奖励的加权和掩盖了碰撞惩罚的上升。因为覆盖率涨得更快总奖励还是净增长。可视化回放的时候人一看就露馅了。我后来养成了一个习惯每次训练达到一个里程碑比如提升100分就回放一遍10个奖励项的日志曲线看各项是否健康。如果某项异常恶化哪怕总分在涨也要回滚配置。6. 迭代实录从100分到778分的完整路径6.1 阶段一补全约束从100分到220分这一阶段做的事情加了第4、6、8项重复清扫惩罚、转弯惩罚、卡死惩罚。训练日志上最明显的变化是“绕圈自嗨”消失路径变得收敛。22万步左右奖励均值开始稳定在220分。这次改进验证了“行为惩罚”的价值。但问题也很明显边界覆盖率几乎没有提升策略依然龟缩在开阔区域。6.2 阶段二拆出边界覆盖率从220分到430分把覆盖率拆成“中部覆盖率”和“边界覆盖率”并给边界奖励加系数是这次跨越的核心。训练到40万步时模型开始出现明显的贴墙行为。我看了录制下来的动作录像机器人在墙角附近不再“路过”而是真正地停下来沿边扫一圈。这个从“路过”到“驻留”的行为变化靠的就是一个单独拆出来的边界奖励。430分时覆盖率94%边界覆盖率81%。但此时路径效率很差机器人绕路绕得很夸张一整堵墙扫下来要走两趟。6.3 阶段三路径平滑与动态缩放从430分到610分加了路径平滑奖励、调整转弯惩罚权重同时对覆盖率后期做动态放大。训练第58万步的时候覆盖率第一次超过98%边界覆盖率到了91%。这个阶段还有个隐藏工程我把时间效率惩罚从每步0.01降到了0.005。原因是惩罚过重导致策略“赶时间冒进”墙边清扫匆匆忙忙。调低后单位任务的清扫深度上升总分又从610分小幅上升到650分附近。后来我把“完成任务奖励”从10分调整到了12分总分突破670分。6.4 阶段四打磨与稳定性最终锁在778分最后一个阶段主要清理了“探索噪声周期性放大”策略引入的副作用探索阶段碰撞率升高导致策略偶尔回退到保守模式。我用学习率分段衰减前30万步LR3e-4后30万步LR1e-4替代统一的探索噪声稳定性明显提升。最终评测时100个随机初始化的地图中96个地图覆盖率达到95%以上平均奖励分数定在778分。这个数字的含金量不在于“高”而在于稳定。同配置模型跑不同随机种子分数方差只有±35分左右——这对清扫类任务来说已经算非常收敛了。7. 最后分享几条我现在回头看最想告诉自己的经验奖励工程没有标准答案但有些弯路是可以直接避开的。第一奖励项要少而精但要“结构冗余”。少而精是不要让奖励项之间过度耦合导致调一个权重牵一发动全身结构冗余是说同一个目标你可以用两个角度去约束比如重复清扫惩罚能耗惩罚双保险。关键是冗余要有边界别无限堆。第二可视化永远比数字更能说明问题。我大量时间不是在看奖励曲线而是在看机器人行为视频。一段60秒的失败视频比60页奖励日志更能说明策略在钻什么空子。每次训到新的里程碑都值得录下来慢放看看尤其是墙角、障碍物缝隙、门框这三个地方。第三权重配平是“算”出来的不是“感觉”出来的。上面那个量级估算表建议每个项目都建。我知道很多人嫌麻烦但一次量级算错导致的白训一个星期远比你五分钟填一张表贵得多。第四“完成目标”和“节约资源”之间需要一个缓冲。清扫任务里“完美主义”的机器人可能为了多扫2%的灰尘多走30%的路程这个策略显然不实用。所以我在完成覆盖率阈值上用了95%而不是98%作为一个硬性门槛并在奖励计算里对到达95%之后的继续清扫做了衰减。你做类似任务时不管任务是搬运还是分拣都要想清楚这个缓冲区间放哪里。第五奖励工程不是一次性的它是跟训练过程一起长大的。同样的奖励函数在训练前期、中期、后期的效果完全不同。前期探索阶段需要“鼓励尝试”的奖励中后期需要“约束行为”的惩罚。所以我建议提前规划奖励调整的演练环境每次调整前先在低步数下做一对A/B测试确认有效再放到长训练里。这些经验不是什么高深理论就是土办法加耐心。但说实话清扫机器人的强化学习技术瓶颈从来不在车体、不在感知就在奖励定义上——你把“你到底想要一个什么样的清扫机器人”想清楚了奖励函数其实就写出来一半了。另一半是拿训练失败喂出来的。
返回列表