一文读懂马尔可夫决策过程—强化学习(1)
就是 “逛超市时,你现在在哪,决定了你下一步可能去哪,并且每到一个地方能攒多少积分,最后算清楚每个地方到底值多少分拆成 4 个你能摸到的东西:状态:超市里的位置,比如 “入口、零食区、生鲜区、收银台(结账走人)”。转移:从当前位置能走到哪。比如 “在零食区,60% 概率去生鲜区,40% 概率回入口”(只和现在在哪有关,和你之前去过玩具区没关系 —— 这就是 “马尔可夫性”)。奖励:到每个位置给的积
目录
3.1、 状态价值函数(V (s)):“现在复习到这个程度,最后能考多少分?”
3.2、 动作价值函数(Q (s,a)):“现在选这个复习方式,最后能多拿多少分?”
1、什么是马尔可夫奖励过程(MRP)
就是 “逛超市时,你现在在哪,决定了你下一步可能去哪,并且每到一个地方能攒多少积分,最后算清楚每个地方到底值多少分”。
拆成 4 个你能摸到的东西:
- 状态:超市里的位置,比如 “入口、零食区、生鲜区、收银台(结账走人)”。
- 转移:从当前位置能走到哪。比如 “在零食区,60% 概率去生鲜区,40% 概率回入口”(只和现在在哪有关,和你之前去过玩具区没关系 —— 这就是 “马尔可夫性”)。
- 奖励:到每个位置给的积分。比如 “零食区给 1 分,生鲜区给 3 分,回入口扣 1 分(绕路了),收银台给 10 分(结账奖励)”。
- 目标:算明白 “站在入口 / 零食区 / 生鲜区,最后总共能攒多少分(包括以后能拿到的)”。
举个具体场景:
你从入口进超市,可能的路线:
- 顺利路线:入口→零食区→生鲜区→收银台
积分:入口(0)→零食区(+1)→生鲜区(+3)→收银台(+10)- 绕路路线:入口→零食区→入口→零食区→生鲜区→收银台
积分:0→1→-1(回入口)→1→3→10MRP 不管你走哪条路,它会算:
- “站在零食区,平均下来能攒多少分?”(比如算出来是 8 分)
- “站在入口,平均下来能攒多少分?”(比如算出来是 5 分)
这样你就知道:哪怕可能绕路,零食区也比入口 “值钱”,所以来了就别回头,赶紧往生鲜区走 —— 这就是 MRP 的用处:帮你判断 “现在的位置到底值不值留”。
总结:MRP 就是给 “会随机乱逛的场景” 算 “每个地方的真实价值”,让你知道下一步该往哪走更划算。
2、什么是回报?
回报(Return)就是:你玩这一轮抓娃娃,从头到尾总共得到的 “好处”。
具体场景:
假设抓娃娃机有 3 个状态:
- 投币处(刚投币)、操作区(正在抓)、出口(抓到娃娃 / 没抓到,游戏结束)。
规则:
- 投币后(到投币处),必然去操作区(100% 概率),奖励 0(刚投币,还没好处)。
- 在操作区,50% 概率抓到娃娃(去出口,奖励 + 100 分),50% 概率没抓到(去出口,奖励 0 分)。
两种情况的 “回报”:
抓到娃娃的路径:投币处 → 操作区 → 出口(抓到)
总好处:0(投币处) + 0(操作区) + 100(出口) = 100 分(这就是这条路径的回报)。没抓到的路径:投币处 → 操作区 → 出口(没抓到)
总好处:0 + 0 + 0 = 0 分(这是另一条路径的回报)。核心点:
- 回报只看 “这一轮从开始到结束,所有好处加起来是多少”,走的路不同,回报可能不一样。
- 哪怕过程中没即时好处(比如操作区没奖励),也算在里面(加 0 而已)。
一句话:回报就是 “一次完整流程的总收益”,就像你玩一局游戏,从开玩到结束,总共得了多少分、赢了多少钱,这就是回报。
3、什么是价值函数?
场景:期末复习(目标是考高分)
假设你有 3 门课要复习:数学、英语、思政。每门课的复习难度(当下的 “痛苦”)和考试分值(未来的 “收益”)不同,而且你每天只能选一门课复习(动作),最终目标是总分最高。
3.1、 状态价值函数(V (s)):“现在复习到这个程度,最后能考多少分?”
- 状态 s:比如 “数学复习了 30%”“英语完全没看”“距离考试还有 2 天”。
- V(s) 就像你心里估算的 “保底总分”:
- 比如 “数学复习 30% + 英语没看 + 剩 2 天” 这个状态,你估算最后能考 50 分(因为数学能拿基础分,英语蒙选择题,时间够补一点)。
- 另一个状态 “数学复习 80% + 英语复习 50% + 剩 1 天”,你估算能考 80 分,显然这个状态的 “价值” 更高。
作用:帮你判断 “现在的处境好不好”。如果现在的状态价值低,你就知道必须调整复习计划了。
3.2、 动作价值函数(Q (s,a)):“现在选这个复习方式,最后能多拿多少分?”
- 比如你现在处于 “数学复习 30% + 剩 2 天” 的状态(s),有两个选择(动作 a):
- 动作 A:今天专攻数学(能多复习 20%,但英语彻底放弃)。
- 动作 B:今天花 1 小时看英语(英语能多拿 10 分,数学进度不变)。
- Q(s,A) 就是 “选 A 的最终总分”:比如数学能提到 50%(多 20 分),英语 0 分,最后估算 60 分。
- Q(s,B) 就是 “选 B 的最终总分”:数学 30%(20 分),英语 10 分,最后估算 30 分。
作用:帮你在选项中挑最优。显然你会选 A,因为它的 “动作价值” 更高。

