ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

从零实践强化学习:奖励设计与Q-Learning入门指南

从零实践强化学习:奖励设计与Q-Learning入门指南 1. 从“世界冠军”这个前缀说起为什么强化学习需要“陪练思维”第一次看到“世界冠军带你从零实践强化学习”这个标题我脑子里蹦出来的不是算法公式而是一个很具体的画面一个职业棋手坐在棋盘前旁边站着一个完全不懂棋的普通人棋手说“你随便下下完我告诉你哪一步臭”。这个画面其实就是强化学习最朴素的形态——智能体在环境里乱动环境给它反馈它慢慢学会怎么动才能拿到更多奖励。很多人学强化学习卡在第一步不是数学太难而是没有建立起“陪练思维”。他们习惯性地把强化学习当成监督学习来学找数据集、标标签、训模型、看准确率。但强化学习里根本没有现成的标签标签是智能体自己“试”出来的。这就好比你想学游泳看再多教学视频都没用必须下水呛几口身体才会告诉你“这个姿势要沉”。“世界冠军”这个前缀之所以有价值是因为它暗示了一种高水平的示范与反馈机制。在强化学习里这个“冠军”可以是人类专家也可以是一个已经训练好的强策略还可以是环境本身设计的精妙奖励函数。从零实践强化学习核心不是背下PPO、DQN的公式而是理解一个智能体如何从完全无知到逐渐开窍的完整链路。这篇文章适合谁看如果你已经学过机器学习基础知道什么是损失函数、梯度下降但一打开强化学习教材就被MDP、贝尔曼方程、策略梯度绕晕那这篇就是写给你的。如果你是完全零基础也没关系我会用大量生活化的类比把概念拆开。整篇内容会围绕“从零搭建一个能跑通的强化学习实践流程”展开不堆公式重点讲为什么这么设计、实际跑起来会遇到什么、怎么判断自己的智能体是不是在学。提示强化学习的“从零”不是指从零写代码而是指从零理解一个智能体如何通过试错获得策略。代码可以抄但试错过程中的判断逻辑必须自己建立。2. 强化学习的第一道门槛把“奖励”翻译成智能体能懂的语言2.1 奖励不是打分而是智能体唯一的生存信号很多人第一次接触强化学习会下意识地把奖励理解成“考试分数”——越高越好但具体高多少、什么时候给并不在意。这是一个致命的误解。在强化学习里奖励是智能体唯一的信息来源它决定了智能体学什么、怎么学、学多快。举个例子。假设你要训练一个智能体玩一个简单的网格游戏从左上角走到右下角每走一步扣1分走到终点加100分。如果你把“每走一步扣1分”改成“每走一步扣0.1分”智能体的行为会完全不同。扣1分时它会拼命找最短路径甚至冒险穿墙扣0.1分时它可能慢悠悠地绕路因为“磨蹭”的代价变小了。这就是奖励设计的威力——你给什么奖励智能体就变成什么样子。在实际操作中我习惯把奖励设计分成三层来思考稀疏奖励只有达到目标才给奖励。比如迷宫走到出口才加1分。这种设计最接近真实世界但智能体学得极慢因为它大部分时间都在“盲走”得不到任何反馈。稠密奖励每走一步都给反馈。比如离目标越近奖励越高。这种设计学得快但容易让智能体“钻空子”——它可能发现原地转圈也能刷分因为转圈时离目标的距离在微小波动。分层奖励把大目标拆成小目标每个小目标给一次奖励。比如先走到中间点给10分再走到终点给100分。这是实践中用得最多的折中方案。注意奖励设计没有标准答案但有一个铁律——奖励必须能区分“好行为”和“坏行为”。如果你自己都说不清什么样的行为该拿高奖励智能体更不可能学会。2.2 从零写一个奖励函数的实操步骤假设我们要做一个最简单的实践项目让一个智能体学会在一条直线上走到目标点。环境是一条长度为10的线段智能体初始位置在0目标位置在10。动作空间是离散的向左走一步、向右走一步、原地不动。第一步定义状态。状态就是智能体当前的位置用一个整数表示范围是0到10。第二步定义动作。动作空间是{0, 1, 2}分别代表左、右、停。第三步定义奖励。这里我试过三种方案实测效果差异很大奖励方案具体设计实测结果方案A到达目标100其他情况0智能体平均需要8000步才能稳定到达前期几乎不学方案B每向右走一步1向左走一步-1到达目标100智能体300步内就能学会一直向右走但会“冲过头”方案C距离目标越近奖励越高公式为-abs(位置-10)智能体200步内学会稳定停在目标点但偶尔会抖动最后我选了方案C的变体奖励 -abs(位置-10) 到达目标额外加50。这样智能体既有稠密的距离反馈又有稀疏的到达奖励学得又快又稳。第四步定义终止条件。到达目标位置或者步数超过200步回合结束。这个例子虽然简单但它包含了强化学习奖励设计的全部核心逻辑稠密反馈引导方向稀疏奖励确认目标终止条件控制节奏。你把这个逻辑套到任何任务上都不会出大错。2.3 奖励缩放一个容易被忽略但影响巨大的细节在实际跑代码时我发现一个很隐蔽的坑奖励的绝对数值会影响学习速度。如果你把到达奖励设成10000每步惩罚设成0.01智能体会变得极度保守因为它害怕任何一步的惩罚哪怕这个惩罚小到可以忽略。反过来如果到达奖励只有1每步惩罚是-1智能体又会变得极度冒险因为它觉得“反正走错一步就扣光了不如赌一把”。我的经验是把单步奖励控制在[-1, 1]之间把目标奖励控制在[10, 100]之间。这个比例下智能体既能感受到每一步的轻重又不会因为目标奖励太大而忽略过程。如果你用的框架有奖励裁剪功能可以开启但要注意裁剪阈值不能太小否则会丢失奖励的区分度。3. 环境搭建为什么我劝你先用现成环境再自己造轮子3.1 从零手写环境的代价与收益很多教程一上来就教你用gym.make(CartPole-v1)然后直接开始训模型。这没错但如果你真的想“从零实践”我建议你至少手写一次环境。原因很简单只有自己写过环境你才会真正理解状态、动作、奖励、终止这四个要素是怎么耦合在一起的。我最早学强化学习时直接拿现成环境跑DQN代码跑通了曲线也上升了但我完全不知道智能体到底在学什么。后来我自己写了一个“猜数字”环境智能体每次猜一个0到100的数环境告诉它“大了”或“小了”猜中给奖励。写完之后我才恍然大悟——原来状态可以是一个区间动作可以是区间内的一个数奖励可以是“距离真实值多远”的负数。手写环境的代价是耗时。一个最简单的环境从设计到调试至少需要半天。但收益是长期的之后你看任何强化学习论文都能在脑子里把它的环境还原出来理解作者为什么这么设计状态和奖励。3.2 一个最小可运行环境的代码骨架下面是我常用的环境骨架基于Python不依赖任何强化学习框架只用numpy。你可以直接复制过去改import numpy as np class LineEnv: def __init__(self, length10): self.length length self.position 0 self.steps 0 self.max_steps 200 def reset(self): self.position 0 self.steps 0 return self.position def step(self, action): # action: 0左, 1右, 2停 if action 0: self.position max(0, self.position - 1) elif action 1: self.position min(self.length, self.position 1) # action 2 时位置不变 self.steps 1 # 奖励设计 reward -abs(self.position - self.length) done False if self.position self.length: reward 50 done True if self.steps self.max_steps: done True return self.position, reward, done, {}这个骨架只有30行但它包含了强化学习环境的全部要素。你可以把LineEnv换成任何任务把位置换成股票价格把动作换成买/卖/持把奖励换成收益就是一个交易环境。环境是强化学习的试验场试验场越简单你越容易看清智能体的行为。3.3 环境验证怎么判断你的环境没写错写完环境后不要急着上算法。先做三件事第一手动跑几个回合。用随机策略跑10个回合看看奖励范围是否合理。如果随机策略的奖励是-1000到-900而最优策略的奖励是100那说明奖励尺度有问题智能体很难从-1000爬到100。第二检查状态边界。把智能体放在边界位置执行所有动作看看状态是否越界。我踩过的坑是位置在0时向左走代码里写了max(0, position-1)但忘了在奖励里体现“撞墙惩罚”结果智能体学会了疯狂撞墙因为撞墙不扣分还能刷步数。第三验证终止条件。确保达到目标或超过步数时done一定为True。如果done永远为False智能体会陷入无限循环训练永远不结束。提示环境写完后用随机策略跑100个回合记录平均奖励和平均步数。这两个数字是你后续判断智能体是否在学的基准线。如果训练后的智能体还不如随机策略那一定是哪里出了问题。4. 算法选型从表格法到策略梯度什么时候该换武器4.1 为什么你的第一个算法应该是Q-Learning而不是PPO现在网上很多教程一上来就讲PPO因为PPO在连续控制任务上表现好。但如果你是从零实践我强烈建议你先用Q-Learning。原因有三个第一Q-Learning是表格法状态和动作都是离散的你可以把Q表打印出来看。你能亲眼看到每个状态-动作对的数值在训练过程中怎么变化。这种“看得见”的反馈对建立直觉至关重要。PPO是神经网络你只能看到损失曲线看不到策略内部在发生什么。第二Q-Learning的更新公式只有一行Q(s,a) Q(s,a) α * (r γ * max(Q(s,a)) - Q(s,a))。这一行包含了强化学习的全部核心思想当前估计、即时奖励、未来折扣、学习率。你把这行公式手写十遍比看十篇PPO论文都有用。第三Q-Learning的失败模式很直观。如果学习率太大Q值会震荡如果折扣因子太小智能体会短视如果探索率太高智能体会一直乱走。这些失败模式在PPO里会被神经网络的非线性掩盖你很难定位问题。我的建议是用Q-Learning跑通一个离散任务再用PPO跑通一个连续任务。两个都跑通之后你自然就知道什么时候该用哪个了。4.2 Q-Learning在直线环境上的完整实现继续用上面的LineEnv状态是0到10的整数动作是0到2的整数。Q表就是一个11x3的矩阵。import numpy as np env LineEnv() q_table np.zeros((11, 3)) alpha 0.1 gamma 0.9 epsilon 0.1 episodes 500 for episode in range(episodes): state env.reset() done False while not done: if np.random.random() epsilon: action np.random.randint(3) else: action np.argmax(q_table[state]) next_state, reward, done, _ env.step(action) # Q-Learning更新 best_next np.max(q_table[next_state]) q_table[state, action] alpha * (reward gamma * best_next - q_table[state, action]) state next_state跑完500个回合后把q_table打印出来你会看到在位置0到9时动作1向右的Q值最高在位置10时动作2停的Q值最高。这就是智能体学到的策略。这里有几个参数需要解释alpha0.1学习率。太大如0.9会导致Q值震荡太小如0.01会导致学习过慢。0.1是一个经验值适合大多数离散任务。gamma0.9折扣因子。它决定了智能体有多看重未来奖励。0.9意味着10步之后的奖励打0.35折。如果任务需要长期规划可以调到0.99。epsilon0.1探索率。10%的时间随机行动90%的时间按Q表行动。这个比例在训练初期可以设高一点如0.5后期逐渐降低。4.3 从Q-Learning切换到策略梯度的信号Q-Learning很好但它有两个硬伤状态空间不能太大动作空间不能连续。如果你的状态是图像或者动作是关节角度Q表就无能为力了。这时候你需要策略梯度方法比如REINFORCE或PPO。什么时候该切换我的判断标准是当你发现Q表的维度超过1000x1000时就该考虑神经网络了。1000x1000的Q表有100万个条目每个条目需要至少几十次访问才能估计准确这意味着你需要上亿步的训练。而神经网络可以通过泛化用更少的样本学到相似的状态。从Q-Learning切换到策略梯度最大的思维转变是你不再估计每个动作的价值而是直接学习一个策略函数输入状态输出动作的概率分布。这个转变类似于从“查字典”变成“学语法”——字典只能查你见过的词语法能生成你没见过的句子。5. 训练过程中的“灵异事件”智能体为什么不学、学歪、学废5.1 智能体完全不学奖励曲线一条直线这是最常见的问题。你跑了1000个回合奖励曲线纹丝不动和随机策略一模一样。可能的原因有五个第一奖励太稀疏。如果只有到达目标才给奖励智能体在随机探索阶段几乎不可能碰到目标。解决办法是加入稠密奖励或者用课程学习——先让目标离得近再逐渐拉远。第二探索率太低。如果epsilon0.01智能体99%的时间都在按当前Q表行动而Q表初始全是0argmax返回的动作永远是第一个动作。解决办法是把epsilon初始值设高比如0.5然后慢慢降到0.05。第三学习率太大。Q值更新时如果alpha1新估计完全覆盖旧估计Q值会剧烈震荡永远收敛不了。解决办法是把alpha降到0.01到0.1之间。第四折扣因子太小。如果gamma0.1智能体只关心下一步的奖励而下一步的奖励通常是0因为还没到目标所以它学不到任何长期策略。解决办法是把gamma调到0.9以上。第五状态表示有问题。如果状态是连续的但你直接把它当离散的用智能体可能永远无法区分相似状态。解决办法是做状态离散化或者改用神经网络。我踩过最坑的一次是奖励函数里写了reward -abs(position - target)但忘了在到达目标时给正奖励。结果智能体学会了“原地不动”因为原地不动时距离目标的距离不变奖励是稳定的负数而乱走会让奖励波动。智能体是极度风险厌恶的它宁愿要稳定的-5也不要波动的-3到-10。5.2 智能体学歪了奖励很高但行为很蠢这种情况比完全不学更隐蔽。奖励曲线在上升但你一看智能体的行为发现它在“刷分”。比如在直线环境里智能体发现“向右走一步再向左走一步”可以无限循环而每步的奖励是-abs(position-10)如果它在位置9和10之间来回走奖励是-1和0交替平均-0.5比一直向右走奖励从-10到0的初期奖励高得多。这就是奖励黑客现象。智能体没有学会完成任务而是学会了利用奖励函数的漏洞。解决办法有两个一是重新设计奖励让刷分行为的奖励低于正常行为二是加入动作惩罚每走一步额外扣一个小分让刷分变得不划算。我的经验是奖励函数写完后自己先模拟几种“作弊策略”看看它们的奖励是不是比正常策略高。如果是赶紧改奖励。这个步骤花10分钟能省你10小时的训练时间。5.3 智能体学废了训练后期突然崩溃有时候奖励曲线先上升然后突然断崖式下跌再也回不去了。这在策略梯度方法里尤其常见原因是策略更新步长太大导致策略崩溃。神经网络输出的动作概率分布突然变得极端比如某个动作的概率从0.3变成0.99智能体失去了探索能力陷入局部最优。解决办法是使用PPO的裁剪机制限制每次策略更新的幅度。PPO的裁剪参数通常设0.1到0.2意思是新策略和旧策略的概率比不能超过1.2或低于0.8。这个约束看起来很小但它能防止策略“一步走太大扯到蛋”。另一个原因是学习率没有衰减。训练初期需要大学习率快速探索训练后期需要小学习率精细调整。如果学习率一直不变后期就会在最优解附近震荡甚至震荡出去。解决办法是加一个学习率衰减策略比如每1000步乘以0.99。注意训练崩溃后不要直接重启训练。先保存崩溃前的模型然后降低学习率从崩溃前的检查点继续训练。很多时候稍微调小学习率就能救回来。6. 从“能跑”到“跑得好”我常用的调参顺序与评估方法6.1 调参不是玄学而是有优先级的排查强化学习的超参数很多但它们的优先级差别巨大。我通常按以下顺序调优先级参数作用常用范围调整方向1奖励函数决定智能体学什么任务相关先确保奖励能区分好坏行为2探索率决定智能体探索多少0.05~0.5先高后低逐渐衰减3学习率决定更新步长0.0001~0.1先大后小配合衰减4折扣因子决定未来奖励权重0.9~0.99长期任务用大值5网络结构决定拟合能力2~4层先小后大过拟合再减这个顺序的逻辑是奖励函数错了后面全错探索率错了学不到东西学习率错了学不稳定折扣因子错了学不到长期策略网络结构错了最多是拟合能力不足。所以每次调参从优先级高的开始不要一上来就调网络层数。6.2 评估智能体是否真的学会了训练奖励高不代表智能体学会了。我见过太多案例训练奖励曲线很漂亮但一测试就原形毕露。评估智能体需要看三个指标第一测试奖励的均值和方差。用训练好的策略跑100个回合计算平均奖励和标准差。如果均值高但方差也高说明智能体不稳定可能在某些初始状态下表现很差。第二行为可视化。把智能体的动作序列打印出来或者画成图。在直线环境里如果智能体从位置0出发一路向右走到10然后停下那就是学会了。如果它走到8又退回6再走到9又退回7那就是没学扎实。第三泛化测试。改变初始状态或环境参数看看智能体还能不能完成任务。比如把直线长度从10改成15如果智能体还能走到终点说明它学到了“向右走”的通用策略而不是死记硬背了“从0走到10”的固定路径。我习惯在训练过程中每100个回合做一次评估把评估奖励和训练奖励画在同一张图上。如果评估奖励远低于训练奖励说明智能体过拟合了训练环境需要增加探索或正则化。6.3 一个容易被忽略的细节随机种子的影响强化学习对随机种子极其敏感。同一个算法同一个环境换个随机种子结果可能天差地别。我试过用5个不同的随机种子跑同一个配置最终奖励的波动范围能达到30%。所以永远不要用单次实验的结果下结论。至少跑3到5个随机种子看平均表现。如果某个配置在5个种子上都稳定那才是真的好配置。如果只有1个种子好其他4个都崩那说明这个配置是运气好不是真的好。在代码里我通常这样设置import random import numpy as np import torch def set_seed(seed): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) if torch.cuda.is_available(): torch.cuda.manual_seed_all(seed)然后在实验循环里用不同的seed跑多次记录每次的最终奖励最后取平均和标准差。这个习惯能帮你避免很多“假阳性”的结论。7. 从零实践之后下一步该往哪里走跑通一个最简单的强化学习项目后你可能会觉得“就这”——确实直线环境太简单了智能体几分钟就学会了。但这几分钟里你经历的是强化学习的完整闭环设计环境、定义奖励、选择算法、调参、评估、排错。这个闭环跑通了后面换任何任务都是在这个闭环上做替换。下一步我建议你尝试把直线环境改成二维网格。状态从一维变成二维动作从三个变成四个上下左右奖励还是距离目标越近越高。你会发现Q表的维度从11x3变成100x4训练时间变长但智能体依然能学会。这个过程中你会直观感受到状态空间增长对训练效率的影响。再下一步你可以尝试把Q-Learning换成DQN。DQN用神经网络代替Q表能处理连续状态。你会遇到新的问题经验回放、目标网络、梯度爆炸。每一个问题都会逼你去理解新的概念。但因为你已经跑通过表格法你知道“理想情况下应该发生什么”所以当DQN出问题时你能更快定位。最后如果你对策略梯度感兴趣可以试试REINFORCE算法。它比Q-Learning更简单只有一行更新公式theta alpha * reward * grad_log_prob(action)。但它的方差极大训练极不稳定。你会亲身体会到“为什么需要基线”和“为什么需要优势函数”。这些体会比看任何教材都深刻。我个人在实际操作中的体会是强化学习最难的不是算法而是判断“智能体到底在干什么”。算法是死的环境是活的奖励是你写的但智能体的行为往往出乎你的意料。每次训练前先问自己三个问题我的奖励能区分好坏行为吗我的探索率够高吗我的评估方法能反映真实能力吗这三个问题答清楚了训练就成功了一半。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表