第四章:蒙特卡洛方法

第四章:蒙特卡洛方法

标签 :强化学习、蒙特卡洛方法、无模型学习、策略评估、策略控制、探索与利用
难度:⭐⭐⭐(中级)


📖 目录

  • [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
  • 遍历所有状态:需要访问所有状态-动作对

但在实际应用中:

  • 环境模型往往未知
  • 状态空间可能很大,无法遍历所有状态
蒙特卡洛方法的优势
  1. 无模型:不需要环境模型
  2. 只关注实际访问的状态:不需要遍历所有状态
  3. 简单直观:直接从经验中学习
  4. 可以处理非马尔可夫环境:通过完整回合学习

4.1.4 蒙特卡洛方法的基本流程

否 是 初始化价值函数/策略 生成一个回合 计算回报 更新价值函数/策略 收敛? 输出最优策略

4.1.5 蒙特卡洛方法的关键特点

  1. 需要完整回合:必须等到回合结束才能更新
  2. 基于经验:从实际交互中获得数据
  3. 样本平均:用样本平均值估计期望值
  4. 无偏估计:在足够样本下,估计是无偏的

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 控制问题的挑战

控制问题的目标是找到最优策略,而不仅仅是评估给定策略。

挑战

  1. 探索问题:需要保证所有状态-动作对被访问
  2. 策略改进:需要基于Q函数改进策略
  3. 策略评估:需要评估改进后的策略

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控制中,探索至关重要:

  1. 需要访问所有状态-动作对:才能准确估计Q函数
  2. 避免局部最优:充分探索可能发现更好的策略
  3. 样本效率:好的探索策略可以提高学习效率

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 本章小结

本章详细介绍了蒙特卡洛方法,这是无模型强化学习的重要方法。

核心概念

  1. 无模型学习:不需要环境模型
  2. 样本平均:用样本平均值估计期望值
  3. 完整回合:需要等到回合结束
  4. 探索与利用:需要平衡探索和利用

关键算法

  1. 首次访问MC:每个状态只使用首次访问的回报
  2. 每次访问MC:使用所有访问的回报
  3. MC控制:epsilon-贪婪策略保证探索
  4. 增量式更新:实时更新,不需要存储所有回报

优势与局限性

优势

  • 无模型
  • 简单直观
  • 无偏估计
  • 可以处理非马尔可夫环境

局限性

  • 需要完整回合
  • 高方差
  • 样本效率较低
  • 探索问题

下一步

在掌握了蒙特卡洛方法后,可以继续学习:

  • 第五章:时序差分学习(结合DP和MC的优点)
  • 第六章:Q-Learning算法(离线策略TD控制)

参考文献

  1. Sutton, R. S., & Barto, A. G. (2018). Reinforcement learning: An introduction (2nd ed.). MIT press.

  2. Rubinstein, R. Y., & Kroese, D. P. (2016). Simulation and the Monte Carlo method (3rd ed.). John Wiley & Sons.


下一章预告:第五章将介绍时序差分学习,它结合了动态规划和蒙特卡洛方法的优点,可以在线学习且不需要环境模型。


持续更新中... 🚀

如有问题或建议,欢迎留言讨论!

相关推荐
__万波__16 小时前
二十三种设计模式(十二)--代理模式
java·设计模式·代理模式
敲代码的瓦龙2 天前
what?动态规划?
代理模式
老毛肚3 天前
Java两种代理模式详解
java·开发语言·代理模式
Wnq100725 天前
鸿蒙 OS 与 CORBA+DDS+QOS+SOA 在工业控制领域的核心技术对比研究
物联网·性能优化·wpf·代理模式·信号处理·harmonyos·嵌入式实时数据库
ZouZou老师6 天前
C++设计模式之代理模式:以家具生产示例
c++·设计模式·代理模式
菜鸡的升级之路6 天前
ngrok
前端·代理模式
roman_日积跬步-终至千里7 天前
【计算机算法与设计(5)】贪心法、分治法、动态规划的原理和问题求解
算法·动态规划·代理模式
阿波罗尼亚8 天前
Head First设计模式(十一) 设计原则 代理模式
设计模式·代理模式
繁华似锦respect9 天前
C++ 智能指针底层实现深度解析
linux·开发语言·c++·设计模式·代理模式