免模型强化学习:蒙特卡洛与时序差分算法原理与实战

📅 2026/7/5 3:29:48 👁️ 阅读次数 📝 编程学习
免模型强化学习:蒙特卡洛与时序差分算法原理与实战

🚀 30+款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度

在生物信息学、计算生物学乃至更广泛的生物科学研究中,我们常常需要让计算机学习如何在复杂、不确定的环境中做出最优决策,例如预测蛋白质结构、设计基因调控网络或优化实验流程。传统的监督学习需要大量标注好的“标准答案”,而这在探索性生物研究中往往难以获得。这时,强化学习提供了一种全新的范式:智能体通过与环境互动试错,从“奖励”信号中自主学习策略。

本系列文章旨在为生物背景的研究者和学生打开强化学习的大门,剥去其数学外壳,聚焦于直观理解与实战应用。在前两篇中,我们搭建了强化学习的基础框架,并区分了基于模型免模型这两大核心场景。当环境的动态模型(即状态转移概率)未知时,我们便进入了“免模型”的广阔天地。本文将深入讲解解决免模型问题的两大基石算法:蒙特卡洛方法时序差分算法。你将理解它们如何在不依赖环境模型的情况下,仅凭经验序列来评估和改进策略,并掌握其核心思想、实现差异以及适用场景。

无论你是想用RL优化湿实验步骤,还是分析动态生物过程,本文都将提供可直接运行的代码示例和清晰的算法对比,帮助你从原理到实践,稳步跨越这道关键门槛。

1. 核心概念回顾:为何需要“免模型”方法?

在深入蒙特卡洛和时序差分之前,我们有必要明确它们所要解决的根本问题。

1.1 基于模型 vs. 免模型:一个关键抉择

