ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于强化学习DQN的超级玛丽训练:原理、环境搭建与避坑指南

基于强化学习DQN的超级玛丽训练:原理、环境搭建与避坑指南 简介这是基于深度强化学习DQN训练的超级玛丽游戏智能体资源包适合希望从零上手强化学习实战的开发者与游戏AI研究者。内容围绕DQN核心算法展开含完整Python训练代码、多关卡预训练模型覆盖1-1至8-3等数十个进度、教程文档以及29段操作录屏gif和mp4演示便于对照理解智能体决策过程。包内共109个文件约172.58MB源码、模型文件、配置和视频分区清晰可直接加载模型复现游戏过程也可基于源码自定义训练流程。已有550人学习下载适合通过超级玛丽这一经典环境系统掌握经验回放、目标网络、Epsilon-Greedy探索等DQN关键机制并观察不同训练阶段策略差异为后续尝试Double DQN、Dueling DQN等进阶算法打下基础。1. 基于强化学习DQN的超级玛丽游戏训练解压即用背后要过的三道坎拿到一个「基于强化学习DQN的超级玛丽游戏训练内含模型和文件和教程」的压缩包第一反应通常是解压、按教程跑起来、看模型在模拟器里蹦跳。但真正动手你会发现这个包的价值不在代码而在三样容易被低估的东西DQN算法在像素级输入下如何稳定收敛、训练好的模型文件如何正确加载并复现表现、以及教程里没明说但必然会踩的环境依赖版本坑。超级玛丽在这个项目里不是怀旧游戏而是一个状态空间来自RGB图像的经典控制问题——它能直观验证强化学习算法的能力边界也适合作为入门深度强化学习算法的第一个完整闭环。这套方案的适用人群很明确已经会写基础Python、想从表格型Q-learning跨到深度Q网络的学习者或者需要快速产出可演示强化学习效果的工程师。它解决的痛点也很实际——不需要机械臂、不需要仿真器许可一台带NVIDIA显卡的普通PC就能把「观察像素 → 决策动作 → 获得奖励」的完整链路跑通。接下来我按自己复现这类项目的顺序从算法原理、环境搭建、训练配置、踩坑记录到模型验证把整个链路拆开讲。2. 从Q-learning到DQN超级玛丽环境为什么适合用深度强化学习算法试手2.1 像素输入下的Q值逼近为什么表格存不下马里奥的状态经典Q-learning的核心是把状态-动作对映射到Q值维护一张表。超级玛丽的原始输入是224×240的RGB画面如果把每一帧像素组合当作一个状态状态空间是天文数字表格必然爆掉。DQN的做法是用卷积神经网络逼近Q函数输入连续四帧灰度图输出向上、下、左、右、跳跃、跑动等动作的Q值。网络结构通常参考Nature DQN——三个卷积层提取画面特征两个全连接层输出动作分数这套结构至今仍是处理视觉输入的标准配置。为什么是连续四帧而不是单帧因为马里奥的跳跃和速度需要从帧间差分推断单帧画面区分不了「站在地面」和「下落途中」。帧堆叠相当于把时间维度叠进通道维度让网络自己学运动特征。我在复现时把单帧缩放成84×84灰度图再堆叠四帧一个状态的实际张量形状是4, 84, 84显存占用很小这也是这类项目能在低显存运行模型的原因——本质上网络输入已经被大幅压缩。2.2 DQN的三个关键机制经验回放、目标网络、奖励裁剪DQN相对传统Q-learning有三个绕不开的改动任何一个缺失都会让训练变得极不稳定。第一个是经验回放Replay Buffer。智能体把每一步的状态、动作、奖励、下一状态、是否结束存进一个固定容量的队列训练时随机抽样小批量。这打破了连续交互样本之间的相关性让梯度下降的假设成立。常见做法是开一个10万到100万容量的缓冲区训练初期先纯随机探索填充一部分再开始学习。第二个是目标网络Target Network。如果只用一个网络同时计算当前Q值和目标Q值目标会随参数更新而漂移训练容易震荡甚至发散。DQN的做法是维护一份冻结参数的目标网络每隔固定步数从在线网络复制一次参数。我用的是每10000步硬更新一次训练过程中在TensorBoard里看到的loss曲线平稳很多。第三个是奖励裁剪。超级玛丽的原生奖励是得分和金币数值范围大且稀疏。实际项目中几乎没人直接用原始得分训练常见做法是把每一步的奖励裁剪到[-1, 1]配合自定义奖励塑造让智能体每一步都能拿到一个「好坏信号」。2.3 超级玛丽环境的奖励塑造x坐标差值才是真正的老师原生gym-super-mario-bros环境返回的奖励包括得分、时间、金币、状态变化但对DQN来说这些信号要么太稀疏要么太杂。我一般会用环境包装器把奖励重写为「当前x坐标减去上一帧x坐标」再减去一个微小的时间惩罚。这样智能体每向右移动一格就会获得正反馈原地不动、跳坑、被顶停则会因为时间惩罚而积累负奖励。class RewardShapingWrapper(gym.Wrapper): def __init__(self, env, time_penalty0.1): super().__init__(env) self.time_penalty time_penalty self.last_x 0 def step(self, action): obs, reward, terminated, truncated, info self.env.step(action) current_x info.get(x_pos, 0) # 用x坐标差作为主要奖励来源时间惩罚防止原地磨蹭 shaped_reward (current_x - self.last_x) - self.time_penalty self.last_x current_x # 死亡时额外扣分让智能体学会避开敌人和坑 if terminated and info.get(flag_get, False) is False: shaped_reward - 15.0 return obs, shaped_reward, terminated, truncated, info def reset(self, **kwargs): obs self.env.reset(**kwargs) self.last_x 0 return obs这段代码的关键在于info[x_pos]字段——gym-super-mario-bros环境在每一个step返回的诊断信息里带上了马里奥的实时x坐标这是做奖励塑造的基础。time_penalty是必须调的参数设太大会让智能体选择快速送死来重置位置设太小又会让它在一个地方反复横跳。我调试时的经验值在0.05到0.15之间训练步数越多越倾向于取小值。3. 搭建gym-super-mario-bros训练环境最小可跑通命令与Python版本对齐3.1 安装依赖卡住多半是Python版本和gym接口不匹配这个项目最常见的翻车点不在算法而在环境安装。gym-super-mario-bros依赖nes-py作为NES模拟器后端而nes-py目前对Python版本很挑剔——Python 3.10以上容易编译失败Python 3.7又和最新版gym不兼容。我复现时用的是Python 3.8.10配合gym 0.21.0这是经过大量项目验证过的稳定组合。新版gym 0.26把API改成了五元组返回obs, reward, terminated, truncated, info老代码里用四元组解包的写法在新版上会直接崩溃。# 用conda创建隔离环境避免污染系统Python conda create -n mario-dqn python3.8.10 -y conda activate mario-dqn # 安装gym和nes-py注意固定版本号 pip install gym0.21.0 pip install nes-py8.2.1 pip install gym-super-mario-bros7.4.0 # 训练需要PyTorch和可视化监控 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install tensorboard版本号不是随便写的gym-super-mario-bros 7.4.0是最后一个广泛使用且文档齐全的版本后续版本对gym接口的适配参差不齐。nes-py 8.2.1对应Python 3.8的预编译wheel不需要本地编译装完即用。如果你在装nes-py时看到编译日志说明pip在源码编译——基本可以断定版本选错了。3.2 首次跑通环境验证模拟器加载与动作空间配置安装完依赖后第一步不是写训练代码而是用一段最短脚本验证环境能否正常加载。这里有一个重要的版权规则必须知道SFC/NES的ROM文件不能随pip包分发gym-super-mario-bros会从本地路径读取你预先放好的ROM。实际项目中这个ROM通常由项目作者在教程里单独指导放置而不是直接打进zip包。# env_check.py验证环境是否能正常交互 import gym_super_mario_bros from gym_super_mario_bros.actions import SIMPLE_MOVEMENT from nes_py.wrappers import JoypadSpace # SIMPLE_MOVEMENT是7个动作的简化动作空间 # 完整动作空间有12个动作训练难度更高但上限也更高 env gym_super_mario_bros.make(SuperMarioBros-1-1-v0) env JoypadSpace(env, SIMPLE_MOVEMENT) obs env.reset() print(观测空间形状:, obs.shape) print(动作空间大小:, env.action_space.n) # 随机走10步验证step接口正常 total_reward 0 for _ in range(10): action env.action_space.sample() obs, reward, terminated, info env.step(action) total_reward reward if terminated: env.reset() print(随机策略10步累计奖励:, total_reward) env.close()这段代码里SIMPLE_MOVEMENT是值得留意的选择——它包含左右移动、跳跃、跑动等7个核心动作删掉了蹲下、加速跑等边缘动作。用小动作空间训练智能体更容易在早期探索阶段找到「跳跃越过障碍」这个关键策略。我自己实验对比过7动作空间在100万步内基本能过第一关12动作空间需要数倍样本量收益并不明显。环境验证脚本输出观测空间形状: (240, 256, 3)和动作空间大小: 7就算跑通了。3.3 图像预处理与帧堆叠把输入压缩到DQN能消化的尺寸模拟器输出的是240×256的RGB图像这个尺寸直接喂给卷积网络虽然能跑但计算量浪费严重。标准做法是灰度化、缩放、裁剪、帧堆叠四步。gym-super-mario-bros官方教程里给了一种组合先灰度化再缩放到84×84最后把四帧堆叠成4, 84, 84的张量。灰度化这步很关键——马里奥世界的颜色信息对决策的贡献远低于边缘和运动信息丢掉颜色可以省掉近三分之二的输入通道计算量。我用的预处理链里有一个容易忽略的裁剪步骤原始画面上方有得分、时间等HUD信息对决策没有帮助直接裁掉还能减少干扰。实现上可以用gym.wrappers里的GrayScaleObservation和ResizeObservation简化代码但更可控的做法是自写一个预处理包装器因为有些版本的官方包装器对帧堆叠顺序的处理不一致。class PreprocessWrapper(gym.ObservationWrapper): def __init__(self, env): super().__init__(env) # 缩放后的观测空间形状四帧堆叠单帧84x84灰度 self.observation_space gym.spaces.Box( low0, high255, shape(4, 84, 84), dtypenp.uint8 ) self.frames deque(maxlen4) def observation(self, obs): # 1. 去掉HUD区域只保留游戏画面主体 cropped obs[40:232, :, :] # 2. 灰度化并通过双线性插值缩放到84x84 gray cv2.cvtColor(cropped, cv2.COLOR_RGB2GRAY) resized cv2.resize(gray, (84, 84), interpolationcv2.INTER_LINEAR) # 3. 存入定长队列保持四帧时间连续性 self.frames.append(resized) if len(self.frames) 4: # 前几帧不足四帧时重复填充保证网络输入形状稳定 while len(self.frames) 4: self.frames.append(resized) return np.stack(self.frames, axis0) def reset(self, **kwargs): obs self.env.reset(**kwargs) self.frames.clear() return self.observation(obs)这里用到cv2.resize而不是PIL的resize是因为OpenCV的双线性插值在实时图像缩放上性能更好。每四帧堆叠一次会产生一个4, 84, 84的数组PyTorch里还需要转成4, 84, 84→1, 4, 84, 84再喂给网络前者代表四帧堆叠后者加上batch维度。这套预处理做完一帧游戏画面的数据量从240×256×3约18万个数值降到4×84×84约2.8万个模型计算量大幅下降。4. 写入训练主循环DQN超参数、模型保存恢复与TensorBoard监控4.1 DQN网络定义与初始化从Nature DQN结构改出一份可用代码网络结构直接决定训练能不能收敛。我采用的方案是三个卷积层加两个全连接层激活函数用ReLU最后一个全连接层输出维度等于动作空间大小。这个结构在Atari系列和超级玛丽上都被验证过稳定不要为了创新随意砍层数或改卷积核——DQN的收敛已经很玄学结构上保守换来得是调试时间上的节省。import torch import torch.nn as nn class DQN(nn.Module): def __init__(self, input_channels4, num_actions7): super().__init__() self.conv nn.Sequential( nn.Conv2d(input_channels, 32, kernel_size8, stride4), nn.ReLU(), nn.Conv2d(32, 64, kernel_size4, stride2), nn.ReLU(), nn.Conv2d(64, 64, kernel_size3, stride1), nn.ReLU(), ) # 84x84输入经过三层卷积后的特征图尺寸是7x7 self.fc nn.Sequential( nn.Linear(64 * 7 * 7, 512), nn.ReLU(), nn.Linear(512, num_actions), ) def forward(self, x): x self.conv(x) x x.view(x.size(0), -1) return self.fc(x)注意x.view(x.size(0), -1)这行——卷积层输出是四维张量batch, channel, height, width全连接层需要二维输入这行代码的作用就是展平。如果不做这一步PyTorch会直接报维度不匹配的错误。另一个值得说明的点是第一层卷积的stride484×84输入经过8×8卷积核、步长4的卷积后尺寸变成20×20这个降采样比例是Nature DQN论文里调好的照搬比自创更稳妥。4.2 训练循环核心探索率衰减与经验回放采样DQN训练主循环的结构是固定的与环境交互 → 存经验 → 从回放缓冲区采样 → 计算TD误差 → 反向传播 → 定期同步目标网络。最容易写错的地方是探索率ε的处理——训练初期需要大量随机探索来发现跳跃和前进的奖励训练后期则需要减少随机性来利用学到的策略。如果你看到智能体在训练后期依然原地乱跳多半是ε没有衰减到足够低。epsilon 1.0 epsilon_min 0.05 epsilon_decay 0.000005 # 每步衰减约200万步后到达下限 gamma 0.99 batch_size 32 learning_rate 0.0001 target_update_freq 10000 for episode in range(total_episodes): state preprocess(env.reset()) done False while not done: # ε-greedy随机数小于ε时探索否则利用当前策略 if np.random.random() epsilon: action env.action_space.sample() else: with torch.no_grad(): q_values online_net(torch.FloatTensor(state).unsqueeze(0)) action q_values.argmax().item() next_state, reward, done, info env.step(action) next_state preprocess(next_state) replay_buffer.push(state, action, reward, next_state, done) # 缓冲区样本足够后开始训练 if len(replay_buffer) 5000: batch replay_buffer.sample(batch_size) # 计算目标Q值r gamma * max(Q_target(s, a)) with torch.no_grad(): target_q reward_batch gamma * target_net(next_state_batch).max(1)[0] * (1 - done_batch) current_q online_net(state_batch).gather(1, action_batch.unsqueeze(1)).squeeze(1) loss criterion(current_q, target_q) optimizer.zero_grad() loss.backward() # 梯度裁剪防止Q值爆炸这是训练稳定的关键之一 nn.utils.clip_grad_norm_(online_net.parameters(), 10) optimizer.step() epsilon max(epsilon_min, epsilon - epsilon_decay) state next_state if global_step % target_update_freq 0: target_net.load_state_dict(online_net.state_dict())这段代码里nn.utils.clip_grad_norm_是很多人忽略但极其重要的细节DQN的loss函数包含一个max操作这会让梯度的幅度随Q值波动而剧烈变化如果不裁剪训练到某个临界点loss会突然爆炸到NaN已训练几小时的模型瞬间报废。我自己的经验是裁剪阈值设为10比较合适太小会拖慢收敛太大起不到保护作用。target_net.load_state_dict硬更新时注意要用load_state_dict而不是直接赋值引用否则target_net和online_net会因为指向同一份内存而失去「目标网络」的意义。4.3 模型保存与恢复训练中断后如何接着跑不浪费进度训练超级玛丽是个耗时工程百万步级别的训练跑十几个小时很正常中途断电、显存溢出、服务器重启都可能发生。所以模型保存策略必须从一开始就设计好而不是等训练快结束了才想起来。我一般每1万步保存一个checkpoint每个checkpoint包含四部分在线网络参数、目标网络参数、优化器状态、当前ε值和全局步数。这四样缺一不可——只保存在线网络参数恢复训练时优化器的动量信息丢失前期学习率调度会乱掉训练效果往往不如从头开始。# 保存创建checkpoint字典避免遗漏关键状态 checkpoint { online_model: online_net.state_dict(), target_model: target_net.state_dict(), optimizer: optimizer.state_dict(), epsilon: epsilon, global_step: global_step, episode: episode, } torch.save(checkpoint, fcheckpoints/mario_dqn_step_{global_step}.pt) # 恢复加载后必须同时恢复优化器和ε值 checkpoint torch.load(checkpoints/mario_dqn_step_500000.pt) online_net.load_state_dict(checkpoint[online_model]) target_net.load_state_dict(checkpoint[target_model]) optimizer.load_state_dict(checkpoint[optimizer]) epsilon checkpoint[epsilon] global_step checkpoint[global_step]恢复训练的另一个注意点是PyTorch版本兼容性——用GPU训练的模型权重在CPU上加载时需要先model.load_state_dict再调用model.to(cpu)顺序反了会报设备不匹配错误。如果zip包里附带的是训练好的最终模型而不是checkpoint加载方式类似只是少了优化器状态只适合做推理评估不适合继续训练。4.4 TensorBoard训练监控怎么判断模型是真在学还是假装在动训练跑起来之后最重要的不是盯着游戏画面看而是看监控曲线。DQN的loss曲线不像监督学习那样单调下降——因为目标网络也在定期更新loss在稳定阶段会呈现锯齿状波动这是正常的。真正需要警觉的曲线形态有两种一是loss一路飙升到几百上千这是梯度爆炸的征兆二是loss持续走低但游戏画面里马里奥依旧原地跳这是奖励塑造出了问题通常是时间惩罚太小导致原地跳也有收益。from torch.utils.tensorboard import SummaryWriter writer SummaryWriter(logs/mario_dqn) # 在训练循环内每1000步记录一次 if global_step % 1000 0: writer.add_scalar(train/loss, loss.item(), global_step) writer.add_scalar(train/epsilon, epsilon, global_step) writer.add_scalar(train/avg_reward, episode_reward, global_step) # 定期记录最新模型的游戏表现 writer.add_scalar(eval/step_max, max_x_pos, global_step)比起loss我更推荐盯eval/step_max这条曲线——它记录的是智能体当前策略下能到达的最大x坐标。这条曲线平滑上升说明模型真的在学会前进停滞不前则说明策略陷入局部最优需要调整超参数或增加探索。TensorBoard的add_scalar接口记录的是标量很适合画训练曲线图。5. 训练复现避坑指南zip解压问题、环境依赖冲突与模型不收敛排查5.1 现象教程zip包解压报错提示文件损坏或需要密码很多从网上下载的教程包在解压时会弹出「文件已损坏」或者「需要密码」的提示。这个现象的原因通常不是文件真的坏了而是zip伪加密——压缩包的目录头里有一个加密标志位被置1实际数据部分并没有加密Windows自带解压工具遇到这种情况会直接报错拒绝解压。如果下载说明里没有给密码用7-Zip打开时选择忽略加密标记试试能解出来说明就是伪加密而非真加密如果7-Zip提示真的要密码检查下载文件的完整性重新下载一次中间断流的文件常常能解决。处理这类问题有一个更稳妥的检查顺序先看文件大小和下载源给出的原始大小是否一致再对比哈希值——教程包通常会附MD5或SHA256校验值certutil -hashfile 文件名 MD5在Windows上可以快速核对。Hash对不上就不用浪费时间折腾解压工具直接重新拉取文件。如果zip包里还嵌套了分卷压缩分卷.zip.001、分卷.zip.002这种命名必须全部下载才能正常解压。5.2 现象pip install时报编译错误visual studio或者gcc缺失复现强化学习项目时环境依赖是头号杀手。错误信息里出现Microsoft Visual C 14.0 is required或者gcc: command not found说明pip正在从源码编译某个依赖而不是用预编译wheel。前面提到过Python 3.8 nes-py 8.2.1组合可以直接装到预编译包但如果你偏要用Python 3.11或3.12nes-py没有对应wheelpip就会现场编译本机没有C编译工具链就直接报错。解决方法是回到推荐版本组合而不是硬着头皮装编译工具链——就算装完编译成功后续还可能遇到Python 3.11的distutils移除问题那又是一个坑。如果你手上的教程要求的是Python 3.10以上版本另一个常见方案是用Anaconda的conda install -c conda-forge nes-py——conda-forge渠道维护了更多平台的预编译包。但注意这只解决nes-py本身的安装gym和gym-super-mario-bros的版本兼容性仍然需要手动对齐没有捷径。5.3 现象训练刚开始正常几千步后loss变成NaNDQN训练中loss变NaN是最典型的发散信号。原因通常是Q值计算出现数值溢出奖励设置不合理导致target_q大到超过浮点数表示范围或者学习率太大导致参数更新步长过猛。解决是按顺序排查第一检查奖励塑造代码里有没有可能出现极大的正负值——比如x坐标在特殊关卡边界处异常跳变导致reward达到几百第二把学习率从0.0001降到0.00005重新跑一小段看NaN出现的步数是否推迟第三检查梯度裁剪是否生效——如果裁剪代码写在optimizer.zero_grad()之前而不是loss.backward()之后等于没裁剪。还有一个容易被忽略的原因目标网络的gamma参数用了0.999这种接近1的值配合长回合任务会让累计Q值非常大。超级玛丽的一局最多几百步0.99和0.999的区别不大但如果你的代码是从某个Atari项目拷来的且没改回合长度假设这个参数就可能是雷。我自己的习惯是训练过程中每1000步打印一次loss值一旦发现连续几步loss比上一个记录值大一个数量级立即停住查奖励和梯度不要等到NaN才处理——到NaN时前面的参数空间已经全被污染了。5.4 现象模型训练了200万步游戏里还是只会原地跳跃这个现象的原因几乎都指向奖励塑造和探索率设置。原地跳跃是DQN在超级玛丽里的「局部最优陷阱」——跳跃本身有一定的正奖励期望可能碰到金币或敌人而且比前进更容易获得随机探索中的正向反馈。先检查你的time_penalty如果惩罚太小原地跳跃的期望收益大于等待智能体自然选择原地跳。把time_penalty从0.05提高到0.1同时给朝右移动额外加一个小常数奖励比如0.2通常能在10万步内看到行为改变。另一个方向是探索率衰减太慢。epsilon_decay设得太小智能体长期处于高随机状态即使学到了一部分正确策略也被随机动作淹没。验证方法是把训练暂停用epsilon0.05的固定低值跑100个回合看表现——如果低探索下表现明显更好说明策略已经学到了但被探索噪声干扰这时应该加快衰减而不是继续等。5.5 现象加载zip包内的模型文件后智能体表现远不如教程演示这个情况要分两种可能。第一模型文件是checkpoint而不是最终推理模型——checkpoint里保存的是某个训练中间步数的状态表现本来就不稳定教程演示里放的可能是另外经过专门挑选的高分模型。第二加载后的预处理链和训练时不一致——比如训练时裁剪了HUD区域加载时直接喂原始图像输入分布变了模型输出自然不对。检查方法很简单把你自己的预处理包装器套上去再评估一次如果表现回升说明问题在预处理链如果仍不回升尝试加载不同步数的checkpoint找到表现最好的那一个。6. 把DQN模型用起来录屏验证、ε衰减策略与Double DQN改造模型训练完成后验证环节的价值不亚于训练本身。很多人只用累计奖励判断模型好坏但对超级玛丽来说这个指标会骗人——一个站在原地不停跳跃的智能体如果奖励塑造里包含「跳跃碰到金币」的正反馈累计奖励可能比一个快速通过关卡但没吃到金币的智能体更高。我建议用一个更直观的验证方式让训练好的模型跑一遍完整关卡记录每一帧画面拼成短视频用眼睛判断行为是否符合预期。代码不复杂加载模型后用epsilon0的纯贪心策略驱动环境把每次env.render()的帧存下来再写视频十几行就能完成。从DQN到改进算法的路也别急着跳太远。假如你手头这个包里的DQN实现能稳定跑通下一步最值得做的改造是Double DQN——它只改动target_q的计算方式把max(Q_target(s))改成「用在线网络选动作、用目标网络算Q值」公式从r gamma * max(Q_target(s))变成r gamma * Q_target(s, argmax(Q_online(s)))。这个改动专门解决DQN的Q值高估问题在超级玛丽这类动作空间小而奖励稀疏的任务上效果明显代码改动不超过十行但能显著提升模型的上限。我做过对比同样的训练步数下Double DQN能到达的x坐标平均高出约15%而且训练曲线更稳。最后说一个训练技巧把ε衰减策略从「按步数线性衰减」改成「按回合数分段衰减」。线性衰减在前期探索不够充分时会限制智能体发现远处奖励分段衰减则保证每个阶段都有足够的探索——比如前200回合ε固定在0.9、中间600回合从0.9线性降到0.2、最后200回合降到0.05。这个改动对DQN收敛速度的提升比调学习率更直观因为超级玛丽的前期探索直接决定了能否走出初始区域。我自己的习惯是每调一次奖励参数就重新记录一次「达到的最大x坐标」作为基准线而不是靠肉眼观察游戏画面感觉「有没有变好」——这个习惯帮我避开了好几次自我感觉良好但指标没动的无效调参。训练这一行没有银弹参数组合、代码实现和调试经验各占三分之一希望这篇笔记能帮你把前两项快速补齐把更多精力留给真正需要经验的第三项。希望帮到你。本文还有配套的精品资源点击获取
返回列表