第四章:蒙特卡洛方法
标签 :强化学习、蒙特卡洛方法、无模型学习、策略评估、策略控制、探索与利用
难度:⭐⭐⭐(中级)
📖 目录
- [4.1 蒙特卡洛方法概述](#4.1 蒙特卡洛方法概述)
- [4.2 蒙特卡洛策略评估](#4.2 蒙特卡洛策略评估)
- [4.3 蒙特卡洛控制](#4.3 蒙特卡洛控制)
- [4.4 增量式更新](#4.4 增量式更新)
- [4.5 探索与利用](#4.5 探索与利用)
- [4.6 蒙特卡洛方法的优势](#4.6 蒙特卡洛方法的优势)
- [4.7 蒙特卡洛方法的局限性](#4.7 蒙特卡洛方法的局限性)
- [4.8 蒙特卡洛方法的改进](#4.8 蒙特卡洛方法的改进)
- [4.9 实际应用示例](#4.9 实际应用示例)
- [4.10 蒙特卡洛 vs 动态规划](#4.10 蒙特卡洛 vs 动态规划)
- [4.11 常见问题解答](#4.11 常见问题解答)
- [4.12 本章小结](#4.12 本章小结)
4.1 蒙特卡洛方法概述
4.1.1 什么是蒙特卡洛方法?
蒙特卡洛方法(Monte Carlo Methods) 是无模型(Model-free)的强化学习方法,通过采样经验来学习价值函数和策略,不需要知道环境模型。
核心思想:
- 通过实际交互获得经验样本
- 用样本的平均值估计期望值
- 根据大数定律,样本平均值收敛到真实期望
4.1.2 蒙特卡洛方法的历史
蒙特卡洛方法得名于摩纳哥的蒙特卡洛赌场,因为方法依赖于随机采样。在强化学习中,蒙特卡洛方法通过随机采样经验来估计价值函数。
4.1.3 为什么需要蒙特卡洛方法?
动态规划的局限性
动态规划方法需要:
- 完整的环境模型 :状态转移概率 P P P 和奖励函数 R R R
- 遍历所有状态:需要访问所有状态-动作对
但在实际应用中:
- 环境模型往往未知
- 状态空间可能很大,无法遍历所有状态
蒙特卡洛方法的优势
- 无模型:不需要环境模型
- 只关注实际访问的状态:不需要遍历所有状态
- 简单直观:直接从经验中学习
- 可以处理非马尔可夫环境:通过完整回合学习
4.1.4 蒙特卡洛方法的基本流程
否 是 初始化价值函数/策略 生成一个回合 计算回报 更新价值函数/策略 收敛? 输出最优策略
4.1.5 蒙特卡洛方法的关键特点
- 需要完整回合:必须等到回合结束才能更新
- 基于经验:从实际交互中获得数据
- 样本平均:用样本平均值估计期望值
- 无偏估计:在足够样本下,估计是无偏的
4.2 蒙特卡洛策略评估
4.2.1 策略评估的目标
蒙特卡洛策略评估 的目标是估计给定策略 π \pi π 的状态价值函数 V π V^{\pi} Vπ。
根据大数定律,如果我们有足够多的样本,样本平均值会收敛到真实期望:
V π ( s ) = E π [ G t ∣ S t = s ] ≈ 1 N ( s ) ∑ i = 1 N ( s ) G i ( s ) V^{\pi}(s) = \mathbb{E}{\pi}[G_t | S_t = s] \approx \frac{1}{N(s)} \sum{i=1}^{N(s)} G_i(s) Vπ(s)=Eπ[Gt∣St=s]≈N(s)1i=1∑N(s)Gi(s)
其中:
- N ( s ) N(s) N(s) 是访问状态 s s s 的次数
- G i ( s ) G_i(s) Gi(s) 是第 i i i 次访问状态 s s s 时的回报
4.2.2 首次访问MC方法
首次访问MC方法(First-Visit MC) :对于每个状态,只使用首次访问该状态时的回报来估计价值。
算法特点:
- 每个回合中,每个状态只使用一次
- 估计是无偏的
- 方差可能较大
更新规则 :
V ( s ) ← 1 N ( s ) ∑ i = 1 N ( s ) G i ( s ) V(s) \leftarrow \frac{1}{N(s)} \sum_{i=1}^{N(s)} G_i(s) V(s)←N(s)1i=1∑N(s)Gi(s)
其中 G i ( s ) G_i(s) Gi(s) 是第 i i i 次首次访问状态 s s s 时的回报。
4.2.3 每次访问MC方法
每次访问MC方法(Every-Visit MC) :使用每次访问状态时的回报来估计价值。
算法特点:
- 每个回合中,同一状态可能被使用多次
- 估计可能有轻微偏差(但通常可忽略)
- 方差可能较小(使用更多样本)
更新规则 :
V ( s ) ← 1 N ( s ) ∑ i = 1 N ( s ) G i ( s ) V(s) \leftarrow \frac{1}{N(s)} \sum_{i=1}^{N(s)} G_i(s) V(s)←N(s)1i=1∑N(s)Gi(s)
其中 G i ( s ) G_i(s) Gi(s) 是第 i i i 次访问状态 s s s 时的回报(包括重复访问)。
4.2.4 首次访问 vs 每次访问
| 特性 | 首次访问MC | 每次访问MC |
|---|---|---|
| 无偏性 | 无偏 | 可能有轻微偏差 |
| 方差 | 较大 | 较小 |
| 样本效率 | 较低 | 较高 |
| 实现复杂度 | 简单 | 稍复杂 |
选择建议:
- 首次访问MC:理论分析更简单,无偏性保证
- 每次访问MC:实际应用中更常用,样本效率更高
4.2.5 蒙特卡洛策略评估算法
首次访问MC实现
python
import numpy as np
from collections import defaultdict
def first_visit_mc_policy_evaluation(env, policy, num_episodes, gamma=0.9):
"""
首次访问MC策略评估
参数:
env: 环境
policy: 策略函数,输入状态返回动作
num_episodes: 回合数
gamma: 折扣因子
返回:
V: 状态价值函数
returns: 每个状态的回报列表(用于分析)
"""
# 初始化
returns = defaultdict(list) # 每个状态的回报列表
V = {} # 状态价值函数
for episode in range(num_episodes):
# 生成一个回合
episode_data = []
state = env.reset()
visited_states = set() # 记录首次访问的状态
# 执行回合
while True:
action = policy(state)
next_state, reward, done, info = env.step(action)
episode_data.append((state, action, reward))
if done:
break
state = next_state
# 计算回报(从后往前)
G = 0
for t in reversed(range(len(episode_data))):
s, a, r = episode_data[t]
G = gamma * G + r # 累积回报
# 首次访问MC:只使用首次访问的回报
if s not in visited_states:
visited_states.add(s)
returns[s].append(G)
# 更新价值函数(使用所有样本的平均值)
for s in returns:
V[s] = np.mean(returns[s])
return V, returns
每次访问MC实现
python
def every_visit_mc_policy_evaluation(env, policy, num_episodes, gamma=0.9):
"""
每次访问MC策略评估
"""
# 初始化
returns = defaultdict(list)
V = {}
for episode in range(num_episodes):
# 生成一个回合
episode_data = []
state = env.reset()
while True:
action = policy(state)
next_state, reward, done, info = env.step(action)
episode_data.append((state, action, reward))
if done:
break
state = next_state
# 计算回报(从后往前)
G = 0
for t in reversed(range(len(episode_data))):
s, a, r = episode_data[t]
G = gamma * G + r
# 每次访问MC:使用所有访问的回报
returns[s].append(G)
# 更新价值函数
for s in returns:
V[s] = np.mean(returns[s])
return V, returns
4.2.6 动作价值函数的MC评估
对于动作价值函数 Q π ( s , a ) Q^{\pi}(s,a) Qπ(s,a),MC方法类似:
python
def mc_action_value_evaluation(env, policy, num_episodes, gamma=0.9, first_visit=True):
"""
蒙特卡洛动作价值函数评估
"""
returns = defaultdict(list) # (s, a) -> [G1, G2, ...]
Q = {} # 动作价值函数
for episode in range(num_episodes):
# 生成回合
episode_data = []
state = env.reset()
visited_pairs = set() if first_visit else None
while True:
action = policy(state)
next_state, reward, done, info = env.step(action)
episode_data.append((state, action, reward))
if done:
break
state = next_state
# 计算回报
G = 0
for t in reversed(range(len(episode_data))):
s, a, r = episode_data[t]
G = gamma * G + r
# 首次访问或每次访问
if first_visit:
if (s, a) not in visited_pairs:
visited_pairs.add((s, a))
returns[(s, a)].append(G)
else:
returns[(s, a)].append(G)
# 更新Q函数
for (s, a) in returns:
Q[(s, a)] = np.mean(returns[(s, a)])
return Q, returns
4.2.7 收敛性分析
大数定律
根据大数定律 ,当样本数量 N ( s ) → ∞ N(s) \to \infty N(s)→∞ 时:
1 N ( s ) ∑ i = 1 N ( s ) G i ( s ) → E π [ G t ∣ S t = s ] = V π ( s ) \frac{1}{N(s)} \sum_{i=1}^{N(s)} G_i(s) \to \mathbb{E}_{\pi}[G_t | S_t = s] = V^{\pi}(s) N(s)1i=1∑N(s)Gi(s)→Eπ[Gt∣St=s]=Vπ(s)
收敛速度:
- 收敛速度取决于访问频率
- 访问频率低的状态收敛慢
- 需要保证所有状态都被充分访问
方差分析
MC估计的方差:
Var [ V ^ ( s ) ] = Var [ G ] N ( s ) \text{Var}[\hat{V}(s)] = \frac{\text{Var}[G]}{N(s)} Var[V^(s)]=N(s)Var[G]
其中 Var [ G ] \text{Var}[G] Var[G] 是回报的方差。
减少方差的方法:
- 增加样本数量
- 使用基线(Baseline)
- 使用控制变量
4.3 蒙特卡洛控制
4.3.1 控制问题的挑战
控制问题的目标是找到最优策略,而不仅仅是评估给定策略。
挑战:
- 探索问题:需要保证所有状态-动作对被访问
- 策略改进:需要基于Q函数改进策略
- 策略评估:需要评估改进后的策略
4.3.2 蒙特卡洛ES(探索开始)
蒙特卡洛ES(Monte Carlo Exploring Starts) 假设每个状态-动作对都有非零概率被访问到。
关键假设:
- 每个状态-动作对都可以作为回合的起点
- 这在实际应用中往往不现实
算法流程:
python
def monte_carlo_es(env, num_episodes, gamma=0.9):
"""
蒙特卡洛ES(探索开始)
"""
# 初始化
Q = {} # 动作价值函数
returns = defaultdict(list) # (s, a) -> [G1, G2, ...]
pi = {} # 策略(确定性策略)
for episode in range(num_episodes):
# 探索开始:随机选择初始状态-动作对
state = env.reset()
action = env.action_space.sample()
# 生成回合
episode_data = []
while True:
next_state, reward, done, info = env.step(action)
episode_data.append((state, action, reward))
if done:
break
# 后续使用当前策略(贪婪策略)
if state in pi:
action = pi[state]
else:
action = env.action_space.sample()
state = next_state
# 计算回报并更新
G = 0
visited_pairs = set()
for t in reversed(range(len(episode_data))):
s, a, r = episode_data[t]
G = gamma * G + r
# 首次访问
if (s, a) not in visited_pairs:
visited_pairs.add((s, a))
returns[(s, a)].append(G)
# 更新Q函数
Q[(s, a)] = np.mean(returns[(s, a)])
# 策略改进(贪婪)
if s not in pi:
pi[s] = a
else:
# 找到最优动作
best_action = a
best_value = Q[(s, a)]
for a_test in env.action_space:
if (s, a_test) in Q and Q[(s, a_test)] > best_value:
best_value = Q[(s, a_test)]
best_action = a_test
pi[s] = best_action
return pi, Q
4.3.3 非探索开始的MC控制
由于探索开始假设往往不现实,我们需要其他方法来保证探索。
epsilon-贪婪策略
ϵ \epsilon ϵ-贪婪策略保证所有动作都有被选择的概率:
π ( a ∣ s ) = { 1 − ϵ + ϵ ∣ A ( s ) ∣ if a = arg max a ′ Q ( s , a ′ ) ϵ ∣ A ( s ) ∣ otherwise \pi(a|s) = \begin{cases} 1-\epsilon + \frac{\epsilon}{|A(s)|} & \text{if } a = \arg\max_{a'} Q(s,a') \\ \frac{\epsilon}{|A(s)|} & \text{otherwise} \end{cases} π(a∣s)={1−ϵ+∣A(s)∣ϵ∣A(s)∣ϵif a=argmaxa′Q(s,a′)otherwise
特点:
- 以 1 − ϵ 1-\epsilon 1−ϵ 的概率选择最优动作(利用)
- 以 ϵ \epsilon ϵ 的概率随机选择动作(探索)
- 保证所有动作都有非零概率被选择
epsilon-贪婪MC控制算法
python
def epsilon_greedy_mc_control(env, num_episodes, gamma=0.9, epsilon=0.1):
"""
epsilon-贪婪蒙特卡洛控制
"""
Q = {}
returns = defaultdict(list)
pi = {} # epsilon-贪婪策略
def epsilon_greedy_policy(state, Q, epsilon):
"""epsilon-贪婪策略"""
if state not in Q:
# 如果状态未访问过,随机选择
return env.action_space.sample()
# 找到最优动作
best_action = max(Q[state], key=Q[state].get)
# epsilon-贪婪选择
if np.random.random() < epsilon:
return env.action_space.sample()
else:
return best_action
for episode in range(num_episodes):
# 生成回合
episode_data = []
state = env.reset()
while True:
action = epsilon_greedy_policy(state, Q, epsilon)
next_state, reward, done, info = env.step(action)
episode_data.append((state, action, reward))
if done:
break
state = next_state
# 计算回报并更新
G = 0
visited_pairs = set()
for t in reversed(range(len(episode_data))):
s, a, r = episode_data[t]
G = gamma * G + r
# 首次访问
if (s, a) not in visited_pairs:
visited_pairs.add((s, a))
returns[(s, a)].append(G)
# 更新Q函数
if s not in Q:
Q[s] = {}
Q[s][a] = np.mean(returns[(s, a)])
# 更新策略(epsilon-贪婪)
best_action = max(Q[s], key=Q[s].get)
n_actions = len(env.action_space)
pi[s] = {}
for a_test in env.action_space:
if a_test == best_action:
pi[s][a_test] = 1 - epsilon + epsilon / n_actions
else:
pi[s][a_test] = epsilon / n_actions
return pi, Q
4.3.4 epsilon衰减策略
为了平衡探索和利用,可以让 ϵ \epsilon ϵ 随时间衰减:
python
def epsilon_greedy_mc_control_decay(env, num_episodes, gamma=0.9,
epsilon_start=1.0, epsilon_end=0.01,
epsilon_decay=0.995):
"""
epsilon衰减的MC控制
"""
Q = {}
returns = defaultdict(list)
epsilon = epsilon_start
for episode in range(num_episodes):
# epsilon衰减
epsilon = max(epsilon_end, epsilon * epsilon_decay)
# 生成回合并更新(类似上面的代码)
# ...
return Q
4.3.5 策略改进的保证
策略改进定理 :如果策略 π ′ \pi' π′ 是相对于 Q π Q^{\pi} Qπ 的贪婪策略,则 π ′ \pi' π′ 至少和 π \pi π 一样好。
MC控制中的策略改进:
- 每次更新Q函数后,使用贪婪策略改进
- 在epsilon-贪婪策略中,最优动作的概率逐渐增加
- 最终收敛到最优策略(在epsilon衰减的情况下)
4.4 增量式更新
4.4.1 为什么需要增量式更新?
批量更新的问题:
- 需要存储所有回报
- 内存消耗大
- 每次更新需要重新计算平均值
增量式更新的优势:
- 不需要存储所有回报
- 内存效率高
- 可以实时更新
4.4.2 增量式更新公式
增量式更新:
V ( S t ) ← V ( S t ) + α [ G t − V ( S t ) ] V(S_t) \leftarrow V(S_t) + \alpha[G_t - V(S_t)] V(St)←V(St)+α[Gt−V(St)]
其中:
- α \alpha α 是学习率(步长)
- G t G_t Gt 是当前回报
- G t − V ( S t ) G_t - V(S_t) Gt−V(St) 是误差
等价形式 :
V ( S t ) ← ( 1 − α ) V ( S t ) + α G t V(S_t) \leftarrow (1-\alpha) V(S_t) + \alpha G_t V(St)←(1−α)V(St)+αGt
4.4.3 学习率的选择
固定学习率
α = 常数 \alpha = \text{常数} α=常数
特点:
- 简单
- 但可能不收敛(如果学习率太大)
- 适用于非平稳环境
递减学习率
α t = 1 N ( s t ) \alpha_t = \frac{1}{N(s_t)} αt=N(st)1
其中 N ( s t ) N(s_t) N(st) 是访问状态 s t s_t st 的次数。
特点:
- 保证收敛(满足Robbins-Monro条件)
- 样本平均的在线版本
- 适用于平稳环境
Robbins-Monro条件
学习率需要满足:
∑ t = 1 ∞ α t = ∞ 且 ∑ t = 1 ∞ α t 2 < ∞ \sum_{t=1}^{\infty} \alpha_t = \infty \quad \text{且} \quad \sum_{t=1}^{\infty} \alpha_t^2 < \infty t=1∑∞αt=∞且t=1∑∞αt2<∞
示例:
- α t = 1 / t \alpha_t = 1/t αt=1/t:满足条件
- α t = 1 / t \alpha_t = 1/\sqrt{t} αt=1/t :不满足(第二个条件)
4.4.4 增量式MC更新实现
python
def incremental_mc_update(V, state, G, alpha):
"""
增量式MC更新
参数:
V: 价值函数(字典)
state: 当前状态
G: 回报
alpha: 学习率
"""
if state not in V:
V[state] = 0.0
V[state] += alpha * (G - V[state])
return V
def incremental_mc_policy_evaluation(env, policy, num_episodes, gamma=0.9,
alpha_type='constant', alpha_value=0.1):
"""
增量式MC策略评估
"""
V = {}
visit_count = defaultdict(int) # 访问计数
for episode in range(num_episodes):
# 生成回合
episode_data = []
state = env.reset()
visited_states = set()
while True:
action = policy(state)
next_state, reward, done, info = env.step(action)
episode_data.append((state, action, reward))
if done:
break
state = next_state
# 计算回报并更新
G = 0
for t in reversed(range(len(episode_data))):
s, a, r = episode_data[t]
G = gamma * G + r
# 首次访问
if s not in visited_states:
visited_states.add(s)
visit_count[s] += 1
# 选择学习率
if alpha_type == 'constant':
alpha = alpha_value
elif alpha_type == 'decay':
alpha = 1.0 / visit_count[s]
else:
alpha = alpha_value
# 增量式更新
V = incremental_mc_update(V, s, G, alpha)
return V
4.4.5 增量式更新 vs 批量更新
| 特性 | 批量更新 | 增量式更新 |
|---|---|---|
| 内存需求 | 高(存储所有回报) | 低(只存储价值函数) |
| 计算效率 | 每次需要重新计算 | 实时更新 |
| 收敛性 | 保证收敛 | 需要合适的学习率 |
| 适用场景 | 离线学习 | 在线学习 |
4.5 探索与利用
4.5.1 探索的重要性
在MC控制中,探索至关重要:
- 需要访问所有状态-动作对:才能准确估计Q函数
- 避免局部最优:充分探索可能发现更好的策略
- 样本效率:好的探索策略可以提高学习效率
4.5.2 探索策略
1. epsilon-贪婪策略
优点:
- 简单有效
- 保证所有动作都有非零概率
- 可以随时间衰减
缺点:
- 探索是盲目的(随机选择)
- 不考虑动作的不确定性
2. UCB (Upper Confidence Bound)
UCB策略考虑不确定性:
a t = arg max a [ Q ( s , a ) + c ln t N ( s , a ) ] a_t = \arg\max_{a} \left[ Q(s,a) + c \sqrt{\frac{\ln t}{N(s,a)}} \right] at=argamax[Q(s,a)+cN(s,a)lnt ]
其中:
- N ( s , a ) N(s,a) N(s,a) 是访问 ( s , a ) (s,a) (s,a) 的次数
- c c c 是探索参数
- 第二项是不确定性项
3. 乐观初始化
乐观初始化:将Q函数初始化为较大的值,鼓励探索。
python
def optimistic_initialization(env, initial_value=100.0):
"""
乐观初始化Q函数
"""
Q = {}
for s in env.state_space:
Q[s] = {}
for a in env.action_space:
Q[s][a] = initial_value
return Q
4.5.3 探索与利用的平衡
平衡策略:
- 早期 :多探索( ϵ \epsilon ϵ 较大)
- 后期 :多利用( ϵ \epsilon ϵ 较小)
- 使用epsilon衰减 : ϵ t = ϵ 0 × decay t \epsilon_t = \epsilon_0 \times \text{decay}^t ϵt=ϵ0×decayt
4.6 蒙特卡洛方法的优势
4.6.1 无模型学习
优势:
- 不需要环境模型
- 适用于复杂环境
- 更通用
4.6.2 简单直观
优势:
- 算法简单
- 易于理解和实现
- 直接从经验中学习
4.6.3 可以处理非马尔可夫环境
优势:
- 通过完整回合学习
- 不依赖于马尔可夫性质
- 可以学习长期依赖
4.6.4 只关注实际访问的状态
优势:
- 不需要遍历所有状态
- 适用于大状态空间
- 计算效率高(只计算访问的状态)
4.6.5 无偏估计
优势:
- 在足够样本下,估计是无偏的
- 理论保证(大数定律)
- 可以精确估计价值函数
4.7 蒙特卡洛方法的局限性
4.7.1 需要完整回合
问题:
- 必须等到回合结束才能更新
- 不能在线学习
- 对于长回合,学习延迟大
影响:
- 学习速度慢
- 不适合持续任务
- 需要可以重置的环境
4.7.2 高方差
问题:
- 回报的方差可能很大
- 导致估计不稳定
- 需要大量样本才能收敛
原因:
- 随机性累积
- 长期依赖
- 奖励方差大
4.7.3 探索问题
问题:
- 需要保证充分探索
- 探索开始假设不现实
- epsilon-贪婪可能不够高效
影响:
- 可能陷入局部最优
- 学习效率低
- 需要精心设计探索策略
4.7.4 样本效率
问题:
- 需要大量样本
- 每个状态-动作对需要多次访问
- 样本利用率低
影响:
- 学习速度慢
- 不适合样本稀缺的场景
- 计算成本高
4.8 蒙特卡洛方法的改进
4.8.1 重要性采样
重要性采样(Importance Sampling) 允许使用其他策略的数据来评估目标策略:
E π [ G t ∣ S t = s ] = E b [ π ( A t ∣ S t ) b ( A t ∣ S t ) G t ∣ S t = s ] \mathbb{E}_{\pi}[G_t | S_t = s] = \mathbb{E}_b\left[\frac{\pi(A_t|S_t)}{b(A_t|S_t)} G_t | S_t = s\right] Eπ[Gt∣St=s]=Eb[b(At∣St)π(At∣St)Gt∣St=s]
其中 b b b 是行为策略(用于生成数据), π \pi π 是目标策略(要评估的策略)。
4.8.2 加权重要性采样
加权重要性采样(Weighted Importance Sampling) 减少方差:
V ( s ) = ∑ i = 1 N ( s ) ρ i G i ∑ i = 1 N ( s ) ρ i V(s) = \frac{\sum_{i=1}^{N(s)} \rho_i G_i}{\sum_{i=1}^{N(s)} \rho_i} V(s)=∑i=1N(s)ρi∑i=1N(s)ρiGi
其中 ρ i \rho_i ρi 是重要性采样比率。
4.8.3 控制变量
控制变量(Control Variates) 减少方差:
V ^ ( s ) = 1 N ( s ) ∑ i = 1 N ( s ) [ G i − b ( s ) + b ( s ) ] \hat{V}(s) = \frac{1}{N(s)} \sum_{i=1}^{N(s)} [G_i - b(s) + b(s)] V^(s)=N(s)1i=1∑N(s)[Gi−b(s)+b(s)]
其中 b ( s ) b(s) b(s) 是基线(如状态价值函数的估计)。
4.8.4 资格迹
资格迹(Eligibility Traces) 结合MC和TD方法,将在下一章详细介绍。
4.9 实际应用示例
4.9.1 21点游戏
python
import gym
def blackjack_mc_control(num_episodes=500000):
"""
使用MC控制学习21点游戏
"""
env = gym.make('Blackjack-v1')
Q = {}
returns = defaultdict(list)
epsilon = 0.1
for episode in range(num_episodes):
# 生成回合
episode_data = []
state = env.reset()
while True:
# epsilon-贪婪策略
if state not in Q:
Q[state] = {0: 0.0, 1: 0.0} # 0=停牌, 1=要牌
if np.random.random() < epsilon:
action = env.action_space.sample()
else:
action = max(Q[state], key=Q[state].get)
next_state, reward, done, info = env.step(action)
episode_data.append((state, action, reward))
if done:
break
state = next_state
# 更新
G = 0
visited_pairs = set()
for t in reversed(range(len(episode_data))):
s, a, r = episode_data[t]
G = gamma * G + r
if (s, a) not in visited_pairs:
visited_pairs.add((s, a))
returns[(s, a)].append(G)
Q[s][a] = np.mean(returns[(s, a)])
return Q
4.9.2 网格世界
python
def gridworld_mc_control(grid_env, num_episodes=10000):
"""
网格世界的MC控制
"""
Q = {}
returns = defaultdict(list)
epsilon = 0.1
for episode in range(num_episodes):
state = grid_env.reset()
episode_data = []
while True:
# epsilon-贪婪策略
if state not in Q:
Q[state] = {a: 0.0 for a in grid_env.action_space}
if np.random.random() < epsilon:
action = np.random.choice(grid_env.action_space)
else:
action = max(Q[state], key=Q[state].get)
next_state, reward, done = grid_env.step(action)
episode_data.append((state, action, reward))
if done:
break
state = next_state
# MC更新
G = 0
visited_pairs = set()
for t in reversed(range(len(episode_data))):
s, a, r = episode_data[t]
G = 0.9 * G + r
if (s, a) not in visited_pairs:
visited_pairs.add((s, a))
returns[(s, a)].append(G)
Q[s][a] = np.mean(returns[(s, a)])
return Q
4.10 蒙特卡洛 vs 动态规划
4.10.1 详细对比
| 特性 | 动态规划 | 蒙特卡洛 |
|---|---|---|
| 需要模型 | ✅ 是 | ❌ 否 |
| 自举 | ✅ 是 | ❌ 否 |
| 在线学习 | ✅ 是 | ❌ 否 |
| 需要完整回合 | ❌ 否 | ✅ 是 |
| 方差 | 低 | 高 |
| 偏差 | 无 | 无 |
| 样本效率 | 高 | 中 |
| 适用场景 | 已知模型 | 未知模型 |
4.10.2 自举 vs 非自举
自举(Bootstrapping):使用估计值更新估计值。
- DP :使用 V ( s ′ ) V(s') V(s′) 更新 V ( s ) V(s) V(s)(自举)
- MC :使用实际回报 G t G_t Gt 更新 V ( s ) V(s) V(s)(非自举)
影响:
- 自举:可以立即更新,但可能有偏差
- 非自举:需要等待,但无偏
4.10.3 何时使用MC方法?
使用MC方法当:
- 环境模型未知
- 可以重置环境
- 需要无偏估计
- 可以接受高方差
使用DP方法当:
- 环境模型已知
- 需要快速学习
- 需要低方差估计
4.11 常见问题解答
Q1: MC方法需要多少样本才能收敛?
A: 取决于:
- 状态空间大小
- 访问频率
- 方差大小
- 通常需要每个状态-动作对访问多次(几十到几百次)
Q2: 首次访问和每次访问哪个更好?
A:
- 首次访问:理论更简单,无偏性保证
- 每次访问:实际更常用,样本效率更高
- 通常选择每次访问
Q3: 如何选择学习率?
A:
- 固定学习率 : α = 0.1 \alpha = 0.1 α=0.1 到 0.5 0.5 0.5
- 递减学习率 : α t = 1 / N ( s t ) \alpha_t = 1/N(s_t) αt=1/N(st)(保证收敛)
- 根据应用选择
Q4: MC方法可以用于持续任务吗?
A:
- 标准MC方法不能(需要完整回合)
- 可以使用截断MC(截断到一定长度)
- 或使用TD方法(下一章)
Q5: 如何减少MC方法的方差?
A: 方法:
- 增加样本数量
- 使用基线
- 使用控制变量
- 使用重要性采样
4.12 本章小结
本章详细介绍了蒙特卡洛方法,这是无模型强化学习的重要方法。
核心概念
- 无模型学习:不需要环境模型
- 样本平均:用样本平均值估计期望值
- 完整回合:需要等到回合结束
- 探索与利用:需要平衡探索和利用
关键算法
- 首次访问MC:每个状态只使用首次访问的回报
- 每次访问MC:使用所有访问的回报
- MC控制:epsilon-贪婪策略保证探索
- 增量式更新:实时更新,不需要存储所有回报
优势与局限性
优势:
- 无模型
- 简单直观
- 无偏估计
- 可以处理非马尔可夫环境
局限性:
- 需要完整回合
- 高方差
- 样本效率较低
- 探索问题
下一步
在掌握了蒙特卡洛方法后,可以继续学习:
- 第五章:时序差分学习(结合DP和MC的优点)
- 第六章:Q-Learning算法(离线策略TD控制)
参考文献
-
Sutton, R. S., & Barto, A. G. (2018). Reinforcement learning: An introduction (2nd ed.). MIT press.
-
Rubinstein, R. Y., & Kroese, D. P. (2016). Simulation and the Monte Carlo method (3rd ed.). John Wiley & Sons.
下一章预告:第五章将介绍时序差分学习,它结合了动态规划和蒙特卡洛方法的优点,可以在线学习且不需要环境模型。
持续更新中... 🚀
如有问题或建议,欢迎留言讨论!