无模型强化学习核心算法:蒙特卡洛与时序差分原理及Sarsa与Q-learning实战对比 如果你是一名生物专业的学生第一次接触强化学习可能会觉得它离你的领域很远——不就是训练AI玩游戏吗但请先别急着划走。想象一下你正在研究一种蛋白质的折叠过程或者设计一个药物筛选的实验流程。这些任务本质上都是一个智能体比如一个模拟的分子或实验方案在复杂环境中通过不断试错寻找最优“行为”序列的过程。这不正是强化学习要解决的核心问题吗然而当你翻开经典的强化学习教材扑面而来的往往是马尔可夫决策过程、贝尔曼方程等数学概念以及动态规划这类需要完全已知环境模型的方法。这对于没有深厚数学和编程背景的生物学者来说门槛实在太高了。更重要的是在真实的生物问题中环境比如细胞内的生化反应网络、动物行为生态的转移概率和奖励函数几乎不可能被完全、精确地知晓。我们无法像解方程一样“规划”出最优路径只能通过与环境互动、采样数据来“学习”。这就是无模型强化学习登场的时刻。它放弃了“先知”般的全局规划转而拥抱一种更贴近实验科学家的思维方式通过反复试验、观察结果、并基于此更新认知。在无模型强化学习的工具箱里蒙特卡洛方法和时序差分算法是两把至关重要的钥匙。前者像是一位严谨的实验员必须等整个实验一个回合结束后才分析数据后者则像一位敏锐的观察者每进行一步就立刻根据最新观察调整假设。本文将为你彻底拆解这两种核心方法。我们不会停留在公式推导而是通过一个经典的“悬崖漫步”环境用Python代码带你亲手实现Sarsa和Q-learning算法直观感受它们的学习过程与策略差异。你会发现理解这些算法不仅能帮你读懂前沿的AI生物交叉论文其“试错-评估-优化”的核心思想更能为你自己的科研思路带来启发。1. 从动态规划到无模型学习我们为何需要新方法在上一讲中我们介绍了基于动态规划的强化学习方法如策略迭代和价值迭代。它们强大而优雅但有一个致命的前提你必须完全知晓环境模型。具体来说你需要知道状态转移概率P(s|s, a)和奖励函数R(s, a, s)。这好比你在设计一个生化实验前就已经知道了所有试剂反应的精确动力学方程和产物——这在实际的生物学研究中几乎是不可能的。绝大多数现实问题无论是训练机器人走路、让AI玩电子游戏还是模拟生物在复杂环境中的适应行为我们都处在一个模型未知的世界。智能体只能通过实际行动从环境中获得一串串状态、动作、奖励的序列数据并从中学习。这就引出了强化学习的两大范式有模型学习先学习或已知环境模型再利用模型进行规划如动态规划。无模型学习不尝试理解环境的内在机制直接通过与环境的交互数据来学习价值函数和策略。无模型学习是更通用、也更符合我们认知世界方式的方法。它的核心挑战在于如何高效地利用有限的交互经验来估计长期价值并改进策略对此主要有两种思路蒙特卡洛方法等到一个完整的交互序列称为一个“回合”或“episode”结束后利用整个序列的累计回报来更新价值估计。它“看完全局再打分”估计是无偏的但方差大且必须等回合结束。时序差分学习每走一步就立刻更新。它利用当前奖励和下一状态的估计值来更新当前状态的价值。它“边走边学”能在线更新方差小但估计是有偏的。理解这两种方法的区别与联系是掌握现代强化学习包括深度Q网络等的基石。下面我们首先深入它们的原理。2. 核心概念剖析蒙特卡洛 vs. 时序差分让我们暂时忘掉复杂的公式用生物实验来类比。蒙特卡洛方法就像完成一整轮动物行为学实验。你把小鼠放入迷宫记录下它从起点到终点或失败所走过的每一步和获得的奖励比如找到食物的正奖励或电击的负奖励。只有等实验全部结束你才回头分析整条轨迹计算它从每个位置出发最终能获得的总奖励并用这个“总成绩”来评价经过的每个位置的好坏。它的核心是使用完整的实际回报进行更新G_t R_{t1} γ * R_{t2} γ^2 * R_{t3} ...其中G_t是从时刻t开始的累计回报γ是折扣因子。时序差分学习则像实时监控实验过程。小鼠每走一步你不仅记录它这一步得到的即时奖励还会根据它对下一个位置的“预期价值”来立刻调整对上一步位置的评价。你不需要等实验结束。它的更新公式融合了实际观测和现有估计V(S_t) ← V(S_t) α * [R_{t1} γ * V(S_{t1}) - V(S_t)]这个公式非常关键。R_{t1} γ * V(S_{t1})被称为TD目标它是基于当前一步的真实奖励和对下一状态的现有估计形成的对当前状态价值的新估计。TD目标 - V(S_t)被称为TD误差它衡量了当前估计与一步新估计的差距。智能体就根据这个误差来更新价值函数。α是学习率。两者的根本区别在于更新目标蒙特卡洛的目标G_t使用从当前状态到回合结束的所有未来奖励之和。时序差分的目标R_{t1} γ * V(S_{t1})使用即时奖励加上下一状态的估计价值。TD方法可以看作是蒙特卡洛使用真实回报和动态规划使用自举法的结合。它既像蒙特卡洛一样从经验中学习又像动态规划一样利用现有的价值估计进行“自举”。为了直观对比请看下表特性蒙特卡洛方法时序差分学习更新时机必须等待回合结束每一步之后都可以更新偏差/方差无偏估计但方差高依赖单次轨迹的随机性有偏估计依赖现有估计但方差低学习方式离线学习在线学习收敛性通常能收敛到最优解但可能较慢通常也能收敛且常比MC更快对未完结序列无法处理可以处理通过估计生物类比分析完整实验录像实时观察并调整假设理解了核心思想后我们进入实践环节。我们将在一个名为“悬崖漫步”的网格世界环境中实现两种最重要的TD算法Sarsa和Q-learning。3. 环境搭建悬崖漫步问题我们首先需要定义智能体与交互的环境。这里我们实现一个CliffWalkingEnv类它模拟了一个经典的网格世界问题智能体从起点出发需要到达终点但脚下是“悬崖”掉下去会受到巨大惩罚并回到起点。import matplotlib.pyplot as plt import numpy as np from tqdm import tqdm # 用于显示进度条 class CliffWalkingEnv: def __init__(self, ncol, nrow): self.nrow nrow self.ncol ncol self.x 0 # 记录当前智能体位置的横坐标 self.y self.nrow - 1 # 记录当前智能体位置的纵坐标起点在左下角 def step(self, action): # 4种动作: 0:上, 1:下, 2:左, 3:右。坐标系原点在左上角。 change [[0, -1], [0, 1], [-1, 0], [1, 0]] self.x min(self.ncol - 1, max(0, self.x change[action][0])) self.y min(self.nrow - 1, max(0, self.y change[action][1])) next_state self.y * self.ncol self.x reward -1 done False # 判断下一个位置是否是悬崖或者目标 if self.y self.nrow - 1 and self.x 0: # 最下面一行除了起点列是悬崖或目标 done True if self.x ! self.ncol - 1: # 不是最右一列目标那就是悬崖 reward -100 return next_state, reward, done def reset(self): # 回归初始状态坐标原点在左下角 self.x 0 self.y self.nrow - 1 return self.y * self.ncol self.x环境说明环境是一个nrow x ncol的网格。状态用单个整数表示行索引 * 列数 列索引。智能体每走一步获得-1的奖励鼓励尽快到达终点。如果掉下悬崖最底行中间区域获得-100的奖励并结束本轮回到起点。到达最右下角的目标点获得-1奖励并成功结束。我们的目标是让智能体学会一条从起点到终点的安全路径避免掉下悬崖。4. 时序差分算法的两大代表Sarsa vs. Q-learning时序差分学习的核心是更新动作价值函数Q(s, a)。根据如何选取“下一动作”来构成TD目标衍生出两个最重要的算法Sarsa和Q-learning。它们的区别是理解无模型强化学习的关键。4.1 Sarsa同策略的保守学习者Sarsa的名字来源于其更新所需的数据元组(State, Action, Reward, next State, next Action)。 它的核心更新公式如下Q(S_t, A_t) ← Q(S_t, A_t) α * [R_{t1} γ * Q(S_{t1}, A_{t1}) - Q(S_t, A_t)]注意TD目标中使用的下一个动作A_{t1}是根据当前正在执行的政策通常是ε-greedy策略采样得到的。这意味着Sarsa评估和优化的是它实际执行的策略因此被称为同策略学习。一个生动的比喻Sarsa像一个在悬崖边小心翼翼学走路的人。他决定下一步怎么走A_{t1}时会考虑到自己有时会失足探索因此他评估的路径价值会包含这种风险最终学到的策略会倾向于远离悬崖边缘即使那条路可能更长。下面是Sarsa算法的实现class Sarsa: Sarsa算法 def __init__(self, ncol, nrow, epsilon, alpha, gamma, n_action4): self.Q_table np.zeros([nrow * ncol, n_action]) # 初始化Q(s,a)表格 self.n_action n_action # 动作个数 self.alpha alpha # 学习率 self.gamma gamma # 折扣因子 self.epsilon epsilon # epsilon-贪婪策略中的参数 def take_action(self, state): # 选取下一步的操作具体实现为epsilon-贪婪 if np.random.random() self.epsilon: action np.random.randint(self.n_action) else: action np.argmax(self.Q_table[state]) return action def best_action(self, state): # 用于打印策略 Q_max np.max(self.Q_table[state]) a [0 for _ in range(self.n_action)] for i in range(self.n_action): if self.Q_table[state, i] Q_max: a[i] 1 return a def update(self, s0, a0, r, s1, a1): # Sarsa更新公式 td_error r self.gamma * self.Q_table[s1, a1] - self.Q_table[s0, a0] self.Q_table[s0, a0] self.alpha * td_error4.2 Q-learning异策略的乐观探索者Q-learning的更新公式与Sarsa只有一处关键不同Q(S_t, A_t) ← Q(S_t, A_t) α * [R_{t1} γ * max_{a} Q(S_{t1}, a) - Q(S_t, A_t)]注意TD目标中使用的值是下一状态所有可能动作中的最大Q值即max_{a} Q(S_{t1}, a)。这个最大值对应的是最优策略下的动作而不是智能体实际要执行的动作A_{t1}。这意味着Q-learning在更新时是用最优策略的价值来评估当前行为策略产生的经验。它学习的是最优动作价值函数而与其探索环境时使用的策略如ε-greedy无关。因此被称为异策略学习。继续我们的比喻Q-learning像一个自信的规划师。他在悬崖边学走路时评估每一步的价值是基于“假设我从此以后都走最优路线”的乐观估计。因此他可能会学到一条贴着悬崖走的最短路径因为在他的评估中只要下一步选择最优动作就不会掉下去。但这在实际探索中由于存在随机探索ε-greedy他确实有掉下悬崖的风险。下面是Q-learning算法的实现class QLearning: Q-learning算法 def __init__(self, ncol, nrow, epsilon, alpha, gamma, n_action4): self.Q_table np.zeros([nrow * ncol, n_action]) self.n_action n_action self.alpha alpha self.gamma gamma self.epsilon epsilon def take_action(self, state): if np.random.random() self.epsilon: action np.random.randint(self.n_action) else: action np.argmax(self.Q_table[state]) return action def best_action(self, state): Q_max np.max(self.Q_table[state]) a [0 for _ in range(self.n_action)] for i in range(self.n_action): if self.Q_table[state, i] Q_max: a[i] 1 return a def update(self, s0, a0, r, s1): # Q-learning更新公式注意这里取的是s1状态下所有动作的最大Q值 td_error r self.gamma * self.Q_table[s1].max() - self.Q_table[s0, a0] self.Q_table[s0, a0] self.alpha * td_error关键对比总结特性SarsaQ-learning更新公式核心Q(s,a) α * (r γ * Q(s, a) - Q(s,a))Q(s,a) α * (r γ * max_{a} Q(s, a) - Q(s,a))策略类型同策略评估和改进的是行为策略本身。异策略评估的是目标策略最优策略而用行为策略探索。学习目标学习当前ε-greedy策略下的动作价值。直接学习最优策略的动作价值。风险倾向更保守会考虑探索带来的风险。更乐观假设后续动作总是最优。在线/离线严格在线必须使用下一步实际采取的动作。本质上是离线学习可以使用历史经验回放。5. 实战演练在悬崖漫步中运行与比较现在让我们在悬崖漫步环境中训练并比较这两个算法。我们将设置一个4x12的网格悬崖位于最下方第1-10列。5.1 训练与评估函数我们编写一个通用的训练函数并可视化学习曲线和最终策略。def train_agent(env, agent, num_episodes500): 训练智能体并返回每轮的回报列表 return_list [] for i in range(10): with tqdm(totalint(num_episodes/10), descIteration %d % i) as pbar: for i_episode in range(int(num_episodes/10)): episode_return 0 state env.reset() # 对于Sarsa需要先根据初始状态选择第一个动作 if isinstance(agent, Sarsa): action agent.take_action(state) done False while not done: if isinstance(agent, QLearning): action agent.take_action(state) next_state, reward, done env.step(action) episode_return reward if isinstance(agent, Sarsa): next_action agent.take_action(next_state) agent.update(state, action, reward, next_state, next_action) action next_action # Sarsa需要更新动作 elif isinstance(agent, QLearning): agent.update(state, action, reward, next_state) state next_state return_list.append(episode_return) if (i_episode1) % 10 0: pbar.set_postfix({ episode: %d % (num_episodes/10 * i i_episode 1), return: %.3f % np.mean(return_list[-10:]) }) pbar.update(1) return return_list def print_agent(agent, env, action_meaning, disaster[], end[]): 打印学到的策略 for i in range(env.nrow): for j in range(env.ncol): if (i * env.ncol j) in disaster: print(****, end ) elif (i * env.ncol j) in end: print(EEEE, end ) else: a agent.best_action(i * env.ncol j) pi_str for k in range(len(action_meaning)): pi_str action_meaning[k] if a[k] 0 else o print(pi_str, end ) print()5.2 运行Sarsa算法# 设置环境和参数 ncol 12 nrow 4 env CliffWalkingEnv(ncol, nrow) np.random.seed(0) # 固定随机种子使结果可复现 epsilon 0.1 alpha 0.1 gamma 0.9 agent_sarsa Sarsa(ncol, nrow, epsilon, alpha, gamma) # 训练Sarsa智能体 print(开始训练Sarsa算法...) return_list_sarsa train_agent(env, agent_sarsa, num_episodes500) # 绘制学习曲线 episodes_list list(range(len(return_list_sarsa))) plt.plot(episodes_list, return_list_sarsa) plt.xlabel(Episodes) plt.ylabel(Returns) plt.title(Sarsa on Cliff Walking) plt.show() # 输出最终策略 action_meaning [^, v, , ] print(Sarsa算法最终收敛到的策略为) print_agent(agent_sarsa, env, action_meaning, list(range(37, 47)), [47])运行结果分析 你会看到Sarsa的学习曲线回报逐渐上升从约-100提升到-20左右。打印的策略会显示Sarsa智能体学会了一条远离悬崖顶部边缘的路径。它宁愿绕远路走安全区域也不愿冒险靠近悬崖。这正是其“同策略”保守特性的体现它在学习时评估的是包含探索动作可能掉下悬崖的策略价值因此它认为靠近悬崖的状态-动作对价值很低。5.3 运行Q-learning算法# 使用相同的环境参数 np.random.seed(0) # 使用相同的随机种子保证环境随机性一致 agent_q QLearning(ncol, nrow, epsilon, alpha, gamma) # 训练Q-learning智能体 print(\n开始训练Q-learning算法...) return_list_q train_agent(env, agent_q, num_episodes500) # 绘制学习曲线 episodes_list list(range(len(return_list_q))) plt.plot(episodes_list, return_list_q) plt.xlabel(Episodes) plt.ylabel(Returns) plt.title(Q-learning on Cliff Walking) plt.show() # 输出最终策略 print(Q-learning算法最终收敛到的策略为) print_agent(agent_q, env, action_meaning, list(range(37, 47)), [47])运行结果分析 Q-learning的学习曲线可能波动更大但最终也能收敛。其打印的策略会显示它学到的是一条贴着悬崖边缘的最短路径。这是因为Q-learning在更新时假设下一步会采取最优动作即不跌入悬崖因此它认为贴着悬崖走的那些状态其最优动作价值很高。然而在训练过程中由于行为策略ε-greedy存在探索它实际上会以一定概率掉下悬崖导致单轮回报偶尔出现极低的负值约-100。这就是其“异策略”特性它学到了最优路径的价值但探索时并不完全遵循它。5.4 直观对比与理解将两张学习曲线图放在一起对比你能清晰地看到Sarsa回报曲线相对平滑稳步上升最终稳定在一个较高的值约-20。它学习慢但稳策略安全。Q-learning回报曲线波动剧烈时常出现大幅度的负回报掉下悬崖但最终学到的理论最优路径更短。它的平均回报在训练期可能低于Sarsa因为它要为探索付出代价。这对生物建模的启示如果你的模型旨在模拟一个风险厌恶型的生物体例如能量匮乏的动物在选择觅食路径时会极力避免高风险区域Sarsa的同策略学习可能更合适。如果你的目标是找到一个理论上的最优解例如在已知的蛋白质构象空间中寻找能量最低的折叠路径并且可以接受在探索过程中付出一些“代价”计算资源那么Q-learning可能更有效。此外Q-learning的异策略特性使其能够利用历史经验回放进行更高效的学习这在与深度学习结合时DQN至关重要。6. 进阶多步时序差分与算法选择基础的Sarsa和Q-learning是“一步”TD学习它们只往前看一步。一个自然的扩展是多步TD学习例如n步Sarsa。它折中了蒙特卡洛和一步TD的优点使用接下来n步的真实奖励加上第n步之后的估计值。其更新目标为G_{t:tn} R_{t1} γ R_{t2} ... γ^{n-1} R_{tn} γ^n Q(S_{tn}, A_{tn})当n1时就是Sarsa当n趋于无穷大直到回合结束时就是蒙特卡洛方法。多步学习通常能加速收敛因为它融入了更多实际奖励信息减少了估计的偏差。如何在Sarsa和Q-learning之间选择安全性优先如果交互成本高或危险大如机器人实际控制、临床实验设计应选择更保守的同策略方法如Sarsa或在Q-learning中使用非常小的探索率ε。数据效率与复用如果数据收集困难希望充分利用历史数据异策略方法如Q-learning是更好的选择因为它可以结合经验回放技术。与函数近似结合当状态空间巨大需要使用神经网络等函数近似时Q-learning及其变体DQN是目前的主流和成功范式。策略本身是目标如果你需要的是一个稳健的、考虑探索风险的策略用Sarsa。如果你只关心找到最优策略不介意探索策略用Q-learning。7. 常见问题与调试指南在实现和运行上述代码时你可能会遇到以下问题问题现象可能原因排查方式解决方案回报不收敛始终很低约-100学习率α太高或太低折扣因子γ设置不合理探索率ε太高导致无法有效利用经验。观察学习曲线是否完全无上升趋势。检查超参数设置。调整α到0.01-0.5之间常见范围。确保γ小于1如0.9。尝试降低ε如从0.1到0.01。策略看起来是随机的训练轮数不足学习率太小。增加训练episode数量如到2000。观察Q-table的值是否仍然接近零。增加num_episodes。适当增大α。Q-learning比Sarsa更容易掉下悬崖这是预期行为。Q-learning的探索策略ε-greedy会在最优路径附近探索导致掉崖。比较两者的最终策略图。Q-learning应学到更短但更危险的路径。如果想减少训练中的掉崖可以设置一个衰减的ε随着训练进行逐渐减小探索。代码报错‘CliffWalkingEnv’ object has no attribute ‘step’环境类中的方法名拼写错误或未正确定义。检查CliffWalkingEnv类中step和reset方法的定义。确保方法名拼写正确且参数列表包含self和action。进度条不显示或报错未安装tqdm库或在某些环境中兼容性问题。尝试注释掉tqdm相关代码用简单循环代替。安装tqdm (pip install tqdm)或移除进度条相关代码。8. 最佳实践与深入学习的建议超参数调优强化学习对超参数α, γ, ε敏感。建议使用网格搜索或随机搜索来寻找适合你特定问题的参数。ε通常可以随时间衰减。从表格型到函数近似本文的Q_table只适用于离散、状态空间小的问题。对于绝大多数生物信息学问题如序列空间、连续特征你需要用函数如神经网络来近似Q函数这就是深度Q网络的基础。结合领域知识在生物问题中奖励函数的设计至关重要。它是对“好”行为的数学量化。例如在蛋白质设计中奖励可以是结合亲和力、稳定性得分等。设计一个好的奖励函数本身就是一项重要研究。从仿真到现实在计算生物学中我们通常在仿真环境如分子动力学模拟、生态模型中训练智能体。务必注意仿真与现实的差距。在仿真中学到的策略在应用到真实世界前需要谨慎验证。理解收敛性理论上在满足一定条件下如所有状态-动作对被无限次访问学习率适当衰减Sarsa和Q-learning都能收敛到最优Q值。但在实际应用中由于函数近似和有限采样收敛并不总是保证。9. 总结迈向更复杂的强化学习世界通过本文你已经掌握了无模型强化学习的核心思想与两大经典算法蒙特卡洛方法回合更新和时序差分学习单步更新并重点实现了TD学习中的Sarsa和Q-learning。理解它们之间同策略与异策略的区别是通往现代深度强化学习如DQN、DDPG、PPO的必经之路。对于生物背景的研究者你可以将状态S定义为一种实验条件或分子构象动作A定义为一次实验操作或一次分子修饰奖励R定义为实验结果的好坏如细胞活性、荧光强度。强化学习框架为你提供了一套系统的方法来自动化地寻找最优的“实验协议”或“分子设计”。下一步你可以尝试修改环境将悬崖漫步的网格改成你自己的问题模型。实现多步TD算法如n-step Sarsa观察其收敛速度的变化。引入神经网络当状态空间变大时用一个小型神经网络替换Q_table实现一个最简单的DQN。阅读经典论文如Mnih等人的《Playing Atari with Deep Reinforcement Learning》看看Q-learning是如何与深度学习结合并取得突破性成果的。强化学习不是一个黑箱它是一套关于“试错、评估、优化”的形式化数学框架。希望本文能帮你拆解掉最初的理解障碍让你有能力将这套强大的工具应用于你所在的生物学研究领域去探索那些高维、复杂的序列空间、结构空间或实验设计空间。