读者定位:资深编程经验,学过概率论、求和和函数,但不希望先补完一整本数学教材再理解强化学习。本文的目标是给你一个能直接用于阅读和实现 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 是怎样得到的:是已知模型算出的平均值、完整轨迹的真实回报、表格中下一个状态的值,还是神经网络的输出。阅读下文每个公式时,先问三个问题:
- 左边是谁的估计?它是
V(state)、Q(state, action),还是网络参数; - 右边的 target 由什么组成?即时奖励、折扣后的未来估计,以及可能的概率平均或动作选择;
- 当前这条数据从哪里来?是模型枚举出来的,还是
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.7、0.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]\]这是上一式把“期望”展开后的可执行规格。请从里向外读:
- 方括号 $[r+\gamma V^\pi(s’)]$:假设我们已知道本次动作和环境结果,计算该分支的总分;
- 内层 $\sum_{s’,r}$:遍历所有可能的
next_state和reward,每个分支先乘环境给出的概率 $p(s’,r\mid s,a)$,得到这个动作的平均结果; - 外层 $\sum_a$:遍历所有动作,每个动作再乘策略选择它的概率 $\pi(a\mid s)$;
- 左边:把所有路径汇总为一个状态价值。
若把状态、动作和结果都写成循环,它近似对应:
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 是终止后的未来价值。它不是忽略未来,而是未来确实为空。
这里的第一个 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。替代完整回报。其更新为:
其中 TD 误差为:
\[\delta_t=R_{t+1}+\gamma V(S_{t+1})-V(S_t)\]这两个式子应连着读。第二式先计算 delta:TD 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 损失。因而 prediction 与 target 的形状都应是“每个样本一个数”,这是 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_loss、returns、advantages、gae_lambda,其底层仍离不开贝尔曼递推:Critic 负责让“未来有多好”的估计可用,Actor 借助这个估计提高好动作的概率。PPO 的策略目标有额外的近端约束,但并没有绕开价值估计问题。7
13. 一个适合程序员的阅读与实现路线
建议按下列顺序建立知识,而不是一上来就跳到 DQN 或 PPO 源码:
- 手算本文第 5 节的例子,并把 $\gamma$ 改成 0、0.5、1,观察决策是否改变。
- 在一个 5 到 20 个状态的 Gridworld 中实现策略评估和价值迭代;此时你知道模型,能清晰看到方程每一项。
- 去掉模型表,只保留交互样本,实现表格型 TD(0)、SARSA 和 Q-learning,打印每次 TD error。
- 为 Q-learning 加入 $\epsilon$-greedy,并分别记录训练期回报和纯贪心评估期回报。
- 最后再用小型神经网络替换 Q 表,加入 replay buffer、target network 和独立评估,理解 DQN 的每个组件解决什么问题。
- 阅读 Actor-Critic / PPO 时,把注意力放回
return、TD target、advantage和 value loss,而不是先被裁剪目标和网络结构淹没。
14. 自测:你是否真正理解了
- 为什么 $r+\gamma V(s’)$ 是一个目标,而不是“真实价值”?
- SARSA 与 Q-learning 的更新式只差一个 $a’$ 或
max,为什么学习行为却不同? - 为什么终止样本要屏蔽下一状态价值?
- 若环境状态缺少决定未来的重要历史,贝尔曼更新为何会变得不可靠?
- DQN 的
target_net在数学上近似了哪一部分?它为何不应每次反向传播都同步更新?
若能用自己的话回答:“贝尔曼方程把长期回报按第一步拆开;不同 RL 算法只是以不同方式估计等式右边。”你已经掌握了进入大多数价值型强化学习算法所需的核心直觉。
参考文献
-
Bellman, R. Dynamic Programming. Princeton University Press, 1957. 贝尔曼原理与动态规划的原始系统阐述。 ↩ ↩2
-
Sutton, R. S., and Barto, A. G. Reinforcement Learning: An Introduction, 2nd ed., MIT Press, 2018,尤其是第 3 至第 6 章。本文的 MDP、回报、价值函数与 TD 记号主要遵循该书。 ↩ ↩2 ↩3
-
Puterman, M. L. Markov Decision Processes: Discrete Stochastic Dynamic Programming. Wiley, 1994. 有限 MDP、贝尔曼算子和收敛理论的标准专著。 ↩ ↩2
-
Kaelbling, L. P., Littman, M. L., and Cassandra, A. R. “Planning and Acting in Partially Observable Stochastic Domains”. Artificial Intelligence, 101(1-2), 1998. 部分可观测决策过程的经典综述。 ↩
-
Watkins, C. J. C. H., and Dayan, P. “Q-learning”. Machine Learning, 8, 1992. 表格型 Q-learning 的经典论文与收敛分析。 ↩
-
Mnih, V. et al. “Human-level Control through Deep Reinforcement Learning”. Nature, 518, 2015. DQN、经验回放和目标网络的代表性论文。 ↩
-
Schulman, J. et al. “High-Dimensional Continuous Control Using Generalized Advantage Estimation”, 2015;Schulman, J. et al. “Proximal Policy Optimization Algorithms”, 2017. GAE 与 PPO 的原始论文。 ↩