news 2026/10/19 9:29:54

贝尔曼方程详解:价值函数、折扣因子与最优策略入门

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
贝尔曼方程详解:价值函数、折扣因子与最优策略入门

贝尔曼方程与价值函数,这两个词几乎出现在每一份强化学习入门资料里,也几乎是初学者的第一道分水岭。我第一次读到 V(s) = E[R + γV(s')] 时,第一反应是“这数学看着不难,可它到底在算什么?”后来在完整推导了几轮状态价值函数的迭代之后才彻底明白:它是在用一种递归的方式回答“当前状态到底值多少钱”。这篇笔记面向刚看完马尔可夫决策过程、准备深入强化学习核心公式的人,我会从折扣因子讲到状态价值和动作价值,再把贝尔曼期望方程和最优方程拆开揉碎,最后用一个3×3网格世界手算一遍,把我踩过的坑一并交代清楚。

1. 从回报到价值函数:强化学习真正在“估”什么

1.1 为什么只看单步回报不够?折扣因子的三重含义

初学强化学习时,最容易出现的误区是:把“奖励最大”等同于“单步奖励最大”。如果在某个状态下,往左走能拿+0.5,往右走能拿+0.2,那就无脑选左?这不对。因为强化学习关心的是从当前时刻开始,到终局为止的累积回报,而不是眼前这一口的甜头。

所以我们需要定义“回报”(Return),也就是从 t 时刻开始往后所有折扣奖励的总和:

  • G_t = R_{t+1} + γR_{t+2} + γ²R_{t+3} + … = Σ_{k=0}^{∞} γ^k R_{t+k+1}

这个 γ 就是折扣因子,取值在 [0, 1] 之间。它在数学、直觉和工程三个层面各有含义:

  • 数学层面:当 γ < 1 且每一步奖励有界时,无穷级数收敛,G_t 是有限值,价值函数才有稳定解。
  • 直觉层面:未来的奖励存在不确定性,早拿到的奖励更确定、更有价值;折扣因子天然表达了“眼前的钱比未来的钱更值钱”的偏好。
  • 工程层面:γ 控制了价值“往回看多远”。γ 接近 1,模型会关注极其长远的结果;γ 很小,模型会变得短视,只盯着几步内的收益。

我在实际使用中习惯这样理解:折扣因子不仅是数学技巧,它是一种对“远见”的量化。γ = 0 时只在乎当前一步,γ = 0.99 时基本在乎无穷远期的累积收益。设计一个强化学习任务时,如果每一步都耗时较长、不确定性高,我会倾向选 0.9 到 0.95;如果任务是慢速长线的策略博弈,通常会选 0.99 甚至更高。

这能解决什么问题?它解决了“奖励序列长度不一致”的麻烦。有的回合走 3 步就结束,有的走 300 步才结束,直接比较总奖励不公平,但折算成“按折扣因子加权后的累积回报”后,它们有了统一的比较尺度。

1.2 状态价值函数 V(s) 与动作价值函数 Q(s,a):两把不同的尺子

有了回报 G_t,就可以定义价值函数。严格来说,回报是一个随机变量,因为它依赖未来的状态转移和动作选择。价值函数就是回报的期望,用期望消除随机性。

状态价值函数 V^π(s),表示在策略 π 下,从状态 s 出发的期望回报:

  • V^π(s) = E_π[G_t | S_t = s]

动作价值函数 Q^π(s, a),表示在策略 π 下,从状态 s 出发、先执行动作 a、之后继续遵循策略 π 的期望回报:

  • Q^π(s, a) = E_π[G_t | S_t = s, A_t = a]

两者最核心的关系是:Q 值就是在某个状态执行某个动作的“即时奖励”加上“后继状态的状态价值均值”:

  • Q^π(s, a) = Σ_{s', r} p(s', r | s, a) [r + γV^π(s')]
  • V^π(s) = Σ_a π(a|s) Q^π(s, a)

为什么需要两把尺子?状态价值 V 解决的是“我现在所处的位置到底好不好”,它不考虑当前动作,只考虑整体局势;动作价值 Q 解决的是“我面前这些具体选项哪个更香”,它是决策时直接比较的对象。我在做实际项目时,V 函数往往用于评估当前局势、计算优势函数,而 Q 函数用于选出具体行为。两个都不能缺。

打一个比方:假期你要决定去海岛还是爬山。V 函数告诉你海岛整体性价比高、风景好、口碑稳定;Q 函数告诉你具体到你这趟出行、结合预算和天气,选海岛更划算。V 是局势评估,Q 是动作选择,方向不同,缺一不可。

2. 贝尔曼方程的本质:把“未来”递归地折叠进“现在”

2.1 从一个关键分解讲起:回报的递归身份

贝尔曼方程之所以漂亮,在于它利用了回报本身的递归结构。按定义,G_t 从 R_{t+1} 开始,而 G_{t+1} 从 R_{t+2} 开始,所以:

  • G_t = R_{t+1} + γ(R_{t+2} + γR_{t+3} + …) = R_{t+1} + γG_{t+1}

这个等式看着太简单了,但它是整棵大树的根。把它代进状态价值函数的定义式,就会得到贝尔曼方程:

  • V^π(s) = E_π[R_{t+1} + γV^π(S_{t+1}) | S_t = s]

这里的区别在于:原来 V^π(s) 的定义对整个无穷回报求期望,现在只需要对“即时奖励 + 下一步状态的价值”求期望。无穷的前瞻被压缩成了一步,这就是“把未来折叠进现在”。只要知道下一步各个状态的价值,当前价值就立刻被确定了。这个递归结构把“看得很远”和“只需要看一步”统一了起来,是动态规划思想在强化学习里的真正入口。

我初学时的最大卡点在这里:总觉得折叠一步之后,V(S_{t+1}) 本身还是包含未来无穷步的,这不等于又回到原点吗?对,但它不再需要从无穷远处往回推。只要所有状态的 V 都满足这个自洽方程,它们就是“未来一步接一步的标准答案”。与其说它是一个无限递归,不如说它是一个自洽方程组:N 个状态对应 N 个方程、N 个未知数。这从“无穷视角”变成了“有限线性系统”,求解思路完全变了。

2.2 贝尔曼期望方程:在策略 π 下评估世界

把上面的推导细化,就是完整的贝尔曼期望方程。对于给定策略 π,状态价值函数满足:

  • V^π(s) = Σ_a π(a|s) Σ_{s', r} p(s', r | s, a) [r + γV^π(s')]

动作价值函数也有自己的期望方程:

  • Q^π(s, a) = Σ_{s', r} p(s', r | s, a) [r + γ Σ_{a'} π(a'|s') Q^π(s', a')]

这里有两个数学期望,经常有人混:

  • 对动作求期望,权重是策略 π(a|s)。策略说“这个动作有多大概率被选中”,价值就按这个概率做加权平均。
  • 对状态转移求期望,权重是环境转移概率 p(s', r | s, a)。环境说“执行 a 之后,有多大概率落到 s' 并拿到 r”,价值就按这个概率做加权平均。

两层期望对齐之后,V^π(s) 就算清楚了。这个方程的作用是“策略评估”:给我一个策略 π,我来回答这个策略到底有多好。它的典型应用场景是:在周四的某公司导航 Demo 里,先把一个规则策略(比如“遇到岔路口右转”)的价值函数算出来,才能知道这个策略比随机走强多少。

实际工程里,策略评估不一定真的解线性方程组,更多是用迭代法反复套公式,直到 V 值变化小于阈值。理论上,γ < 1 时有界奖励可以保证收敛;实践上我们还要关心收敛速度和数值稳定性,这在后面实操部分会展开。

贝尔曼期望方程的“为什么”核心在于:它把“一个策略的好坏”从抽象概念变成可解的数值问题。没有它,你根本没法和别人讨论你的策略到底好在哪里、坏在哪里。

3. 贝尔曼最优方程:价值函数与最优策略的相遇

3.1 期望变最大:一个符号之差

学习到贝尔曼最优方程时,最大的冲击是:好像只是把 Σ_a π(a|s) 换成了 max_a,公式就突然从“评估一个给定策略”变成了“求解最优策略”。这个符号之差,背后是价值逻辑的根本变化。

贝尔曼最优方程长这样:

  • V*(s) = max_a Σ_{s', r} p(s', r | s, a) [r + γV*(s')]
  • Q*(s, a) = Σ_{s', r} p(s', r | s, a) [r + γ max_{a'} Q*(s', a')]

注意几个细节:

  • 期望方程的外层对动作求期望,最优方程的外层对动作求最大值。V*(s) 已经不含策略 π,理论上最优策略是确定性的,所以不再需要加权平均。
  • 最优方程里的 V* 是同一个函数出现在等式两边,这意味着“如果我从 s 出发一直按最优方式行动,那当前动作选能让 r + γV*(s') 最大的那个”。
  • Q* 方程里的 max 放在了后继值上:执行 a 之后,下一步会从所有动作中选最大的 Q*;这代表你相信未来每一步都会按最优走。

为什么可以这样取 max?这背后是贪心原理与最优子结构的结合。如果存在一个最优策略,那么从任何状态出发,最优策略的后续决策也必然是最优的。强化学习环境满足马尔可夫性,当前状态已经浓缩了历史信息,所以“剩下所有时刻都按最优行动”是唯一合理假设。从数学上,贝尔曼算子是一个压缩映射,反复迭代会收敛到唯一的不动点,这个不动点就是 V*。理论与直觉在这个点是一致的。

3.2 从价值函数到最优策略的落地路径

重点来了:算出了 V* 不等于立刻就能决策。决策时你要比较的是“各个动作谁更能提高累积回报”,而不是只看当前状态好不好。已知 V* 的情况下,最优策略可以写成:

  • π*(s) = argmax_a Σ_{s', r} p(s', r | s, a) [r + γV*(s')]

这个式子需要知道转移概率 p,也就是需要“环境模型”。如果能拿到 Q*,决策就更直接:

  • π*(s) = argmax_a Q*(s, a)

因为 Q*(s, a) 已经把所有未来最优响应都折进去了,选最大的 Q 就是最优动作,不需要显式知道环境模型。这也是为什么后续各种无模型算法都围绕 Q 值做文章:Q-learning、Double DQN、Dueling DQN,本质都是在逼近 Q*,然后用 argmax 选动作。

在实际项目里,我第一次实现价值迭代时,想当然地以为 V* 收敛了就大功告成,结果发现策略没用对。原因就是 V* 只能告诉“这个状态有多好”,要在已知模型的情况下才能反推动作;如果模型未知,就必须维护 Q* 或者额外学习一个策略。这条路线图想清楚之后,很多模型的代码结构就通透了。

4. 手算小网格世界:3×3环境下的贝尔曼方程实操

4.1 环境参数与转移规则设定

理论讲完必须上手算。我一直认为,贝尔曼方程不亲手算过一遍迭代,永远是纸上的符号体操。下面设计一个最简单的 3×3 网格世界:

  • 状态:9 个格点,s1 到 s9,按 3 行 3 列排列。
  • 动作:上、下、左、右,每个动作等概率执行。
  • 终点:s9(第 3 行第 3 列),进入后回合终止。
  • 奖励:进入终点给 +1;其他所有非终点的转移给 -0.1,代表每步的行动代价。
  • 边界:越界动作停留在原地。
  • 折扣因子:γ = 0.9。
  • 演示策略:均匀随机策略,每个动作概率为 0.25。

这里选择 -0.1 的步数惩罚,是为了在价值函数中体现出“距离终点越远,价值越低”,否则所有非终点状态的价值可能区分度不够。这听起来是教学细节,但设计奖励时就决定了后续价值函数长什么样。真实项目里也一样,步数惩罚的数值直接影响最优策略是否倾向于尽快到达目标。

4.2 第一次、第二次迭代的手算与解读

用价值迭代的同步更新公式,从 V^0(s) = 0 开始。

第一次迭代,对非终点状态,因为 V^0 处处为 0,所以只需要看一步奖励的期望。计算后得到 V^1:

  • s1 到 s5、s7 这些不直接接触终点的状态:V^1 = -0.1
  • s6 和 s8:一个向下到 s9,一个向右到 s9,四个动作里包含一个 +1,所以 V^1 = 0.25 × (+1 - 0.1 - 0.1 - 0.1) = 0.175
  • s9 是终止状态:V^1 = 0

这轮结果其实不意外,它只反映“一步内能不能吃到终点奖励”。真正的信息在第二轮开始。

第二次迭代,以 s1(左上角)为例,它的两个动作(上、左)会撞墙留在原地,另外两个动作(右、下)分别进入 s2 和 s4。V^2(s1) 的计算过程是:

  • 上:-0.1 + 0.9 × (-0.1) = -0.19
  • 左:-0.1 + 0.9 × (-0.1) = -0.19
  • 右:-0.1 + 0.9 × (-0.1) = -0.19
  • 下:-0.1 + 0.9 × (-0.1) = -0.19
  • V^2(s1) = 0.25 × (-0.19 - 0.19 - 0.19 - 0.19) = -0.19

再看中心状态 s5(第 2 行第 2 列),四个方向分别进入 s2、s8、s4、s6。注意 s8 和 s6 在 V^1 中已经是 0.175,所以:

  • 上到 s2:-0.1 + 0.9 × (-0.1) = -0.19
  • 下到 s8:-0.1 + 0.9 × 0.175 = 0.0575
  • 左到 s4:-0.1 + 0.9 × (-0.1) = -0.19
  • 右到 s6:-0.1 + 0.9 × 0.175 = 0.0575
  • V^2(s5) = 0.25 × (-0.19 + 0.0575 - 0.19 + 0.0575) = -0.06625

第二次迭代后,完整 V^2 可以整理成下表:

状态V^2 值
s1-0.19
s2-0.19
s3-0.128125
s4-0.19
s5-0.06625
s60.169375
s7-0.128125
s80.169375
s90

这组数字非常有意思:离终点近的 s6、s8 已经变成正值,中心 s5 次之,角落 s1、s4 最差。价值函数开始“把距离翻译成数值”,这就是贝尔曼方程递归传播信息的效果。手算的价值不在于算出精确数字,而在于体会“未来价值是如何一步步传回当前的”。我强烈建议初学者至少手算一次这种小网格,比盯着代码看一小时都有用。

4.3 用一个小脚本验证迭代收敛

手算到第二轮已经略微繁琐,继续手写全部收敛过程不现实。工程上我们直接用价值迭代脚本完成后续计算。下面是我在本地跑过的完整脚本,结构刻意保持简单:

import numpy as np rows, cols = 3, 3 gamma = 0.9 actions = [(-1, 0), (1, 0), (0, -1), (0, 1)] # 上、下、左、右 V = np.zeros((rows, cols)) terminal = (2, 2) def step(state, action): r, c = state dr, dc = action nr, nc = r + dr, c + dc # 越界则原地不动 if nr < 0 or nr >= rows or nc < 0 or nc >= cols: nr, nc = r, c next_state = (nr, nc) if next_state == terminal: return next_state, 1.0 return next_state, -0.1 for k in range(30): newV = np.zeros_like(V) for r in range(rows): for c in range(cols): if (r, c) == terminal: continue state = (r, c) values = [] for a in actions: ns, rew = step(state, a) values.append(rew + gamma * V[ns]) newV[r, c] = np.mean(values) # 均匀随机策略 V = newV print(np.round(V, 4))

脚本里有两个值得注意的工程点:

  • 同步更新:每次迭代用上一轮完整的 V 表计算新表,不边算边改。这样可以保证每一步都在解同一个方程,结果更稳定。
  • 用 np.mean(values) 对应均匀随机策略;如果改成 np.max(values),就变成求解贝尔曼最优方程的价值迭代。两套方程在代码上只差一个函数,正是数学中“期望变最大”的直观体现。

运行结果会收敛到一个稳定矩阵,越靠近终点的状态 V 值越高,角落状态 V 值最低。看到这个结果再回头读一遍公式,很多疑问会自然消解。

5. 高频翻车现场:贝尔曼方程学习中的常见问题

5.1 期望方程与最优方程混为一谈

这是我在给组里新人讲强化学习时遇到最有代表性的问题:代码里明明在做价值迭代,更新公式却带着策略π;或者明明在做策略评估,却无脑用了 max。一句话判别方式:公式里如果出现策略 π(a|s),那就是期望方程;如果出现 max_a,那就是最优方程。期望方程告诉你“这个策略有多好”,最优方程告诉你“最好的活法长什么样”。

实际操作里另一个更隐蔽的误用是:用期望方程做策略评估时,没有把终止状态单独处理。终止状态的 V 应该恒为 0,并且不再参与更新。如果漏掉这个条件,终止状态会不断累积假价值,收敛结果完全失真。我在小网格例子里专门让 s9 跳过更新,就是这个原因。

5.2 折扣因子选不对,收敛和策略都受影响

γ 是超参数里最“灵活”但最容易被随意设置的一个。我见过有同学直接照抄别人的 0.99,结果在短任务上收敛奇慢,策略还显得过度远视;也有把 γ 设成 0.7 就跑去跑长线任务,最后策略只看眼前几步,完全不敢大胆探索。

实际经验是:

  • 任务步数短(几步到几十步),γ 可以取 0.9 左右。
  • 长线任务(几百上千步),γ 取 0.99 或更高。
  • 如果每一步都有不低的执行成本,γ 太大不仅收敛慢,还会在价值图中制造“拥挤的假高值区域”,影响策略质量。

另一个容易踩的坑:γ = 1 时,如果环境存在循环、且累积奖励不递减,价值函数可能发散。理论上无折扣有限步问题可以用 γ = 1,但工程上我几乎不用,因为数值稳定性太差。绝大多数强化学习框架默认值在 0.9 到 0.99 之间,是有道理的。

5.3 同步更新与原地更新,数值稳定性的坑

价值迭代有两种常见实现方式:同步更新和原地更新。同步更新需要维护新旧两张表,写的代码稍长,但每次迭代都基于完整旧表,行为更可控。原地更新只维护一张表,边算边覆盖,代码短、占用内存小,但迭代顺序会引入偏差,可能让收敛轨迹更“拧巴”,偶尔还会出现局部震荡的观感。

数学上,压缩映射保证两者最终都收敛到相同不动点,但收敛路径不同。我的建议是:调试阶段一定用同步更新,方便对照公式检查每一步数学是否符合预期;等代码稳定、环境超大、内存吃紧时,再考虑原地更新。亲手试过这两种实现后,你会对“为什么教程里总是强调用两个数组”有体感。

还有一个小技巧:判断是否收敛时,不要只看矩阵是否完全不再变化,而要看最大变化量是否在容差内。我在实现中用过:

delta = np.max(np.abs(newV - V)) if delta < 1e-4: break

这个小细节可以在长任务上省下大量无效迭代。

个人体会与下一步建议

我最初学贝尔曼方程时,最大的误区是想把公式背熟再去做题,结果背来背去还是绕不清。后来换了思路:不背公式,而是拿着纸笔在网格上一步一步写“站在这个格子,我的出路是什么,每条出路的即时收益加后续价值是多少”,几轮迭代后,期望方程和最优方程的差异自然而然地刻在脑子里了。如果你想真正突破这个章节,强烈建议你也把教程里的环境换成自己的小网格,设一组手算能处理的参数,务必亲自算到第二轮。这个过程里踩的坑,会变成后面理解 Q-learning 和深度强化学习时最扎实的底层直觉。下一步就可以开始看策略迭代和时序差分学习,到时候你会发现,贝尔曼方程这条根,几乎长在所有后续算法的主干上。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 9:29:44

Rocky Linux 部署 DHCP 服务器:配置、租约管理与运维实战

前阵子给一套内网做设备梳理&#xff0c;原路由器上挂着 DHCP 服务&#xff0c;平时看着正常&#xff0c;终端数量一过百&#xff0c;日志就开始冒出各种怪问题。折腾一圈后&#xff0c;我把 DHCP 迁到了独立的 Rocky Linux 服务器上&#xff0c;顺便把整个流程彻底整理了一遍。…

作者头像 李华
网站建设 2026/10/19 9:29:10

Wi-Fi标准演进的三大维度:PHY、MAC与兼容性解构

1. 为什么“初探”这个词在Wi-Fi标准学习中反而最危险刚接触Wi-Fi协议栈的开发者、网络运维新人&#xff0c;甚至不少做了多年无线设备测试的工程师&#xff0c;第一次看到“802.11a/b/g/n/ac/ax初探”这类标题时&#xff0c;下意识会松一口气——“哦&#xff0c;入门级内容&a…

作者头像 李华
网站建设 2026/10/19 9:28:25

840D SL TOOLBOX安装避坑指南:V4.7控制器匹配V4.7.3.0版本实操

简介&#xff1a;840D SL TOOLBOX 是西门子840D SL数控系统专用的全套调试与开发辅助工具集&#xff0c;面向机床电气工程师、PLC程序员及数控系统集成技术人员&#xff0c;用于完成PLC程序下载、报警配置、GSD/GSDML设备描述文件管理、NC变量监控、硬件组态&#xff08;S7HW A…

作者头像 李华
网站建设 2026/10/19 9:27:25

Lambda架构详解:从实时离线矛盾到数据一致性落地

搞数据平台时间长了&#xff0c;你会发现一个特别拧巴的现象&#xff1a;业务方白天盯着实时大屏&#xff0c;数字跳来跳去&#xff0c;晚上凌晨跑完批任务&#xff0c;出来的报表又是另一套数字。两边对不上&#xff0c;业务方就会质疑平台的数据能力。这个"实时要快、离…

作者头像 李华
网站建设 2026/10/19 9:27:12

基于SpringBoot的网上问卷调查系统:从数据库建模到统计报表实战解析

1. 项目概览&#xff1a;这个问卷调查系统到底能做什么做技术这么多年&#xff0c;我接触过不少“看起来很基础、做起来全是细节”的系统&#xff0c;网上问卷调查系统就是其中典型的一个。很多朋友一开始觉得它就是“问卷CRUD 答题页面”&#xff0c;真上手之后才发现&#x…

作者头像 李华
网站建设 2026/10/19 9:26:16

JAVA对接声网实现直播画面真实性监控

1. 为什么直播监控不能只靠“看画面”——从被动盯屏到主动截帧的思维转变在某跨平台教育直播系统上线后的第三周&#xff0c;运维团队连续收到三条来自不同区域的投诉&#xff1a;某导师在讲解高数微分方程时&#xff0c;学生端突然黑屏长达47秒&#xff0c;但后台日志显示推流…

作者头像 李华