读者定位:资深编程经验,学过概率论、求和和函数,但不希望先补完一整本数学教材再理解强化学习。本文的目标是给你一个能直接用于阅读和实现 RL 算法的理论骨架。

先给结论:贝尔曼方程在说什么

强化学习关心的不是“这一步奖励有多大”,而是“从现在开始,长期来看有多好”。贝尔曼方程把这个长期问题拆成一小步:

\[\boxed{\text{当前价值}=\text{本步奖励的期望}+\text{折扣后的下一状态价值的期望}}\]

如果当前还可以选择动作,就在各种动作带来的长期价值中选最大的那个。这个递推思想叫作贝尔曼原理:最优决策的后半段,本身也必须是从后续状态出发的最优决策。1

这不是强化学习后来附加的技巧。它先来自动态规划;强化学习的关键贡献是:即使不知道环境的完整规律,也能从交互样本中近似执行这种递推更新。2

先用一行程序读所有后续公式

如果暂时不看数学记号,价值型强化学习反复执行的核心数据流就是:

target = reward + gamma * estimated_value_of_next_state
error = target - estimated_value_of_current_state
estimate += learning_rate * error

上面三行几乎已经包含 TD、SARSA、Q-learning 和 DQN 的共同骨架。它们的差异只在于 estimated_value_of_next_state 是怎样得到的:是已知模型算出的平均值、完整轨迹的真实回报、表格中下一个状态的值,还是神经网络的输出。阅读下文每个公式时,先问三个问题:

  1. 左边是谁的估计?它是 V(state)Q(state, action),还是网络参数;
  2. 右边的 target 由什么组成?即时奖励、折扣后的未来估计,以及可能的概率平均或动作选择;
  3. 当前这条数据从哪里来?是模型枚举出来的,还是 env.step(action) 返回的一次样本。

这样读,公式不再是另一种语言,而是在描述一段数据如何流入训练循环。

0. 学习前的最小地图

先把最容易混淆的对象分开。下表中的时间下标遵循 Sutton 与 Barto 的惯例:在时刻 $t$ 位于 $S_t$,执行 $A_t$,随后拿到 $R_{t+1}$ 并到达 $S_{t+1}$。2

符号 程序员视角 含义
$s$ 或 $S_t$ 当前程序状态 / 输入 环境在某时刻的完整决策信息
$a$ 或 $A_t$ 一次函数调用的选择 智能体可执行的动作
$r$ 或 $R_{t+1}$ 单步反馈 执行动作后得到的即时奖励
$\pi(a\mid s)$ policy(state) 的概率输出 在 $s$ 下选择 $a$ 的规则
$\gamma$ 未来收益的权重 折扣因子,通常在 $[0,1]$ 内
$V(s)$ 状态的评分函数 从状态 $s$ 出发的长期价值
$Q(s,a)$ 动作的评分函数 在 $s$ 做 $a$ 后的长期价值

在本篇中,价值不是道德判断,也不是一次运行的真实得分;它是“在给定条件下,未来折扣回报的期望”。

0.1 先建立一个最小的数据契约

把一次与环境的交互想成一条不可变事件记录:

transition = {
    "state": s,          # 做决定前所处的位置
    "action": a,         # 此刻选择的动作
    "reward": r,         # 环境立刻返回的反馈
    "next_state": s_next,# 动作执行后到达的位置
    "done": terminated,  # 这一回合是否已经结束
}

数学里的 $(S_t,A_t,R_{t+1},S_{t+1})$ 正是这条记录。下标并不表示数组访问:它只是在严格说明先后顺序。你在 $t$ 时刻看到 $S_t$、选 $A_t$;调用环境后才得到 $R_{t+1}$ 和 $S_{t+1}$。这个顺序也是为什么奖励写成 $R_{t+1}$,而不是 $R_t$。

1. 从一次交互到长期目标

一次环境交互可以画成:

S_t --执行 A_t--> 环境 --返回 R_{t+1}, S_{t+1}--> S_{t+1}

一条完整轨迹可能是:

状态 S_0, 动作 A_0, 奖励 R_1, 状态 S_1, 动作 A_1, 奖励 R_2, ...

从时刻 $t$ 开始的折扣回报定义为:

\[G_t=R_{t+1}+\gamma R_{t+2}+\gamma^2R_{t+3}+\cdots\]

请把它像一个表达式求值一样从左到右拆开:

  • $G_t$:从当前时刻 $t$ 起的最终答案,即我们想让智能体变大的“长期分数”;
  • $R_{t+1}$:刚做完当前动作得到的第一笔反馈,权重是 $1$,所以原样计入;
  • $\gamma R_{t+2}$:下一步的奖励。它不是消失,而是乘以一次折扣;
  • $\gamma^2R_{t+3}$:两步后的奖励,所以折扣两次;
  • $\cdots$:后面每多隔一步,就再多乘一个 $\gamma$。

