简介:深度学习算法 Q-learning 原理是一份面向强化学习入门者与算法工程师的 PDF 笔记,系统讲解 Q-learning 为何属于 value-based 方法,以及 critic 网络、value function、Q-function 等核心概念。内容重点对比蒙特卡洛(MC)与时间差分(TD)两种价值估计方式的原理、方差差异和适用场景,帮助读者理解如何通过迭代更新找到最优策略。资源还覆盖 target network 固定目标以稳定训练、epsilon greedy 与 Boltzmann exploration 等实用技巧,配合图示和逐步推导,降低理解门槛。压缩包仅 1 个 PDF 文件,大小约 999KB,内容精炼适合快速通读与反复查阅。已有 1313 人学习,适合希望系统梳理 Q-learning 理论脉络、准备算法面试或开展强化学习实践的读者。
1. 为什么 Q-learning 常被误当成深度学习,却又常和深度学习绑定出现
一说到深度学习算法 Q-learning,很多刚入门的同学会以为它是某个深度神经网络结构。实际上 Q-learning 是强化学习里最经典的基于价值迭代的算法,它的“学习”发生在维护一张 Q 表,而不是调整神经网络的权重。我在做无人车绕障的仿真项目时,最开始就用 Q-learning 控制小车在离散栅格地图上寻找路线,收敛速度快、策略可解释,效果非常直观;后来状态空间扩大到连续坐标,表格方法直接撑不住了,才换成深度 Q 网络。这篇文章就从 Q-learning 的原理讲起,给出一份可以直接复现的 Python 网格世界代码,再把我调参时踩过的坑逐个拆开。适合准备做小规模控制任务、课程设计,以及从传统强化学习过渡到深度强化学习算法的工程师和同学。
2. Q-learning 的核心迭代:状态、动作、奖励与 Q 表的更新规则
2.1 从“走迷宫”说起:状态、动作与奖励的建模
Q-learning 处理的问题通常建模为马尔可夫决策过程,也就是当前状态只影响下一步的转移,不依赖历史状态。我在实际项目中习惯用网格世界作为最小可运行样例,因为它足够简单,又能完整暴露 Q-learning 的所有行为特征。
以一个 5x5 的网格为例:智能体从左上角出发,目标是到达右下角,地图里有几个陷阱。状态就是智能体所在的格子编号,动作是上、下、左、右四个方向,奖励函数按任务需要自定义。关键点在于,奖励并不等同于 Q 值。奖励是环境给的一次性反馈,比如到达目标给 +10,踩到陷阱给 -10,普通移动给 -0.1。Q 值则是“从当前格子出发,执行某个动作后”,未来累计奖励的折扣期望。
这个建模过程有一个容易被忽视的细节:普通步数的惩罚值一定要小,但又不能是零。我最早偷懒把普通步奖励设为 0,结果智能体学到的方法是满地图乱逛,因为反正没有负奖励,就算多走几步也能到终点。加上 -0.1 之后,它才会主动寻找最短路径。奖励的含义越明确,Q-learning 学到的策略越贴近任务本意,这是一个在前面阶段就决定训练成败的设计点。
2.2 Bellman 方程与 Q 值更新:为什么下一步的估计也参与当前更新
Q-learning 的核心更新公式如下:
Q[s][a] = Q[s][a] + alpha * (r + gamma * max(Q[s1]) - Q[s][a])其中s是当前状态,a是当前动作,r是执行动作后拿到的奖励,s1是转移后的新状态。max(Q[s1])表示新状态下所有动作中最大的 Q 值,也就是假设下一步采取最优动作的价值估计。
我在理解这个公式时,走了很多弯路。初学者最容易犯的错是把r + gamma * max(Q[s1])看成“一步奖励加上未来最大奖励”,但实际它的意义是:用一个已经存在的估计去修正当前估计。训练刚开始时 Q 表全是 0,目标值就是r;随着训练继续,靠近目标的格子先获得非零 Q 值,这些 Q 值会像水波一样向远处传播。因此,最终每个格子都能学到“离终点越近,Q 值越大”的规律,策略也就是每一步都选 Q 值最大的方向。
Bellman 方程之所以叫“方程”,是因为它描述了一个自洽关系:最优策略下,当前状态的价值必须等于一步奖励加上下一个最优状态的价值。Q-learning 没有直接解这个方程,而是通过不断采样试错去逼近它,这也是时序差分方法的精髓。它和动态规划的区别很明显:动态规划需要完整的转移概率,Q-learning 只需要转移样本;它和蒙特卡洛的区别在于,蒙特卡洛必须等一个回合结束才更新,Q-learning 每走一步就能更新一次,非常适合长时间运行的在线控制任务。
2.3 学习率、折扣因子与探索率:三个参数分别管什么
这三个参数是 Q-learning 里绕不开的旋钮,它们影响的是完全不同的训练维度,分别说下我在调参时的经验。
学习率alpha控制每次更新的修正幅度。alpha 太大,Q 值会在目标值附近来回震荡,很难稳定;alpha 太小,更新过程会很慢,而且一旦环境发生变化,旧的 Q 值需要大量步数才能纠正过来。早期我做网格实验时用 0.8,结果每轮结果都剧烈跳动;后来降到 0.1,曲线平缓了,但到 3000 回合才收敛。我现在的惯例是:确定性环境下用 0.2 到 0.3,随机环境下先用 0.1,观察训练曲线的方差再微调。
折扣因子gamma代表智能体对未来奖励的重视程度。gamma 越接近 1,远期奖励和近期奖励权重越接近,智能体越有远见;gamma 太小,它只会盯住眼前几步。对于迷宫这类确定性任务,0.9 是个常用起点;如果环境里存在随机转移,我建议不超过 0.85,否则未来的噪声会被指数放大,Q 值方差会很大。
探索率epsilon决定智能体在每一步是选当前最优动作还是随机动作。为了学到全局最优,必须保证有概率尝试非最优动作。我的做法是从 0.5 开始,每 100 回合乘以 0.95,最低保底到 0.05。这个“保底”很重要,因为如果 epsilon 最终降到 0,智能体就完全失去了探索能力,一旦环境非平稳,策略就会僵死。后面我会专门讲一个同学把 epsilon 线性降到 0 导致训练停滞的案例。
2.4 Q-learning 的标准训练循环:一回合内发生了什么
把上面的概念串起来,一个完整的训练循环包括:初始化 Q 表为 0,设置当前状态为起点;在每一步用 epsilon-greedy 策略选择动作;执行动作得到奖励和新状态;用更新公式更新 Q 表;进入下一个状态;直到到达目标或陷阱,结束一回合;然后重复足够多的回合。这里有一个隐藏的关键点:每回合内智能体看到的轨迹可能完全不同,但 Q 表的更新是逐步累积的,所以哪怕一开始全是随机移动,只要探索足够充分,最终也能学到最优策略。
我习惯在训练过程中记录每个回合拿到总奖励值,用它画一条学习曲线。如果曲线的整体趋势是上升的,说明 Q-learning 在正常工作;如果曲线纹丝不动或者在下跌,那问题往往出在奖励设置、epsilon 衰减或转移逻辑上,而不是算法本身。这也是我在验证新环境时第一个会去看的信号。
3. 用 Python 从零写一个 Q-learning 智能体:以网格世界为例
3.1 定义环境:用 5x5 网格模拟一个带陷阱的寻宝任务
我先把网格世界环境封装成一个类,这样做的好处是后续换地图、换奖励都很方便,不用反复改训练逻辑。环境里定义 25 个格子,编号从 0 到 24,起点是 0,终点是 24。陷阱放在几个固定编号上,智能体掉进陷阱会立刻结束这一回合。
奖励规则如下:到达终点得到 10 分,掉进陷阱得到 -10 分,普通移动得到 -0.1 分,撞墙(试图走出边界)同样得到 -0.1 分并留在原地。这里的撞墙不算终止,只是惩罚一步,相当于训练智能体尽早学会绕开边界。
import numpy as np class GridWorld: def __init__(self, size=5, traps=[6, 12, 18]): self.size = size self.start = 0 self.end = size * size - 1 self.traps = traps self.state = self.start def reset(self): self.state = self.start return self.state def step(self, action): # action: 0=上, 1=下, 2=左, 3=右 row = self.state // self.size col = self.state % self.size if action == 0: row -= 1 elif action == 1: row += 1 elif action == 2: col -= 1 elif action == 3: col += 1 if row < 0 or row >= self.size or col < 0 or col >= self.size: next_state = self.state # 撞墙留在原地 reward = -0.1 else: next_state = row * self.size + col if next_state == self.end: reward = 10.0 elif next_state in self.traps: reward = -10.0 else: reward = -0.1 self.state = next_state done = (next_state == self.end) or (next_state in self.traps) return next_state, reward, done这段代码逻辑很直白:先根据动作计算新坐标,再由坐标映射回一维编号。重点看撞墙的处理:我把撞墙动作的下一个状态设成原状态,这样智能体知道“撞击”不会有进一步转移,同时也会因为 -0.1 的惩罚逐渐避开墙。奖励分支的判断顺序非常关键:先判断终点,再判断陷阱,否则如果陷阱和终点重合,智能体会得到相反信号。实际项目中,这个顺序往往就是 bug 的来源,我建议写环境时明确把奖励判定做成独立函数,方便单元测试。
3.2 实现 Q 表迭代:可复制的完整代码
Q 表用二维数组表示,行数等于状态数,列数等于动作数。这里不涉及神经网络,所以直接用一个 NumPy 数组存储每个状态-动作对的 Q 值。训练主体就是一个双层循环:外层跑回合数,内层跑单回合的每一步。
alpha = 0.2 # 学习率 gamma = 0.9 # 折扣因子 epsilon = 0.5 # 初始探索率 epsilon_min = 0.05 epsilon_decay = 0.95 # 每回合衰减为原来的95% episodes = 3000 env = GridWorld() Q = np.zeros((env.size * env.size, 4)) def choose_action(state): if np.random.uniform(0, 1) < epsilon: return np.random.choice(4) else: return np.argmax(Q[state]) for ep in range(episodes): state = env.reset() total_reward = 0 while True: action = choose_action(state) next_state, reward, done = env.step(action) # Q-learning 更新公式 best_next = np.max(Q[next_state]) td_target = reward + gamma * best_next Q[state][action] += alpha * (td_target - Q[state][action]) total_reward += reward state = next_state if done: break # 探索率衰减,但保留最低保底 if epsilon > epsilon_min: epsilon *= epsilon_decay if (ep + 1) % 200 == 0: print(f"Episode {ep+1}, total reward: {total_reward:.2f}, epsilon: {epsilon:.3f}")这里最关键的一行是td_target = reward + gamma * best_next,它对应前面讲的 Bellman 目标值。best_next是Q[next_state]的最大值,代表从下一个状态出发能获得的最高价值估计。注意动作选择用了epsilon-greedy,但更新时使用的是贪心动作的 Q 值,而不是实际采集动作的 Q 值,这就是 Q-learning 作为 off-policy 算法的典型特征。
epsilon_decay我设置为每回合乘 0.95,所以到第 200 回合时 epsilon 约为 0.5 的 0.0003 倍,但因为有epsilon_min=0.05的下限,它不会被压到 0。保底探索的意义在于,即使训练后期,也有 5% 的概率尝试非最优动作,这能帮助智能体在环境变化时重新找出路。
3.3 训练循环中的关键参数设置与作用
上面的代码里出现了四个超参数:alpha、gamma、epsilon 初始值、epsilon 衰减率。我给它们定的默认值是经过多次实验的经验起点,但不代表所有环境都适用。
alpha=0.2 意味着每次更新只向目标值移动 20%。这在确定性环境中已经够快,而且不会导致 Q 值震荡。如果环境中存在随机转移,比如“向上走有 10% 概率滑到左边”,我会把 alpha 降到 0.1,让智能体慢慢平均这些随机样本带来的噪声。
gamma=0.9 表示未来 10 步的奖励对当前决策的影响大约是 0.9^10 ≈ 0.35,衰减较快。如果任务要求智能体为了更远的终点牺牲眼前短期收益,可以调高到 0.95;但要注意 gamma 越高,Q 值的变化越依赖对远期状态的估计,训练初期的 Q 值全是虚的,过高 gamma 会导致初始阶段学得很不稳定。
epsilon 从 0.5 开始,在 3000 回合里衰减到 0.05,前半段大部分时间都在试探环境,后半段才开始利用学到的策略。如果你只想观察收敛结果,把衰减率设成 0.98,这样训练过程会更平滑。如果你希望智能体更早进入利用阶段,可以把初始 epsilon 降到 0.3。总之,这三个参数是互相影响的,调整时一次只动一个,否则出了问题很难定位。
4. Q-learning 的五个常见坑:从奖励稀疏到 Q 表爆炸
4.1 现象:学习曲线一直不动;原因:探索率归零太快;解决:使用衰减但保底
有次帮师弟调一个倒立摆环境,他设置的 epsilon 线性下降,从 1.0 每回合减 0.001,到第 1000 回合就严格变成 0。理论上这没问题,但问题是他的环境在 2000 回合内还没学会基本动作,探索空间已经锁死了。结果就是 Q 表里绝大多数状态-动作对仍然是 0,智能体只会机械地按照最初的随机经验行动,学习曲线在中后段完全是一条平线。
原因是探索率和任务难度不匹配。Q-learning 需要足够的随机动作样本才能覆盖所有状态-动作对,尤其是在奖励稀疏的环境里,可能需要几千甚至上万步的随机尝试才能偶然碰到一次正奖励。如果探索窗口提前关闭,等于把搜索过程截断。
解决方法很简单:epsilon 设置下限,比如 0.05,并且衰减策略从线性改成指数衰减。我习惯写成epsilon = max(epsilon_min, epsilon * 0.95),这样探索比重前期下降快,后期保持一个稳定底线。如果环境特别复杂,还可以使用 epsilon 周期性回升的策略,比如每隔 500 回合把 epsilon 重新拉高到 0.3,让智能体重新探索一部分状态空间。
4.2 现象:Q 值越来越大不收敛;原因:奖励绝对值过大或折扣因子接近 1;解决:归一化奖励和调整 gamma
训练到后期,打印 Q 表发现某些值达到了几千上万,而且还在不断增长。这通常有两个原因:一是单步奖励设得太大,比如 +100,加上 gamma 接近 1,长期累积价值会在数值上持续膨胀;二是折扣因子设成 0.99 甚至 1,而环境没有终止时刻,Q 值就会因为无限期累积而发散。
奖励值的量级要跟 Q 值的性质匹配。Q 值是对未来总奖励的折扣求和,如果单步奖励是 10,gamma 是 0.9,那么一个最优路径长度为 5 的状态,Q 值大致在 10 * (0.9^0 + 0.9^1 + ... + 0.9^4) 左右,也就是几十的量级。如果你发现 Q 值比这个估算高出几个数量级,说明奖励设置或 gamma 有问题。
解决方式是把奖励压缩到 -1 到 1 之间,比如奖励 1.0,惩罚 -1.0,普通步 -0.01。这样即使 gamma 接近 1,Q 值的上限也被限制在可预测的范围内。另一个常见做法是使用奖励归一化,即统计最近 100 回合的平均奖励和标准差,将奖励标准化后再更新。这种方法在深度 Q 网络里更常见,但 Q-learning 表格版本同样适用。
4.3 现象:状态太多导致 Q 表过大;原因:表格型方法的维度灾难;解决:状态聚合或转向深度 Q 网络
当状态是多维连续量,比如机器人的关节角度、车辆的坐标与速度,用表格记录是灾难级的。一个 10 维连续状态,每维离散成 10 档,就有 10^10 个状态,每个状态 4 个动作,Q 表需要存储 400 亿个浮点数,显然不现实。
我在一个机械臂轨迹规划任务里就栽过跟头:一开始把关节角度直接离散化成整数,状态维度 6,每个维度取 20 档,Q 表大小是 20^6 * 4,6.4 亿条目,内存直接爆掉。后来我把连续的关节角度聚合为粗粒度区间,再合并相似状态,才勉强能跑。但这只是权宜之计,真正靠谱的方案是用函数近似,也就是把 Q(s, a) 从查表改为神经网络预测,这就是深度强化学习算法的出发点。
对于小规模离散状态,状态聚合依然有效。你可以用人工规则把连续状态映射到若干区间,比如把速度分为“慢、中、快”三档。但要注意聚合粒度不能太粗,否则不同状态被合并后,最优动作可能互相冲突,导致 Q 值反复横跳。如果遇到这种情况,就该考虑 DQN 的路线了。
4.4 现象:明明找到路径却绕路;原因:奖励设计问题;解决:给每步微惩罚
在迷宫里,智能体最终学会了从起点到终点,但是走的路线明显绕了一个大弯。检查 Q 表发现,它其实知道终点附近的状态有高 Q 值,但从远处到终点附近的过程并不短。原因是我把每一步的奖励设成了 0,只有终点给正奖励。在没有步数惩罚的情况下,绕多长的路都能拿到同样的正奖励,智能体就没有动机去找最短路径。
这是奖励稀疏环境的典型问题,也是强化学习里最容易被吐槽的“玄学”之一。解决办法有两个方向:一是给每一步设一个小的负奖励,比如 -0.05,这样路径越长,累计负奖励越多,智能体自然倾向短路径;二是增加引导型奖励,比如每靠近终点一步就多给 0.1 分,但这需要额外计算距离,有可能引入局部最优,让智能体困在“靠近但永远到不了”的地方。
我更推荐第一种方案,因为它不改变任务语义,只是对步数施加了惩罚,对于离散网格问题尤其好用。但要注意惩罚值不能大于正奖励,否则智能体会为了减少步数而故意踩陷阱尽快终止,形成另一种坏策略。一个经验是,步数惩罚的绝对值应小于单步正奖励除以平均路径长度。
4.5 现象:训练时好时坏不稳定;原因:随机种子与初始化问题;解决:固定种子并记录随机状态
同一份代码,跑第一次收敛得很快,第二次换台机器或者换个时间运行,可能完全学不出来。这种不稳定性在黑盒调试时非常恼人。根源躲藏在随机数里:动作选择用随机数,状态转移可能带随机性,Q 表初始值也可能随机。只要随机源不同,训练的轨迹就完全不同。
我现在的习惯是,在训练脚本最前面固定随机种子,比如设置np.random.seed(42)。固定种子带来的好处是实验可复现,调参时的判断能准确归因到参数本身,而不是被随机波动干扰。同时我会在训练过程中每隔一定回合数打印累积奖励和 Q 表变化,及时判断是收敛还是发散。
但固定种子也有坑:如果种子选得不好,恰好让探索轨迹非常倒霉,整个训练可能错过关键状态。遇到这种情况不要急着改参数,换一个种子跑一遍,观察是否仍然无法收敛。如果多个种子都失败,才说明问题出在奖励或环境逻辑上。我会同时记录每个种子的最终策略,用多个种子取最优结果作为该参数的评估,而不是凭单次结果下结论。
5. 从 Q-learning 到深度学习:当 Q 表变成一个神经网络
5.1 为什么表格 Q-learning 在复杂状态前会失效
前面说过,表格方法把每个状态-动作对独立存储,好处是精确、可解释,坏处是完全没有泛化能力。状态稍微连续化、维度稍微提高,表就会指数膨胀,学不完也存不下。就算勉强离散化,相邻状态之间学到的 Q 值也是隔离的,一个状态的经验无法迁移到另一个类似状态,导致采样效率极低。
我在做行人运动预测的项目时,曾尝试把行人坐标、速度、方向离散成多个区间,结果状态空间轻松超过百万级。Q 表在数百万条目下更新极慢,每次随机探索只能影响其中很小一部分,整体收敛需要天文数字般的回合数。这个阶段,深度学习是必然出路,因为它能用有限参数去拟合一个函数,通过神经网络对输入状态自动做特征映射,从而对相近状态输出相近 Q 值。
5.2 DQN 的基本结构:用深度神经网络拟合 Q 函数
深度 Q 网络(DQN)的基本思想是:用一个多层神经网络替代 Q 表,输入是状态的特征表示,输出是每个动作对应的 Q 值。网络结构通常是全连接层,输入维度等于状态特征数,输出维度等于动作数。损失函数用均方误差,目标是让网络输出的 Q 值逼近“即时奖励 + gamma * 下一状态最大 Q 值”这个目标。
训练过程有两个 Q-learning 没有的关键组件:经验回放和目标网络。经验回放把每一步采样到的(state, action, reward, next_state, done)存在一个缓冲区里,每次从缓冲区随机抽一个小批量样本来更新网络,打乱了样本相关性,让梯度更新更稳定。目标网络是另一个参数冻结的 Q 网络,它的参数不随每次训练立即更新,而是每隔固定步数从主网络复制一次,用来计算 TD 目标。这里用目标网络是为了防止“用一个正在变化的网络去估计它自己”,避免训练发散。
如果你已经能跑通前面的表格 Q-learning,改造到 DQN 的路径其实很清晰:把Q[s,a]的读取变成Q_network(state)[a],把max(Q[s1])变成target_network(next_state)输出的最大值,把更新公式从手动更新 Q 表改为计算损失并反向传播。动作选择依然可以用 epsilon-greedy,探索率和衰减策略保持不变。实际落地时,深度学习环境配置通常需要安装 PyTorch 或 TensorFlow,并确认 GPU 驱动是否可用,但单卡 CPU 也能跑小规模 DQN 训练,只是速度慢几倍。
5.3 用深度强化学习算法改造已有网格世界代码
我在自己项目里写过一个最小改造:沿用前面 5x5 网格世界,但把即时 Q 表替换成一个三层全连接网络。状态输入不再用格子编号,而是一个 one-hot 向量,也就是长度为 25 的向量,当前状态对应的位置为 1,其余为 0。网络隐藏层各 16 个神经元,输出 4 个动作的 Q 值。训练时每 200 步从经验池里采样 32 个样本,更新一次网络。
关键代码如下,我贴的是训练循环中一小段,展示目标 Q 的计算逻辑:
# 假设 q_net 和 target_net 是两个结构相同的网络 # replay_buffer 是一个存了 (state, action, reward, next_state, done) 的列表 batch_states = np.array([t[0] for t in batch]) batch_actions = np.array([t[1] for t in batch]) batch_rewards = np.array([t[2] for t in batch]) batch_next_states = np.array([t[3] for t in batch]) batch_dones = np.array([t[4] for t in batch]) # 当前状态下所有动作的 Q 值 current_q = q_net(batch_states) # 取出实际执行动作的 Q 值 current_q = current_q.gather(1, batch_actions.unsqueeze(1)).squeeze(1) # 目标网络计算下一状态的最大 Q next_q = target_net(batch_next_states).max(1)[0] # 终止状态下没有未来奖励 target_q = batch_rewards + (1 - batch_dones) * gamma * next_q loss = mse_loss(current_q, target_q.detach()) optimizer.zero_grad() loss.backward() optimizer.step()我特别强调batch_dones的使用:当回合终止时,next_state已经不存在未来奖励,目标 Q 值就只有即时奖励。不少初学 DQN 的同学忘记乘(1 - batch_dones),导致终点状态的 Q 值被严重高估。这种错误的表现是:学习曲线前期很好,后期突然发散,因为 Q 值在终点附近被不存在的未来奖励拉偏了。
改造完成后,网络要通过梯度下降学到的 Q 值,理论上和表格版本收敛到同一套最优策略,但泛化能力更强。实际项目中,神经网络会带来新的问题,比如超参数增多、训练不稳定、复现困难。所以我的建议是:如果任务的状态空间能控制在几千以内,优先用表格 Q-learning;只有状态维度真正威胁到内存和采样效率时,才值得投入深度学习改造,毕竟深度强化学习算法的调试成本要高出不止一个量级。
6. 验证你的 Q-learning 是否真学会了:三条检验手段
训练完成后,不要只看最终累积奖励指标,那容易被局部最优骗过。我的习惯是同时做三件事:画出学习曲线、打印贪心策略、可视化 Q 值热力图。
学习曲线看趋势:如果总奖励随回合上升且后期稳定在一个较高值,说明算法收敛。如果曲线反复震荡,检查 alpha 是否过大、epsilon 是否没有保底。策略可视化则是把每个状态上np.argmax(Q[state])对应的方向画成箭头,一眼能看出智能体是否在朝目标移动。这种方法最直接,能立刻暴露“绕路”“原地踏步”“陷阱附近处理错误”等问题。Q 值热力图把每个状态的最大 Q 值涂成颜色深浅,目标终点的 Q 值最高,起点最低,中间应该平滑过渡;如果出现明显断层,比如某些格子 Q 值异常高,很可能是奖励设计或转移逻辑的 bug。
我也会做稳定性验证:用同一个训练好的 Q 表,重新启动五个新环境实例,让智能体按照贪心策略跑 100 次,统计成功率和平均步数。成功率 100% 且步数接近理论最短路径才算合格。如果成功率偏低,我一般会先怀疑 epsilon 保底是不是被减没了。这类验证步骤虽然简单,却能在调参时省下大量时间,我现在的习惯是每轮完整训练后都必须跑一遍,否则不看训练曲线。
从表格 Q-learning 到深度 Q 网络的落地,最重要的事情就是保持怀疑:算法不收敛时,先检查环境奖励逻辑,再检查探索策略,最后才去调整网络结构。我用这套排查顺序解决过不少翻车现场,也把成功的经验沉淀成了固定的参数模板。希望帮到你。
本文还有配套的精品资源,点击获取