
从马尔可夫决策过程到贝尔曼方程,理解强化学习的核心算法
开头:怎么让机器「学会」决策?
上一篇我们学习了玻尔兹曼机,用能量函数建模概率分布。
今天我们学习动态规划------强化学习的数学基础。
监督学习: 输入 → 正确答案(标签)
强化学习: 状态 → 动作 → 奖励(没有正确答案)
问题:
机器怎么知道哪个动作是「好」的?
答案:
最大化累积奖励
动态规划提供了解决这个问题的数学框架
一、马尔可夫决策过程(MDP)
1.1 MDP 的定义
马尔可夫决策过程(MDP)
═══════════════════════════════════════════════════════════════════
五元组:(S, A, P, R, γ)
S:状态空间(所有可能的状态)
A:动作空间(所有可能的动作)
P:转移概率 P(s'|s, a)
R:奖励函数 R(s, a, s')
γ:折扣因子 γ ∈ [0, 1)
马尔可夫性:
P(s_{t+1} | s_t, a_t, s_{t-1}, a_{t-1}, ...) = P(s_{t+1} | s_t, a_t)
→ 未来只依赖于当前状态,与历史无关
1.2 例子:网格世界
网格世界示例
═══════════════════════════════════════════════════════════════════
状态:网格位置 (i, j)
动作:上、下、左、右
转移:移动到相邻格子(可能有随机性)
奖励:到达目标 +100,撞墙 -1,每步 -1
┌───┬───┬───┬───┐
│ │ │ │ G │ G = 目标(+100)
├───┼───┼───┼───┤
│ │ X │ │ │ X = 障碍物(-100)
├───┼───┼───┼───┤
│ S │ │ │ │ S = 起点
└───┴───┴───┴───┘
目标:找到从 S 到 G 的最优路径
二、贝尔曼方程
2.1 值函数
值函数(Value Function)
═══════════════════════════════════════════════════════════════════
状态值函数 V^π(s):
在状态 s 下,遵循策略 π 的期望累积奖励
V^π(s) = E[Σ_{t=0}^∞ γ^t r_t | s_0 = s]
动作值函数 Q^π(s, a):
在状态 s 下,执行动作 a,然后遵循策略 π 的期望累积奖励
Q^π(s, a) = E[Σ_{t=0}^∞ γ^t r_t | s_0 = s, a_0 = a]
关系:
V^π(s) = Σ_a π(a|s) Q^π(s, a)
2.2 贝尔曼期望方程
贝尔曼期望方程
═══════════════════════════════════════════════════════════════════
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')]
直觉:
当前值 = 即时奖励 + 折扣的未来值
2.3 贝尔曼最优方程
贝尔曼最优方程
═══════════════════════════════════════════════════════════════════
V*(s) = max_a Σ_{s'} 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')]
最优策略:
π*(s) = argmax_a Q*(s, a)
意义:
最优值满足贝尔曼最优方程
求解这个方程就能得到最优策略
三、值迭代
3.1 算法
值迭代算法
═══════════════════════════════════════════════════════════════════
输入:
MDP (S, A, P, R, γ)
收敛阈值 θ
步骤:
1. 初始化 V(s) = 0 for all s
2. 重复直到收敛:
for each state s:
V_old(s) = V(s)
V(s) = max_a Σ_{s'} P(s'|s,a) [R(s,a,s') + γ V(s')]
if max_s |V(s) - V_old(s)| < θ:
break
3. 提取最优策略:
π*(s) = argmax_a Σ_{s'} P(s'|s,a) [R(s,a,s') + γ V(s')]
输出:
最优值函数 V*
最优策略 π*
3.2 收敛性
值迭代的收敛性
═══════════════════════════════════════════════════════════════════
定理:
值迭代算法收敛到唯一的最优值函数 V*
收敛速度:
|V_k - V*| ≤ γ^k |V_0 - V*|
→ 几何级数收敛
条件:
- 0 ≤ γ < 1
- 状态空间有限
四、策略迭代
4.1 算法
策略迭代算法
═══════════════════════════════════════════════════════════════════
输入:
MDP (S, A, P, R, γ)
步骤:
1. 初始化策略 π(随机或贪心)
2. 重复直到收敛:
a. 策略评估:计算 V^π
重复直到收敛:
for each state s:
V(s) = Σ_a π(a|s) Σ_{s'} P(s'|s,a) [R(s,a,s') + γ V(s')]
b. 策略改进:更新 π
for each state s:
π(s) = argmax_a Σ_{s'} P(s'|s,a) [R(s,a,s') + γ V(s')]
if π 没有变化:
break
输出:
最优策略 π*
4.2 值迭代 vs 策略迭代
| 特性 | 值迭代 | 策略迭代 |
|---|---|---|
| 每次迭代 | 更新值函数 | 评估 + 改进策略 |
| 收敛速度 | 慢 | 快 |
| 计算量 | 小 | 大 |
| 实现难度 | 简单 | 复杂 |
五、Python 实现
5.1 网格世界环境
python
import numpy as np
import matplotlib.pyplot as plt
class GridWorld:
"""网格世界环境"""
def __init__(self, rows=4, cols=4, goal_pos=(0, 3), obstacle_pos=(1, 1)):
self.rows = rows
self.cols = cols
self.goal_pos = goal_pos
self.obstacle_pos = obstacle_pos
# 动作:上、下、左、右
self.actions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
self.n_actions = len(self.actions)
# 状态数
self.n_states = rows * cols
def state_to_pos(self, state):
"""状态编号转坐标"""
return (state // self.cols, state % self.cols)
def pos_to_state(self, pos):
"""坐标转状态编号"""
return pos[0] * self.cols + pos[1]
def step(self, state, action):
"""执行动作,返回 (next_state, reward, done)"""
pos = self.state_to_pos(state)
new_pos = (pos[0] + self.actions[action][0],
pos[1] + self.actions[action][1])
# 边界检查
if new_pos[0] < 0 or new_pos[0] >= self.rows or \
new_pos[1] < 0 or new_pos[1] >= self.cols:
new_pos = pos # 撞墙,不动
# 障碍物检查
if new_pos == self.obstacle_pos:
new_pos = pos # 撞障碍物,不动
next_state = self.pos_to_state(new_pos)
# 奖励
if new_pos == self.goal_pos:
reward = 100
done = True
else:
reward = -1
done = False
return next_state, reward, done
def get_transitions(self, state, action):
"""获取转移概率(确定性环境)"""
next_state, reward, done = self.step(state, action)
return [(1.0, next_state, reward)]
5.2 值迭代实现
python
def value_iteration(env, gamma=0.99, theta=1e-6):
"""值迭代算法"""
V = np.zeros(env.n_states)
policy = np.zeros(env.n_states, dtype=int)
iteration = 0
while True:
V_old = V.copy()
for s in range(env.n_states):
q_values = []
for a in range(env.n_actions):
q = 0
for prob, next_state, reward in env.get_transitions(s, a):
q += prob * (reward + gamma * V[next_state])
q_values.append(q)
V[s] = max(q_values)
policy[s] = np.argmax(q_values)
iteration += 1
if np.max(np.abs(V - V_old)) < theta:
break
print(f"值迭代收敛于 {iteration} 轮")
return V, policy
5.3 策略迭代实现
python
def policy_evaluation(env, policy, gamma=0.99, theta=1e-6):
"""策略评估"""
V = np.zeros(env.n_states)
while True:
V_old = V.copy()
for s in range(env.n_states):
a = policy[s]
q = 0
for prob, next_state, reward in env.get_transitions(s, a):
q += prob * (reward + gamma * V[next_state])
V[s] = q
if np.max(np.abs(V - V_old)) < theta:
break
return V
def policy_iteration(env, gamma=0.99):
"""策略迭代算法"""
policy = np.random.randint(0, env.n_actions, env.n_states)
iteration = 0
while True:
# 策略评估
V = policy_evaluation(env, policy, gamma)
# 策略改进
new_policy = np.zeros(env.n_states, dtype=int)
for s in range(env.n_states):
q_values = []
for a in range(env.n_actions):
q = 0
for prob, next_state, reward in env.get_transitions(s, a):
q += prob * (reward + gamma * V[next_state])
q_values.append(q)
new_policy[s] = np.argmax(q_values)
iteration += 1
if np.array_equal(new_policy, policy):
break
policy = new_policy
print(f"策略迭代收敛于 {iteration} 轮")
return V, policy
5.4 测试
python
# 创建环境
env = GridWorld(rows=4, cols=4, goal_pos=(0, 3), obstacle_pos=(1, 1))
# 值迭代
V_vi, policy_vi = value_iteration(env, gamma=0.99)
# 策略迭代
V_pi, policy_pi = policy_iteration(env, gamma=0.99)
# 可视化值函数
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# 值迭代结果
ax1 = axes[0]
ax1.imshow(V_vi.reshape(4, 4), cmap='viridis')
ax1.set_title('Value Iteration')
for i in range(4):
for j in range(4):
ax1.text(j, i, f'{V_vi[i*4+j]:.1f}', ha='center', va='center')
# 策略迭代结果
ax2 = axes[1]
ax2.imshow(V_pi.reshape(4, 4), cmap='viridis')
ax2.set_title('Policy Iteration')
for i in range(4):
for j in range(4):
ax2.text(j, i, f'{V_pi[i*4+j]:.1f}', ha='center', va='center')
plt.tight_layout()
plt.show()
# 可视化策略
action_symbols = ['↑', '↓', '←', '→']
policy_grid = np.array([action_symbols[policy_vi[i]] for i in range(16)]).reshape(4, 4)
print("最优策略(值迭代):")
print(policy_grid)
六、工业应用
6.1 机器人控制
机器人控制
═══════════════════════════════════════════════════════════════════
状态:机器人的位置、速度、姿态
动作:电机控制信号
奖励:到达目标 +100,碰撞 -100
应用:
- 路径规划
- 运动控制
- 自主导航
6.2 游戏 AI
游戏 AI
═══════════════════════════════════════════════════════════════════
AlphaGo:
状态:棋盘局面
动作:落子位置
奖励:赢 +1,输 -1,平 0
方法:
- 蒙特卡洛树搜索(MCTS)
- 深度强化学习
6.3 推荐系统
推荐系统
═══════════════════════════════════════════════════════════════════
状态:用户历史行为
动作:推荐物品
奖励:用户点击/购买 +1,忽略 0
应用:
- 个性化推荐
- 广告投放
- 内容分发
七、避坑指南:使用动态规划的 3 个陷阱
坑 1:γ 太大 → 收敛慢
错误做法:gamma=0.9999
python
# ❌ γ 太大
V, policy = value_iteration(env, gamma=0.9999)
# 需要很多轮才能收敛
正确做法:根据问题选择合适的 γ
python
# ✅ 通常 γ = 0.9 ~ 0.99
V, policy = value_iteration(env, gamma=0.99)
坑 2:γ 太小 → 只考虑短期奖励
错误做法:gamma=0.1
python
# ❌ γ 太小
V, policy = value_iteration(env, gamma=0.1)
# 只考虑下一步的奖励,忽略长期目标
正确做法:需要平衡短期和长期奖励
python
# ✅ γ = 0.9 可以看到较远的未来
V, policy = value_iteration(env, gamma=0.9)
坑 3:状态空间太大 → 计算量爆炸
错误做法:100×100 网格
python
# ❌ 状态空间太大
env = GridWorld(rows=100, cols=100)
# 10000 个状态,每个状态要计算 4 个动作
# 计算量太大
正确做法:用函数逼近(如深度强化学习)
python
# ✅ 用神经网络逼近值函数
# Deep Q-Network (DQN)
import torch
import torch.nn as nn
class DQN(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
self.fc1 = nn.Linear(state_dim, 128)
self.fc2 = nn.Linear(128, 128)
self.fc3 = nn.Linear(128, action_dim)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
return self.fc3(x)
八、本篇总结
核心要点回顾
- MDP:状态、动作、转移概率、奖励、折扣因子
- 值函数:V(s) 状态值,Q(s,a) 动作值
- 贝尔曼方程:当前值 = 即时奖励 + 折扣的未来值
- 值迭代:迭代更新值函数,直到收敛
- 策略迭代:交替进行策略评估和策略改进
- γ 的作用:平衡短期和长期奖励
下篇预告
下一篇我们学习 Hopfield 网络。
动态规划解决的是「决策」问题,Hopfield 网络解决的是「记忆」问题。
下一篇你将学到:
- Hopfield 网络的结构
- 联想记忆的原理
- 能量函数与稳定性
- 用 Python 手写 Hopfield 网络
本期互动
你对动态规划有什么看法?
- 你用过强化学习吗?在什么场景下?
- 你觉得 DQN 和传统动态规划有什么区别?
- 你知道强化学习的哪些应用?
欢迎在评论区留言。
系列目录
| 篇 | 标题 | 状态 |
|---|---|---|
| 01 | Haykin 精讲开篇:从「只会调参」到「理解神经网络的灵魂」 | ✅ 完成 |
| 02 | 感知器:神经网络的「鼻祖」,为什么它能「学会」分类? | ✅ 完成 |
| 03 | LMS 算法:从最小二乘到随机梯度下降,工业自适应滤波的核心 | ✅ 完成 |
| 04 | 反向传播:神经网络为什么能「学习」?用 NumPy 手写 BP | ✅ 完成 |
| 05 | 核方法:为什么 SVM 能处理非线性问题?理解「升维」的本质 | ✅ 完成 |
| 06 | 支持向量机:最大间隔的「艺术」,为什么它是「小数据之王」? | ✅ 完成 |
| 07 | 正则化:为什么模型越复杂越容易过拟合?L1/L2/Dropout | ✅ 完成 |
| 08 | PCA:为什么降维能「去噪」?从特征值分解到核 PCA | ✅ 完成 |
| 09 | SOM:无监督学习的「聚类之王」,为什么它能「自组织」? | ✅ 完成 |
| 10 | 信息论:为什么「信息最大化」能学特征?从熵到 ICA | ✅ 完成 |
| 11 | 玻尔兹曼机:深度学习的「前世」,从统计力学到 RBM | ✅ 完成 |
| 12 | 动态规划:强化学习的「数学基础」,从 MDP 到值迭代 | ✅ 当前 |
| 13 | Hopfield 网络:联想记忆的「鼻祖」,为什么它能「回忆」? | ⏳ 下一篇 |
| 14 | 卡尔曼滤波:为什么它能「预测」?从贝叶斯推断到粒子滤波 | ⏳ 待写 |
| 15 | Haykin 精讲终篇:从感知器到深度学习------一部神经网络的「进化史」 | ⏳ 待写 |
点赞收藏转发,是我持续更新的动力!