【Agentic RL 智能体强化学习】第 02 篇:马尔可夫决策过程 — 强化学习的数学语言
本系列定位:从强化学习数学基础出发,系统讲解 LLM 对齐(RLHF/DPO/GRPO)到 Agentic RL(多轮智能体强化学习)的全链路,以 OpenRLHF 框架为实战主线。
本篇你将学到
- 马尔可夫决策过程(MDP)五元组 (S, A, P, R, γ) 的精确定义
- 状态转移、奖励函数、折扣因子的数学含义
- 如何用 ChatGPT 对齐场景类比 MDP——抽象数学的直觉化理解
- 贝尔曼方程的推导与直觉
- 用 Python 实现一个完整的 GridWorld MDP 环境
学完本篇,你将掌握强化学习最核心的数学框架,后续所有算法(PPO、GRPO 等)都在这个框架上构建。
一、为什么需要 MDP
在第 01 篇中,我们看到 ε-贪心策略通过"记住经验并利用"超越了随机策略。但那只解决了一个极简问题(多臂老虎机)。
真实的强化学习问题远比老虎机复杂:
- AlphaGo:棋盘上有 361 个位置,每步有数百种合法落子,要考虑几十步之后的影响
- ChatGPT:上下文窗口里有上千个 token,每个 token 的选择都影响后续生成的质量
- AI Agent:每一步可以选择生成文字、调用工具、执行代码,交互可能持续几十轮
这些场景有一个共同的数学结构——马尔可夫决策过程(Markov Decision Process, MDP)。MDP 是所有强化学习算法的基础语言。理解了它,你就理解了 RL 的"语法"。
二、MDP 五元组:定义 RL 世界的物理定律
2.1 形式化定义
一个 MDP 由五元组 ( S , A , P , R , γ ) (S, A, P, R, \gamma) (S,A,P,R,γ) 定义:
| 符号 | 名称 | 含义 | LLM 类比 |
|---|---|---|---|
| S S S | 状态空间 (State Space) | 所有可能状态的集合 | 上下文窗口中的 token 序列 |
| A A A | 动作空间 (Action Space) | 所有可能动作的集合 | 词汇表中所有可选的 token |
| P P P | 状态转移 (Transition) | P ( s ′ ∣ s , a ) P(s' | s, a) P(s′∣s,a):在状态 s s s 执行动作 a a a 后转到 s ′ s' s′ 的概率 | 选了 token a a a 后,新的上下文(状态)是确定的 |
| R R R | 奖励函数 (Reward) | R ( s , a ) R(s, a) R(s,a) 或 R ( s , a , s ′ ) R(s, a, s') R(s,a,s′):在状态 s s s 执行 a a a 的即时奖励 | 奖励模型对该回答的打分 |
| γ \gamma γ | 折扣因子 (Discount) | γ ∈ [ 0 , 1 ] \gamma \in [0, 1] γ∈[0,1]:未来奖励的重要性权重 | 对长对话中远处奖励的重视程度 |
2.2 马尔可夫性质
MDP 的"马"字来自马尔可夫性质(Markov Property):
未来只与现在有关,与过去无关。
数学表述:
P ( s t + 1 ∣ s t , a t , s t − 1 , a t − 1 , … , s 0 , a 0 ) = P ( s t + 1 ∣ s t , a t ) P(s_{t+1} | s_t, a_t, s_{t-1}, a_{t-1}, \ldots, s_0, a_0) = P(s_{t+1} | s_t, a_t) P(st+1∣st,at,st−1,at−1,…,s0,a0)=P(st+1∣st,at)
翻译成大白话:给定当前状态 s t s_t st 和当前动作 a t a_t at,未来状态 s t + 1 s_{t+1} st+1 的概率分布与所有历史无关。
为什么这个假设合理? 以 LLM 为例:当前状态就是"上下文窗口中的全部 token",它已经包含了所有历史信息。下一步生成什么 token,只取决于当前上下文,不需要知道"这个上下文是怎么一步步生成的"。Transformer 的自注意力机制天然满足马尔可夫性质。
2.3 用 ChatGPT 场景理解 MDP
让我们把 ChatGPT 的对齐过程映射到 MDP:
具体映射关系:
| MDP 要素 | ChatGPT RLHF 中的对应 |
|---|---|
| 状态 s t s_t st | [BOS] 用户:怎样学Python? [SEP] 助手: |
| 动作 a t a_t at | 下一个 token,如 "Python" |
| 状态转移 | 确定性的:新状态 = 旧状态 + 新 token |
| 奖励 R R R | 回答结束后,奖励模型对完整回答打分 |
| 策略 π ( a ∣ s ) \pi(a|s) π(a∣s) | LLM 的 token 概率分布 π θ ( ⋅ ∣ s t ) \pi_\theta(\cdot | s_t) πθ(⋅∣st) |
| 折扣因子 γ \gamma γ | 通常设为 1(不折扣,整个回答视为一个 Episode) |
💡 关键洞察:LLM 生成文本的过程,本质上就是一个 MDP。每个 token 的选择是一个"动作",模型就是一个"策略"。这就是为什么 RL 可以用来训练 LLM。
三、回合、回报与折扣因子
3.1 Episode(回合)
RL 中的一次完整交互称为一个 Episode(回合/轨迹)。从初始状态出发,经过一系列状态-动作-奖励,到达终止状态。
Episode = ( s 0 , a 0 , r 1 , s 1 , a 1 , r 2 , s 2 , … , s T ) \text{Episode} = (s_0, a_0, r_1, s_1, a_1, r_2, s_2, \ldots, s_T) Episode=(s0,a0,r1,s1,a1,r2,s2,…,sT)
| 场景 | Episode 示例 |
|---|---|
| AlphaGo | 一盘棋:从空棋盘到终局 |
| CartPole | 一次游戏:从平衡开始到杆子倒下 |
| ChatGPT 单轮 | 一次生成:从 prompt 到完整回答 |
| Agentic RL | 一次任务:从接收指令到调用工具完成任务 |
3.2 Return(回报)
回报 G t G_t Gt 是从时刻 t t t 开始到 Episode 结束的累积奖励:
G t = r t + 1 + γ r t + 2 + γ 2 r t + 3 + ⋯ = ∑ k = 0 ∞ γ k r t + k + 1 G_t = r_{t+1} + \gamma r_{t+2} + \gamma^2 r_{t+3} + \cdots = \sum_{k=0}^{\infty} \gamma^k r_{t+k+1} Gt=rt+1+γrt+2+γ2rt+3+⋯=k=0∑∞γkrt+k+1
折扣因子 γ \gamma γ 的作用是让近期的奖励比远期的更重要:
| γ \gamma γ 值 | 含义 | 效果 |
|---|---|---|
| γ = 0 \gamma = 0 γ=0 | 只看眼前 | 完全贪心,只关心下一步奖励 |
| γ = 0.9 \gamma = 0.9 γ=0.9 | 适度远视 | 未来 10 步的奖励权重降到 35% |
| γ = 0.99 \gamma = 0.99 γ=0.99 | 高度远视 | 未来 10 步的奖励权重还有 90% |
| γ = 1.0 \gamma = 1.0 γ=1.0 | 无折扣 | 所有未来奖励同等重要 |
在 LLM RLHF 中, γ \gamma γ 通常设为 1.0——因为一次生成被视为一个完整的 Episode,中间步骤没有独立的奖励信号(奖励只在回答结束时给出)。
3.3 折扣因子的数学意义
为什么需要折扣因子?三个原因:
- 数学便利:保证回报 G t G_t Gt 是有限的(当 Episode 无限长时)
- 不确定性:远期奖励更难预测,应该权重更低
- 人类偏好:生物本能上更偏好即时满足
对于有限长度的 Episode(如 LLM 生成), γ = 1 \gamma=1 γ=1 是合理的。对于可能无限延续的环境(如 Agent 与工具的持续交互), γ < 1 \gamma < 1 γ<1 是必要的。
四、策略与价值函数
4.1 策略 (Policy)
策略 π ( a ∣ s ) \pi(a|s) π(a∣s) 是状态到动作概率分布的映射:
π ( a ∣ s ) = P ( A t = a ∣ S t = s ) \pi(a|s) = P(A_t = a | S_t = s) π(a∣s)=P(At=a∣St=s)
它回答了一个核心问题:在状态 s s s 下,应该以多大概率选择动作 a a a?
| 策略类型 | 定义 | 示例 |
|---|---|---|
| 确定性策略 | π ( s ) = a \pi(s) = a π(s)=a | 在状态 s s s 永远选固定的动作 a a a |
| 随机性策略 | π ( a ∣ s ) ∈ [ 0 , 1 ] \pi(a|s) \in [0,1] π(a∣s)∈[0,1] | 以一定概率分布选择动作 |
LLM 天然是随机性策略——在给定上下文下,它输出词汇表上的概率分布。采样温度(temperature)控制这个分布的"随机程度"。
4.2 状态价值函数 V π ( s ) V_\pi(s) Vπ(s)
状态价值函数回答:从状态 s s s 出发,遵循策略 π \pi π,预期能获得多少回报?
V π ( s ) = E π [ G t ∣ S t = s ] = E π [ ∑ k = 0 ∞ γ k r t + k + 1 ∣ S t = s ] V_\pi(s) = \mathbb{E}_\pi \left[ G_t | S_t = s \right] = \mathbb{E}_\pi \left[ \sum_{k=0}^{\infty} \gamma^k r_{t+k+1} \bigg| S_t = s \right] Vπ(s)=Eπ[Gt∣St=s]=Eπ[k=0∑∞γkrt+k+1 St=s]
直觉: V π ( s ) V_\pi(s) Vπ(s) 高 → 当前状态"好"; V π ( s ) V_\pi(s) Vπ(s) 低 → 当前状态"差"。
4.3 动作价值函数 Q π ( s , a ) Q_\pi(s, a) Qπ(s,a)
动作价值函数回答:在状态 s s s 执行动作 a a a,之后遵循策略 π \pi π,预期获得多少回报?
Q π ( s , a ) = E π [ G t ∣ S t = s , A t = a ] Q_\pi(s, a) = \mathbb{E}_\pi \left[ G_t | S_t = s, A_t = a \right] Qπ(s,a)=Eπ[Gt∣St=s,At=a]
V V V 和 Q Q Q 的关系:
V π ( s ) = ∑ a π ( a ∣ s ) ⋅ Q π ( s , a ) V_\pi(s) = \sum_a \pi(a|s) \cdot Q_\pi(s, a) Vπ(s)=a∑π(a∣s)⋅Qπ(s,a)
翻译成大白话:状态 s s s 的价值 = 所有可能动作的价值按策略概率加权求和。
4.4 价值函数的直觉
用一个简单例子来理解。假设你在迷宫中:
在这个迷宫中:
- V ( C ) = − 1 V(C) = -1 V(C)=−1(到达死路,获得 -1 奖励)
- V ( D ) = + 10 V(D) = +10 V(D)=+10(到达宝藏,获得 +10 奖励)
- V ( B ) = 0.5 × V ( C ) + 0.5 × V ( D ) = 0.5 × ( − 1 ) + 0.5 × 10 = 4.5 V(B) = 0.5 \times V(C) + 0.5 \times V(D) = 0.5 \times (-1) + 0.5 \times 10 = 4.5 V(B)=0.5×V(C)+0.5×V(D)=0.5×(−1)+0.5×10=4.5(如果上下各 50% 概率)
- 在 B 点, Q ( B , 下走 ) = 10 > Q ( B , 上走 ) = − 1 Q(B, \text{下走}) = 10 > Q(B, \text{上走}) = -1 Q(B,下走)=10>Q(B,上走)=−1,所以应该往下走
这就是 RL 的核心思想:通过比较 Q Q Q 值来做出更好的决策。
五、贝尔曼方程:RL 的递归灵魂
5.1 直觉
价值函数有一个优美的递归结构——当前状态的价值 = 即时奖励 + 下一状态的价值。
就像复利公式:今天的财富 = 今天的收入 + 明天的财富 × 折扣率。
5.2 贝尔曼期望方程
状态价值的贝尔曼方程:
V π ( s ) = ∑ a π ( a ∣ s ) ∑ s ′ P ( s ′ ∣ s , a ) [ R ( s , a , s ′ ) + γ V π ( s ′ ) ] V_\pi(s) = \sum_a \pi(a|s) \sum_{s'} P(s'|s,a) \left[ R(s,a,s') + \gamma V_\pi(s') \right] Vπ(s)=a∑π(a∣s)s′∑P(s′∣s,a)[R(s,a,s′)+γVπ(s′)]
动作价值的贝尔曼方程:
Q π ( s , a ) = ∑ s ′ P ( s ′ ∣ s , a ) [ R ( s , a , s ′ ) + γ ∑ a ′ π ( a ′ ∣ s ′ ) Q π ( s ′ , a ′ ) ] Q_\pi(s,a) = \sum_{s'} P(s'|s,a) \left[ R(s,a,s') + \gamma \sum_{a'} \pi(a'|s') Q_\pi(s',a') \right] Qπ(s,a)=s′∑P(s′∣s,a)[R(s,a,s′)+γa′∑π(a′∣s′)Qπ(s′,a′)]
用文字解读这个方程:
5.3 贝尔曼最优方程
当我们想找到最优策略 π ∗ \pi^* π∗ 时,对应的贝尔曼最优方程:
V ∗ ( s ) = max a ∑ s ′ P ( s ′ ∣ s , a ) [ R ( s , a , s ′ ) + γ V ∗ ( s ′ ) ] V^*(s) = \max_a \sum_{s'} P(s'|s,a) \left[ R(s,a,s') + \gamma V^*(s') \right] V∗(s)=amaxs′∑P(s′∣s,a)[R(s,a,s′)+γV∗(s′)]
Q ∗ ( s , a ) = ∑ s ′ P ( s ′ ∣ s , a ) [ R ( s , a , s ′ ) + γ max a ′ Q ∗ ( s ′ , a ′ ) ] Q^*(s,a) = \sum_{s'} P(s'|s,a) \left[ R(s,a,s') + \gamma \max_{a'} Q^*(s',a') \right] Q∗(s,a)=s′∑P(s′∣s,a)[R(s,a,s′)+γa′maxQ∗(s′,a′)]
注意:最优方程把期望 ∑ a π ( a ∣ s ) \sum_a \pi(a|s) ∑aπ(a∣s) 换成了 max a \max_a maxa——不再"平均",而是"选最好的"。
🔑 后续关联:Q-Learning(第 04 篇)直接利用贝尔曼最优方程来学习 Q ∗ Q^* Q∗。PPO(第 07 篇)通过策略梯度来逼近最优策略。
六、部分可观测 MDP(POMDP)
6.1 现实中的不完全信息
经典 MDP 假设 Agent 完全知道当前状态。但现实中,Agent 往往只能观察到状态的一部分——这就是 POMDP(Partially Observable MDP)。
POMDP 在 MDP 五元组基础上增加两个要素:
| 新增要素 | 含义 |
|---|---|
| 观测空间 O O O | Agent 能感知到的信息 |
| 观测函数 Z ( o ∣ s , a ) Z(o|s,a) Z(o∣s,a) | 执行动作 a a a 后到达状态 s ′ s' s′ 时,观测到 o o o 的概率 |
6.2 LLM 与 POMDP
LLM 的生成过程实际上更接近 POMDP 而非标准 MDP:
- 观测:输入上下文(token 序列),而非"真实状态"
- 隐藏状态:Transformer 的内部表征(注意力模式、隐藏层激活)
- 策略:基于观测(token 序列)生成动作(下一个 token)
不过在实际 RLHF 实现中,我们把 token 序列直接当作"状态"来处理,这样就回到了标准 MDP 框架。这是一种合理的简化。
七、实战:GridWorld MDP 环境实现
现在让我们用代码实现一个完整的 MDP 环境。GridWorld 是 RL 教学的经典场景——一个网格世界,Agent 需要从起点走到终点。
7.1 环境设计
"""
AgentRL-Lab v0.1: GridWorld MDP 环境
这是一个标准的网格世界 MDP:
- 4×4 网格,左上角为起点,右下角为终点
- 每步奖励 -1(鼓励快速到达终点)
- 碰墙不动,原地奖励 -1
- 到达终点奖励 +10,游戏结束
"""
import numpy as np
import matplotlib.pyplot as plt
from typing import Tuple, Optional
class GridWorld:
"""GridWorld MDP 环境"""
# 动作定义
UP, DOWN, LEFT, RIGHT = 0, 1, 2, 3
ACTION_NAMES = ["↑ 上", "↓ 下", "← 左", "→ 右"]
def __init__(self, size: int = 4):
self.size = size
self.n_states = size * size
self.n_actions = 4
# 终止状态:右下角
self.terminal_state = self.n_states - 1
# 起始状态:左上角
self.start_state = 0
# 构建状态转移矩阵 P[s][a] = (next_state, reward, done)
self.P = self._build_transition_matrix()
self.current_state = self.start_state
def _state_to_pos(self, state: int) -> Tuple[int, int]:
"""状态编号 → (行, 列)"""
return state // self.size, state % self.size
def _pos_to_state(self, row: int, col: int) -> int:
"""(行, 列) → 状态编号"""
return row * self.size + col
def _build_transition_matrix(self):
"""
构建状态转移矩阵
P[s][a] = (next_state, reward, is_terminal)
"""
P = {}
for s in range(self.n_states):
P[s] = {}
row, col = self._state_to_pos(s)
for a in range(self.n_actions):
if s == self.terminal_state:
# 终止状态:保持在原地,奖励 0
P[s][a] = (s, 0.0, True)
continue
# 计算下一个位置
next_row, next_col = row, col
if a == self.UP:
next_row = max(0, row - 1)
elif a == self.DOWN:
next_row = min(self.size - 1, row + 1)
elif a == self.LEFT:
next_col = max(0, col - 1)
elif a == self.RIGHT:
next_col = min(self.size - 1, col + 1)
next_state = self._pos_to_state(next_row, next_col)
# 奖励设计
if next_state == self.terminal_state:
reward = 10.0 # 到达终点
else:
reward = -1.0 # 每步惩罚
P[s][a] = (next_state, reward, next_state == self.terminal_state)
return P
def reset(self, seed: Optional[int] = None) -> int:
"""重置环境,返回初始状态"""
if seed is not None:
np.random.seed(seed)
self.current_state = self.start_state
return self.current_state
def step(self, action: int) -> Tuple[int, float, bool]:
"""
执行动作
返回: (next_state, reward, done)
"""
next_state, reward, done = self.P[self.current_state][action]
self.current_state = next_state
return next_state, reward, done
def render(self):
"""可视化当前状态"""
grid = np.full((self.size, self.size), "·")
grid[0][0] = "S" # 起点
grid[self.size - 1][self.size - 1] = "G" # 终点
row, col = self._state_to_pos(self.current_state)
if self.current_state not in (self.start_state, self.terminal_state):
grid[row][col] = "A" # Agent
print("\nGridWorld 状态:")
print("+" + "--+" * self.size)
for r in range(self.size):
row_str = "|"
for c in range(self.size):
row_str += f" {grid[r][c]}|"
print(row_str)
print("+" + "--+" * self.size)
if __name__ == "__main__":
env = GridWorld(size=4)
print(f"状态空间: {env.n_states} 个状态")
print(f"动作空间: {env.n_actions} 个动作 {env.ACTION_NAMES}")
print(f"起点: 状态 {env.start_state}, 终点: 状态 {env.terminal_state}")
print()
# 展示状态转移矩阵的一部分
print("=== 状态转移矩阵示例 ===")
for s in [0, 5, 10]:
print(f"\n状态 {s} (位置 {env._state_to_pos(s)}):")
for a in range(env.n_actions):
next_s, r, done = env.P[s][a]
print(f" {env.ACTION_NAMES[a]:>6} → 状态{next_s:2d}, 奖励={r:+.0f}, 结束={done}")
# 运行一个随机策略的 Episode
print("\n=== 随机策略 Episode 示例 ===")
state = env.reset(seed=42)
env.render()
total_reward = 0
steps = 0
while True:
action = np.random.randint(env.n_actions)
next_state, reward, done = env.step(action)
total_reward += reward
steps += 1
print(f"步骤 {steps}: {env.ACTION_NAMES[action]} → 状态{next_state}, 奖励={reward:+.0f}")
if done or steps >= 50:
break
state = next_state
print(f"\nEpisode 结束: 总步数={steps}, 总奖励={total_reward:+.0f}")
运行后你会看到类似输出:
状态空间: 16 个状态
动作空间: 4 个动作 ['↑ 上', '↓ 下', '← 左', '→ 右']
起点: 状态 0, 终点: 状态 15
=== 状态转移矩阵示例 ===
状态 0 (位置 (0, 0)):
↑ 上 → 状态 0, 奖励=-1, 结束=False
↓ 下 → 状态 4, 奖励=-1, 结束=False
← 左 → 状态 0, 奖励=-1, 结束=False
→ 右 → 状态 1, 奖励=-1, 结束=False
状态 5 (位置 (1, 1)):
↑ 上 → 状态 1, 奖励=-1, 结束=False
↓ 下 → 状态 9, 奖励=-1, 结束=False
← 左 → 状态 4, 奖励=-1, 结束=False
→ 右 → 状态 6, 奖励=-1, 结束=False
7.2 用价值迭代求解最优策略
有了 MDP 环境后,我们可以用价值迭代(Value Iteration)来求解最优策略。这直接利用了贝尔曼最优方程:
"""
GridWorld 价值迭代:用贝尔曼最优方程求最优策略
"""
import numpy as np
def value_iteration(env, gamma=0.99, theta=1e-6, max_iter=1000):
"""
价值迭代算法
直接利用贝尔曼最优方程 V*(s) = max_a Σ P(s'|s,a)[R + γV*(s')]
Args:
env: GridWorld 环境
gamma: 折扣因子
theta: 收敛阈值
max_iter: 最大迭代次数
Returns:
V: 最优状态价值
policy: 最优策略
"""
V = np.zeros(env.n_states)
for iteration in range(max_iter):
delta = 0
for s in range(env.n_states):
# 跳过终止状态
if s == env.terminal_state:
continue
# 计算每个动作的价值
action_values = []
for a in range(env.n_actions):
next_s, reward, done = env.P[s][a]
# Q(s,a) = R + γV(s')(GridWorld 是确定性的)
q_value = reward + gamma * V[next_s] * (not done)
action_values.append(q_value)
# 贝尔曼最优方程:取最大的 Q 值
old_v = V[s]
V[s] = max(action_values)
delta = max(delta, abs(old_v - V[s]))
if delta < theta:
print(f"价值迭代在第 {iteration + 1} 轮收敛")
break
# 从最优价值函数提取最优策略
policy = np.zeros(env.n_states, dtype=int)
for s in range(env.n_states):
if s == env.terminal_state:
continue
action_values = []
for a in range(env.n_actions):
next_s, reward, done = env.P[s][a]
q_value = reward + gamma * V[next_s] * (not done)
action_values.append(q_value)
policy[s] = np.argmax(action_values)
return V, policy
def print_value_function(env, V):
"""以网格形式打印价值函数"""
print("\n最优状态价值函数 V*(s):")
print("+" + "--------+" * env.size)
for r in range(env.size):
row_str = "|"
for c in range(env.size):
s = r * env.size + c
row_str += f" {V[s]:+6.2f} |"
print(row_str)
print("+" + "--------+" * env.size)
def print_policy(env, policy):
"""以网格形式打印策略"""
arrows = ["↑", "↓", "←", "→"]
print("\n最优策略 π*(s):")
print("+" + "----+" * env.size)
for r in range(env.size):
row_str = "|"
for c in range(env.size):
s = r * env.size + c
if s == env.terminal_state:
row_str += " G |"
elif s == env.start_state:
row_str += f" S{arrows[policy[s]]} |"
else:
row_str += f" {arrows[policy[s]]} |"
print(row_str)
print("+" + "----+" * env.size)
if __name__ == "__main__":
from gridworld import GridWorld
env = GridWorld(size=4)
# 价值迭代求解
V, policy = value_iteration(env, gamma=0.99)
print_value_function(env, V)
print_policy(env, policy)
# 用最优策略走一遍
print("\n=== 最优策略 Episode ===")
state = env.reset(seed=42)
total_reward = 0
steps = 0
while True:
action = policy[state]
next_state, reward, done = env.step(action)
total_reward += reward
steps += 1
action_name = env.ACTION_NAMES[action]
print(f" 步骤 {steps}: 状态{state:2d} → {action_name} → 状态{next_state:2d}, 奖励={reward:+.0f}")
state = next_state
if done or steps >= 20:
break
print(f"\n最优策略: 总步数={steps}, 总奖励={total_reward:+.0f}")
print("💡 对比随机策略(通常需要 20-50 步),最优策略只需要 6 步!")
预期输出:
价值迭代在第 22 轮收敛
最优状态价值函数 V*(s):
+--------+--------+--------+--------+
| +4.80 | +5.86 | +6.93 | +7.92 |
+--------+--------+--------+--------+
| +5.86 | +6.93 | +7.92 | +8.92 |
+--------+--------+--------+--------+
| +6.93 | +7.92 | +8.92 | +9.50 |
+--------+--------+--------+--------+
| +7.92 | +8.92 | +9.50 | +0.00 |
+--------+--------+--------+--------+
最优策略 π*(s):
+----+----+----+----+
| S→ | → | ↓ | ↓ |
+----+----+----+----+
| ↓ | ↓ | ↓ | ↓ |
+----+----+----+----+
| ↓ | ↓ | ↓ | ↓ |
+----+----+----+----+
| → | → | → | G |
+----+----+----+----+
=== 最优策略 Episode ===
步骤 1: 状态 0 → →右 → 状态 1, 奖励=-1
步骤 2: 状态 1 → →右 → 状态 2, 奖励=-1
步骤 3: 状态 2 → ↓下 → 状态 6, 奖励=-1
步骤 4: 状态 6 → ↓下 → 状态10, 奖励=-1
步骤 5: 状态10 → ↓下 → 状态14, 奖励=-1
步骤 6: 状态14 → →右 → 状态15, 奖励=+10
最优策略: 总步数=6, 总奖励=+5
💡 对比随机策略(通常需要 20-50 步),最优策略只需要 6 步!
注意价值函数的规律:离终点越近的状态价值越高,这完全符合直觉——离目标越近,预期回报越大。
7.3 代码解读
价值迭代算法的核心是一个两步循环:
这段代码虽然是为 GridWorld 写的,但它体现的思想是通用的:
- 贝尔曼最优方程是可计算的——通过反复迭代,价值函数会收敛到最优
- 最优策略可以从最优价值函数提取——在每个状态选 Q 值最大的动作
- 折扣因子影响收敛速度和策略——gamma 越大,考虑越远,收敛越慢
在后续文章中,当我们讨论 PPO 和 GRPO 时,你会看到同样的"估计价值 → 选择更好的动作 → 更新策略"的范式,只是从精确计算变成了用神经网络去逼近。
本篇小结
| 知识点 | 核心内容 |
|---|---|
| MDP 五元组 | ( S , A , P , R , γ ) (S, A, P, R, \gamma) (S,A,P,R,γ):状态、动作、转移、奖励、折扣 |
| 马尔可夫性质 | 未来只与现在有关: P ( s ′ ∣ s , a ) P(s'|s,a) P(s′∣s,a) 不依赖历史 |
| Return(回报) | G t = ∑ k = 0 ∞ γ k r t + k + 1 G_t = \sum_{k=0}^{\infty} \gamma^k r_{t+k+1} Gt=∑k=0∞γkrt+k+1:累积折扣奖励 |
| 状态价值 V π ( s ) V_\pi(s) Vπ(s) | 从状态 s s s 出发遵循策略 π \pi π 的预期回报 |
| 动作价值 Q π ( s , a ) Q_\pi(s,a) Qπ(s,a) | 在状态 s s s 执行动作 a a a 后遵循 π \pi π 的预期回报 |
| 贝尔曼方程 | V ( s ) = ∑ a π ( a ∣ s ) ∑ s ′ P ( s ′ ∣ s , a ) [ R + γ V ( s ′ ) ] V(s) = \sum_a \pi(a|s) \sum_{s'} P(s'|s,a)[R + \gamma V(s')] V(s)=∑aπ(a∣s)∑s′P(s′∣s,a)[R+γV(s′)]:递归结构 |
| 价值迭代 | 反复用贝尔曼最优方程更新 V 直到收敛,再提取最优策略 |
下篇预告
第 03 篇:值函数与贝尔曼方程 — 评估"好不好"的数学工具
深入贝尔曼方程的计算方法——蒙特卡洛估计和时序差分学习。这两种方法是对后续 PPO 和 GRPO 理解的基础。
如果本篇内容对你有帮助,欢迎点赞收藏!有任何疑问,欢迎在评论区交流。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/m0_68987304/article/details/163877913