其中 $\gamma$ 是折扣因子。若 $\gamma=0$,智能体只在乎下一次奖励;若 $\gamma=0.9$,两步后的 10 分折算到现在是 $0.9^2\times10=8.1$ 分。有限回合中也可以令最后一步之后的价值为 0。

从代码角度,若一局的奖励序列是 [2, 0, 10],且 gamma = 0.9,起点的回报就是 2 + 0.9 * 0 + 0.9 * 0.9 * 10 = 10.1。注意“回报”是整条未来轨迹算完的数;“奖励”只是其中某一个元素。

折扣不只是“偏好眼前利益”。在无限时域里,当奖励有界且 $\gamma<1$ 时,这个无穷和有界;更重要的是,它让后面的递推算子具有收敛所需的压缩性质。3

1.1 为什么要用期望

同一状态执行同一动作,结果也可能不同:游戏中的暴击、网络系统的延迟、机器人轮胎打滑都会造成随机转移。因此算法不能问“这次一定拿多少分”,而要问“反复从这里开始,平均长期回报是多少”。

若随机变量 $X$ 以 70% 概率为 10、30% 概率为 0,则:

\[\mathbb{E}[X]=0.7\times10+0.3\times0=7\]

$\mathbb{E}$ 就是“按发生概率加权的平均”。这里的 $X$ 是一个会随机变化的结果;0.70.3 是两个结果的发生概率;右边把每个结果乘以其概率后相加。它不是说下一次必得 7,而是说把同样的实验重复足够多次,平均接近 7。贝尔曼方程中的大求和,本质上只是在系统地做这个操作。

2. MDP:方程成立的建模前提

贝尔曼方程通常写在马尔可夫决策过程(Markov Decision Process,MDP)上。一个 MDP 可记为:

\[(\mathcal{S},\mathcal{A},p,r,\gamma)\]
  • $\mathcal{S}$:所有可能状态的集合,类似一个类型允许取到的全部合法值;
  • $\mathcal{A}$:所有可选动作的集合,类似 API 可接受的命令枚举;
  • $p$:环境的“概率版实现”。输入 $(s,a)$,它定义后续 $(s’,r)$ 的分布;
  • $r$:奖励规则或一次具体奖励;有些教材将奖励函数单独写成 $r(s,a,s’)$;
  • $\gamma$:折扣因子,决定后面价值函数的时间跨度。

其中 $p(s’,r\mid s,a)$ 可读作:在已知输入状态为 $s$、已执行动作 $a$ 的条件下,输出 next_state = s'reward = r 的概率。竖线 $\mid$ 不是除法,而是“在……条件下”。若环境完全确定性,这个概率要么是 1,要么是 0;若环境可调用但没有模型,env.step(a) 只会给你这个分布的一次抽样。

“马尔可夫”意味着:已知当前状态和动作后,下一步的概率分布不再依赖更久以前的历史。换成工程语言,状态必须足够像一个完整的 snapshot,能够让未来逻辑不必再读取旧日志。

这是一项建模假设,不是永远成立的事实。例如,只把一帧摄像头图像当作状态,可能看不出物体速度;只把当前订单当作状态,可能遗漏库存历史。此时观测并非完整状态,问题更接近 POMDP,单纯的 $V(s)$ 或 $Q(s,a)$ 需要结合历史、循环网络或信念状态。4

3. 策略、状态价值与动作价值

3.1 策略 $\pi$

策略是“给定状态如何选择动作”的规则。确定性策略可以写为 $a=\pi(s)$;随机策略写为:

\[\pi(a\mid s)=\Pr(A_t=a\mid S_t=s)\]

左边 $\pi(a\mid s)$ 是策略函数的一个输出;$a$ 是正在询问的那个动作;$s$ 是输入状态。右边的 $\Pr$ 与 $p$ 一样表示概率,只是这里的随机性来自智能体自己的选择,而不是环境的响应。

例如 $\pi(\text{左}\mid s)=0.8$,不是说代码有 80% 的概率出错,而是说智能体在状态 $s$ 下以 80% 概率选左边。训练期间保留这种随机性,通常是为了探索。对于离散动作,它可以是一个数组,例如 policy(s) = [0.8, 0.2];对于连续动作,它通常是一个概率分布的参数,而不是枚举数组。

3.2 状态价值 $V^\pi(s)$

在策略已经固定为 $\pi$ 时,状态价值定义为:

\[V^\pi(s)=\mathbb{E}_\pi[G_t\mid S_t=s]\]