在强化学习中,智能体追求的是最大化长期累积奖励。为了实现这一目标,我们需要评估某个状态或某个状态-动作对的价值(Value),即预期能获得多少回报。

  • 基于模型(Model-Based):如果我们像拥有“上帝视角”一样,完全知晓环境的运作机制——即知道在状态s执行动作a后,转移到状态s'的概率P(s'|s,a)以及获得的即时奖励R(s,a,s')——那么我们可以通过动态规划(如策略迭代、价值迭代)精确地求解出最优价值函数和策略。这好比在已知所有化学反应速率和规则的条件下,精确模拟细胞代谢通路。
  • 免模型(Model-Free):然而,在绝大多数现实生物问题中,尤其是与真实生物系统或复杂仿真环境交互时,我们无法获得完整、精确的环境模型。环境的动态特性可能是未知的、随机的或过于复杂难以建模。例如,我们无法精确知道某个药物分子与靶蛋白结合后,具体会以多大概率引发下游一系列复杂的生物信号响应。这时,我们就需要免模型方法。

免模型强化学习的核心思想是:放弃对环境模型的依赖,直接通过智能体与环境的交互经验(轨迹序列)来学习价值函数和策略。蒙特卡洛方法和时序差分算法正是实现这一思想的两种主流途径。

1.2 本文目标:策略评估与预测

本文聚焦于策略评估(Policy Evaluation)问题,也称为预测(Prediction)问题。即,给定一个固定的策略π,如何评估这个策略的好坏?具体来说,就是如何计算出在该策略下,每个状态(或状态-动作对)的价值函数Vπ(s)(或Qπ(s,a))。

一旦我们能准确评估一个策略,策略改进(如贪心策略)便水到渠成,进而通过策略迭代逐步逼近最优策略。蒙特卡洛和时序差分首先解决的就是这个“评估”问题。

2. 环境准备与工具说明

我们将使用 Python 和经典的gym库进行算法演示。gym提供了多种标准环境,便于我们专注于算法本身的理解。

2.1 环境配置

请确保你已安装 Python(推荐 3.8 及以上版本)。然后通过 pip 安装必要库:

# 安装强化学习环境库和数值计算库 pip install gym numpy matplotlib

版本兼容性说明gym库近期有较大更新(如gym->gymnasium)。为保证代码稳定运行,我们使用经典的gym版本。如果遇到问题,可以尝试指定版本安装:pip install gym==0.25.2

2.2 示例环境:Blackjack(21点)

为了直观展示算法,我们选择一个状态空间离散且规则明确的环境:Blackjack-v1。在这个环境中:

  • 状态:由玩家当前点数、庄家明牌点数、玩家是否有可用Ace组成。
  • 动作:0 表示“停牌”,1 表示“要牌”。
  • 奖励:+1 表示赢,-1 表示输,0 表示平局。回合结束时结算。
  • 目标:学习一个策略,使得获胜概率最大化。

这个环境完美契合免模型学习:我们不知道发牌盒里下一张牌的具体概率分布(模型未知),只能通过反复玩牌(交互)来学习。

3. 蒙特卡洛方法:从完整回合中学习

蒙特卡洛方法的灵感来源于统计学中的蒙特卡洛模拟:通过大量随机采样来估计未知量。在RL中,它通过运行大量完整的回合(从开始到终止),然后利用整个回合获得的实际回报来更新价值估计。

3.1 核心思想:用经验平均代替期望

对于一个状态s,其价值Vπ(s)定义为遵循策略π后所能获得的期望回报。蒙特卡洛方法用经验平均来近似这个数学期望。

具体步骤:

  1. 生成回合:使用策略π与环境交互,产生一个从起始状态到终止状态的状态、动作、奖励序列(轨迹)。
  2. 计算回报:对于轨迹中的每一个状态s,计算从该状态开始到回合结束的实际累积回报G_t(考虑折扣因子γ)。
  3. 增量平均:将该次回报G_t纳入到状态s的价值估计中。通常采用增量更新的方式:V(s) ← V(s) + α [G_t - V(s)]其中α是学习率。

关键特性:蒙特卡洛方法必须等到一个回合完全结束后,才能知道每个状态的最终回报G_t,从而进行更新。这意味着学习是“回合制”的,更新方差较大,但偏差小。

3.2 首次访问 vs. 每次访问

在同一个回合中,一个状态s可能出现多次。如何用这个回合的回报来更新V(s)

  • 首次访问蒙特卡洛:只使用状态s在该回合中第一次出现时计算的回报G_t进行更新。
  • 每次访问蒙特卡洛:使用状态s在该回合中每次出现时计算的回报G_t进行更新。

理论上两者在采样次数趋于无穷时都会收敛到Vπ(s)。首次访问法更常用,因为其估计是无偏的。

3.3 代码实战:蒙特卡洛策略评估

下面我们用代码实现首次访问蒙特卡洛方法,来评估 Blackjack 环境中的一个简单策略:“点数≥18则停牌,否则要牌”。

import gym import numpy as np from collections import defaultdict import matplotlib.pyplot as plt def simple_blackjack_policy(observation): """ 一个简单的策略:玩家点数 >= 18 时停牌,否则要牌。 observation: (玩家点数, 庄家明牌点数, 是否有可用Ace) """ player_score, _, _ = observation return 0 if player_score >= 18 else 1 # 0: 停牌, 1: 要牌 def mc_prediction(policy, env, num_episodes, gamma=1.0, alpha=0.01): """ 首次访问蒙特卡洛策略评估。 参数: policy: 一个函数,输入状态,输出动作。 env: Gym 环境。 num_episodes: 运行的回合数。 gamma: 折扣因子。 alpha: 学习率(恒定步长)。 返回: V: 估计的状态价值字典。 """ # 初始化价值表,默认值为0.0 V = defaultdict(float) # 用于记录每个状态是否已被首次访问(在当前回合内) seen_in_episode = set() for episode in range(1, num_episodes + 1): # 重置环境,开始一个新回合 state, _ = env.reset() episode_history = [] # 记录 (状态, 奖励) done = False # 生成轨迹 while not done: action = policy(state) next_state, reward, terminated, truncated, _ = env.step(action) done = terminated or truncated # 存储当前状态和后续获得的奖励(注意奖励是执行动作后获得的) # 为了计算回报,我们先存状态,奖励在得到后补到上一个元组里,这里用更清晰的方式: episode_history.append((state, reward)) state = next_state # 回合结束,最后一个状态转移的奖励已经包含在内 # 现在 episode_history 包含 [(s0, r1), (s1, r2), ..., (sT-1, rT)] # 最后一个状态 sT 是终止状态,其后的奖励为0。 G = 0 # 回报 # 从后向前遍历,计算每个状态的回报 for t in range(len(episode_history) - 1, -1, -1): state_t, reward_t_plus_1 = episode_history[t] # 注意:state_t 下执行动作后得到 reward_t_plus_1 G = gamma * G + reward_t_plus_1 # 首次访问检查 if state_t not in seen_in_episode: seen_in_episode.add(state_t) # 增量更新状态价值 V[state_t] += alpha * (G - V[state_t]) # 清空本回合的首次访问记录,为下一回合准备 seen_in_episode.clear() # 可选:每50000回合打印进度 if episode % 50000 == 0: print(f"Episode {episode}/{num_episodes}") return V # 创建环境 env = gym.make('Blackjack-v1', sab=True) # sab=True 使用简化规则 # 运行蒙特卡洛预测 print("开始蒙特卡洛策略评估...") num_episodes = 200000 V_mc = mc_prediction(simple_blackjack_policy, env, num_episodes, gamma=1.0, alpha=0.01) print(f"评估完成,共评估了 {len(V_mc)} 个不同的状态。") # 查看几个典型状态的价值 print("\n--- 简单策略下部分状态的价值估计 ---") test_states = [ (21, 6, False), # 玩家21点,庄家明牌6 (18, 7, False), # 玩家18点,庄家明牌7 (12, 2, False), # 玩家12点,庄家明牌2 ] for s in test_states: print(f"状态 {s}: V(s) ≈ {V_mc.get(s, 0.0):.4f}") env.close()

代码解读与输出分析

  1. simple_blackjack_policy定义了我们要评估的固定策略。
  2. mc_prediction函数实现了首次访问蒙特卡洛算法。它维护一个价值字典V,每回合结束后,从后向前计算每个状态的回报G,并对首次访问的状态进行增量更新。
  3. 运行20万回合后,我们得到了该策略下不同状态的价值估计。例如,(21, 6, False)的价值很可能接近+1(因为玩家已21点,胜率极高),而(12, 2, False)的价值可能为负(点数小且庄家明牌小,局势不利)。
  4. 关键点:学习率alpha用于平滑更新。折扣因子gamma=1.0表示我们关心整个回合的总输赢。

4. 时序差分学习:在每一步中学习

蒙特卡洛方法必须等待回合结束,这在长回合或连续任务中学习效率很低。时序差分算法解决了这个问题。

4.1 核心思想:利用估计进行估计

时序差分算法的核心是自举(Bootstrapping):用当前的估计值来更新另一个估计值。其更新公式基于一个非常直观的概念——“预测误差”。

最经典的时序差分算法是TD(0),其状态价值更新公式为:V(s_t) ← V(s_t) + α [ r_{t+1} + γ * V(s_{t+1}) - V(s_t) ]

让我们拆解这个公式:

  • r_{t+1} + γ * V(s_{t+1}):这被称为TD 目标。它由两部分组成:
    • r_{t+1}:在状态s_t执行动作后获得的即时奖励
    • γ * V(s_{t+1}):对下一个状态s_{t+1}的价值估计,乘以折扣因子。这代表了对未来回报的预估。
  • V(s_t):状态s_t的当前价值估计。
  • [TD目标 - 当前估计]:这就是TD 误差。它衡量了当前估计与“更好”的估计(TD目标)之间的差距。
  • 整个更新过程:用 TD 误差来修正当前状态s_t的价值估计,步长为学习率α

与蒙特卡洛的对比

  • 蒙特卡洛更新V(s_t) ← V(s_t) + α [ G_t - V(s_t) ],其中G_t实际的完整回报。
  • TD(0)更新V(s_t) ← V(s_t) + α [ r_{t+1} + γV(s_{t+1}) - V(s_t) ],其中r_{t+1} + γV(s_{t+1})估计的回报。

TD 方法在每一步交互后都能立即更新,无需等待回合结束,因此学习更快,更适合在线学习和连续任务。

4.2 代码实战:TD(0) 策略评估

现在,我们用 TD(0) 算法来评估同一个 Blackjack 策略。

def td_prediction(policy, env, num_episodes, gamma=1.0, alpha=0.01): """ TD(0) 策略评估。 参数: policy: 一个函数,输入状态,输出动作。 env: Gym 环境。 num_episodes: 运行的回合数。 gamma: 折扣因子。 alpha: 学习率。 返回: V: 估计的状态价值字典。 """ V = defaultdict(float) for episode in range(1, num_episodes + 1): state, _ = env.reset() done = False while not done: action = policy(state) next_state, reward, terminated, truncated, _ = env.step(action) done = terminated or truncated # TD(0) 更新 # 获取下一个状态的价值估计,如果未访问过则默认为0 next_state_value = V[next_state] if not done else 0.0 td_target = reward + gamma * next_state_value td_error = td_target - V[state] V[state] += alpha * td_error state = next_state if episode % 50000 == 0: print(f"Episode {episode}/{num_episodes}") return V # 创建环境 env = gym.make('Blackjack-v1', sab=True) # 运行TD(0)预测 print("开始TD(0)策略评估...") num_episodes = 200000 V_td = td_prediction(simple_blackjack_policy, env, num_episodes, gamma=1.0, alpha=0.01) print(f"评估完成,共评估了 {len(V_td)} 个不同的状态。") # 查看相同状态的价值,与MC结果对比 print("\n--- TD(0)评估结果对比 ---") for s in test_states: v_mc = V_mc.get(s, 0.0) v_td = V_td.get(s, 0.0) print(f"状态 {s}: MC ≈ {v_mc:.4f}, TD ≈ {v_td:.4f}, 差异: {abs(v_mc - v_td):.4f}") env.close()

代码解读与输出分析

  1. td_prediction函数实现了 TD(0) 算法。注意,在每一步(s_t, a_t, r_{t+1}, s_{t+1})之后,我们立即用下一个状态s_{t+1}的当前估计值V[s_{t+1}]来更新当前状态s_t的价值V[s_t]
  2. 如果s_{t+1}是终止状态,则其价值定义为0.0
  3. 运行相同回合数后,对比 MC 和 TD 的结果。你会发现两者的估计值非常接近,这验证了 TD 算法的有效性。但由于 TD 使用了自举(依赖现有估计V(s_{t+1})),其估计的方差通常比 MC 小,但会引入一些偏差。

5. 算法对比与深入理解

为了更直观地对比 MC 和 TD,我们将其核心特性总结如下:

特性蒙特卡洛方法时序差分方法
更新时机必须等待整个回合结束每一步之后都可以立即更新
自举否。使用实际回报G_t是。使用估计值V(s_{t+1})构建目标
偏差/方差无偏,高方差(依赖单次回合的随机结果)有偏(依赖初始估计),低方差
收敛性对函数近似(大状态空间)问题可能不稳定通常更稳定,在函数近似下收敛性更好
在线学习不适合,延迟高非常适合,实时学习
处理非终止环境需要将回合截断,可能不自然天然适合连续任务

5.1 一个比喻:生物实验中的学习

假设你的目标是评估一种新的细胞培养方案(策略)的效果(价值)。

  • 蒙特卡洛方法:你进行一批完整的实验(回合),从接种到收获,记录最终产量(回报G_t)。然后,你用这批实验的最终产量,来回过头评估中间某个时间点(状态s_t)的培养条件好坏。你必须等实验全部做完才能分析。
  • 时序差分方法:你每小时(每一步)取样检测一次。你不仅看当前的细胞密度(即时奖励r_{t+1}),还会根据已有的经验模型,预测照此趋势下一小时的密度(估计价值V(s_{t+1}))。你将当前观测与预测结合,立即调整对该培养阶段效果的评估。你无需等待实验结束就能持续优化判断。

5.2 从预测到控制:SARSA 与 Q-Learning

上述 MC 和 TD(0) 都用于策略评估。如何将其用于策略控制(寻找最优策略)?关键在于从学习状态价值V(s)转向学习状态-动作价值Q(s,a)

两种经典的 TD 控制算法是:

  • SARSA (On-Policy TD Control):其更新公式为Q(s_t, a_t) ← Q(s_t, a_t) + α [ r_{t+1} + γ * Q(s_{t+1}, a_{t+1}) - Q(s_t, a_t) ]。它遵循并优化当前策略(a_{t+1}由当前策略产生)。
  • Q-Learning (Off-Policy TD Control):其更新公式为Q(s_t, a_t) ← Q(s_t, a_t) + α [ r_{t+1} + γ * max_a Q(s_{t+1}, a) - Q(s_t, a_t) ]。它直接学习最优策略的价值,而不依赖于当前执行的动作。

以下是 Q-Learning 在 Blackjack 中的一个极简示例,展示如何从评估走向控制:

def q_learning(env, num_episodes, alpha=0.1, gamma=1.0, epsilon=0.1): """ Q-Learning 算法寻找最优策略。 """ # 初始化 Q 表。状态是元组,动作是0或1。 Q = defaultdict(lambda: np.zeros(env.action_space.n)) for episode in range(num_episodes): state, _ = env.reset() done = False while not done: # epsilon-贪婪策略选择动作 if np.random.random() < epsilon: action = env.action_space.sample() # 探索 else: action = np.argmax(Q[state]) # 利用 next_state, reward, terminated, truncated, _ = env.step(action) done = terminated or truncated # Q-Learning 核心更新 current_q = Q[state][action] # 下一个状态的最大Q值,如果是终止状态则为0 next_max_q = np.max(Q[next_state]) if not done else 0.0 td_target = reward + gamma * next_max_q Q[state][action] = current_q + alpha * (td_target - current_q) state = next_state # 从Q表推导出最优策略 policy = {} for s, q_vals in Q.items(): policy[s] = np.argmax(q_vals) return Q, policy # 运行Q-Learning print("\n开始Q-Learning寻找最优策略...") env = gym.make('Blackjack-v1', sab=True) num_episodes = 500000 Q_opt, policy_opt = q_learning(env, num_episodes, alpha=0.1, gamma=0.95, epsilon=0.1) print("Q-Learning 完成。") # 查看学到的策略在几个状态下的决策 print("\n--- 学到的策略示例 ---") for s in test_states: action = policy_opt.get(s, 0) # 默认停牌 action_str = "停牌" if action == 0 else "要牌" print(f"状态 {s}: 最优动作 -> {action_str}") env.close()

这段代码展示了如何用 TD 方法(Q-Learning)直接学习最优动作价值函数Q*,并从中提取最优策略。你会发现,学到的策略可能比我们之前手工设定的简单策略更优。

6. 在生物信息学中的应用场景与挑战

理解了蒙特卡洛和时序差分,你就能看懂许多前沿生物信息学RL应用的核心。

  • 蛋白质折叠与设计:将蛋白质序列或构象作为状态,每一步调整氨基酸或扭转二面角作为动作,最终结构的稳定性(如Rosetta能量)作为奖励。由于折叠轨迹长,TD方法(如PPO、SAC等高级算法的基础)更受青睐。
  • 药物分子生成:状态是当前分子图,动作是添加一个原子或化学键,奖励基于生成的分子属性(如与靶点的结合力、类药性)。MC方法可用于评估完整分子的性质,TD方法可用于优化生成过程。
  • 实验流程优化:状态是实验的当前条件和历史结果,动作是选择下一个实验参数(如温度、浓度),奖励是实验产出(如产物纯度、产量)。这是一个典型的序列决策问题,TD方法能实现实时、在线优化。

挑战与注意事项

  1. 奖励设计:这是RL在科学问题中成功的关键。奖励函数必须准确、平滑地反映科学目标。设计不当会导致智能体“钻空子”,找到奖励高但无科学意义的策略。
  2. 状态/动作空间:生物系统的状态和动作空间往往是连续、高维的(如分子坐标、基因表达谱)。这需要与深度学习结合(深度强化学习),用神经网络来近似价值函数或策略。
  3. 样本效率:与环境的交互(湿实验、分子动力学模拟)可能极其昂贵。需要关注样本效率高的算法(如基于模型的RL、离线RL)或利用模拟器预训练。
  4. 探索与利用:在生物空间中,盲目探索成本高,需要设计合理的探索策略(如基于不确定性的探索),平衡尝试新事物和利用已知好方案。

7. 总结与学习路线

本文深入探讨了免模型强化学习的两大支柱:蒙特卡洛方法和时序差分算法。我们从策略评估问题出发,揭示了MC通过完整回合的经验平均进行无偏但高方差学习,而TD通过一步自举实现快速、在线但略有偏差的学习。通过Blackjack环境的代码实战,你应该已经掌握了两种算法的实现细节,并理解了它们各自的更新公式V(s) ← V(s) + α [G - V(s)]V(s) ← V(s) + α [r + γV(s') - V(s)]背后的深刻含义。

关键收获

  1. 免模型是RL应对复杂未知环境的利器,MC和TD是其中最基本且强大的工具。
  2. MC和TD的根本区别在于更新目标:MC用实际回报G_t,TD用估计目标r + γV(s')
  3. 从评估到控制,只需将状态价值V(s)替换为状态-动作价值Q(s,a),并引入策略改进(如ε-贪婪),就能得到SARSA、Q-Learning等经典控制算法。

下一步学习建议

  1. 动手实验:尝试修改代码中的策略、学习率alpha、折扣因子gamma,观察对学习速度和结果的影响。在FrozenLakeCliffWalking等更简单的环境中验证算法。
  2. 深入理论:理解TD(λ)算法,它是MC和TD(0)的广义形式,通过资格迹(Eligibility Trace)在多步回报间取得平衡。
  3. 迈向深度强化学习:当状态空间巨大或连续时,我们需要用神经网络来近似V(s)Q(s,a)。这就是DQN (Deep Q-Network),它结合了Q-Learning和深度学习。理解DQN是通往现代RL应用(如AlphaFold的某些组件)的重要一步。
  4. 探索策略梯度方法:对于动作空间连续或策略本身需要参数化的场景(如机器人控制、分子连续优化),策略梯度方法(如REINFORCE,以及更先进的PPO、SAC)是另一大家族。它们直接优化策略参数,与本文介绍的价值函数方法相辅相成。

强化学习为生物复杂系统的分析与优化提供了强大的框架。从蒙特卡洛的“回顾式总结”到时序差分的“步步为营”,这些算法思想不仅能帮你解决计算问题,更能启发你思考生物系统中学习与适应的本质。希望本文能成为你探索这一交叉领域的一块坚实垫脚石。

🚀 30+款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度