☰
强化学习基础核心:马尔可夫决策过程与Q学习实战
2026/10/22 18:03:15 网站建设 项目流程

聊到第13章,我习惯先把前面十二章的思路停一下。前面的内容,不管是线性回归、决策树、支持向量机还是各种神经网络结构,本质上都在做同一件事:从一批带标签或没标签的数据里学出一个静态规律,然后用它去预测没见过的新样本。强化学习完全不在这个框架里。它的目标是让一个智能体在与环境不断交互的过程中,学会一套决策策略,在长期回报上拿到最好的结果。这一章讲的强化学习基础,核心就是两个概念——马尔可夫决策过程(MDP)和Q学习,它们是后面几乎所有强化学习算法的地基。

这套基础能做什么,先举一个最小例子。假设你有一只小机器人在一个棋盘格子上,它不知道终点在哪,只能试,走到终点就加分,走到坑里就减分。它没有老师,只有一个环境给出的实时信号,你得让它学会避坑并尽快到达终点。这一章学完后,你能亲手写一个Q学习智能体,让它跑几千个回合就学会接近最短的路线。对多数人来说,这是强化学习的第一堂实验课,也是理解价值函数、策略、时序差分这些进阶概念的必经之路。

如果你是第一次接触强化学习,或者之前学过基本机器学习和深度学习,但对“智能体循环试错”的流程没有直观体感,这一章可以直接按顺序看。如果你已经看过一些教程但没跑通代码,我建议重点看第6节的完整实现和第7节的调参经验,那是真正会花掉时间的地方。

1. 第13章的岔路口:从“看懂数据”切换到“学会做决定”

先弄清楚我们到底换了什么赛道。前几章里,训练集里的每个样本基本都有一个明确的监督信号:分类有类别标签,回归有目标数值,模型学的是输入到输出的映射。强化学习的场景里通常没有人每时每刻告诉你“这一步动作对错”,你只知道到达某一步之后收到一个数字——奖励,而一个动作好不好,要看它之后一串状态里累积下来的总收益。这就是“延迟回报”:眼前这一步可能不赚,甚至亏,但整体能让后续吃到红利。

举个例子,下棋的时候你丢掉一个子,从局部看是负回报,但如果这个交换能换来之后的局面优势,就是一个好决策。强化学习智能体要学的正是这种带前瞻性的判断。它不会像监督学习那样直接被告诉“这里应该下哪一步”,而是通过反复尝试,把每种操作的长期后果记下来,最终形成一套策略。这套策略可以是一张查找表,也可以是一个神经网络,但底层都是同一个逻辑:评估每个状态下每个行动的价值。

这个转变看起来不大,实际上一旦理解了,之前很多“为什么模型要这样设计”的问题都会通顺起来。你不再纠结某个样本的预测误差,而是关心整条轨迹上的累计奖励如何被最大化,关心的对象也从“模型参数”变成了“策略”。这也是为什么马尔可夫决策过程这一套形式化框架如此重要——它给“和环境交互、从经验中学习”这件事提供了一个干净的数学底座。

第13章适合两类人。一类是刚学完基础模型,想知道机器学习还能解决什么“非标准问题”的学习者。另一类是已经看过一些强化学习名词(Q值、奖励、回合、探索率),但没理清它们之间关系的工程师。学完之后,你应该能回答三个问题:一个决策问题怎么写成MDP,Q值为什么能指导动作选择,以及Q学习算法在什么条件下能收敛。

2. 马尔可夫决策过程拆解:状态、动作、奖励、转移概率是怎么协作的

马尔可夫决策过程其实是一个很朴素的建模框架。它把智能体和环境的交互抽象成一条不断循环的链路:t时刻,智能体处于状态S_t,它选择一个动作A_t,环境根据当前状态和动作给出奖励R_{t+1},并转移到一个新状态S_{t+1},接着进入t+1时刻,重复这个过程。这个循环写出来就是(S_t, A_t) → (R_{t+1}, S_{t+1}) → (A_{t+1}) → … 简洁,但足够描述绝大多数序贯决策问题。

