动态规划:强化学习的「数学基础」,从 MDP 到值迭代

从马尔可夫决策过程到贝尔曼方程,理解强化学习的核心算法


开头:怎么让机器「学会」决策?

上一篇我们学习了玻尔兹曼机,用能量函数建模概率分布。

今天我们学习动态规划------强化学习的数学基础。

复制代码
监督学习:  输入 → 正确答案(标签)
强化学习:  状态 → 动作 → 奖励(没有正确答案)

问题:
    机器怎么知道哪个动作是「好」的?

答案:
    最大化累积奖励

动态规划提供了解决这个问题的数学框架

一、马尔可夫决策过程(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)

八、本篇总结

核心要点回顾

  1. MDP:状态、动作、转移概率、奖励、折扣因子
  2. 值函数:V(s) 状态值,Q(s,a) 动作值
  3. 贝尔曼方程:当前值 = 即时奖励 + 折扣的未来值
  4. 值迭代:迭代更新值函数,直到收敛
  5. 策略迭代:交替进行策略评估和策略改进
  6. γ 的作用:平衡短期和长期奖励

下篇预告

下一篇我们学习 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 精讲终篇:从感知器到深度学习------一部神经网络的「进化史」 ⏳ 待写

点赞收藏转发,是我持续更新的动力!

相关推荐
搞科研的小刘选手1 小时前
【计算机方向 | IEEE出版 | 杭州站】第七届机器学习与计算机应用国际学术会议(ICMLCA 2026)
机器学习·学术会议·计算机应用·会议推荐·浙江工业大学
mmmmath_31 小时前
LeetCode.225.用队列实现栈
算法
Elaine3361 小时前
数据结构与算法-程序
数据结构·python·算法·计算机基础·编程基础
2601_965742221 小时前
布局GEO AI本地营销,我重点看这几个细节
大数据·人工智能·算法·ai·新媒体运营
EatFan1 小时前
AI Agent 上生产前先加三道闸门:审批、限权、可回放的工程实践
人工智能·python·算法·多智能体·ai agent·mcp·harness
思茂信息2 小时前
CST软件BCI仿真模型及仿真案例
开发语言·单片机·嵌入式硬件·算法·emc
wshzd2 小时前
LLM之Agent(103)|当「快思考」遇上「深理解」:Laya 和 BERT 到底有什么区别?
人工智能·深度学习·bert
Persistent的粽子!2 小时前
双指针算法:最大盛水容器
c++·算法·leetcode
科研online2 小时前
用可解释机器学习XGBoost+SHAP发SCI期刊的优势?
人工智能·机器学习·学习方法