4、蒙特卡洛方法:蒙特卡洛预测、蒙特卡洛控制、探索与利用的平衡(ε-贪婪策略),以及首次访问与每次访问MC的区别
4.1 蒙特卡洛方法:不靠模型,靠采样
蒙特卡洛方法,说白了就是「用大量随机采样来逼近真实值」。在强化学习里,它不依赖环境模型,直接通过完整的 episode 来估计状态价值或动作价值。
我个人习惯把蒙特卡洛方法理解为「事后诸葛亮」——你先把一整局游戏打完,然后回头看看每个状态到底得了多少回报,用这些回报的平均值来更新价值估计。嗯,听起来很直觉,对吧?
我在项目中遇到过这样一个场景:一个机器人导航任务,环境太复杂,根本建不出准确的转移概率模型。这时候蒙特卡洛方法就派上用场了——让机器人自己跑,跑完一局算一局,慢慢就能学会怎么走。
4.2 蒙特卡洛预测:如何估计状态价值?
预测问题,就是给定一个策略 π,估计每个状态的价值 v_π(s)。蒙特卡洛的做法很简单:
- 从状态 s 开始,按照策略 π 走完一个 episode
- 记录下这个 episode 中 s 之后获得的累计回报 G_t
- 重复多次,取 G_t 的平均值作为 v_π(s) 的估计
你想想看,这其实就是一个大数定律的应用。采样次数越多,估计越准。
# 蒙特卡洛预测的伪代码
def mc_prediction(episodes, gamma):
returns = defaultdict(list)
V = defaultdict(float)
for episode in episodes:
G = 0
# 从后往前计算回报
for t in range(len(episode)-1, -1, -1):
state, reward = episode[t]
G = gamma * G + reward
returns[state].append(G)
V[state] = mean(returns[state])
return V
4.3 首次访问 vs 每次访问:一个关键区别
这两个概念,我刚开始学的时候也绕了一阵。它们的区别其实就一句话:
| 类型 | 做法 | 特点 |
|---|---|---|
| 首次访问 MC | 一个 episode 中,状态 s 第一次出现时才更新 | 无偏估计,方差稍大 |
| 每次访问 MC | 一个 episode 中,状态 s 每次出现都更新 | 有偏估计(但偏差渐近消失),方差更小 |
为什么会这样?因为首次访问只取第一次出现的回报,而每次访问把所有出现都算进去。理论上首次访问更「干净」,但实践中每次访问往往收敛更快。
我曾经在一个棋类游戏中对比过两者,发现每次访问 MC 在相同 episode 数下,价值估计的波动更小。嗯,当然这跟任务性质有关,不能一概而论。
4.4 蒙特卡洛控制:从预测到决策
预测学会了,接下来就是控制——找到最优策略。蒙特卡洛控制的核心是「广义策略迭代」:
- 策略评估: 用 MC 方法估计当前策略的动作价值 q(s, a)
- 策略改进: 对每个状态,选择 q 值最大的动作
但这里有个坑:如果你总是选当前最好的动作,那些没试过的动作就永远没机会被评估了。这就是探索与利用的平衡问题。
4.5 ε-贪婪策略:给探索留一扇窗
我建议用 ε-贪婪策略来解决这个问题。它的逻辑很简单:
- 以概率 1-ε 选择当前最优动作(利用)
- 以概率 ε 随机选择一个动作(探索)
def epsilon_greedy(Q, state, epsilon, n_actions):
if random.random() < epsilon:
return random.randint(0, n_actions-1) # 探索
else:
return argmax(Q[state]) # 利用
ε 的取值很关键。我刚开始做项目时,把 ε 设成 0.1 就扔在那不管了,结果算法到后期还在乱探索,收敛很慢。后来我改成 ε 随时间衰减,效果好了很多。
4.6 蒙特卡洛控制完整流程
把上面这些拼起来,就是完整的蒙特卡洛控制算法:
def mc_control(episodes, gamma, epsilon):
Q = defaultdict(lambda: zeros(n_actions))
returns = defaultdict(list)
for episode in episodes:
G = 0
# 从后往前
for t in range(len(episode)-1, -1, -1):
state, action, reward = episode[t]
G = gamma * G + reward
# 首次访问 MC
if (state, action) not in episode[:t]:
returns[(state, action)].append(G)
Q[state][action] = mean(returns[(state, action)])
# 策略改进:ε-贪婪
for state in Q:
best_action = argmax(Q[state])
for a in range(n_actions):
if a == best_action:
policy[state][a] = 1 - epsilon + epsilon/n_actions
else:
policy[state][a] = epsilon/n_actions
return Q, policy
4.7 本章知识体系
下面这张图总结了蒙特卡洛方法的核心脉络:
蒙特卡洛方法虽然简单,但非常实用。它不需要环境模型,只需要能采样完整轨迹。我个人觉得,对于初学者来说,这是理解强化学习「从经验中学习」这一核心理念的最佳切入点。
嗯,记住一点:蒙特卡洛方法只适用于有终止状态的 episodic 任务。如果你的任务没有明确的终止点,那就要考虑其他方法了——不过那是后面章节的内容了。
- 蒙特卡洛预测:用完整 episode 的回报均值估计价值
- 首次访问 vs 每次访问:更新时机不同,各有优劣
- 蒙特卡洛控制:策略评估 + 策略改进的迭代
- ε-贪婪策略:在利用和探索之间找平衡