3.3、为什么需要价值函数?
想象一下,如果没有这个 “计算器”:
- 你可能会凭感觉选动作(比如觉得英语简单就先看英语),但最后发现数学丢分更多,总分更低。
- 有了价值函数,你能算清 “现在的选择对未来的影响”,哪怕当下辛苦(比如啃数学),但长远来看更划算。
价值函数就像你做决策时心里的 “小算盘”:
- 算 “现在的处境值多少”(状态价值),
- 算 “选这个做法能赚多少”(动作价值),
- 帮你不被眼前的好坏迷惑,盯着最终目标做对选择。
3.4、价值函数代码
"""
文件名: 3.3 回报
作者: 墨尘
日期: 2025/7/21
项目名: d2l_learning
备注:
"""
import numpy as np
def compute_returns(start_index, chain, gamma):
G = 0
for i in reversed(range(start_index, len(chain))):
G = gamma * G + rewards[chain[i] - 1]
return G
if __name__ == '__main__':
np.random.seed(0)#设置相同的seed值可以确保每次运行程序时生成的随机数相同,从而实现随机数据的可预测性
# 定义状态转移概率矩阵P
P=[
[0.9, 0.1, 0.0, 0.0, 0.0, 0.0],
[0.5, 0.0, 0.5, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.6, 0.0, 0.4],
[0.0, 0.0, 0.0, 0.0, 0.3, 0.7],
[0.0, 0.2, 0.3, 0.5, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
]
P=np.array(P)
rewards = [-1,-2,-2,10,1,0] #定义奖励函数
gamma=0.5 #定义折扣因子
# 给定一条序列,计算从某个索引(起始状态)开始到序列最后(终止状态)得到的回报
chain = [ 1,2 ,3 ,6]
start_index = 0
G=compute_returns(start_index, chain, gamma)
print(G)
4、价值函数怎么计算?
4.1、计算方法:以马尔可夫奖励过程(MRP)为例
假设我们有一个简单的 MRP:
- 状态集合:
- 转移概率矩阵 P:
(例如:
表示从
到
的概率为 0.5)
- 奖励函数 R:
- 折扣因子
方法 1:直接求解(适用于状态少的情况)
写出每个状态的贝尔曼方程:
→ 解得
代入
到方程 2,再解出
,最后代入方程 1 解出
。 结果:
方法 2:迭代法(适用于状态多的情况)
用动态规划迭代更新每个状态的价值,直到收敛:
- 初始化:
对所有 s
- 重复更新:
- 直到
不再变化(收敛)。
示例迭代过程(简化版):
- 第 1 次迭代:
- 第 2 次迭代:
- ... 重复迭代直到收敛 → 最终得到
4.2、直观理解:为什么这样算?
价值函数的本质是 “未来期望总收益”,贝尔曼方程把它拆解成:
- 即时奖励:现在能拿到的好处。
- 未来价值的期望:下一步可能去的所有状态的价值,按转移概率加权平均,再打个折扣(因为未来不确定)。
迭代法的核心思想是:不断用 “已知的未来状态价值” 来更新 “当前状态价值”,直到每个状态的价值都稳定下来。
4.3、完整代码
4.3.1、迭代法计算马尔可夫奖励过程的价值函数
""" 文件名: 3.3.1 迭代法计算马尔可夫奖励过程的价值函数 作者: 墨尘 日期: 2025/7/21 项目名: d2l_learning 备注: """ import numpy as np if __name__ == '__main__': # 定义MRP参数 states = [1, 2, 3] # 状态集合 rewards = {1: 1, 2: 2, 3: 0} # 奖励函数 R(s) gamma = 0.9 # 折扣因子 # 状态转移概率矩阵 P[s][s'] = P(s'|s) transition_probs = { 1: {1: 0.5, 2: 0.5, 3: 0}, 2: {1: 0, 2: 0.5, 3: 0.5}, 3: {1: 0, 2: 0, 3: 1} } # 初始化价值函数 V(s) = 0 V = {s: 0 for s in states} # 迭代计算价值函数(动态规划) max_iterations = 1000 tolerance = 1e-10 for i in range(max_iterations): new_V = {} for s in states: # 计算贝尔曼方程的右侧 expected_future_value = sum( transition_probs[s][s_next] * V[s_next] for s_next in states ) new_V[s] = rewards[s] + gamma * expected_future_value # 检查收敛性 max_diff = max(abs(new_V[s] - V[s]) for s in states) if max_diff < tolerance: print(f"在第 {i + 1} 次迭代后收敛") break V = new_V # 打印结果 print("\n状态价值函数 V(s):") for s in states: print(f"V({s}) = {V[s]:.4f}")4.3.2、直接矩阵求逆法计算价值函数
""" 文件名: 3.3.2 直接矩阵求逆法计算价值函数 作者: 墨尘 日期: 2025/7/21 项目名: d2l_learning 备注: """ import numpy as np if __name__ == '__main__': # 定义MRP参数 gamma = 0.9 # 折扣因子 # 状态转移概率矩阵 P P = np.array([ [0.5, 0.5, 0.0], # 从状态1转移到其他状态的概率 [0.0, 0.5, 0.5], # 从状态2转移到其他状态的概率 [0.0, 0.0, 1.0] # 从状态3转移到其他状态的概率 ]) # 奖励向量 R R = np.array([1, 2, 0]) # 状态1、2、3的奖励 # 计算价值函数 V = (I - γP)^(-1) * R I = np.eye(len(P)) # 单位矩阵 V = np.linalg.inv(I - gamma * P).dot(R) # 打印结果 print("\n状态价值函数 V(s):") for i, v in enumerate(V): print(f"V({i + 1}) = {v:.4f}")4.3.3、状态价值函数V(s)计算
""" 文件名: 3.3.3 状态价值函数V(s)计算 作者: 墨尘 日期: 2025/7/21 项目名: d2l_learning 备注: """ import numpy as np if __name__ == '__main__': # 定义环境参数 num_states = 4 # 状态数:s0, s1, s2, s3 gamma = 0.9 # 折扣因子 # 状态转移概率矩阵 P[s][s'] = P(s'|s) P = np.array([ [0.7, 0.3, 0.0, 0.0], # 从s0转移到其他状态的概率 [0.0, 0.5, 0.5, 0.0], # 从s1转移到其他状态的概率 [0.0, 0.0, 0.3, 0.7], # 从s2转移到其他状态的概率 [0.0, 0.0, 0.0, 1.0] # 从s3(终止状态)转移到自身 ]) # 奖励向量 R[s] = 从状态s获得的即时奖励 R = np.array([1, -1, -2, 0]) # 状态s3为终止状态,奖励为0 # 初始化价值函数 V(s) = 0 V = np.zeros(num_states) # 迭代计算价值函数(动态规划) max_iterations = 1000 tolerance = 1e-10 for i in range(max_iterations): new_V = np.zeros(num_states) for s in range(num_states): # 计算贝尔曼方程的右侧:R(s) + γ * Σ P(s'|s)V(s') new_V[s] = R[s] + gamma * np.sum(P[s] * V) # 检查收敛性 max_diff = np.max(np.abs(new_V - V)) if max_diff < tolerance: print(f"在第 {i + 1} 次迭代后收敛") break V = new_V # 打印结果 print("\n状态价值函数 V(s):") for s in range(num_states): print(f"V(s{s}) = {V[s]:.4f}")4.3.4、动作价值函数 Q(s,a)计算
""" 文件名: 3.3.4 动作价值函数 Q(s,a)计算 作者: 墨尘 日期: 2025/7/21 项目名: d2l_learning 备注: """ import numpy as np if __name__ == '__main__': # 定义环境参数 num_states = 3 # 状态数:s0, s1, s2 num_actions = 2 # 动作数:a0, a1 gamma = 0.9 # 折扣因子 # 奖励函数 R[s][a] = 在状态s执行动作a的即时奖励 R = np.array([ [1, -2], # 状态s0执行a0、a1的奖励 [3, -1], # 状态s1执行a0、a1的奖励 [0, 2] # 状态s2执行a0、a1的奖励 ]) # 状态转移概率 P[s][a][s'] = 在状态s执行动作a后转移到s'的概率 P = np.array([ [ # 状态s0 [0.8, 0.2, 0.0], # 执行动作a0的转移概率 [0.1, 0.9, 0.0] # 执行动作a1的转移概率 ], [ # 状态s1 [0.0, 0.7, 0.3], # 执行动作a0的转移概率 [0.0, 0.2, 0.8] # 执行动作a1的转移概率 ], [ # 状态s2 [0.0, 0.0, 1.0], # 执行动作a0的转移概率(终止状态) [0.0, 0.0, 1.0] # 执行动作a1的转移概率(终止状态) ] ]) # 初始化动作价值函数 Q(s,a) = 0 Q = np.zeros((num_states, num_actions)) # 迭代计算动作价值函数 max_iterations = 1000 tolerance = 1e-10 for i in range(max_iterations): new_Q = np.zeros((num_states, num_actions)) for s in range(num_states): for a in range(num_actions): # 计算贝尔曼方程的右侧:R(s,a) + γ * Σ P(s'|s,a) * max_a' Q(s',a') expected_future_value = np.sum( P[s, a, s_next] * np.max(Q[s_next]) for s_next in range(num_states) ) new_Q[s, a] = R[s, a] + gamma * expected_future_value # 检查收敛性 max_diff = np.max(np.abs(new_Q - Q)) if max_diff < tolerance: print(f"在第 {i + 1} 次迭代后收敛") break Q = new_Q # 打印结果 print("\n动作价值函数 Q(s,a):") for s in range(num_states): for a in range(num_actions): print(f"Q(s{s}, a{a}) = {Q[s, a]:.4f}")
5、R(s,a)和 R(s) 的不同之处?
R(s,a)和 R(s) 是两种不同的奖励定义方式,核心区别在于是否与动作相关。以下是具体对比:
5.1、 定义与适用场景
| 符号 | 定义 | 适用场景 | 核心特点 |
|---|---|---|---|
| R(s) | 状态奖励:处于状态 s 时获得的即时奖励 | 马尔可夫奖励过程(MRP) | 不涉及动作,仅与当前状态相关 |
| R(s,a) | 动作奖励:在状态 s 执行动作 a 获得的即时奖励 | 马尔可夫决策过程(MDP) | 与当前状态和选择的动作均相关 |
5.2、直观理解

更多推荐
所有评论(0)