从OpenAI Gym的CliffWalking实战出发:手把手教你用Python代码区分Model-based与Model-free算法 从CliffWalking实战看强化学习Model-based与Model-free算法代码对比在强化学习领域Model-based和Model-free是两种截然不同的技术路径。很多初学者在理解这两种方法时容易陷入理论迷雾而实际上最好的学习方式莫过于亲手实现它们。本文将带您使用Python和OpenAI Gym的CliffWalking环境通过可运行的代码实例直观感受两种方法的差异。1. 环境准备与问题定义CliffWalking-v0是OpenAI Gym中一个经典的网格世界环境它模拟了一个4x12的网格其中底部一行除起点和终点外是悬崖。智能体需要从起点左下角安全移动到终点右下角每走一步获得-1的奖励掉下悬崖获得-100奖励并回到起点。首先安装必要的库pip install gym numpy matplotlib然后初始化环境import gym import numpy as np import matplotlib.pyplot as plt env gym.make(CliffWalking-v0) print(动作空间:, env.action_space) print(状态空间:, env.observation_space)CliffWalking环境有4个动作上、右、下、左和48个状态4x12网格。与原始文章提到的不同这里的状态转移是确定的——执行一个动作必然会到达预期状态除非碰到边界。2. Model-based方法实现动态规划Model-based方法的核心是构建环境模型即状态转移概率T和奖励函数R。在CliffWalking中我们可以利用环境的确定性特性简化实现。2.1 构建环境模型def build_model(env): nS env.observation_space.n nA env.action_space.n T np.zeros((nS, nA, nS)) # 转移概率 R np.zeros((nS, nA, nS)) # 即时奖励 for s in range(nS): for a in range(nA): env.env.s s # 设置当前状态 next_s, r, done, _ env.step(a) T[s, a, next_s] 1.0 R[s, a, next_s] r env.reset() # 重置环境 return T, R T, R build_model(env)这个模型准确记录了每个状态-动作对的下一个状态和对应奖励。有了完整模型后我们可以使用策略迭代算法求解最优策略。2.2 策略迭代算法def policy_iteration(env, T, R, gamma0.9, max_iter1000): nS env.observation_space.n nA env.action_space.n # 初始化随机策略和价值函数 policy np.ones((nS, nA)) / nA V np.zeros(nS) for _ in range(max_iter): # 策略评估 while True: delta 0 for s in range(nS): v V[s] V[s] sum([policy[s, a] * sum([T[s, a, s1] * (R[s, a, s1] gamma * V[s1]) for s1 in range(nS)]) for a in range(nA)]) delta max(delta, abs(v - V[s])) if delta 1e-4: break # 策略改进 policy_stable True for s in range(nS): old_action np.argmax(policy[s]) q_values [sum([T[s, a, s1] * (R[s, a, s1] gamma * V[s1]) for s1 in range(nS)]) for a in range(nA)] best_action np.argmax(q_values) policy[s] np.eye(nA)[best_action] if old_action ! best_action: policy_stable False if policy_stable: break return policy, V policy, V policy_iteration(env, T, R)2.3 可视化结果def plot_policy(policy): policy_grid np.argmax(policy, axis1).reshape(4, 12) plt.figure(figsize(12, 4)) plt.imshow(policy_grid, cmapcool) for i in range(4): for j in range(12): action policy_grid[i, j] arrow [↑, →, ↓, ←][action] plt.text(j, i, arrow, hacenter, vacenter) plt.title(Model-based策略) plt.axis(off) plt.show() plot_policy(policy)Model-based方法找到了沿悬崖边缘的安全路径这与人类直觉一致。它需要存储整个环境模型T和R矩阵在状态空间较大时会占用较多内存。3. Model-free方法实现Q-LearningModel-free方法不构建环境模型而是直接学习状态-动作值函数Q(s,a)。Q-Learning是一种经典的Model-free算法。3.1 Q-Learning实现def q_learning(env, episodes1000, alpha0.1, gamma0.9, epsilon0.1): nS env.observation_space.n nA env.action_space.n Q np.zeros((nS, nA)) for _ in range(episodes): s env.reset() done False while not done: # ε-贪婪策略选择动作 if np.random.random() epsilon: a env.action_space.sample() else: a np.argmax(Q[s]) # 执行动作 next_s, r, done, _ env.step(a) # Q值更新 Q[s, a] Q[s, a] alpha * (r gamma * np.max(Q[next_s]) - Q[s, a]) s next_s return Q Q q_learning(env)3.2 从Q值提取策略def q_to_policy(Q): policy np.zeros_like(Q) policy[np.arange(len(Q)), np.argmax(Q, axis1)] 1 return policy policy_q q_to_policy(Q) plot_policy(policy_q)Q-Learning同样找到了安全路径但训练过程中需要大量探索。它只存储Q表格内存效率更高但需要更多训练样本。4. 两种方法对比分析4.1 代码结构差异特性Model-basedModel-free (Q-Learning)环境知识依赖需要构建完整模型仅需与环境交互存储需求存储T和R矩阵 (O(nS²nA))存储Q表格 (O(nSnA))训练数据效率数据效率高需要更多样本适用场景状态空间小、模型易构建的环境状态空间大或模型复杂的环境4.2 性能对比我们在相同环境下运行两种方法比较它们的表现def evaluate_policy(env, policy, episodes100): total_rewards 0 for _ in range(episodes): s env.reset() done False episode_reward 0 while not done: a np.argmax(policy[s]) s, r, done, _ env.step(a) episode_reward r total_rewards episode_reward return total_rewards / episodes mb_score evaluate_policy(env, policy) mf_score evaluate_policy(env, policy_q) print(fModel-based平均得分: {mb_score:.1f}) print(fModel-free平均得分: {mf_score:.1f})4.3 实际应用选择建议选择Model-based当环境模型容易构建且状态空间不大需要高样本效率如真实机器人训练需要预测环境行为如安全关键应用选择Model-free当环境复杂难以建模状态空间非常大可以承受大量试错如游戏AI5. 高级技巧与优化5.1 Model-based的模型不确定性处理在实际环境中状态转移往往不是完全确定的。我们可以修改模型构建部分来处理不确定性def build_probabilistic_model(env, samples100): nS env.observation_space.n nA env.action_space.n T_counts np.zeros((nS, nA, nS)) R_sum np.zeros((nS, nA, nS)) for s in range(nS): for a in range(nA): for _ in range(samples): env.env.s s next_s, r, done, _ env.step(a) T_counts[s, a, next_s] 1 R_sum[s, a, next_s] r env.reset() # 归一化转移概率 T T_counts / T_counts.sum(axis2, keepdimsTrue) # 计算平均奖励 R np.divide(R_sum, T_counts, whereT_counts!0) return T, R5.2 Model-free的探索优化Q-Learning的性能很大程度上取决于探索策略。我们可以实现更智能的探索方法def decaying_epsilon_q_learning(env, episodes1000, initial_epsilon1.0, final_epsilon0.01, alpha0.1, gamma0.9): nS env.observation_space.n nA env.action_space.n Q np.zeros((nS, nA)) epsilon initial_epsilon decay (initial_epsilon - final_epsilon) / episodes for episode in range(episodes): s env.reset() done False while not done: if np.random.random() epsilon: a env.action_space.sample() else: a np.argmax(Q[s]) next_s, r, done, _ env.step(a) # Q值更新 Q[s, a] alpha * (r gamma * np.max(Q[next_s]) - Q[s, a]) s next_s # 线性衰减ε epsilon max(final_epsilon, epsilon - decay) return Q6. 扩展思考从CliffWalking到现实问题虽然CliffWalking是一个简化环境但它很好地展示了强化学习的关键概念。在实际项目中状态表示真实问题往往需要设计合适的状态表示可能涉及特征工程或神经网络奖励设计奖励函数的设计直接影响智能体行为需要谨慎设计超参数调优学习率、折扣因子等参数需要根据具体问题调整评估指标除了累计奖励还需考虑安全性、稳定性等指标# 示例使用神经网络近似Q函数 import torch import torch.nn as nn class QNetwork(nn.Module): def __init__(self, input_dim, output_dim): super().__init__() self.fc nn.Sequential( nn.Linear(input_dim, 64), nn.ReLU(), nn.Linear(64, 64), nn.ReLU(), nn.Linear(64, output_dim) ) def forward(self, x): return self.fc(x)在实际项目中Model-free方法常与深度结合如DQN而Model-based方法则可用于规划或与Model-free方法结合如Dyna-Q。