别再死磕理论了!用Python手搓一个蒙特卡洛强化学习小游戏(附完整代码) 用Python实战蒙特卡洛强化学习从零构建Grid World游戏在咖啡厅里我盯着笔记本屏幕上密密麻麻的强化学习公式发呆。贝尔曼方程、价值迭代、策略评估...这些概念在论文里看起来很美但当我试图用代码实现时却总感觉少了点什么。直到有一天我决定抛开理论直接用Python构建一个简单的网格世界环境并实现蒙特卡洛强化学习算法——那一刻所有抽象的概念突然变得清晰可见。1. 环境搭建创建你的第一个Grid World我们先从构建游戏环境开始。Grid World是强化学习的经典沙盒一个智能体在网格中移动寻找目标位置同时避开障碍物。import numpy as np import pygame import time class GridWorld: def __init__(self, size5): self.size size self.grid np.zeros((size, size)) self.agent_pos [0, 0] self.goal_pos [size-1, size-1] self.obstacles [[1, 1], [2, 3], [3, 1]] # 障碍物位置 self.actions [up, down, left, right] # 初始化Pygame pygame.init() self.cell_size 80 self.screen pygame.display.set_mode( (size * self.cell_size, size * self.cell_size)) pygame.display.set_caption(Grid World - 蒙特卡洛强化学习)这个基础环境包含5x5的网格世界智能体起始位置(0,0)目标位置(4,4)三个固定障碍物四种基本移动动作关键参数说明参数类型描述默认值sizeint网格边长5cell_sizeint像素绘制尺寸80obstacleslist障碍物坐标列表[[1,1],[2,3],[3,1]]提示可以通过调整size参数轻松扩展网格尺寸但要注意计算复杂度会呈平方增长2. 游戏逻辑与可视化实现接下来我们添加环境的核心逻辑和可视化部分def reset(self): 重置环境到初始状态 self.agent_pos [0, 0] return self.agent_pos.copy() def step(self, action): 执行动作并返回(next_state, reward, done) x, y self.agent_pos # 动作执行 if action up and x 0: x - 1 elif action down and x self.size - 1: x 1 elif action left and y 0: y - 1 elif action right and y self.size - 1: y 1 # 碰撞检测 new_pos [x, y] if new_pos in self.obstacles: reward -5 # 碰到障碍物惩罚 done False elif new_pos self.goal_pos: reward 10 # 到达目标奖励 done True else: reward -1 # 每步小惩罚鼓励快速到达 done False self.agent_pos new_pos return new_pos.copy(), reward, done def render(self): 可视化当前状态 self.screen.fill((255, 255, 255)) # 绘制网格线 for i in range(self.size 1): pygame.draw.line(self.screen, (200, 200, 200), (0, i * self.cell_size), (self.size * self.cell_size, i * self.cell_size)) pygame.draw.line(self.screen, (200, 200, 200), (i * self.cell_size, 0), (i * self.cell_size, self.size * self.cell_size)) # 绘制障碍物 for obs in self.obstacles: pygame.draw.rect(self.screen, (139, 69, 19), (obs[1] * self.cell_size, obs[0] * self.cell_size, self.cell_size, self.cell_size)) # 绘制目标 pygame.draw.circle(self.screen, (0, 255, 0), (int((self.goal_pos[1] 0.5) * self.cell_size), int((self.goal_pos[0] 0.5) * self.cell_size)), int(self.cell_size * 0.3)) # 绘制智能体 pygame.draw.circle(self.screen, (255, 0, 0), (int((self.agent_pos[1] 0.5) * self.cell_size), int((self.agent_pos[0] 0.5) * self.cell_size)), int(self.cell_size * 0.2)) pygame.display.flip()这个实现有几个值得注意的设计选择奖励机制采用稀疏奖励设置只有到达目标和碰到障碍物时有显著奖励/惩罚步数惩罚每步小惩罚(-1)鼓励智能体尽快找到目标边界处理智能体不能移出网格边界可视化使用不同颜色区分环境元素3. 蒙特卡洛强化学习算法实现现在来到核心部分——蒙特卡洛强化学习算法的实现。我们将采用首次访问型MC预测结合ε-greedy策略改进。class MonteCarloAgent: def __init__(self, actions, epsilon0.1, gamma0.9): self.actions actions self.epsilon epsilon # 探索概率 self.gamma gamma # 折扣因子 self.Q {} # 动作价值函数 self.returns {} # 累计回报 self.policy {} # 当前策略 def get_action(self, state): 基于当前策略选择动作 state_key tuple(state) if state_key not in self.policy: # 新状态初始化为随机策略 self.policy[state_key] np.random.choice(self.actions) # ε-greedy策略 if np.random.random() self.epsilon: return np.random.choice(self.actions) else: return self.policy[state_key] def update_policy(self, episode): 基于完整episode更新策略 states, actions, rewards zip(*episode) G 0 # 累计回报 # 反向遍历episode for t in range(len(episode)-1, -1, -1): state, action, _ episode[t] G self.gamma * G rewards[t] state_action (tuple(state), action) # 首次访问型MC if state_action not in [(tuple(episode[i][0]), episode[i][1]) for i in range(t)]: if state_action not in self.returns: self.returns[state_action] [] self.returns[state_action].append(G) self.Q[state_action] np.mean(self.returns[state_action]) # 更新策略为当前最优动作 state_key tuple(state) max_q -float(inf) for a in self.actions: if (state_key, a) in self.Q and self.Q[(state_key, a)] max_q: max_q self.Q[(state_key, a)] best_action a self.policy[state_key] best_action算法关键点解析ε-greedy策略以1-ε概率选择当前最优动作以ε概率随机探索其他动作平衡探索(exploration)与利用(exploitation)首次访问型MC只考虑状态-动作对的第一次出现计算从该点开始的累计回报相比每次访问型方差更小策略改进基于新的Q值更新策略总是选择当前估计价值最高的动作保留ε概率的随机探索注意折扣因子γ控制未来奖励的重要性通常设置在0.9-0.99之间。γ越小智能体越注重即时奖励。4. 训练流程与效果展示最后我们整合训练流程并观察学习效果def train_agent(episodes1000, render_every100): env GridWorld() agent MonteCarloAgent(env.actions) for episode in range(episodes): state env.reset() done False episode_history [] # 生成episode while not done: action agent.get_action(state) next_state, reward, done env.step(action) episode_history.append((state, action, reward)) state next_state # 定期渲染 if episode % render_every 0: env.render() time.sleep(0.1) # 策略更新 agent.update_policy(episode_history) # 打印进度 if episode % 100 0: print(fEpisode {episode}, Steps: {len(episode_history)}) return agent # 启动训练 trained_agent train_agent()训练过程典型输出Episode 0, Steps: 50 Episode 100, Steps: 28 Episode 200, Steps: 12 Episode 300, Steps: 8 Episode 400, Steps: 8 ... Episode 900, Steps: 6可以看到随着训练进行智能体找到目标的步数明显减少。在可视化窗口中你能观察到智能体从最初的随机游走到最终学会避开障碍物、直奔目标的有趣过程。性能优化技巧动态ε调整随着训练进行逐渐减小ε值agent.epsilon max(0.01, 0.1 * (1 - episode/episodes))经验回放存储历史episode片段重复利用from collections import deque memory deque(maxlen1000) # 存储最近的1000个transition并行采样同时运行多个环境实例加速数据收集在实现这个项目时最让我惊讶的是看到智能体从完全随机行为逐渐发展出有目的性的策略。大约在300次episode后它已经能稳定找到避开障碍物的路径。不过我也发现如果ε值降得太快智能体可能会陷入局部最优——这提醒我们探索与利用平衡的重要性。