2.1 为什么说马尔可夫性质是“当前局面说了算”

马尔可夫性质是整个框架中最关键也最容易被忽略的假设:给定当前状态,未来的状态转移和奖励分布与过去的历史无关。说人话就是——现在这一刻的信息已经包含了所有决定下一步所需要的知识,你不需要记得三天前做过什么。

用棋类来类比最直观。下棋时你只看当前棋盘局面,就足以决定下一步,因为局面本身就是过往所有落子的结果。你不会因为“当初第一步走的是哪个角落”就改变当前这一手的判断,该看的是盘面本身。但如果换成一个机器人导航任务,想判断它现在的坐标,可能还需要知道它过去走过多长距离来估算累积噪声,这时纯用当前坐标就不满足马尔可夫性质。实际工程里,我们通常会通过重新设计状态空间,把历史信息塞进当前状态里,例如把“已经消耗的资源数”也作为一个状态维度,来强行满足这个假设。

这个性质之所以是基石,是因为它把规划问题从“需要考虑整个历史轨迹”压缩成“只需要考虑当前节点”,否则Q表和策略表根本没法建立——每个状态的价值还必须依赖来路,维度会爆炸。学的时候抓住这一点,后面看多智能体、部分可观测环境时,就会明白它们的困难出在哪里。

2.2 一个MDP的标准数学记号

