当前位置: 首页 > news >正文

别再死磕理论了!用Python手搓一个蒙特卡洛强化学习小游戏(附完整代码)

用Python实战蒙特卡洛强化学习:从零构建Grid World游戏

在咖啡厅里,我盯着笔记本屏幕上密密麻麻的强化学习公式发呆。贝尔曼方程、价值迭代、策略评估...这些概念在论文里看起来很美,但当我试图用代码实现时,却总感觉少了点什么。直到有一天,我决定抛开理论,直接用Python构建一个简单的网格世界环境,并实现蒙特卡洛强化学习算法——那一刻,所有抽象的概念突然变得清晰可见。

1. 环境搭建:创建你的第一个Grid World

我们先从构建游戏环境开始。Grid World是强化学习的经典沙盒,一个智能体在网格中移动,寻找目标位置同时避开障碍物。

import numpy as np import pygame import time class GridWorld: def __init__(self, size=5): 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网格边长5
cell_sizeint像素绘制尺寸80
obstacleslist障碍物坐标列表[[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, epsilon=0.1, gamma=0.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

算法关键点解析

  1. ε-greedy策略

    • 以1-ε概率选择当前最优动作
    • 以ε概率随机探索其他动作
    • 平衡探索(exploration)与利用(exploitation)
  2. 首次访问型MC

    • 只考虑状态-动作对的第一次出现
    • 计算从该点开始的累计回报
    • 相比每次访问型方差更小
  3. 策略改进

    • 基于新的Q值更新策略
    • 总是选择当前估计价值最高的动作
    • 保留ε概率的随机探索

注意:折扣因子γ控制未来奖励的重要性,通常设置在0.9-0.99之间。γ越小,智能体越注重即时奖励。

4. 训练流程与效果展示

最后,我们整合训练流程并观察学习效果:

def train_agent(episodes=1000, render_every=100): 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(f"Episode {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(maxlen=1000) # 存储最近的1000个transition
  • 并行采样:同时运行多个环境实例加速数据收集

在实现这个项目时,最让我惊讶的是看到智能体从完全随机行为逐渐发展出有目的性的策略。大约在300次episode后,它已经能稳定找到避开障碍物的路径。不过我也发现,如果ε值降得太快,智能体可能会陷入局部最优——这提醒我们探索与利用平衡的重要性。

http://www.jsqmd.com/news/886705/

相关文章:

  • pan-baidu-download:百度网盘多线程下载加速器架构解析与性能优化指南
  • 【绝密PEST压力测试报告】:Claude 3.5在金融/医疗/政务三大敏感领域的17项穿透式评估结果(仅剩最后87份)
  • 边缘AI落地总失败?DeepSeek架构的4层容错机制,92%故障在毫秒级自愈
  • DeepSeek多卡训练通信开销超62%?紧急发布:NCCL拓扑感知AllReduce重排+梯度压缩阈值动态调优指南
  • Neon Glowing效果失效全解析,深度解读--v 6.2下--style raw与--no ambient_light的冲突机制及绕过方案
  • 面试必问:Temperature=0为何仍不确定?真相揭秘
  • 博弈论导向的车辆队列运动协同分层控制算法【附算法】
  • 幽灵请求与内存泄漏:一次全栈高并发下的性能惊魂复盘
  • 【2026收藏版】小白程序员必学的20个核心AI大模型基础概念(通俗易懂无废话)
  • Hugging Face 中tokenizer.json 和vocab.json 有区别?
  • 冰雪重制版手游官网下载:冰雪重制版最新官方下载渠道
  • 如何为Nintendo Switch安装游戏?Awoo Installer的3种安装方式全解析
  • 【Lovable电商网站搭建黄金标准】:基于137个真实项目数据验证的6项LCP/CLS/INP硬性阈值
  • 2026年数字化转型真相:为何空有大模型却带不动老系统?
  • 三维视图查看器项目(QT/C++)
  • Python中构造函数init与类的实例化
  • 收藏2026版|后端行业遇冷已成定局?程序员该扎根Java还是全力冲刺大模型
  • vectorizer图像矢量化工具:3步实现PNG/JPG到SVG的智能转换
  • 为什么你的粒子效果永远“糊”?Midjourney底层采样器对粒子密度的隐式限制(附GPU显存占用热力图)
  • 用Python+OpenCV+MediaPipe做个手势识别小游戏:从摄像头捕捉到虚拟控制
  • 高性能B站m4s格式转换:跨平台兼容的零质量损失技术方案
  • Java反射:从运行时窥探到动态代理的工程实践
  • 从零开始在个人项目中接入Taotoken API的完整记录
  • 2026年义乌餐饮收银服务商专业评估与场景化选型指南 - 万事通达
  • 孤舟笔记 互联网常用框架篇二 Dubbo服务请求失败怎么处理?集群容错策略你用过几种
  • Docker 安装RocktMQ 和管理平台
  • 企业AI编程部署方案:2026最新权威8款AI编程工具必看清单
  • taotoken多模型广场如何在ubuntu开发中辅助模型选型
  • 冒泡排序:经典算法入门指南
  • Windows文件夹共享