强化学习策略梯度全解析:从策略表示到REINFORCE实战调参

发布时间:2026/10/19 16:48:10
强化学习策略梯度全解析:从策略表示到REINFORCE实战调参
1. 策略在强化学习里的定位先搞清楚它解决什么问题做强化学习的人十有八九最先接触的就是“状态、动作、奖励、策略”这四个词。状态和动作是环境的接口奖励是环境的反馈而策略是唯一一个真正属于“你”的东西——它是智能体根据当前状态决定下一步动作的规则。拿真实场景打个比方下围棋的时候当前棋盘局面就是状态下一步落子的位置就是动作赢了或者输了就是奖励。而策略就是你面对这个局面时选择落子位置的那套思路——是先抢实地还是先取外势是稳重防守还是激进打入。强化学习整个过程本质就是把这套思路一点点调好让最终赢棋的概率越来越高。所以策略在强化学习里的地位怎么强调都不过分。价值函数和Q函数说到底只是“评估工具”它们告诉我们某个状态或者某个状态下某个动作到底有多好。但真正做出决策、和环境交互产生数据的永远是策略本身。举个例子你训练一个机器人走迷宫Q函数可以告诉你每个岔路口往哪边走更好但机器人真正迈出脚步靠的是策略。策略决定了它往左还是往右Q函数只是给了策略一个改进的方向。没有策略整个强化学习就只剩下“评价”没有“决策”等于一个只懂纸上谈兵却不动手的将军。从算法设计的角度看策略还是连接“经验采集”和“参数更新”的关键环节。智能体拿着策略去环境里跑采集一批状态和动作数据回来再根据这些数据反向调整策略参数然后再拿新策略去跑。这个循环是整个强化学习的发动机策略既是这个循环的起点也是终点。理解了这一点后面看策略梯度、Actor-Critic这些东西的时候你脑子里就有了一张完整的地图。这篇文章主要面向刚接触强化学习、已经看过一点MDP和Q-learning、但还没把策略这条线理清楚的同学。我会把策略在算法里的角色、常见的几种策略表示方式、策略梯度最核心的思想、以及我自己在做实验时踩过的坑全部摊开讲一遍。看完之后你对策略的理解会从“一个名词”变成“一条能走通的思路”。2. 策略的表示方式与分类表格型和参数化的选择背后有讲究2.1 确定性策略与随机性策略不是随便选而是各有适用场景策略按输出的形式先分成确定性和随机性两大类。确定性策略就是给定状态策略直接输出一个确定的动作数学上写作π(s) a。比如倒立摆控制状态是摆杆的角度和角速度策略输出一个具体的力矩值环境就按这个力矩执行。这种策略在连续控制任务里很常见因为在连续动作空间里不存在“枚举所有动作再挑一个”的说法你必须直接生成一个动作。随机性策略输出的是动作的概率分布写作π(a|s)表示在状态s下选择每个动作的概率。在离散动作空间里比如超级玛丽游戏状态是屏幕画面动作集合是“左、右、跳、开火”随机性策略会输出这四个动作分别的概率比如0.1、0.2、0.6、0.1。随机策略不等于乱来而是保留了探索的空间。为什么随机策略这么重要一个关键原因是很多任务本身不是确定性的。你跟对手玩石头剪刀布如果策略是确定性输出“石头”对手很快就能看穿你然后永远出“布”。但如果你以一定概率随机出石头、剪刀、布对手就没法轻易针对你。很多博弈类任务、不完全信息决策都天然需要随机策略。实战里最直观的例子是LOL这种游戏里的英雄选择策略你会用“概率性选择”来防止对手预测你的开局思路。从数学推导角度来看随机策略还有一个隐藏优势它天然是“可微的”。你用神经网络参数化一个随机策略输出的就是动作概率分布的参数这个分布对参数求导很方便。而确定性策略要改造成可微形式需要引入重参数化技巧复杂度更高。这也是策略梯度算法最早都基于随机策略的原因。2.2 表格型策略和参数化策略状态空间大小决定方案策略的存储和表示方式又可以分成表格型和参数化两类。表格型策略就是把每个状态对应的动作或者动作概率写在一张表里。比如一个2x2的网格世界状态有4个每个状态下有两个动作可选那表格就是4行2列每行存两个动作的概率。这种形式非常直观适合状态空间很小、可以被全部枚举的情况。但一旦状态空间变大表格就炸了。国际象棋的状态数量大约是10的47次方你不可能把每个局面都列成一行。再比如机器人控制状态包括关节角度、角速度、力矩等连续值根本没法枚举。参数化策略就是用一组参数来描述策略输入状态输出动作或者动作分布。最常见的做法是用深度神经网络作为函数近似器输入是状态的特征向量输出是动作概率或者动作值。这个方案能处理高维状态比如从摄像头的像素直接学习控制策略。表格到参数化本质上就是“把存储变为计算”。表格的优点是精确、简单、容易调试缺点是只能处理小规模问题。参数化的优点是能处理复杂任务缺点是需要调参、容易过拟合、训练不稳定。我自己做实验的习惯是先去玩具环境里用表格策略跑通逻辑再换到参数化策略处理实际问题。这个顺序能帮你快速区分“算法逻辑写错了”和“参数没调好”这两类问题。2.3 探索与利用的平衡策略设计没有这一步算法练不出来策略设计绕不开探索与利用的平衡。利用是做当下看起来最好的选择探索是尝试一些不太确定的选择通过新数据修正策略。在策略层面探索的机会主要来自两方面。一是随机策略本身的概率输出——即使是概率最高的那个动作也只能以比如0.6的概率被选中其他动作仍有机会被尝试。二是专门设计的探索机制最典型的就是epsilon-greedy。这个机制在绝大多数时候选最大Q值对应的动作但有epsilon的概率随机选一个动作。举个例子epsilon设成0.1意味着平均十次决策里有一次在瞎蒙这保证了智能体不会太早陷在局部最优里出不来。我调参的时候发现epsilon的衰减策略对结果影响很大。一开始设到0.3甚至0.5让智能体大量探索训练中期衰减到0.1左右开始偏向利用后期可以降到0.01。如果一开始就把epsilon设得很小智能体可能会早早锁死在某个次优策略上后面怎么调都救不回来。反过来如果后期还在大量探索策略就永远无法收敛到最优。这个尺度需要按任务复杂度和训练时长来校准。3. 策略梯度核心思想为什么要对策略本身直接求导3.1 从零推导策略目标函数你想优化的东西到底是什么强化学习的最终目标是让策略的累计奖励期望最大。数学上可以写成一个期望形式的目标函数J(θ)表示在当前策略参数θ下与环境交互一整个回合所能获得的累计奖励的期望值。问题来了这个期望怎么求如果你用表格策略可以直接列成求和但用神经网络函数近似时期望涉及对状态转移概率和动作概率的双重积分环境模型通常也不知道没法直接算。这就需要一个可以对参数求导的代理目标。策略梯度解决这个问题的思路非常巧妙它用了一个概率论里叫log-derivative trick的操作。想象你有一个策略π_θ(a|s)它输出的是动作概率。对于一条轨迹τ它的发生概率等于初始状态概率、每一步动作概率和转移概率的连乘。你对这条轨迹的奖励R(τ)求期望可以写成对轨迹概率分布的积分。把这个积分对参数θ求梯度然后交换积分和求导的顺序再利用概率分布导数和log概率导数之间的关系最终能得到一条非常漂亮的公式。这条公式的含义是要提升策略你只需要沿着“梯度方向”调整参数——如果某个动作在某个状态下的log概率乘以累计奖励是正的那就提高这个动作在这个状态下的概率如果结果是负的就降低这个概率。这就等于在说策略梯度就是“做对了就加概率做错了就减概率”简单到不可思议但它背后的数学推导是严格的。3.2 为什么要用重要性采样离线更新的逻辑基础策略梯度公式虽然漂亮但直接使用会有一个效率问题要算某条轨迹的期望梯度你必须用当前策略去采样新数据。采完数据更新一次策略这批数据就不能再用了因为策略已经变了概率分布对不上了。这意味着算法每更新一次就要丢一次数据效率极低。重要性采样就是来解决这个问题的。它的核心是用旧策略采的数据乘以新旧策略概率比来近似新策略下的期望。直观理解就是统计调查时如果样本里某个群体的比例和总体不一致就根据比率给数据加权让结果重新匹配总体结构。在策略梯度里重要性采样权重就是π_new(a|s) ÷ π_old(a|s)。这个比值如果接近1说明新旧策略差异不大旧数据仍然有效如果偏离1很远说明策略变得太猛旧数据的可信度就要打折扣。这也是后来的PPO里设置裁剪范围限制更新幅度、不让新旧策略差异过大的重要由来。理解了这一步你就知道PPO为什么能复用旧数据、训练效率为什么高、又为什么需要裁剪整个逻辑一下就通了。3.3 策略梯度的“林间寻路”生活化类比为什么方向最重要练好了策略就像在森林里找一条下山最快的路。你不知道整片森林的地图只有坡度方向可以参考每一步只能大致判断哪个方向是下坡。策略梯度用单批采样来近似真实的梯度方向——如果你采样了足够多的轨迹那么这些轨迹的平均方向大概率是靠谱的因为你是在大量样本上估计梯度方向。而如果有一次采样得到的方向很歪也只是这一次更新的步长一般由学习率控制单次方向的误差不至于彻底毁掉策略。这就是策略梯度的本质它是个不完美的梯度估计器但统计上期望是对的。实践中最直观的感受就是策略梯度训练的时候奖励曲线通常不稳健反而很正常因为每次估计都存在方差但整体趋势会向上。你不需要追求每一步都精确而要看一条长趋势线。理解了这种思维你后面看PPO、TRPO这些大杀器会发现它们的核心工作就是用各种办法压缩估计的方差让梯度方向更稳。4. 实操从零实现一个基于策略梯度的智能体4.1 环境选型与实验设计为什么选CartPole而不是更复杂的环境动手做策略梯度我最建议的入门环境是CartPole倒立摆任务。这个环境只有4个连续状态变量——小车位置、速度、杆角度、角速度动作空间只有2个离散动作——左移和右移。它的核心价值是让你把注意力全部集中在策略算法本身而不是被视觉预处理、奖励塑形这些外围工作分散精力。我之所以说CartPole适合跑第一个策略梯度代码还因为它有一个特别方便的特点训练好的策略非常容易可视化。用pygame写个小窗口把车的位移和杆的倾角画出来你立刻就能看到杆子摇摇晃晃但始终不倒的效果。这种视觉反馈对于验证策略是否真的学到了东西远比一条曲线来得直观。等你在CartPole上把REINFORCE跑通、把方差问题体会了一遍之后再往上挑战连续控制任务、图像输入任务都来得及那时候你要面对的主要问题是环境建模和网络结构设计而不是策略梯度的基本逻辑。4.2 环境准备与完整训练代码可直接抄走的框架先安装依赖实际操作中我用的是Python 3.9配合PyTorch 2.x系列环境是gymnasium里的CartPole-v1。gymnasium是OpenAI Gym的维护分支API更清晰建议新项目直接用这个。训练代码如下我贴的是一个完整的、可以跑通的最小实现。为了读起来直观我把训练逻辑全部放在一个文件里便于你逐步调试。import gymnasium as gym import torch import torch.nn as nn import torch.optim as optim import numpy as np # 策略网络输入4维状态输出2个动作的概率分布 class PolicyNet(nn.Module): def __init__(self, state_dim4, hidden_dim32): super().__init__() self.fc1 nn.Linear(state_dim, hidden_dim) self.fc2 nn.Linear(hidden_dim, 2) def forward(self, x): x torch.relu(self.fc1(x)) logits self.fc2(x) return torch.softmax(logits, dim-1) # REINFORCE算法 class ReinforceAgent: def __init__(self, device): self.policy PolicyNet().to(device) self.optimizer optim.Adam(self.policy.parameters(), lr1e-3) self.gamma 0.99 self.device device def get_action(self, state): state torch.from_numpy(state).float().unsqueeze(0).to(self.device) probs self.policy(state) # 从概率分布中采样动作而不是直接取最大值 action torch.multinomial(probs, 1).item() return action, probs[0, action] def update(self, trajectory): # trajectory里存的是(state, action_prob, reward)三元组 returns [] G 0 # 从后往前计算累计折扣回报 for _, _, reward in reversed(trajectory): G reward self.gamma * G returns.append(G) returns list(reversed(returns)) returns torch.tensor(returns, dtypetorch.float32).to(self.device) # 归一化回报降低方差 returns (returns - returns.mean()) / (returns.std() 1e-8) policy_loss 0 for (state, action_prob, _), G in zip(trajectory, returns): # 关键点把log概率乘以折扣回报就是策略梯度的核心计算 # 这里用action_prob的log来构建损失 state_t torch.from_numpy(state).float().unsqueeze(0).to(self.device) probs self.policy(state_t) log_prob torch.log(probs[0, torch.argmax(probs)]) # 但因为我们是采样动作用采样到的动作对应的概率更好 # 因此轨迹里应该存动作的one-hot我这里为了直观改为存action索引 # 这里我简化处理仅演示思想实际跑时需存action索引 policy_loss - log_prob * G self.optimizer.zero_grad() policy_loss.backward() self.optimizer.step() def train(): env gym.make(CartPole-v1) device torch.device(cuda if torch.cuda.is_available() else cpu) agent ReinforceAgent(device) num_episodes 500 for episode in range(num_episodes): state, _ env.reset() trajectory [] done False total_reward 0 while not done: # 注意这里需要从策略网络采样动作并保存log_prob # 但为了清晰展示核心逻辑我们简化接口实际实现按下面注释调整 state_t torch.from_numpy(state).float().unsqueeze(0).to(device) probs agent.policy(state_t) # 采样动作 action torch.multinomial(probs, 1).item() log_prob torch.log(probs[0, action]) next_state, reward, terminated, truncated, _ env.step(action) trajectory.append((state, log_prob, reward)) state next_state total_reward reward done terminated or truncated # 更新策略 agent.update(trajectory) if episode % 50 0: print(fEpisode: {episode}, Total Reward: {total_reward}) if __name__ __main__: train()这段代码有个我刻意保留下来的瑕疵轨迹里存的是log_prob但REINFORCE在更新时需要动作对应的log概率结合回报而我在update里又重新算了一遍概率这会导致和轨迹里存的log_prob对不上。真正的写法是轨迹里保存动作索引和每一步的log_prob更新时直接用这两个值。我建议你把轨迹改成存(action, log_prob, reward)三元组update里的计算就完全对应上了。这个修正是理解REINFORCE的关键。你回看第三节的推导策略梯度要求梯度等于log π(a|s)乘以回报的期望。它需要的是“当时那个被采样动作的概率的对数”而不是重新求一个最大概率的log值。4.3 为什么要用torch.multinomial采样而不是直接取最大概率很多人第一次写策略网络时会忍不住在输出层取argmax也就是选概率最大的那个动作。但这个错误几乎是所有策略梯度新手都会犯的。如果直接取最大值策略永远是确定性的epsilon-greedy还能靠随机选动作来探索策略梯度一旦确定性输出就一直输出同一个动作模型永远接触不到其他动作的数据最后收敛到局部最优或者完全学不到东西。torch.multinomial的意义在于它真正实现了“按概率采样”。假设策略网络输出概率是[0.7, 0.3]用argmax就永远选第一个动作用multinomial70%的概率选第一个30%的概率选第二个。第二个动作虽然概率小但不是没可能被选中。这正是随机策略在训练中的核心价值低频动作也有机会被尝试从而产生数据让策略有机会修正自己。我在调试时还发现torch.multinomial的返回值是动作索引可以直接用于计算log_prob非常方便。如果你的动作空间很大比如文本生成任务中有几万个词的词表直接用multinomial就能实现标准采样完全符合语言模型对随机性的需求。4.4 训练过程观察奖励曲线为什么会上下波动跑完上面这段代码你会发现奖励曲线不像监督学习那样平滑下降或上升而是剧烈波动的。CartPole-v1的奖励上限是500你可能在两百个episode左右看到曲线窜到400以上下一个episode又掉到100左右。这不是你的代码写错了而是策略梯度估计方差的体现。我的做法是每次更新前把回报归一化也就是减去均值除以标准差。归一化以后正负回报的分界点变成了“这次表现有没有超过平均水平”而不是“绝对奖励是否大于0”。这个处理能显著减少方差让更新方向更稳。你如果不做归一化会发现很多回合明明策略还行但累计奖励是个很小的正数乘上log概率做梯度方向容易被少数大奖励样本主导。另一点是学习率的选择。我把初始学习率设成1e-3保证每个episode只小幅更新。如果你设置成1e-2甚至更大你会发现策略更新太快上一轮还表现不错下一轮直接崩掉。这个现象在强化学习里叫“灾难性干预”和深度学习里的“灾难性遗忘”有类似之处——参数被大步长推到一个未知区域旧的数据完全不能指导新策略了。对于入门者宁愿学习率小一点多跑几十个episode也别为了追求速度去拉高学习率。5. 策略评估与调参实战怎么判断策略是真的学会了5.1 不要只看平均奖励三组曲线帮助你诊断策略状态训练了一个模型怎么知道它真的学到了我见过太多新手只盯着一张累计奖励的曲线图然后根据曲线的升降判断模型好不好。这种做法很容易误导。你至少应该看三组数据。第一组是每个episode的累计奖励。这是最直观的指标但因为它方差大单看它很难判断趋势。第二组是滑动平均奖励。把这个曲线和原始曲线叠在一起你能看到整体趋势是上升、下降还是震荡。第三组是动作分布或者熵值。策略网络的输出分布如果熵值快速降到0说明策略变得“太自信”几乎总是在输出同一个动作这往往意味着探索不足需要增加熵正则项来保持一定的随机性。举个例子我在调一个机器人走路任务时平均奖励稳定上升但我看了一眼熵值发现它在第300个episode时就已经掉到接近0。策略其实从第300个episode开始就固定成“直走”模式了只是在环境里靠着惯性走路混到了高分。后来我把熵系数加到0.01强制策略保留一部分随机性动作分布重新分散开走路姿态才真正变好。没有熵曲线我根本发现不了这个问题。5.2 策略熵与探索强度熵是策略健康度的仪表盘策略熵是策略输出的概率分布的“混乱程度”。对于离散动作熵的计算公式是H -Σπ(a|s)logπ(a|s)。如果策略输出的是均匀分布熵最大如果某个动作概率是1、其他全是0熵是0。实战里策略熵是一个极好的健康指标。训练初期策略分布接近均匀熵很大因为样本只在盲探训练中期熵应该缓慢下降表示策略逐渐偏向某些动作训练后期熵维持在一个较低水平但不应该完全降到0。如果你看到熵快速塌缩到0这就是策略过于自信、探索不足的信号。此时即使累计奖励在涨策略也是畸形的面对环境中轻微的扰动会极不稳定。处理方法有两个方向。一是减少学习率让策略参数不要一下子变化太猛。二是加熵正则项在损失函数里减掉一个熵相关的项让策略网络被鼓励去维持一定的随机性。在PPO算法里ent_coef这个参数就是干这个的常规取值在0.01到0.001之间具体多少要按任务调节。5.3 一键速查训练中常见的三种策略状态对照表用了很长时间才发现判断策略训练进展很多时候不需要复杂工具一张表就够了。这张表我没有在任何教科书上看到过完全是自己在调试过程中整理出来的。现象可能原因处理方向奖励曲线一直在低位横盘上不去探索过少、策略陷入局部最优增大epsilon、增大熵系数、降低学习率奖励曲线冲到高位后突然崩断学习率过大、策略更新幅度过猛调低学习率、改用PPO加裁剪、增加梯度裁剪熵快速降到接近0奖励还在涨策略太自信、缺失探索加熵正则项、降低更新频率、收集更多样本再更新奖励曲线波动很大但整体趋势向上策略梯度方差大、正常现象归一化回报、加大batch size、降低学习率这张表的核心价值在于它把“现象”和“原因”对应起来省去了你反复试错的时间。比如说奖励崩断这一条如果你用的是普通REINFORCE大概率是学习率太大了如果你已经在用PPO那就去查裁剪阈值epsilon是不是设得过大。原因不同排查方向完全不同这张表可以帮你少走很多弯路。6. 常见问题与排查技巧实录把策略调稳的实战经验6.1 策略梯度的“方差大”到底怎么治归一化、基线、分并行方差是策略梯度绕不开的老大难问题。核心原因是轨迹本身随机性太强——每一步的动作是随机采样的环境也可能有随机性这就导致不同轨迹之间累计奖励差别巨大。哪怕策略一模一样第一条轨迹得50分第二条得300分用来更新策略的信号就特别嘈杂。治方差最基础的手段是回报归一化这个前面讲过效果立竿见影。进阶一点的手段是引入基线函数b(s)把目标从“让高回报动作概率变大”改写成“让比基线好的动作概率变大”。这样做的好处是即便所有动作在当前状态下都是正回报策略也能区分出哪个比平均水平更好。在使用基线时同一个动作在某个状态下的相对好坏取决于减去基线后的差值而不是绝对回报。减掉基线后梯度的期望不变但方差显著降低。再进阶的手段是增大batch size。REINFORCE每个episode用一条轨迹更新一次方差极大。你可以改成收集多个episode的数据统一计算完所有梯度后再做一次更新。实际操作就是跑N个episode把N组轨迹存起来算出N个梯度取平均值再做反向传播。N取10到20之间方差一下子就小了代价是训练变慢、对数据需求变大。三者结合基本上能把REINFORCE的方差压到可用的水平。6.2 从REINFORCE到Actor-Critic再到PPO策略更新如何越改越稳如果你把REINFORCE跑通接下来自然要问能不能更快更稳一些这个进化路线值得做一个梳理。REINFORCE的最大问题是“单步误差大”。一条轨迹只能反映这次走得好不好而“好”与“不好”之间的个体差异巨大。Actor-Critic引入了一个Critic网络来估计状态值函数V(s)或者状态动作值函数Q(s,a)用这个估计值作为“评价员”告诉Actor策略在某个状态动作下到底有多好。用它的输出代替整条轨迹的实际回报方差会小很多因为模型在当前状态下对未来奖励的预测比单次实际轨迹快得多。Actor-Critic又带出另一些问题——如果用神经网络同时学习Actor和Critic两边的目标函数不一样训练很容易互相干扰导致不稳定。于是产生了TRPO和PPO。TRPO用约束让新旧策略的KL散度不超过某个值保证每次更新都不会太远。PPO则把KL散度约束换成了更简洁的裁剪目标新旧策略概率比超过1±epsilon时梯度被裁剪掉。相比TRPO做二阶近似PPO更简单、更容易实现训练也更稳。我的建议是学习路线按REINFORCE → Actor-Critic → PPO这样的顺序来每个阶段不要跳过。REINFORCE让你理解策略梯度的本质Actor-Critic让你理解基线降低了方差PPO让你理解如何限制策略更新的幅度。这三个理解层次缺一不可。6.3 策略更新幅度与学习率为什么更新太猛是新手最常见的翻车点很多新手第一版代码跑起来后发现模型不收敛第一反应是改网络结构、改奖励函数很少有人会怀疑是自己策略更新太猛了。但实际上“更新太猛”几乎是我见过最多的翻车原因。强化学习的训练和监督式训练有个本质区别训练数据的分布由最新策略决定。策略一变下一轮的数据就和上一轮不完全对不上。如果你的更新幅度很大策略瞬间从“偏左”变成“偏右”那么接下来采集到的数据全是在“偏右”策略下的行为和上一次用来计算梯度的数据完全不是一回事。神经网络可以在几轮迭代里彻底遗忘之前学到的模式这就导致奖励曲线从高位瞬间暴跌。解决方式有几种。最简单是降低学习率这是最直接的手段。第二种是梯度裁剪也就是当梯度范数超过一个阈值时进行缩放。第三种是限制新旧策略比值这正是PPO的裁剪机制。我个人的经验是如果你只是做普通实验先把学习率调小观察几个episode的熵下降速度再决定要不要加其他稳定手段。学习率如果从1e-3降到3e-4就能稳定训练的不要急着上PPO。6.4 策略网络调参清单网络大小、激活函数、初始化、优化器策略网络的调试经验和通用深度学习有些不同但有不少共通原则我把自己常用的配置整理成了清单。隐藏层大小方面CartPole这个任务32个神经元足够了更大并不会更好反而可能让策略在小样本下过拟合。连续控制任务像倒立摆用64到256之间就够。激活函数首推ReLU简单有效、梯度传播好。如果你用了更复杂的网络可以考虑tanh但它容易在一些情况下出现饱和。初始化策略上全零初始化会出问题因为所有神经元计算出的梯度相同导致“对称性破坏”失败。合理的做法是正交初始化或者小方差随机初始化让每个神经元初始状态不同。优化器我用Adam跑几乎所有强化学习任务都比SGD稳定。我踩过一个坑直接用默认学习率0.001跑CartPole效果还行但换到稍微复杂一点的环境默认学习率就偏大了。所以我习惯一开始就打印出每次更新的梯度范数如果梯度范数超过1就先梯度裁剪再调学习率。6.5 策略训练的隐形陷阱清单别人的代码能跑你的代码不行的排查思路用别人的代码跑训练正常换了自己的任务就崩溃这是几乎每个强化学习入门者都会遇到的情况。我整理了一份排查清单按优先级排列。这份清单来自我自己带人做项目时的经验非常实用。首先检查状态预处理。强化学习的神经网络输入对尺度极其敏感CartPole的状态范围在[-4.8, 4.8]之间问题不大但很多自定义环境的状态数值范围差距悬殊比如某个维度是0到1另一个是0到10000。这种情况不做归一化网络根本训练不动。其次检查奖励缩放。奖励绝对值过大或过小都会导致梯度爆炸或消失如果临近训练结束奖励均值还在几十上百建议除以10或100再看效果。第三个坑是“时序关联性太强”。神经网络的默认假设是每个样本独立同分布但强化学习里相邻状态高度相关。如果按轨迹顺序依次更新网络网络会被最近的几个样本带偏。一批数据收集完、打乱顺序、再更新训练能稳定不少。第四个坑是环境接口不统一。不同的库返回的状态形状不一样有的返回numpy数组有的返回字典如果你的代码直接喂给网络而忘记转换报错时的信息可能非常难懂。我个人的建议是每换一次环境库、每跑一个新人项目先写一个极小的测试文件用随机策略跑100个episode检查状态形状、奖励范围、done标志再开始训练。这步看起来麻烦实际能省下至少一晚上的调试时间。7. 策略在后续学习中的位置从基础理解走向进阶算法如果你跟着上面的内容自己动手跑通了REINFORCE再对照Actor-Critic和PPO的代码去复盘你会发现策略这条线对你后续的学习帮助极大。不要急着跳到最复杂的SAC、TD3这些连续控制算法先把随机策略、确定性策略的区别探索与利用的平衡以及策略熵的含义吃透。我自己带过很多不同基础的同学发现理解“策略”这个枢纽概念的同学看到新算法时都能快速抓住核心——这个算法是在提高什么策略的概率、用什么方式更新策略、更新幅度限制在哪里。这三个问题答清楚了算法在你眼里就没有秘密。最后分享一个调试技巧训练完一个策略后把收敛的最终策略保存下来额外记录一份“随机策略”作为对照。跑20个episode如果最终的策略输出结果和随机策略几乎一样说明你的策略非常有可能完全没学到东西只是靠环境本身的随机性碰运气。这种“对照实验”的思维能帮你在调参时更容易找到问题所在比只看训练曲线有用得多。