把一个MDP写成形式化定义,通常包含四个元件:

  • 状态集合S:智能体可能处于的全部局面。
  • 动作集合A:每个状态下可以选择的行动。
  • 转移概率P(s' | s, a):从状态s执行动作a后落到s'的概率。
  • 奖励函数R(s, a, s'):环境在这个转移发生后给智能体的标量信号。

再加一个策略π(a | s),表示在状态s下选择动作a的概率(或确定性选择哪个动作)。策略是我们要学习的东西,而MDP是描述问题世界的参数。强化学习算法做的事情,可以理解为在给定MDP定义下寻找一个最优策略π*,使得从任何初始状态出发的期望累积回报最大化。

我个人的习惯是,每拿到一个实际问题先不要急着写代码,而是先在纸上把四个元件列清楚。状态是离散网格还是连续坐标?动作是一次性选择还是一个连续量?奖励信号是稀疏出现的还是每一步都有?写不清楚这三个问题,后面算法调参会非常痛苦。尤其是奖励信号,很多项目不是算法不行,是奖励设计没有在MDP层面想清楚。

2.3 用一个园区导航场景完整建模

拿一个我实际用作课后练习的“园区无人配送小车”问题来演示。园区是一条6乘6的网格路,小车从西南角出发,要送到东北角的目标楼,途中有些障碍物不能进入,有些坑洼路段会有额外损耗。要素映射如下:

  • 状态S:小车当前所在的格子坐标,例如(0,0)到(5,5)。
  • 动作A:上、下、左、右四个方向。
  • 转移概率P:如果前方不是障碍,就以0.8概率成功移动到目标格,0.2概率滑到旁边的垂直方向;如果前方是边界或障碍,则原地不动。
  • 奖励R:到达目标楼获得+10,撞上障碍或落入坑洼获得-5,普通移动每一步获得-0.1,用于引导走出短路径。

这样一个设定下,智能体的目标就不是简单走到终点,而是在“尽快到达”和“避免滑出问题路段”之间做权衡。你可以试着想象,如果完全没有转移概率的随机性,贪心地一直往右往上就能到终点;加入滑移概率后,靠近障碍物走就有风险,距离惩罚又太狠也不行,只能通过反复试错找到一个平衡路线。这正好是Q学习这类无模型算法最擅长的地方。

3. 折扣因子gamma:为什么未来的奖励要打折扣

在MDP里,智能体要最大化的是从某个时刻开始的累积回报。但这个累积回报不能简单把每一步奖励直接相加,因为时间是无限长的,直接求和会发散。所以我们引入折扣因子γ(gamma),定义回报G_t为:

G_t = R_{t+1} + γ R_{t+2} + γ² R_{t+3} + γ³ R_{t+4} + ...

γ取值在0到1之间。γ越接近1,智能体越看重远期收益;γ越接近0,它越急功近利。为什么需要折扣,不止是数学上为了收敛,更有经济学的类比:现在的1块钱比一年后的1块钱更值钱,因为可以拿去投资产生回报。同样,在决策问题里,奖励到来的时间越晚,不确定性越大,所以把未来收益按指数因子折算。

3.1 折扣因子的实际含义:有效时间视野

如果你把折扣因子的含义翻译成“智能体计划多远的未来”,可以这样近似:γ的k次方缩到一半以下,意味着k步之后的奖励对当前决策几乎没有影响。下面这张表是我常用的参考值:

γ取值大约有效视野适用场景
0只看当前一步纯即时奖励任务,类似瞬时反应
0.5几步以内极短期的控制问题
0.9十步左右大多数格子世界、简单游戏
0.99几十步以上长期规划任务,如围棋、机器人导航
1无限视野有限步任务专用,需要配合episode设计

比如在第2节的园区配送例子里,如果γ=0,小车只会选择“当前这一步奖励最大的动作”,它走哪都是-0.1,只有到终点那一步才+10,那么它永远看不见“只有走到终点才有大奖励”这个事实。γ=0.9时,它开始愿意忍受前面几步的小幅负收益,换得后面较大的正收益。γ=0.99时,它会为更远处的目标规划出绕路方案,即使前几十步没有明显回报。

初学的时候最容易搞混的一点是:折扣因子不是让智能体“短视”的坏东西,而是控制它“愿意为远期目标牺牲多少眼前利益”的旋钮。任务越长,γ一般要调得越接近1,否则智能体根本不会为了30步之后的目标动作。反过来,如果γ太大,奖励信号传播完全依赖后面的奖励判断,早期的Q值会非常不稳定,学习会变慢。

3.2 为什么不用平均回报而用折扣

有人可能会问,为什么不直接定义成“从当前开始的平均每步奖励”,这样不就不用调γ了?答案在于,平均回报丢掉了对“时间偏好”的刻画。同样的总收益,快速拿到和慢慢拖到很久后拿到,在优化意义上应该有不同的价值。折扣形式自带了这个偏好,而且它还有一个非常好的性质:回报序列在任何状态下都是一个有限值,这让贝尔曼方程和Q学习的收敛性有了保障。实际写代码时你不需要手动算无穷级数,算法在一步步迭代中自然会把这些折扣累积进Q值里。

关于γ的选择,我的经验是不要一开始就纠结,先用0.9跑通流程,确认算法本身没问题后,再根据最终策略的“眼光长度”决定是否调大。如果γ=0.9下智能体能走到终点但路径绕远,那就往0.99方向调;如果它看起来完全不在乎中途撞障碍,反而要调小。

4. 贝尔曼方程与Q值:把“未来的最优”压缩进当前价值的等式里

有了MDP的定义和折扣回报,下一步要解决的是怎么比较“哪个状态更好”。状态价值函数V_π(s)定义为:从状态s出发,按照策略π持续行动,期望的折扣回报。值越大,代表这个状态越有利。类似地,动作价值函数Q_π(s, a)定义为:从状态s出发,先执行动作a,之后按策略π行动,期望的折扣回报。V函数是对状态的抽象评价,Q函数是对“状态-动作对”的具体评价。

4.1 从V函数到Q函数的递推关系

这两个函数之间存在一个漂亮的递推关系,它其实是从回报的定义直接变形得到的:

V_π(s) = Σ_a π(a|s) Σ_s' P(s'|s,a) [ R(s,a,s') + γ V_π(s') ]

对应的Q函数版本:

Q_π(s, a) = Σ_s' P(s'|s,a) [ R(s,a,s') + γ Σ_a' π(a'|s') Q_π(s', a') ]

这个式子翻译成大白话就是:当前状态的价值 = 执行动作后的即时奖励 + 折扣后的下一个状态价值。它不是一个新的理论,而是“G_t定义里前后两项关系”的直接展开。之所以重要,是因为它把一个需要看完整条轨迹才能估计的量,变成了一个只依赖相邻两项的局部等式。

4.2 为什么贝尔曼最优方程能成为“自洽解”

当策略是最优策略π*时,V和Q满足的是最优贝尔曼方程。对最优Q函数来说,有一个更简洁的形式:

Q*(s, a) = Σ_s' P(s'|s,a) [ R(s,a,s') + γ max_a' Q*(s', a') ]

核心变化是,下一步的动作不再参考某个固定策略分布,而直接取能达到的最大值。这个方程的意义在于:如果我知道了所有状态下所有动作的最优Q值,那么决策就变成了一件特别简单的事——每步都选Q*(s, a)最大的动作,因为Q值已经把未来的最优结果折现回当前状态了。

这个式子的“自洽性”很值得停下来体会。左边是未知的Q*(s, a),右边也依赖Q*,只不过依赖的是下一个状态的值。这种递归结构意味着,哪怕没有全局奖励地图,只要不断用右边去更新左边,等式最终能够自己“咬合”起来,让两边相等。这正是Q学习能在没有环境模型的情况下工作的理论根基:我们不需要完整转移概率P(s'|s,a),只需要不断和真实环境交互,从抽样中近似那个期望值。

在这个阶段,我建议不要太深钻收敛性证明,先把“最优Q值隐含了未来最优决策”这句话反复咀嚼。后面看到DQN、Actor-Critic等算法时,你会发现它们做的还是同一件事——用各种手段逼近一个满足贝尔曼方程的函数。

5. Q学习的更新公式和时间差分思想:没转移概率也能学

有了理论铺垫,Q学习算法的更新公式就非常自然了:

Q(s, a) ← Q(s, a) + α [ r + γ max_a' Q(s', a') - Q(s, a) ]

这里的α是学习率,r是执行动作a后真实收到的奖励,s'是实际转移到的状态。整个更新过程可以拆成三块:原来的估计、时序差分目标(TD target)、时序差分误差。

5.1 TD target 与“用现实修正估计”

先看带方括号的式子:r + γ max_a' Q(s', a')。这个值叫TD target,它是由两部分拼成的:一部分是刚拿到的真实奖励r,另一部分是对未来收益的现有估计 γ max_a' Q(s', a')。两者相加,代表“现实反馈 + 自身猜想”的组合,比原来单纯依靠某个初始随机估计要可靠得多。而整个方括号项就是TD误差,它刻画的是当前估计与这个更合理期望之间的差距。

这个过程很像一个人在没有地图的情况下找路:一开始脑子里有个模糊的地图,每走一步,根据实际看到的街道情况修正对下一区域的估计。你走的越多,地图越精确。这也是“时序差分”名字的由来——我们不是等一整条轨迹结束后再回看所有奖励,而是每走一步就对比一次预测和现实,把差距增量式地回传给前一步的状态价值。

5.2 更新公式逐项解释

我把每一项再展开说一下:

  • Q(s, a):更新前对这个状态动作对的估计。
  • r:真实奖励,来自环境的唯一反馈,它可能是正、负或零,是更新里最不可替代的信息。
  • γ max_a' Q(s', a'):未来收益的估计,用“下一个状态里最大Q值”来代表最优后续策略的价值。注意这里的max是站在“理想决策者”的视角,不管行为策略实际上怎么选择。
  • α:学习率,控制本次更新愿意改变多少旧估计。α=0意味着完全不见新信息,α=1则直接把旧值替换成新的TD target。

如果认为可信度排序是“真实奖励 > 对整个未来的现有估计”,就能理解为什么要用TD target做底。至于为什么不直接把Q(s,a)更新成r + γ max Q(s',a'),而是保留旧值按比例融合,原因是单次采样存在巨大噪声,一步到位会让Q值剧烈抖动,收敛性质很差。缓慢融合相当于做指数平均,让Q表逐渐稳定下来。

5.3 为什么Q学习属于离策略算法

Q学习里有一个非常容易萌混过关的细节:行为策略(用来产生实际动作)和目标策略(用来评估最优动作)不是同一个。行为策略通常用ε-greedy:以ε概率随机探索,以1-ε概率选当前Q值最大的动作;而更新公式里的max_a' Q(s',a')默认了“下一步一定选最优动作”,两者是分离的。

这正是离策略(off-policy)的含义。优点是,智能体即使在探索过程中走了歪路,学到的东西仍然能反映最优策略的价值;缺点是不像Sarsa那样会考虑“行为策略本身的随机性”对实际收益的影响。这个区别在涉及安全性或需要稳健控制的任务里尤其重要。Sarsa作为同策略(on-policy)版本,后面进阶章节会展开,这里只要知道两个算法的差别根源就是更新公式里有没有那个对后续策略取最大值的操作。

顺带说一个我踩过的坑:如果ε一直保持一个很大的值,Q学习学到的最优Q值仍然是偏乐观的,因为它总是用max估计未来,而行为策略本身还在大量随机乱走。这会导致一个现象:Q表训练结束后,一旦把ε降到0去实际执行,平均回报反而下降,因为Q值是在高探索率环境下“校准”的,测试时的状态访问分布变了。要规避这一点,要么训练后期强制让ε衰减到很小,要么把目标策略的估计也换成带探索修正的形式。

6. 手写一个Q学习智能体:从一个小网格环境跑到收敛

现在到了动手的地方。我准备了一个最简单的网格世界环境,5乘5格子,有起点、终点和一个陷阱,动作只有上下左右。完全不依赖深度强化学习框架,只用Python和numpy就能跑通。这一节请一定自己敲一遍,强化学习不是看会的,是跑会的。

6.1 环境怎么定义

网格按坐标(行, 列)编号,起点是(0,0),终点是(4,4),陷阱在(2,2)。普通每一步奖励-0.1,到达终点+10,掉进陷阱-10。动作0、1、2、3分别代表上、下、左、右。如果动作会撞出边界,留在原地并仍然获得-0.1的移动惩罚。

这里引入了一点随机性:每次移动有0.8概率按指定方向走,0.2概率滑到左右方向。这样可以模拟真实环境的不可控因素,也更容易看出Q学习的价值。如果你第一次跑,也可以把随机性去掉,算法会在更少回合内收敛,效果更直观。

6.2 完整代码:训练、评估、提取策略

import numpy as np import random class GridWorld: def __init__(self, size=5): self.size = size self.start = (0, 0) self.goal = (4, 4) self.trap = (2, 2) self.actions = [(-1, 0), (1, 0), (0, -1), (0, 1)] # 上、下、左、右 self.reset() def reset(self): self.state = self.start return self.state def step(self, action_idx): r, c = self.state dr, dc = self.actions[action_idx] # 以0.8概率按预定方向走,0.2概率横向滑移 if random.random() < 0.8: nr, nc = r + dr, c + dc else: if random.random() < 0.5: nr, nc = r + dc, c + dr # 垂直方向发生滑移 else: nr, nc = r - dc, c - dr # 边界检查:不能走出网格 if 0 <= nr < self.size and 0 <= nc < self.size: self.state = (nr, nc) else: self.state = (r, c) if self.state == self.goal: reward = 10.0 done = True elif self.state == self.trap: reward = -10.0 done = True else: reward = -0.1 done = False return self.state, reward, done def train_q_learning(env, episodes=20000, alpha=0.1, gamma=0.95, epsilon=0.8, epsilon_min=0.01, decay=0.9995): # Q表:用字典,state -> 长度为4的数组 q_table = {} def get_q(s): if s not in q_table: q_table[s] = np.zeros(4) return q_table[s] total_rewards = [] for ep in range(episodes): s = env.reset() done = False total = 0.0 while not done: q = get_q(s) # epsilon-greedy 动作选择 if random.random() < epsilon: a = random.randint(0, 3) else: a = int(np.argmax(q)) s_next, reward, done = env.step(a) q_next = get_q(s_next) # Q学习更新公式 td_target = reward + gamma * np.max(q_next) * (0 if done else 1) td_error = td_target - q[a] q[a] += alpha * td_error s = s_next total += reward total_rewards.append(total) epsilon = max(epsilon_min, epsilon * decay) if (ep + 1) % 2000 == 0: print(f"Episode {ep+1}, avg_total_last_2000={np.mean(total_rewards[-2000:]):.2f}, epsilon={epsilon:.3f}") return q_table env = GridWorld() q_table = train_q_learning(env) # 提取最终策略:每个状态选择Q值最大的动作 action_names = ['上', '下', '左', '右'] print("\n最终策略:") for r in range(5): row = [] for c in range(5): s = (r, c) if s == env.goal: row.append("终") elif s == env.trap: row.append("陷") else: q = q_table.get(s) if q is None: row.append("?") else: row.append(action_names[int(np.argmax(q))]) print(" ".join(f"{x:>3}" for x in row))

这段代码大约90行,没有用到任何额外强化学习库,逻辑清晰。特别强调一下更新公式里的那个(0 if done else 1):当一步到达终止状态后,后面已经没有未来奖励,所以折扣未来项必须乘0。很多初跑代码的同学忘了这个细节,导致终点附近的Q值被重复抬高,策略却收敛得又慢又怪。

6.3 跑完以后看什么

正常跑完2万回合,你会看到两种情况。一是控制台输出的最近2000回合平均回报从负数缓慢爬升,最后稳定在9左右,说明智能体大部分回合都能成功到达终点。二是策略表里,从起点到终点的路径上,每个格子都指向正确的下一步方向。如果你用了带滑移概率的环境,你还会发现靠近陷阱边缘的格子策略变成了“绕开”,而不是直线莽过,这就是Q值正确吸收了风险信号的结果。

我建议你接下来做三个小实验。第一,把epsilon衰减去掉,固定成0.2,看看最终策略和收敛速度有什么变化。第二,把gamma从0.95改成0.5,观察路径会不会变短视。第三,把普通移动奖励从-0.1改成0,看看智能体是否还会倾向于走最短距离。这些实验比看十篇文章都更能建立直觉,因为你会亲自感受到同一个更新公式在不同超参数下如何输出截然不同的行为。

7. 训练基础设施级别的经验:探索率、学习率与奖励设计的常见坑

代码跑通只完成了一半。真正让人头疼的往往不是理解Q学习更新公式,而是在一个具体任务里让它稳定收敛。我把实际带学员做类似实验时最常遇到的四个坑整理一下,这些经验不只适用于这个网格世界,也适用于后续所有强化学习项目。

7.1 探索率衰减方案:不衰减一定出问题,衰减太快也不行

epsilon-greedy是Q学习最基础的动作选择策略。它的作用是在初期保证智能体有足够概率尝试“看起来不是最优”的动作,从而发现全局最优路径。问题在于,epsilon如果一直很大,比如0.5,那么即使训练后期智能体已经知道最佳路线,它还是有相当大的概率去走弯路,平均回报就上不去。反之,如果epsilon衰减过快,从0.9在几千回合内直接跌到0.01,初期还没探索完环境,智能体就过早开始利用局部最优,最终策略可能画在“看起来很合理但明显不是全局最优”的路线上。

我的习惯做法是设置一个下限,让epsilon在训练尾声仍保留一个极小值,例如0.01,而不是衰减到0。这样既保证最终策略稳定,又保留极小概率的补救探索。衰减速度则需要根据任务步数和环境复杂度来试,一个粗略设计是:希望智能体在大约一半的训练回合内完成主导探索,剩下的回合逐步把epsilon从高位压到下限。不要一刀切地固定公式,多跑几组对比输出平均回报曲线,比任何理论指导都直接。

7.2 学习率alpha:过大抖动不收敛,过小又太磨蹭

Q学习的更新是增量式的,学习率alpha决定了每次TD误差有多大的比重被写回Q表。alpha调太大会让Q表来回震荡:一个回合学到终点路径,下一个回合又因为几个失败样本把路径上的Q值打得乱七八糟。alpha调太小则会让Q值像蜗牛一样爬,几万回合都不一定能把奖励信号传播到起点附近。

我在网格环境里的经验是alpha=0.1通常是个安全的起点;如果状态空间较大或奖励尺度很大,可以适当调小到0.05。另有一个实用技巧:训练后半段适当降低alpha,类似学习率退火,可以帮Q表更精细地收敛。很多开源实现里不统一调度alpha,但也跑得动,只是在复杂任务里,固定alpha往往需要额外增加很多回合才能达到同等效果。

7.3 奖励设计的门道:稀疏、正负不对称与奖励塑造

奖励设计是强化学习里最重要也最玄学的部分。最直接的做法是“到了终点+1,其他都是0”,这是纯稀疏奖励。在这种设置下,智能体前几千回合基本上全靠随机探索恰巧踩到终点才能产生一次有效学习,起点附近的状态Q值几乎一直不动,训练非常慢。

常见解法是给每一步加一个小的负奖励(比如-0.1),引导智能体朝“少走步数”的方向优化。但这里有个明显的陷阱:如果负奖励绝对值过大,它会压倒终点奖励,导致智能体宁愿停在原地也不敢乱走;如果过小,它又可能不在意绕路。更隐蔽的问题是奖励信号的正负不对称性:把踩陷阱设置成-10和设置成-0.5,会显著改变智能体对“陷阱附近”状态的看法,进而改变路径选择的风险偏好。我用过不少奖励塑造手段,核心原则是:确保任何中间奖励都不会让智能体发展出“为了刷小分而忽略主目标”的行为。例如,如果每一步都根据“离终点更近就加分”,智能体就可能在一个局部瓶颈区域来回蹭,看起来每步收益都不错,最终任务却完不成。

7.4 从Q表到DQN:状态空间一大,查表就开始失效

最后补一个承上启下的提示。第6节的网格世界只有25个格子,每个格子四种动作,用一张字典写的Q表就完全够用。但真实任务的状态往往远不止这么少,围棋有约10的170次方个状态,不可能给每个状态都存一张Q表。

Q表失效后的自然替代,是用一个函数近似器去拟合Q(s, a),最典型的就是把Q表换成神经网络输入状态、输出各动作的Q值,这也就是DQN的雏形。一旦你接受了这个想法,深度强化学习的整个路线就从“查表”变成了“用网络拟合表格”:仍然用同一个TD更新公式构造目标值,只是每次更新的对象从表格单元格变成了网络权重。值得注意的是,神经网络引入之后,会出现灾难性遗忘、样本相关性、目标不稳定等问题,于是重放缓冲区、目标网络、双Q等等技巧相继而来。你如果现在把Q学习更新公式吃得足够透,后面所有技巧都是在解决“把这个更新放到神经网络上会出什么问题”,不会觉得突兀。

我自己在做这个系列实验时,最大的感受是:Q学习最容易被低估的地方,是它明明只靠一个更新公式,就能让一个完全不认识地图的智能体,逐渐在脑海里长出一张价值地图。这种“从无模型的交互中提取结构化决策”的过程,是强化学习和其他机器学习范式最迷人的差异。如果你第一次跑通网格世界并看到策略表越来越合理,建议停下来多观察几组不同超参数下的策略差异,那比赶进度进入下一个高级算法有用得多。真正影响你后面调试效率的,往往就是现在这些最基础、最朴素的经验。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询