尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从零用进化策略训练游戏AI:以超级马里奥为例的Python实现

从零用进化策略训练游戏AI:以超级马里奥为例的Python实现 为什么一个“AI玩马里奥”的视频能吸引几百万播放很多人的第一反应是游戏画面有趣或者解说幽默。但真正值得技术人关注的是这类视频背后那个非常通用的问题如何让一个对游戏一无所知的模型从零开始学会在一个实时交互环境中做出正确决策。Code Bullet 的“AI 学习玩马力欧”系列恰好把这个问题压缩成了一个可以观察的完整闭环。很多人看完视频觉得“AI 好厉害”其实这里面的核心方法并不神秘也不依赖动辄几千张显卡的大规模训练。它真正展示的是用进化策略 一个很简单的神经网络就能让 AI 从“原地乱跳”慢慢进化到“懂得避开敌人、踩上砖头往前走”。这篇文章不会停留在“看视频喊厉害”的层面而是把这类项目拆开讲清楚它用了什么算法为什么这样做能学出来以及你自己在本地怎么用 Python 搭一个简化版。即使你没看过原视频也不影响阅读如果你正打算做游戏 AI、强化学习入门或者只是好奇“AI 怎么学会玩游戏的”这篇文章可以帮你省掉大量试错时间。1. 这类项目真正值得学习的地方先给一个判断Code Bullet 的价值不在于做出了一个多么无敌的游戏 AI而在于他用最小成本证明了“进化策略 简单神经网络”可以解决实时动作游戏的策略学习问题。很多人容易把这类项目和 AlphaGo 混为一谈。AlphaGo 用的是深度强化学习、蒙特卡洛树搜索、海量自我对弈工程复杂度非常高而 Code Bullet 做马里奥用的是一种更朴素的方式——遗传算法/进化策略。它没有复杂的梯度反传没有大规模分布式训练甚至不需要一个可微分的环境核心就是“生成一堆候选策略 → 让它们玩游戏 → 留下表现好的 → 让它们变异产生下一代”。这带来的启发是如果你只是想让 AI 学会玩某个游戏、控制某个仿真环境、优化某个不太好建模的黑盒问题进化策略往往比强化学习更容易落地。它实现简单对奖励函数的噪声容忍度高也不容易陷入“梯度消失”或“奖励稀疏导致完全学不动”的困境。当然它也有明显局限进化策略不擅长利用海量时序数据做精细决策训练到后期往往不如 PPO 这类强化学习算法精细。所以本文的定位不是“哪种算法更强”而是帮你理解“这一类 AI 学习视频背后到底发生了什么”。对 CSDN 读者来说最实际的收益有三点理解 AI 玩游戏的技术框架包括状态、动作、奖励、策略网络这几个核心组件。掌握一种可以本地复现的简化实现代码不复杂普通电脑也能跑。学会判断“AI 学会了没有”而不是只看视频里的剪辑效果。2. Code Bullet 的做法与强化学习核心概念2.1 游戏 AI 的四个基本组成任何“AI 学会玩游戏”的项目都绕不开四个东西状态StateAI 每时每刻能看到什么。对马里奥来说就是当前的游戏画面以及马里奥的位置、速度、是否踩在地面上等信息。动作ActionAI 能做什么。马里奥的动作就是手柄上的按键组合左移、右移、跳跃、加速跑等。奖励Reward怎么判断“做得好不好”。马里奥每向右移动一定距离就给出正向奖励撞到敌人死亡或者超时则给出负向信号。策略PolicyAI 根据当前状态决定下一个动作的规则。在 Code Bullet 这类项目里策略就是一个神经网络输入屏幕像素输出动作。这四个概念是所有游戏 AI 的通用语言。理解它们之后再看任何 AI 玩游戏的视频你都能快速拆解出“它到底在学什么”。2.2 进化策略的核心思路Code Bullet 的马里奥 AI本质上采用了一种非常直观的优化思路初始化一个由若干个体组成的种群每个个体携带一组随机的神经网络参数。让每个个体分别玩一局游戏记录它取得的分数累计奖励。删除表现差的个体保留表现好的个体。让保留的个体互相“繁殖”即对它们的参数进行交叉和变异得到下一代种群。重复上述过程直到 AI 能顺利通关或达到预期表现。这里的“变异”通常是在参数上加一点高斯噪声让下一代在优秀参数附近小幅探索。这个思路和生物进化非常相似没有哪个个体知道“跳跃”这个动作的意义但那些“碰巧在合适位置按下跳跃键”的个体获得了更高奖励因此它们的参数被保留下来并在后代中得到放大。用代码表达进化策略的训练循环大概是这样的for generation in range(total_generations): # 1. 评估当前种群 fitness [evaluate(individual) for individual in population] # 2. 按表现排序选前 K 个 sorted_idx np.argsort(fitness)[::-1] elites [population[i] for i in sorted_idx[:elite_num]] # 3. 生成下一代精英保留 变异 new_population elites.copy() while len(new_population) population_size: parent random.choice(elites) child mutate(parent) new_population.append(child) population new_population这个流程最迷人的地方在于它完全不需要知道游戏规则也不需要梯度信息。只要你能让 AI 玩一局游戏并返回一个分数就能启动优化。2.3 进化策略和强化学习的区别很多人会把进化策略和强化学习混在一起这里做一个简单对比对比项进化策略强化学习如 PPO核心思想种群竞争、变异择优智能体与环境交互通过奖励反馈更新策略是否需要梯度不需要需要实现复杂度低代码量小较高需要经验回放、策略更新等机制对奖励噪声的容忍度较高一般样本效率低需要大量环境交互相对较高适合场景黑盒优化、奖励稀疏、环境难以建模复杂策略、长时间序列决策Code Bullet 选择进化策略一个重要原因就是实现门槛低、调试直观。你不需要搭建复杂的训练框架用一个普通 Python 脚本就能跑起来。对于很多独立开发者来说这是非常友好的入门路径。2.4 为什么马里奥是很好的测试环境超级马里奥是一个非常适合 AI 学习的测试环境它需要精确的时序控制起跳早了会撞到敌人跳晚了会掉进坑里AI 必须学会“什么时候按跳”这个节奏。它的状态空间复杂但不极端画面是二维像素理解起来比 3D 游戏简单但足够表达“识别障碍物、规划跳跃时机”等能力。它的奖励信号天然存在向右移动就有奖励死了就结束很容易定义。正因为如此超级马里奥成了游戏 AI 领域的“Hello World”。从学术界到独立开发者大量研究都在这个环境上用强化学习、进化策略、模仿学习等方式验证算法效果。3. 环境准备与依赖安装如果你想本地复现一个简化版“AI 学玩马里奥”建议先搭好环境。以下环境信息以目前社区常用的开源方案为例版本号请以实际安装结果为准本文重点演示通用思路。3.1 推荐环境操作系统Windows 10/11、Ubuntu 20.04 或 macOS 均可Python 版本3.8 及以上主要依赖gym、gym-super-mario-bros、nes-py、numpy、torch可选如果只用多项式策略也可以不用硬件要求普通 CPU 即可运行不需要独立显卡用 GPU 可以加速但并非必需gym-super-mario-bros是 OpenAI Gym 生态中专门用于马里奥游戏的环境包它封装了 NES 模拟器提供了标准化的强化学习接口。Code Bullet 原版视频更多是自己编写的模拟器交互脚本但从工程复现的角度看使用这个开源环境更简单、更稳定。3.2 安装步骤首先创建一个干净的 Python 虚拟环境避免依赖冲突python -m venv mario_ai_env # Windows 激活 mario_ai_env\Scripts\activate # Linux / macOS 激活 source mario_ai_env/bin/activate然后安装依赖pip install gym-super-mario-bros pip install nes-py pip install numpy pip install torch --index-url https://download.pytorch.org/whl/cpu如果只需要 CPU 环境建议安装 CPU 版 PyTorch体积更小。如果你不想引入 PyTorch也可以直接用 NumPy 实现一个简单策略网络后面的示例会提到这种替代方案。3.3 验证安装在 Python 中执行以下代码确认环境能正常创建import gym import gym_super_mario_bros from gym_super_mario_bros.actions import SIMPLE_MOVEMENT env gym.make(SuperMarioBros-1-1-v0, render_modergb_array, apply_api_compatibilityTrue) print(动作空间, env.action_space) print(观测空间, env.observation_space) # 重置环境 state, info env.reset() print(初始状态形状, state.shape) env.close()如果能看到动作空间和观测空间的输出说明环境安装成功。这里需要注意的是gym和gym-super-mario-bros的版本兼容性偶尔会出问题遇到报错时优先检查 gym 版本。4. 核心流程拆解4.1 数据流AI 看什么、做什么在强化学习和进化策略项目中运行一局游戏的循环是固定的环境输出画面 → AI 根据画面生成动作 → 环境执行动作 → 返回新画面和奖励 → 循环用代码表达就是state, info env.reset() done False total_reward 0 while not done: action policy.predict(state) # AI 决策 next_state, reward, terminated, truncated, info env.step(action) total_reward reward state next_state done terminated or truncated这个循环是整个项目的灵魂。无论后面的算法多复杂最终都是在调整policy.predict这一步的参数让 total_reward 越来越大。4.2 状态预处理把原始画面变成 AI 能理解的数据原始 NES 游戏画面分辨率不高但直接作为神经网络输入仍然有两个问题一是数据量偏大二是画面包含大量无关信息比如背景云朵、计分板。常用的做法是灰度化把彩色画面转成灰度图减少通道数量。缩放把画面缩放到更小的尺寸比如 84x84减少参数数量。帧堆叠把最近的几帧堆叠在一起作为状态让 AI 感知运动方向和速度。因为单张图片看不出马里奥是向左跑还是向右跑而连续几帧能表达运动趋势。这些预处理步骤看起来简单但对训练效果影响非常大。Code Bullet 视频中之所以能较快看到 AI 学会移动很大一部分原因是状态表示足够简洁让神经网络把有限的容量集中在了“马里奥的位置、障碍物的位置”这些关键信息上。4.3 奖励塑形告诉 AI 什么重要马里奥环境自带的奖励信号主要是“向右移动的距离”。这个设定非常巧妙AI 不需要理解“过关”“躲避敌人”这些高维概念只需要知道“向右走是好的停在原地是不好的”就能通过简单策略获得正向反馈。不过在本地复现时你可能还需要额外处理超时奖励。如果 AI 在某一关卡停留太长时间即使没有死亡也应该给一个负向奖励或直接结束本局否则 AI 可能学会“原地站着不动”这种零奖励的消极策略。奖励塑形是游戏 AI 项目中最容易低估的部分。很多人在训练中遇到“AI 一直不学习”的问题八成不是神经网络有问题而是奖励信号设计得不够清晰。马里奥环境默认已经解决了这个问题这也是我推荐新手从这里入手的原因。4.4 策略网络用最简单的结构表达决策Code Bullet 原版视频中的神经网络结构并不复杂完全可以理解成一个“像素输入 → 简单神经网络 → 动作输出”的映射。用 PyTorch 实现时一个两到三层的全连接网络就足够处理 84x84 的输入了。更关键的一点是如果你的输入状态是 84x84x4四帧堆叠直接展平成 28224 维向量可能对 CPU 训练有些压力。实际项目中可以先用更小的分辨率比如 42x42或者只在训练刚开始时使用单帧输入跑通流程后再逐步增加复杂度。4.5 进化策略的训练主循环这是整个项目的核心。为了便于理解我给出一版完整的简化实现思路你可以在本地运行后观察 AI 的表现逐渐变化。5. 完整示例代码实现下面提供一个可以在本地运行的简化版本。由于完整训练需要的时间较长这里用一个小分辨率和较小的种群规模演示流程实际训练时你可以逐步加大。5.1 文件一mario_env.py —— 环境与预处理# 文件路径mario_env.py import gym import gym_super_mario_bros from gym_super_mario_bros.actions import SIMPLE_MOVEMENT from gym.wrappers import GrayScaleObservation, ResizeObservation, FrameStack def create_mario_env() - gym.Env: 创建马里奥环境并做基础预处理。 env gym.make( SuperMarioBros-1-1-v0, render_modergb_array, apply_api_compatibilityTrue, ) # 使用简洁动作集共 7 个动作 env gym.wrappers.ActionWrapper(env, SIMPLE_MOVEMENT) # 灰度化、缩放、帧堆叠 env GrayScaleObservation(env, keep_dimFalse) env ResizeObservation(env, (42, 42)) env FrameStack(env, 4) return env这段代码的核心是GrayScaleObservation和FrameStack。灰度化把彩色画面转成单通道缩放把分辨率降到 42x42帧堆叠让 AI 看到最近四帧的运动信息。SIMPLE_MOVEMENT包含以下动作什么都不做、向右走、向右跳、向右跑、向右跑跳、原地跳、向左走。需要注意的是不同版本的gym对ActionWrapper的用法略有差异。如果运行时报错可以直接使用环境返回的原始 Discrete 动作空间然后在后续代码中做一个动作映射。5.2 文件二policy.py —— 策略网络与参数管理这里给出两个版本一个是 PyTorch 版本一个是 NumPy 版本。PyTorch 版本更接近真实项目NumPy 版本不依赖深度学习框架更容易理解参数是怎么变异的。# 文件路径policy.py import numpy as np class SimplePolicy: 基于 NumPy 的简单策略网络。 输入展开后的像素状态向量 输出每个动作的分数取分数最大的动作作为决策 def __init__(self, input_dim: int, hidden_dim: int 64, n_actions: int 7): # 两层全连接网络input_dim - hidden_dim - n_actions self.w1 np.random.randn(input_dim, hidden_dim) * 0.01 self.b1 np.zeros(hidden_dim) self.w2 np.random.randn(hidden_dim, n_actions) * 0.01 self.b2 np.zeros(n_actions) def predict(self, state: np.ndarray) - int: 根据状态输出动作。 x state.flatten() h np.maximum(0, x self.w1 self.b1) # ReLU logits h self.w2 self.b2 return int(np.argmax(logits)) def get_params(self) - list: 返回所有参数用于变异。 return [self.w1, self.b1, self.w2, self.b2] def set_params(self, params: list) - None: 设置参数用于把变异后的参数写回策略。 self.w1, self.b1, self.w2, self.b2 params def mutate_params(params: list, noise_scale: float 0.05) - list: 对参数做高斯变异返回新参数。 new_params [] for p in params: noise np.random.randn(*p.shape) * noise_scale new_params.append(p noise) return new_params def crossover_params(params_a: list, params_b: list) - list: 简单交叉每个参数按 50% 概率来自父本或母本。 child [] for p_a, p_b in zip(params_a, params_b): mask np.random.rand(*p_a.shape) 0.5 child.append(np.where(mask, p_a, p_b)) return childSimplePolicy的predict方法就是一个核心的前向推理把像素展平经过一个隐藏层和一个输出层输出每个动作的分数。这个策略内部没有设定任何游戏规则它不知道跳跃是什么、敌人是什么只在训练中通过参数变异慢慢学会“什么样的输入对应什么样的动作”。5.3 文件三train.py —— 进化策略训练主循环# 文件路径train.py import numpy as np from mario_env import create_mario_env from policy import SimplePolicy, mutate_params, crossover_params POPULATION_SIZE 20 ELITE_NUM 4 GENERATIONS 100 MAX_STEPS 2000 NOISE_SCALE 0.05 def evaluate(env, policy, max_stepsMAX_STEPS): 让一个策略玩一局游戏返回累计奖励。 state, info env.reset() total_reward 0.0 done False steps 0 while not done and steps max_steps: action policy.predict(np.array(state)) next_state, reward, terminated, truncated, info env.step(action) total_reward reward state next_state done terminated or truncated steps 1 return total_reward def main(): env create_mario_env() state_shape env.observation_space.shape # 计算输入维度42 * 42 * 4 input_dim int(np.prod(state_shape)) print(f输入维度{input_dim}, 观测空间{state_shape}) # 初始化种群 population [] for _ in range(POPULATION_SIZE): policy SimplePolicy(input_diminput_dim) population.append(policy) for generation in range(GENERATIONS): # 1. 评估所有个体 fitness [] for policy in population: # 关闭渲染训练阶段不需要画面能明显加快速度 reward evaluate(env, policy) fitness.append(reward) # 2. 选择精英 sorted_idx np.argsort(fitness)[::-1] elites [population[i] for i in sorted_idx[:ELITE_NUM]] best_fitness fitness[sorted_idx[0]] print(fGeneration {generation}: best reward {best_fitness:.2f}) # 3. 生成下一代 new_population [SimplePolicy(input_diminput_dim) for _ in range(POPULATION_SIZE)] for i in range(ELITE_NUM): new_population[i] elites[i] # 精英直接保留 for i in range(ELITE_NUM, POPULATION_SIZE): # 从精英中随机选两个交叉 变异 parent_a elites[np.random.randint(ELITE_NUM)] parent_b elites[np.random.randint(ELITE_NUM)] child_params crossover_params( parent_a.get_params(), parent_b.get_params() ) child_params mutate_params(child_params, NOISE_SCALE) new_population[i].set_params(child_params) population new_population env.close() if __name__ __main__: main()这段代码完整实现了进化策略的训练流程每一代的流程是让当前种群里的每个个体分别玩一局游戏得到累计奖励。按奖励排序取前ELITE_NUM个作为精英。下一代由精英直接保留和“交叉 变异”产生的新个体组成。从打印结果可以看到随着迭代次数增加best reward 通常会逐渐上升。最开始时AI 可能一动不动就死在原地最佳奖励很低几十代之后它会慢慢学会向右移动、跳跃甚至能躲过一些敌人。5.4 文件四demo.py —— 让训练好的 AI 可视化玩游戏训练完成后你想看到 AI 的实际表现可以单独跑一个演示脚本。这里假设你已经把训练好的最优策略保存下来了建议在训练循环中把精英个体的参数保存成.npy文件。# 文件路径demo.py import numpy as np from mario_env import create_mario_env from policy import SimplePolicy def load_policy(input_dim: int, params_path: str) - SimplePolicy: 从 .npy 文件加载参数并生成策略。 policy SimplePolicy(input_diminput_dim) w1 np.load(f{params_path}_w1.npy) b1 np.load(f{params_path}_b1.npy) w2 np.load(f{params_path}_w2.npy) b2 np.load(f{params_path}_b2.npy) policy.set_params([w1, b1, w2, b2]) return policy def main(): env create_mario_env() state_shape env.observation_space.shape input_dim int(np.prod(state_shape)) policy load_policy(input_dim, best_policy) state, info env.reset() total_reward 0.0 done False while not done: action policy.predict(np.array(state)) state, reward, terminated, truncated, info env.step(action) total_reward reward done terminated or truncated # 渲染当前画面 env.render() print(fDemo finished, total reward {total_reward:.2f}) env.close() if __name__ __main__: main()运行demo.py时你会看到一个小窗口实时播放 AI 玩游戏的过程。如果训练效果不错AI 会表现出明显的“向右移动”倾向并在遇到障碍物时尝试跳跃。如果训练效果不好AI 可能一直原地跳或者撞墙这时候需要调整参数或加大种群规模。5.5 保存最优策略在训练循环中每一代结束后应该把当前最优个体保存下来避免 demo 时用的是随机策略。可以在train.py的 main 函数里加几行# 在每一代循环结束后保存最优个体 best_policy elites[0] w1, b1, w2, b2 best_policy.get_params() np.save(best_policy_w1.npy, w1) np.save(best_policy_b1.npy, b1) np.save(best_policy_w2.npy, w2) np.save(best_policy_b2.npy, b2)保存参数文件后即使训练中断也可以随时用demo.py查看当前最优策略的表现。6. 运行验证与效果判断6.1 如何判断训练是否有效训练过程中控制台会不断打印类似下面的信息Generation 0: best reward 0.00 Generation 1: best reward 1.50 Generation 2: best reward 12.00 Generation 3: best reward 45.00 ... Generation 50: best reward 320.00你可以从两个角度判断训练是否有效最佳奖励曲线整体上升虽然中间会有波动但整体趋势向上说明进化策略在起作用。AI 的实际行为有变化跑一次 demo观察 AI 是否从一开始的原地不动慢慢变成了“向右走”“跳跃”等行为。需要注意的是最佳奖励是单调不减的因为每代都保留了精英个体但每一代的最大值可能因为变异而产生波动。如果你看到最佳奖励长时间不增长优先检查奖励信号是否正确返回、种群规模是否太小、变异噪声是否过大。6.2 运行 demo 时的预期表现训练 100 代后AI 的表现取决于你设置的参数和环境随机性。一般预期会有以下几个阶段前几代AI 基本不会动或者只会在原地随机跳跃。十代以后AI 学会了持续向右移动遇到砖块会撞上去不动。几十代后AI 在部分位置能成功跳过障碍物但还不稳定。训练后期AI 能连贯地移动和跳跃偶尔能通过第一个关卡部分路段。这个“渐进式学习”的过程正是这类视频最有观赏价值的部分。Code Bullet 的视频剪辑也保留了这种“从笨拙到熟练”的过程给观众一种“AI 真的在进化”的直观感受。6.3 训练失败的排查路径如果运行完 100 代AI 依然什么都不学可以按以下顺序排查检查环境是否真的能返回奖励。单独跑一个脚本手动让马里奥向右走看reward是否为正值。检查输入维度是否正确。policy.predict接收的是展平后的像素如果 shape 不匹配会直接报错。检查变异噪声是否太大。如果NOISE_SCALE过大精英参数会被完全打乱下一代不保留优秀信息。检查种群规模是否太小。至少 10 个个体以上不然随机搜索的覆盖面不够。检查max_steps是否太短。如果每局只允许 200 步AI 还没走出几步就被强制结束了很难学到有效行为。7. 常见问题与排查思路本地复现这类项目时遇到的问题通常集中在依赖安装、环境接口、训练效果三个方面。下面整理一份常见问题清单问题现象可能原因排查方式解决方案安装gym-super-mario-bros报错Python 版本或依赖冲突查看错误信息中的依赖版本要求使用 Python 3.8-3.10 创建新虚拟环境后重装env.reset()返回数据格式不对gym 版本接口差异打印返回值的类型和 shape加apply_api_compatibilityTrue或升级 gym运行demo.py报错找不到渲染模块环境中没有安装pygame或显示驱动检查渲染依赖是否完整pip install pygame或使用render_modergb_array并自己保存图像帧训练时最佳奖励一直是 0奖励信号未正确返回单独跑一步env.step(1)查看 reward 值确认动作映射正确确认环境版本支持奖励返回AI 一直原地跳跃不往前走神经网络没有学到“向右移动”动作查看动作集中是否包含向右动作增大变异噪声或增加训练代数检查奖励是否以距离为主训练速度非常慢输入分辨率太大、帧堆叠过多打印状态 shape 并估算计算量把分辨率降到 42x42或者减少帧堆叠数量环境随机性导致结果不稳定没有设置随机种子在 main 函数中调用np.random.seed(0)固定 NumPy 和环境随机种子方便复现其中最容易忽略的是第二个问题。gym-super-mario-bros早期版本的接口和现在差别较大很多教程的代码直接复制会报错。遇到问题优先看官方仓库的 README而不是东拼西凑改代码。8. 最佳实践与工程建议把“AI 学玩马里奥”从玩具项目推向更工程化需要关注下面几个方面。8.1 设置随机种子进化策略看似简单但参数量一大随机性就会非常明显。同样的代码不同的随机种子可能得到完全不同的训练曲线。在实验阶段建议固定三个位置的随机种子import random import numpy as np random.seed(0) np.random.seed(0)这能让你在调参时排除随机性的干扰也能帮助定位“到底是算法问题还是运气问题”。8.2 控制训练时间成本CPU 上跑进化策略虽然比深度学习训练快很多但依然需要耐心。一个经验值是在 42x42 分辨率、单局 2000 步、种群 20 个、训练 100 代的情况下每代大约需要跑 20 局游戏总耗时可能在几十分钟到几小时之间取决于 CPU 性能。如果你的 CPU 性能一般可以先把分辨率降到 32x32把MAX_STEPS降到 1000先验证代码能跑通再逐步加大规模。8.3 保存中间结果与断点续训进化学策略训练不是直线上升的可能某个中间代已经学得不错但后续变异把它带偏了。建议每隔一定代数保存一次最优个体形成检查点if generation % 10 0: np.save(fcheckpoints/gen_{generation}_w1.npy, w1) np.save(fcheckpoints/gen_{generation}_b1.npy, b1)这样即使训练过程中断也可以从最近的检查点继续变异而不必重新训练。8.4 关注奖励塑形的可解释性马里奥环境的默认奖励来自向右移动的距离这是非常直观的。但在更复杂的自定义游戏或仿真项目中你可能会遇到“AI 刷分”“AI 原地抖”“AI 卡在某个状态”等玩法漏洞。建议在每次实验时记录每个个体每局的平均奖励每局的最大移动距离每局的存活步数三个指标放在一起看才能判断 AI 是真的学会了策略还是碰巧刷到了高分。8.5 从进化策略平滑过渡到强化学习如果你在跑通进化策略后想继续深入一个自然的路线是保持上面的环境和预处理代码不变把“变异 选择”替换成 PPO 或 DQN 等强化学习算法。很多开源项目正是在这个基础上改的。你会发现环境搭建和奖励设计在这两类方法中是通用的唯一变的只是“如何利用奖励更新策略”这一步。9. 总结与后续学习方向这篇文章从 Code Bullet 的“AI 学习玩马力欧”视频切入拆解了游戏 AI 的核心框架状态、动作、奖励、策略并重点讲解了他采用的进化策略为什么能高效地学会玩马里奥。我给出的判断是这类项目的学习价值不在“AI 通关”这种结果而在于它用最少的工程成本完整地展示了“从随机尝试到策略涌现”的过程。你不需要掌握复杂的强化学习理论也可以写出一个能玩的游戏 AI这对树立工程直觉非常有帮助。如果你打算继续深入这里有几条实践路径可以参考先跑通上面的简化代码观察 AI 从完全不会到会向右移动的过程建立对进化策略的直观感受。替换成 PyTorch 版本把SimplePolicy改成torch.nn.Module然后用同样的进化策略训练比较两个版本的训练速度和效果。改造奖励函数比如加入“碰到敌人扣分”“踩到敌人加分”等自定义规则观察 AI 行为如何变化。尝试强化学习在同一个马里奥环境上改用 PPO 或 DQN 算法体验强化学习与进化策略的本质差异。Code Bullet 视频的可贵之处在于他把 AI 训练中的失败和迭代过程都展示了出来那些“把 AI 骂骂咧咧”的剪辑本来就是技术故事的张力来源。而技术人真正要学的是如何在面对一个看似简单的任务时用最小可行方案把问题跑通再用数据慢慢逼近理想效果。
返回列表