逐项读:$V$ 表示 value;上标 $\pi$ 表示“这份估计绑定到哪一套后续行为规则”;括号中的 $s$ 是函数输入;$G_t$ 是前一节定义的整段未来回报;下标 $\pi$ 表示取期望时,动作要由该策略产生;条件 $S_t=s$ 表示只讨论当前正好处在 $s$ 的情况。

读法是:“现在在 $s$,此后始终按 $\pi$ 行动,预期能拿到多少折扣回报?”如果后续策略改了,严格说应写成另一个 $V^{\pi’}$,因为同一状态在不同计划下当然会有不同的长期价值。

3.3 动作价值 $Q^\pi(s,a)$

若我们还想比较“现在该选哪个动作”,就定义:

\[Q^\pi(s,a)=\mathbb{E}_\pi[G_t\mid S_t=s,A_t=a]\]

这里 $Q$ 常被理解为 quality;$s,a$ 是一对输入。条件中的 $A_t=a$ 很关键:它把“当前动作”钉死为 $a$,所以 $Q$ 能比较同一状态下的不同选择。只有从下一步开始,才恢复按 $\pi$ 行动。

它的含义是:先强制执行 $a$,之后再遵循 $\pi$,长期回报的期望是多少。若你要在运行时直接选动作,$Q(s,a)$ 通常比 $V(s)$ 更顺手,因为它已经把候选动作分开打分。

二者的关系很自然:状态价值是按策略对动作价值求平均。

\[V^\pi(s)=\sum_a\pi(a\mid s)Q^\pi(s,a)\]

这是一段“对动作数组做加权求和”的数学写法。$\sum_a$ 表示遍历所有可选动作;$\pi(a\mid s)$ 是该动作的权重;$Q^\pi(s,a)$ 是该动作的分数;两者相乘后相加。如果 policy(s) = [0.8, 0.2],而两动作的 Q 值为 [10, 0],则 V(s) = 0.8 * 10 + 0.2 * 0 = 8。若策略是确定性的,这个平均只剩被选中的那一个动作。

4. 第一次推导:为什么会出现“奖励 + 下一状态价值”

从回报的定义出发:

\[\begin{aligned} G_t &=R_{t+1}+\gamma R_{t+2}+\gamma^2R_{t+3}+\cdots\\ &=R_{t+1}+\gamma(R_{t+2}+\gamma R_{t+3}+\cdots)\\ &=R_{t+1}+\gamma G_{t+1} \end{aligned}\]

这一步没有神秘数学,只是把后半段括起来。对两边在“当前状态为 $s$ 且遵循 $\pi$”这个条件下取期望:

\[V^\pi(s)=\mathbb{E}_\pi\left[R_{t+1}+\gamma V^\pi(S_{t+1})\mid S_t=s\right]\]

这就是最紧凑的贝尔曼期望方程。先不要把外层的 $\mathbb{E}_\pi$ 忽略:一次真实交互只会给出一个 reward 和一个 next_state,而这个方程描述的是把所有可能交互按概率平均后的值。

  • 左边 $V^\pi(s)$:当前状态的旧问题,“从这里长期能拿多少”;
  • $R_{t+1}$:本次动作立即产生的那笔奖励;
  • $\gamma$:把下一阶段的分数换算到当前尺度;
  • $V^\pi(S_{t+1})$:到达哪一个下一状态,就查询哪一个状态的长期价值;大写 $S_{t+1}$ 强调它是随机变量;
  • 外层期望:因为奖励和下一状态可能随机,也因为策略可能随机,必须平均。

它说的是:固定策略的当前价值,等于该策略产生的一步奖励加上下一状态价值的期望。把它想成递归函数的规格说明:value(s) 不需要展开所有无限后续分支;它只需要知道本步结果和 value(next_s)

如果你知道策略和环境的全部概率,把期望完全展开就是:

\[V^\pi(s)= \sum_a\pi(a\mid s) \sum_{s',r}p(s',r\mid s,a) \left[r+\gamma V^\pi(s')\right]\]

这是上一式把“期望”展开后的可执行规格。请从里向外读:

  1. 方括号 $[r+\gamma V^\pi(s’)]$:假设我们已知道本次动作和环境结果,计算该分支的总分;
  2. 内层 $\sum_{s’,r}$:遍历所有可能的 next_statereward,每个分支先乘环境给出的概率 $p(s’,r\mid s,a)$,得到这个动作的平均结果;
  3. 外层 $\sum_a$:遍历所有动作,每个动作再乘策略选择它的概率 $\pi(a\mid s)$;
  4. 左边:把所有路径汇总为一个状态价值。

若把状态、动作和结果都写成循环,它近似对应:

value = 0.0
for action in actions:
    for probability, next_state, reward in model[state][action]:
        branch_value = reward + gamma * values[next_state]
        value += policy[state][action] * probability * branch_value

这里的 model 不是训练数据集,而是能枚举所有结果及其概率的环境规范。现实中通常没有它,因此才需要后面的采样算法。

同理,动作价值的贝尔曼期望方程为:

\[Q^\pi(s,a)= \sum_{s',r}p(s',r\mid s,a) \left[r+\gamma\sum_{a'}\pi(a'\mid s')Q^\pi(s',a')\right]\]

这次当前动作 $a$ 已由函数参数固定,因此外面没有“对当前动作做平均”的 $\sum_a\pi(a\mid s)$。进入下一状态 $s’$ 后,策略才再次随机选择动作 $a’$:

  • $a’$ 的撇号仅表示“下一决策时刻的候选动作”,不是导数;
  • $\sum_{a’}\pi(a’\mid s’)Q^\pi(s’,a’)$ 就是下一状态的 $V^\pi(s’)$;
  • 外层仍按环境结果 $(s’,r)$ 的概率平均。

注意:方程右侧仍然是同一个 $V^\pi$ 或 $Q^\pi$。这不是循环论证,而是一个方程组;下文会说明如何用反复更新解它。

5. 一道可手算的例子

设折扣因子 $\gamma=0.9$。你在状态 A,有两个动作:

  • 兑现:立即得到 3 分,随后终止;
  • 投入:立即得到 0 分,确定到达状态 B。

在 B 中只有一个动作:立即得到 5 分并终止。终止后没有未来,所以 $V(B)=5$。

这里把终止状态当作函数返回点很有帮助:在 B 做动作拿到 5 分后,程序不会再执行一次有效的决策,因此后续价值是 0。严格地说,是“B 中唯一动作的动作价值为 $5+0.9\times0=5$”,状态 B 只有这一个选择,所以 $V(B)=5$。

于是:

\[Q(A,\text{兑现})=3+0.9\times0=3\]

左边问的是“处于 A 时点兑现,长期值多少”。右边的 3 是当前奖励;0.9 是折扣;最后的 0 是终止后的未来价值。它不是忽略未来,而是未来确实为空。

\[Q(A,\text{投入})=0+0.9\times V(B)=4.5\]

这里的第一个 0 是投入动作的即时奖励,而不是“这个动作没价值”;V(B)=5 是到达 B 后还能拿到的未来分数;乘上 0.9 后才与当前奖励处在同一时间尺度。代码里对应 target = 0 + 0.9 * values['B']

若允许在 A 自由选择最优动作,显然应投入,且 $V^*(A)=4.5$。这里的关键不是“投入立刻拿到 0 分”,而是它通向一个价值为 5 的后续状态。

再加一点随机性:假设有动作“冒险”,0.8 的概率到 B 并立即获得 0 分,0.2 的概率直接终止并损失 2 分。那么:

\[Q(A,\text{冒险})=0.8\times(0+0.9\times5)+0.2\times(-2)=3.2\]

这一次没有把 $0.8$ 和 $0.2$ 写在动作外面,而是写在两个环境结果分支外面:80% 的分支价值为 $0+0.9\times5=4.5$,20% 的分支价值为 $-2$。概率在这里不是装饰。它令“冒险”的平均长期价值为 3.2,仍低于“投入”的 4.5。

6. 从“评价既有策略”到“寻找最优策略”

到目前为止,$\pi$ 是固定的。但 RL 更常见的问题是:怎样找到好策略?定义最优状态价值:

\[V^*(s)=\max_\pi V^\pi(s)\]

以及最优动作价值:

\[Q^*(s,a)=\max_\pi Q^\pi(s,a)\]

星号 $*$ 不表示乘法,也不表示某一次样本;它表示“在所有允许策略中能达到的最优版本”。$\max_\pi$ 的意思是概念上枚举所有策略,取价值最大的那个。实际算法通常不会真的枚举全部策略,而是通过迭代或梯度逐步逼近。

最优策略可以从最优 $Q$ 直接读出:

\[\pi^*(s)\in\arg\max_a Q^*(s,a)\]

这里有一个容易被忽略的符号差异:max 返回最大数值argmax 返回让数值最大的输入。因此 $\max_a Q^(s,a)$ 是“最好的分数”,而 $\arg\max_a Q^(s,a)$ 是“应执行的动作”。$\in$ 允许并列第一时存在多个同样好的动作。

6.1 贝尔曼最优方程

把“按既定策略平均动作”替换成“选择价值最大的动作”,可得到:

\[V^*(s)=\max_a\sum_{s',r}p(s',r\mid s,a) \left[r+\gamma V^*(s')\right]\]

以及更常用于控制的形式:

\[Q^*(s,a)=\sum_{s',r}p(s',r\mid s,a) \left[r+\gamma\max_{a'}Q^*(s',a')\right]\]

逐项看,$Q^*(s,a)$ 仍把当前动作 $a$ 固定;环境仍可能随机,所以仍有 $\sum_{s’,r}p(\cdot)$;区别只在下一状态的决策:不再按 $\pi(a’\mid s’)$ 平均,而是假设届时选择 Q 值最高的 $a’$。这就是“最优”进入方程的唯一位置。

两类方程一定要分清:

名称 动作如何处理 回答的问题
贝尔曼期望方程 按 $\pi(a\mid s)$ 做加权平均 “固定按这套策略走,长期多好?”
贝尔曼最优方程 取动作价值的最大值 “所有策略中,能达到的最好长期价值是多少?”

“最大化”发生在智能体选择动作时;环境随机性仍须按转移概率取期望。把两者都写成 max 是常见错误。

7. 已知模型时:动态规划如何求解

如果 $p(s’,r\mid s,a)$ 已知,而且状态、动作集合有限,可以直接对贝尔曼方程反复做全量更新。这类算法属于动态规划(DP)。1

7.1 策略评估

给定策略 $\pi$,对每个状态反复更新:

\[V_{k+1}(s)\leftarrow \sum_a\pi(a\mid s) \sum_{s',r}p(s',r\mid s,a) [r+\gamma V_k(s')]\]

下标 $k$ 不是环境时间,而是“第几轮离线计算”。$V_k$ 是当前这轮的估计,$V_{k+1}$ 是用它计算出的下一轮估计。右边与贝尔曼期望方程相同,只是故意使用旧的 $V_k(s’)$,避免同一轮更新顺序影响定义。

这相当于不断给“下一状态价值”的旧估计打补丁。对有限 MDP,且 $\gamma<1$,这个贝尔曼期望算子是压缩映射,迭代会收敛到唯一的 $V^\pi$。3 不必先证明压缩映射;对实现者而言,重要含义是:在上述前提下,只要持续扫过所有状态,delta 会变小,估计不会永远震荡。

7.2 价值迭代

不把“评估策略”和“改进策略”分开,直接用最优方程更新:

values = {state: 0.0 for state in states}

while True:
    delta = 0.0
    for state in states:
        old_value = values[state]
        action_values = [
            sum(prob * (reward + gamma * values[next_state])
                for prob, next_state, reward in model[state][action])
            for action in actions[state]
        ]
        values[state] = max(action_values)
        delta = max(delta, abs(values[state] - old_value))
    if delta < tolerance:
        break

这个循环中的 reward + gamma * values[next_state] 就是一次 Bellman backup:使用后继状态的估计,回填当前状态。工程上,model 就是环境转移表;现实 RL 中,这张表通常不存在。

再逐行对应:values[state] 是当前的 $V(s)$;最内层 sum(...) 是对环境随机结果求期望;action_values 存每个动作的候选分数;max(action_values) 是贝尔曼最优方程中的 $\max_a$;delta 是本轮所有状态最大改变量,作为停止条件。这里的循环先解决了一个最容易忽略的问题:当模型已知时,贝尔曼方程不是训练数据的拟合目标,而是可直接计算的更新规则。

8. 未知模型时:从样本近似贝尔曼更新

现实环境往往不能枚举 $p(s’,r\mid s,a)$。你只能观察到一条样本:

(s, a, r, next_s, terminated)

这时不能精确计算期望,但可以把单次观测当作期望的带噪样本,并在大量交互中取平均。强化学习的主要算法家族,正是对“右侧目标值如何取得”的不同回答。

8.1 Monte Carlo:等整段轨迹结束

若回合已经结束,可得到完整的实际回报 $G_t$,然后更新:

\[V(S_t)\leftarrow V(S_t)+\alpha[G_t-V(S_t)]\]

左箭头 $\leftarrow$ 是“用右侧新值覆盖左侧变量”,不是代数等式。把它翻译成赋值语句:

value[state] = value[state] + alpha * (observed_return - value[state])

其中 $V(S_t)$ 是更新前的预测,$G_t$ 是这次完整轨迹观察到的真实回报,括号是预测误差,$\alpha\in(0,1]$ 是每次接受多少新证据的学习率。若 alpha = 1,直接相信最新样本;若很小,则像移动平均一样缓慢更新。它不需要模型,也不用下一状态的价值估计;代价是必须等到回合结束,且长轨迹的方差可能较大。

8.2 TD(0):只等一步,立刻自举

TD(Temporal-Difference)用:

\[\underbrace{R_{t+1}+\gamma V(S_{t+1})}_{\text{TD target}}\]

\underbrace{...}_{\text{TD target}} 只是给一段表达式加标签,括号内才是重点。$R_{t+1}$ 来自当前样本;$V(S_{t+1})$ 来自当前估计表或网络;两者之和不是完整回报,而是用“一步事实 + 对更远未来的预测”拼出的临时 target。替代完整回报。其更新为:

\[V(S_t)\leftarrow V(S_t)+\alpha\delta_t\]

其中 TD 误差为:

\[\delta_t=R_{t+1}+\gamma V(S_{t+1})-V(S_t)\]

这两个式子应连着读。第二式先计算 deltaTD target - current prediction;第一式再把当前预测沿着误差方向移动一小步。逐项解释:

  • $V(S_t)$:当前状态的旧预测;
  • $\delta_t$:本次转移暴露出来的缺口,正数表示低估,负数表示高估;
  • $\alpha$:更新步长,不是折扣;
  • $R_{t+1}+\gamma V(S_{t+1})$:只看一步后构造的目标。

这可以直接写成 value[s] += alpha * (r + gamma * value[s_next] - value[s])。当转移终止时,应把 value[s_next] 当成 0,或显式乘 (1 - done)

可以把它直接翻译成调试语言:

预测值:V(S_t)
新证据给出的目标:R_{t+1} + gamma * V(S_{t+1})
TD 误差:target - prediction

“用自己的下一步预测来更新当前预测”叫作自举(bootstrapping)。它让学习无需等回合结束,但也引入了由估计误差传播而来的偏差。TD 与 Monte Carlo 的取舍,是偏差、方差与在线更新能力之间的取舍。2

8.3 SARSA:学习正在执行的策略

SARSA 的名字来自一条样本的五元组:$(S_t,A_t,R_{t+1},S_{t+1},A_{t+1})$。它更新动作价值:

\[Q(S_t,A_t)\leftarrow Q(S_t,A_t)+\alpha \left[R_{t+1}+\gamma Q(S_{t+1},A_{t+1})-Q(S_t,A_t)\right]\]

它与 TD 更新的结构没有变化,只是将 value[state] 换成 q[state, action]。括号内当前预测是 $Q(S_t,A_t)$;本步事实仍是 $R_{t+1}$;未来项是实际已经由当前策略选出的 $Q(S_{t+1},A_{t+1})$。所以实现 SARSA 时,必须在更新前拿到下一动作:

next_action = epsilon_greedy(q[next_state])
target = reward + gamma * q[next_state, next_action]
q[state, action] += alpha * (target - q[state, action])

由于右侧使用实际由当前行为策略选出的 $A_{t+1}$,SARSA 是同策略(on-policy)方法:它评估并改进的,是自己真正拿来探索的策略。

8.4 Q-learning:学习最优贪心策略

Q-learning 使用:

\[Q(S_t,A_t)\leftarrow Q(S_t,A_t)+\alpha \left[R_{t+1}+\gamma\max_a Q(S_{t+1},a)-Q(S_t,A_t)\right]\]

前半段和 SARSA 一模一样,只有未来项变了:$\max_a Q(S_{t+1},a)$ 会遍历下一状态全部动作,取当前估计最高的数值。这里的 $a$ 是局部哑变量,更严谨可写作 $a’$;它不是当前已经执行的 $A_t$。

对应代码是:

best_next_q = max(q[next_state, candidate] for candidate in actions[next_state])
target = reward + gamma * best_next_q * (1 - done)
q[state, action] += alpha * (target - q[state, action])

右侧假设“下一步会选择估计最好的动作”,无论实际采样时是否因为探索选了别的动作。因此它是异策略(off-policy)方法:行为策略负责收集数据,目标策略负责定义要学的最优行为。Watkins 与 Dayan 给出了表格型 Q-learning 在适当探索和学习率条件下收敛到最优动作价值的经典结果。5

算法 bootstrap target 学习的对象
TD(0) $r+\gamma V(s’)$ 固定策略的 $V^\pi$
SARSA $r+\gamma Q(s’,a’)$ 当前行为策略的 $Q^\pi$
Q-learning $r+\gamma\max_{a’}Q(s’,a’)$ 最优 $Q^*$

9. 从表格到神经网络:DQN 没有改变方程

状态很少时可用 dict[(state, action)] 存 $Q$。图像、文本或连续向量状态无法枚举时,用神经网络 $Q_\theta(s,a)$ 近似它。

DQN 仍以 Q-learning 的贝尔曼目标为核心:

\[y=r+\gamma(1-\text{done})\max_{a'}Q_{\theta^-}(s',a')\]

并让在线网络拟合这个目标:

\[\mathcal{L}(\theta)=\mathbb{E}\left[(y-Q_\theta(s,a))^2\right]\]

先把第一式当作一行训练代码的规格:$y$ 是 target,不是网络直接输出;$r$ 是 batch 中真实观察到的即时奖励;$s’$ 是样本里的 next_state;$a’$ 枚举下一状态的候选动作;$Q_{\theta^-}$ 是目标网络估计的未来 Q 值;$\max$ 取其中最大值。

$(1-\text{done})$ 是一个很实用的布尔掩码:非终止样本中 done = 0,乘数为 1,保留未来项;终止样本中 done = 1,乘数为 0,整个未来项被清零。这比为终止状态伪造一个价值更直接。

第二式是损失函数。$\mathcal{L}(\theta)$ 是随在线网络参数 $\theta$ 变化的标量;$Q_\theta(s,a)$ 是在线网络对当前样本的预测;$y-Q_\theta(s,a)$ 就是 TD 误差;平方让正误差和负误差都受惩罚,$\mathbb{E}$ 表示对 replay buffer 抽出的一个 batch 求平均。训练器通过反向传播减小这个损失,并不直接对公式左边的 $Q$ 表做赋值。

其中:

  • done 为 1 时,目标就只剩 $r$;这正是“终止后未来价值为 0”;
  • $\theta$ 是正在梯度更新的在线网络参数;
  • $\theta^-$ 是较慢更新的目标网络参数;
  • 经验回放从历史转移中随机抽样,减少相邻样本强相关带来的训练问题。

目标网络和经验回放不是贝尔曼方程本身的组成部分,而是让“神经网络 + 自举 + 异策略数据”这种组合更稳定的工程措施。这个组合可能发散,常被称为 deadly triad;不能因为表格型 Q-learning 有收敛结论,就假定任意深度实现也必然收敛。DQN 的稳定训练设计和局限应结合原论文理解。6

如果你只记住 DQN 的一个调用链,可以记住:replay_buffer.sample() 提供 $(s,a,r,s’,done)$;target_net(s') 提供未来项;online_net(s) 提供当前预测;loss.backward() 只更新在线网络;每隔一段时间再把在线参数复制给目标网络。贝尔曼方程出现的位置,就是 target 的构造。

10. 把符号对应到训练代码

看到以下代码时,可以立即定位其理论含义:

with torch.no_grad():
    next_q = target_net(next_states).max(dim=1).values
    target = rewards + gamma * (1.0 - dones) * next_q

prediction = online_net(states).gather(1, actions).squeeze(1)
loss = torch.nn.functional.smooth_l1_loss(prediction, target)
代码变量 数学对象 作用
rewards $r$ 当前一步的观察结果
next_q $\max_{a’}Q_{\theta^-}(s’,a’)$ 对未来最优价值的估计
target $y$ 贝尔曼右侧的样本目标
prediction $Q_\theta(s,a)$ 网络对当前状态动作对的预测
target - prediction TD 误差 本次样本指出的预测偏差
loss TD 误差的平方或 Huber 损失 让网络逼近贝尔曼目标的优化目标

torch.no_grad()detach() 至关重要:计算 target 时不应通过目标分支反向传播。否则模型会一边移动目标、一边追目标,训练语义就与通常的半梯度 TD 更新不同。

再按张量操作读一遍:target_net(next_states) 为 batch 中每个下一状态输出所有动作的 Q 值;.max(dim=1).values 沿动作维取最大 Q 值;gather(1, actions) 从在线网络的“所有动作预测”中取出样本真正执行的那个动作;smooth_l1_loss 是比平方误差对极端 TD 误差更温和的 Huber 损失。因而 predictiontarget 的形状都应是“每个样本一个数”,这是 DQN 实现中很常见的维度检查点。

11. 常见误解与排错清单

11.1 “价值就是奖励”

不对。奖励是环境对当前一步的反馈;价值是从当前起所有未来折扣奖励的期望。一个动作可以即时亏损,却因通向高价值状态而最优。

11.2 “$\max$ 是对随机结果取最大值”

不对。$\max$ 只代表智能体选择动作;随机转移的结果仍应通过 $p$ 或样本平均处理。正确顺序通常是“对环境结果求期望,再对动作取最大”。

11.3 “终止状态还要 bootstrap”

通常不需要。若该转移终止,下一状态没有后续回报,目标应为 $y=r$。漏掉 (1 - done) 会把无意义的终止状态估计混进目标。

11.4 “训练时总选当前最大 Q 值就行”

不行。若从不探索,未尝试动作的价值永远没有可靠数据。典型 $\epsilon$-greedy 策略以概率 $\epsilon$ 随机选动作,以 $1-\epsilon$ 选择当前最大 $Q$ 动作。探索策略和学习目标策略是两个应分开描述的对象。

11.5 “只要损失下降,策略一定更好”

不成立。TD loss 只说明网络更贴近当前自举目标;而目标自身也在变化。应同时评估独立 episode 的平均回报、成功率、长度和方差,并固定随机种子或多个种子比较。

11.6 “观测值就是状态”

只在观测满足马尔可夫性时近似成立。若同一观测对应不同的隐藏历史,价值函数会面对相互矛盾的学习目标。先检查状态设计,往往比盲调学习率更有效。

12. 与 Actor-Critic、PPO 的连接

价值学习不只服务于 Q-learning。Actor-Critic 中:

  • Actor 学习策略 $\pi_\theta(a\mid s)$;
  • Critic 学习 $V_\phi(s)$ 或 $Q_\phi(s,a)$;
  • Critic 常用 TD 误差提供低方差的学习信号;
  • 优势函数常写为 $A^\pi(s,a)=Q^\pi(s,a)-V^\pi(s)$。

用一步估计近似优势时:

\[\hat A_t\approx R_{t+1}+\gamma V_\phi(S_{t+1})-V_\phi(S_t)=\delta_t\]

这个近似式中的 $\hat A_t$ 读作“估计出的优势”;帽子表示它是近似值,不是精确的 $A^\pi$。$V_\phi$ 是 Critic 网络,参数用 $\phi$ 与 Actor 的 $\theta$ 区分;最后的 $=\delta_t$ 表示这一项恰好就是一步 TD 误差。直觉上,若本步奖励加未来估计比 Critic 原先预测得更多,$\delta_t>0$,当前动作比预期好;反之则较差。

因此,在 PPO 或 A2C 日志里看到 value_lossreturnsadvantagesgae_lambda,其底层仍离不开贝尔曼递推:Critic 负责让“未来有多好”的估计可用,Actor 借助这个估计提高好动作的概率。PPO 的策略目标有额外的近端约束,但并没有绕开价值估计问题。7

13. 一个适合程序员的阅读与实现路线

建议按下列顺序建立知识,而不是一上来就跳到 DQN 或 PPO 源码:

  1. 手算本文第 5 节的例子,并把 $\gamma$ 改成 0、0.5、1,观察决策是否改变。
  2. 在一个 5 到 20 个状态的 Gridworld 中实现策略评估和价值迭代;此时你知道模型,能清晰看到方程每一项。
  3. 去掉模型表,只保留交互样本,实现表格型 TD(0)、SARSA 和 Q-learning,打印每次 TD error。
  4. 为 Q-learning 加入 $\epsilon$-greedy,并分别记录训练期回报和纯贪心评估期回报。
  5. 最后再用小型神经网络替换 Q 表,加入 replay buffer、target network 和独立评估,理解 DQN 的每个组件解决什么问题。
  6. 阅读 Actor-Critic / PPO 时,把注意力放回 returnTD targetadvantage 和 value loss,而不是先被裁剪目标和网络结构淹没。

14. 自测:你是否真正理解了

  1. 为什么 $r+\gamma V(s’)$ 是一个目标,而不是“真实价值”?
  2. SARSA 与 Q-learning 的更新式只差一个 $a’$ 或 max,为什么学习行为却不同?
  3. 为什么终止样本要屏蔽下一状态价值?
  4. 若环境状态缺少决定未来的重要历史,贝尔曼更新为何会变得不可靠?
  5. DQN 的 target_net 在数学上近似了哪一部分?它为何不应每次反向传播都同步更新?

若能用自己的话回答:“贝尔曼方程把长期回报按第一步拆开;不同 RL 算法只是以不同方式估计等式右边。”你已经掌握了进入大多数价值型强化学习算法所需的核心直觉。

参考文献

  1. Bellman, R. Dynamic Programming. Princeton University Press, 1957. 贝尔曼原理与动态规划的原始系统阐述。  2

  2. Sutton, R. S., and Barto, A. G. Reinforcement Learning: An Introduction, 2nd ed., MIT Press, 2018,尤其是第 3 至第 6 章。本文的 MDP、回报、价值函数与 TD 记号主要遵循该书。  2 3

  3. Puterman, M. L. Markov Decision Processes: Discrete Stochastic Dynamic Programming. Wiley, 1994. 有限 MDP、贝尔曼算子和收敛理论的标准专著。  2

  4. Kaelbling, L. P., Littman, M. L., and Cassandra, A. R. “Planning and Acting in Partially Observable Stochastic Domains”. Artificial Intelligence, 101(1-2), 1998. 部分可观测决策过程的经典综述。 

  5. Watkins, C. J. C. H., and Dayan, P. “Q-learning”. Machine Learning, 8, 1992. 表格型 Q-learning 的经典论文与收敛分析。 

  6. Mnih, V. et al. “Human-level Control through Deep Reinforcement Learning”. Nature, 518, 2015. DQN、经验回放和目标网络的代表性论文。 

  7. Schulman, J. et al. “High-Dimensional Continuous Control Using Generalized Advantage Estimation”, 2015;Schulman, J. et al. “Proximal Policy Optimization Algorithms”, 2017. GAE 与 PPO 的原始论文。