Files
super-mario/mario-rl-mvp

Mario RL MVP (macOS Apple Silicon)

最小可运行工程:使用像素输入 + 传统 CNN policystable-baselines3 PPO训练 gym-super-mario-bros / nes-py 智能体,不使用大语言模型。

最新进度

PixPin_2026-02-14_12-57-02.gif

1. 项目结构

mario-rl-mvp/
  src/
    env.py
    train_ppo.py
    eval.py
    record_video.py
    plot_model_max_x_trend.py
    utils.py
  artifacts/
    models/
    videos/
    logs/
  requirements.txt
  README.md

2. 环境准备macOS / Apple Silicon

建议 Python 3.9+(本机默认 python3 即可)。

cd /Users/roog/Work/FNT/SpMr/mario-rl-mvp
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip setuptools wheel
pip install -r requirements.txt

2.1 环境准备WSL / Ubuntu

如果系统 Python 缺少 venv/pip,推荐直接用 uv 创建环境并安装依赖:

cd /home/roog/super-mario/mario-rl-mvp
uv venv .venv -p /usr/bin/python3.10
uv pip install --python .venv/bin/python -r requirements.txt

如果你更倾向用系统 venv,先安装:

sudo apt-get update
sudo apt-get install -y python3.10-venv python3-pip

RTX 50 系列(如 RTX 5080GPU 说明

如果你看到类似:

... CUDA capability sm_120 is not compatible with the current PyTorch installation ...

说明当前 torch wheel 不包含 sm_120 内核。可直接升级到 cu128 nightly

cd /home/roog/super-mario/mario-rl-mvp
uv pip install --python .venv/bin/python --upgrade --pre torch --index-url https://download.pytorch.org/whl/nightly/cu128

验证 GPU

.venv/bin/python -c "import torch; print(torch.__version__); print(torch.version.cuda); print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'N/A'); print(torch.cuda.get_device_capability(0) if torch.cuda.is_available() else 'N/A')"

可选系统依赖(用于 ffmpeg 转码与潜在 SDL 兼容):

brew install ffmpeg sdl2

3. 一条命令开始训练

默认 --device auto 训练(优先 CUDA其次 MPS最后 CPU

python -m src.train_ppo

显式指定 --device cuda--device mps 时,如果该设备不可用,脚本会默认报错(避免静默回退到 CPU。 若你明确接受回退,可加:

python -m src.train_ppo --device cuda --allow-device-fallback

常用覆盖参数:

python -m src.train_ppo \
  --total-timesteps 1000000 \
  --n-envs 4 \
  --save-freq 50000 \
  --env-id SuperMarioBros-1-1-v0 \
  --movement right_only \
  --seed 42

从已有 checkpoint 初始化后继续训练(可同时改超参数,如 --ent-coef

python -m src.train_ppo \
  --init-model-path artifacts/models/latest_model.zip \
  --total-timesteps 500000 \
  --ent-coef 0.02 \
  --learning-rate 1e-4

如果切换了动作空间(例如 checkpoint 是 right_only,当前想用 simple),可用部分加载:

python -m src.train_ppo \
  --init-model-path artifacts/models/latest_model.zip \
  --allow-partial-init \
  --movement simple \
  --total-timesteps 300000

我目前的参数

python -m src.train_ppo \
  --init-model-path artifacts/models/latest_model.zip \
  --n-envs 16 \
  --allow-partial-init \
  --reward-mode progress \
  --movement simple \
  --ent-coef 0.001 \
  --learning-rate 2e-5 \
  --n-steps 2048 \
  --gamma 0.99 \
  --death-penalty -50 \
  --stall-penalty 0.05 \
  --stall-steps 40 \
  --backward-penalty-scale 0.01 \
  --milestone-bonus 2.0 \
  --no-progress-terminate-steps 300 \
  --no-progress-terminate-penalty 10 \
  --time-penalty -0.01 \
  --total-timesteps 1200000

3.1 从已有模型继续训练(--init-model-path

  • 用途:加载已有 .zip 权重后继续训练,适合“不中断实验目标但调整探索参数”。
  • 常见场景:当前策略陷入局部最优(例如 approx_klpolicy_gradient_loss 长期接近 0希望从已有模型继续探索。
  • 注意:这不是“热更新”,仍然需要停止当前训练进程后用新命令重启。
python -m src.train_ppo \
  --init-model-path artifacts/models/latest_model.zip \
  --ent-coef 0.02 \
  --learning-rate 1e-4 \
  --total-timesteps 300000

训练输出:

  • stdoutPPO 训练日志
  • TensorBoardartifacts/logs/<run_name>/tb/
  • checkpointartifacts/models/<run_name>/ppo_mario_ckpt_*.zip
  • final modelartifacts/models/<run_name>/final_model.zip
  • latest 指针:artifacts/models/latest_model.zip + LATEST_MODEL.txt

启动 TensorBoard

tensorboard --logdir artifacts/logs --port 6006

3.2 训练日志字段速查PPO

训练时你会看到类似:

| rollout/ep_len_mean | rollout/ep_rew_mean | ... |
| train/approx_kl     | train/entropy_loss  | ... |

下面是常用字段的含义(对应你贴出来那组):

  • rollout/ep_len_mean:最近一批 episode 的平均步数。越大不一定越好,要结合 reward 一起看。
  • rollout/ep_rew_mean:最近一批 episode 的平均回报。通常越高越好。
  • time/fps:训练吞吐(每秒环境步数),只代表速度,不代表策略质量。
  • time/iterations:第几次 rollout + update 循环。
  • time/time_elapsed:训练已运行的秒数。
  • time/total_timesteps:累计环境交互步数(达到你设定的 --total-timesteps 会停止)。
  • train/approx_kl:新旧策略差异大小。太大说明更新过猛;接近 0 说明几乎没在更新。极小负数通常是数值误差,可当作 0。
  • train/clip_fraction:有多少样本触发 PPO clipping。长期为 0 且 KL 也接近 0常见于“策略基本不再更新”。
  • train/clip_rangePPO 的 clipping 阈值(默认 0.2)。
  • train/entropy_loss:探索强度指标。绝对值越接近 0策略越确定、探索越少。
  • train/explained_variance:价值网络对回报的解释度,越接近 1 越好,接近 0 说明 value 还不稳。
  • train/learning_rate:优化器步长(参数更新幅度),不是硬件速度。
  • train/loss:总损失(由多个部分组成),主要看趋势,不单看绝对值。
  • train/policy_gradient_loss:策略网络的更新信号。长期接近 0 可能表示 actor 更新很弱。
  • train/value_loss:价值网络误差。过大通常代表 critic 拟合还不稳定。

快速判断(实用版)

  • ep_rew_mean / avg_max_x_pos 持续上升:一般在变好。
  • approx_kl≈0 + clip_fraction=0 + policy_gradient_loss≈0:大概率卡住(更新几乎停了)。
  • entropy_loss 绝对值太小且长期不变:探索不足,可尝试提高 --ent-coef

4. 评估模型

加载最新模型,跑 N 个 episode输出平均指标

python -m src.eval \ 
  --model-path artifacts/models/latest_model.zip \
  --episodes 20 \
  --movement simple \
  --reward-mode progress \
  --no-progress-terminate-steps 300 \
  --no-progress-terminate-penalty 10 \
  --death-penalty -50 \
  --stall-penalty 0.05 \
  --stall-steps 40 \
  --time-penalty -0.01 \
  --epsilon 0.08

可指定模型:

python -m src.eval \
  --model-path artifacts/models/latest_model.zip \
  --episodes 20 \
  --movement simple \
  --reward-mode progress \
  --no-progress-terminate-steps 300 \
  --no-progress-terminate-penalty 10 \
  --death-penalty -50 \
  --stall-penalty 0.05 \
  --stall-steps 40 \
  --time-penalty -0.01 \
  --stochastic

注意:eval.py 默认 --movement auto,会按模型动作维度自动匹配 right_only/simple,避免动作空间不一致导致 KeyError

输出指标包括:

  • avg_reward
  • avg_max_x_pos
  • clear_rateflag_get=True 的比例)

查看步数

unzip -p artifacts/models/latest_model.zip data | rg '"num_timesteps"|"_total_timesteps"|"_tensorboard_log"'

num_timesteps = 151552 _total_timesteps = 150000

5. 录制回放视频(无窗口/headless

默认录制约 10 秒 mp4 到 artifacts/videos/

python -m src.record_video \
  --model-path artifacts/models/latest_model.zip \
  --movement simple \
  --reward-mode progress \
  --no-progress-terminate-steps 300 \
  --no-progress-terminate-penalty 10 \
  --death-penalty -50 \
  --stall-penalty 0.05 \
  --stall-steps 40 \
  --time-penalty -0.01 \
  --epsilon 0.08 \
  --duration-sec 30
  --stochastic

或者稳定版本

python -m src.record_video \
  --model-path artifacts/models/latest_model.zip \
  --movement simple \
  --reward-mode progress \
  --no-progress-terminate-steps 300 \
  --no-progress-terminate-penalty 10 \
  --death-penalty -50 \
  --stall-penalty 0.05 \
  --stall-steps 40 \
  --time-penalty -0.01 \
  --epsilon 0.08 \
  --epsilon-random-mode uniform \
  --max-steps 6000

可选:

--output artifacts/videos/mario_eps008.mp4

注意:record_video.py 默认 --movement auto,会按模型自动匹配动作空间。

实现方式:

  • 使用 render_mode=rgb_array,无需打开窗口
  • 默认通过 imageio + ffmpeg 输出 mp4
  • 若 mp4 写入失败会自动降级保存帧序列PNG并打印 ffmpeg 转码命令

5.1 模型趋势可视化HTML / Markdown

用于可视化 artifacts/models/ 里的模型在训练过程中的关键指标趋势,输出中文 HTML 或 Markdown 报告。

默认命令:

python -m src.plot_model_max_x_trend

默认输出:

  • artifacts/reports/model_max_x_trend.html

输出 Markdown 报告:

python -m src.plot_model_max_x_trend --format markdown

Markdown 默认输出:

  • artifacts/reports/model_max_x_trend.md

可选参数(自定义目录/输出):

uv run python -m src.plot_model_max_x_trend \
  --models-dir artifacts/models \
  --logs-dir artifacts/logs \
  --format markdown \
  --output artifacts/reports/model_max_x_trend.md

报告内容:

  • 主趋势:max_x(最大前进距离)
  • 多维趋势:平均回报、平均回合步数、通关率、无进展终止率、死亡终止率、超时终止率、硬卡死终止率
  • 模型明细表:每个 checkpoint/final 模型对应的指标值、匹配步数、来源 TensorBoard tag
  • 术语解释Run、Checkpoint、model_step、matched_step、TensorBoard Tag 等专有名词

6. 动作空间选择说明

默认 RIGHT_ONLY,原因:

  • 动作更少探索空间更小MVP 更快收敛到“向右推进”策略
  • 适合先验证训练闭环

可切到 SIMPLE_MOVEMENT(动作更丰富):

python -m src.train_ppo --movement simple

7. 预处理与奖励

默认预处理链路:

  • 跳帧:frame_skip=4
  • 灰度:RGB -> Gray
  • 缩放:84x84
  • 帧堆叠:4
  • 通道布局:CHW(兼容 CnnPolicy

奖励:

  • --reward-mode raw:原始奖励(默认)
  • --reward-mode clip:裁剪奖励 sign(reward)(等价于旧参数 --clip-reward
  • --reward-mode progress:奖励塑形模式,额外包含:
    • 前进增益奖励(--progress-scale
    • 死亡惩罚(--death-penalty
    • 通关奖励(--flag-bonus
    • 原地卡住惩罚(--stall-penalty + --stall-steps
    • 后退惩罚(--backward-penalty-scale

使用裁剪奖励:

python -m src.train_ppo --reward-mode clip

针对“卡在固定位置(如 x=314 撞蘑菇)”的推荐续训命令:

python -m src.train_ppo \
  --init-model-path  /home/roog/super-mario/mario-rl-mvp/artifacts/models/ppo_SuperMarioBros-1-1-v0_20260212_205220/ppo_mario_ckpt_100000_steps.zip \
  --n-envs 16 \
  --allow-partial-init \
  --reward-mode progress \
  --movement simple \
  --ent-coef 0.01 \
  --learning-rate 1e-4 \
  --n-steps 1024 \
  --gamma 0.99 \
  --death-penalty -50 \
  --stall-penalty 0.05 \
  --stall-steps 40 \
  --backward-penalty-scale 0.01 \
  --milestone-bonus 2.0 \
  --no-progress-terminate-steps 300 \
  --no-progress-terminate-penalty 10 \
  --total-timesteps 300000

8. 常见问题排查

8.1 pip install 失败nes-py/gym-super-mario-bros 编译问题)

先安装工具链并重试:

xcode-select --install
brew install cmake swig sdl2
pip install --upgrade pip setuptools wheel
pip install -r requirements.txt

8.2 MPS 不稳定或报错

强制 CPU

python -m src.train_ppo --device cpu

说明:脚本会先做一次 MPS 张量 sanity check失败自动回退 CPU。

8.3 视频写入失败ffmpeg/codec

  1. 安装系统 ffmpeg
brew install ffmpeg
  1. 已降级保存帧序列时,手动转码:
ffmpeg -framerate 30 -i artifacts/videos/<name>_frames/frame_%06d.png -c:v libx264 -pix_fmt yuv420p artifacts/videos/<name>.mp4

8.4 图形窗口相关报错

本工程默认 rgb_array 录制,不依赖 GUI 窗口。 若仍遇到 SDL 问题,可显式设置:

export SDL_VIDEODRIVER=dummy
python -m src.record_video --duration-sec 10

8.5 size mismatch for action_net(加载旧模型时报错)

典型原因:旧 checkpoint 的动作空间与当前配置不同(如 right_only=5 动作,simple=7 动作)。

可选修复:

  1. 保持和 checkpoint 一致的动作空间:
python -m src.train_ppo --init-model-path /Users/roog/Work/FNT/SpMr/mario-rl-mvp/artifacts/models/ppo_SuperMarioBros-1-1-v0_20260212_164717/ppo_mario_ckpt_150000_steps.zip --movement right_only
  1. 若你确实要切动作空间,用部分初始化(跳过不兼容动作头):
python -m src.train_ppo --init-model-path artifacts/models/latest_model.zip --movement simple --allow-partial-init
  1. 或者直接不加载旧模型,从头训练新动作空间。

8.6 cudaGetDeviceCount ... Error 304WSL 下 CUDA 初始化失败)

如果训练启动时看到:

[device] cpu | CUDA unavailable, using CPU.
[device_diag] ... torch.cuda.is_available()=False ... Error 304 ...

说明不是 device 参数没传,而是 CUDA 运行时在当前环境初始化失败。

先做两步确认:

nvidia-smi --query-gpu=name,driver_version,compute_cap --format=csv,noheader
.venv/bin/python -c "import torch; print(torch.__version__); print(torch.version.cuda); print(torch.cuda.is_available())"

常见原因是 WSL GPU 栈/驱动状态异常,而不是 PPO 代码本身。若你是临时跑通实验,可先显式 CPU

python -m src.train_ppo --device cpu

9. 最小 smoke test按顺序执行

cd /Users/roog/Work/FNT/SpMr/mario-rl-mvp
source .venv/bin/activate

# 1) 训练 1e4 steps并至少写出 checkpoint + final model
python -m src.train_ppo \
  --total-timesteps 10000 \
  --save-freq 2000 \
  --n-envs 1 \
  --device cpu \
  --movement right_only

# 2) 快速评估
python -m src.eval --episodes 2 --max-steps 2000

# 3) 录制 10 秒视频
python -m src.record_video --duration-sec 10 --fps 30

验收标准:

  • artifacts/models/ 下有 .zip 模型
  • artifacts/logs/ 下有 TensorBoard event 文件
  • artifacts/videos/ 下有 .mp4(或失败时有 _frames/ 帧序列)

python -m src.eval
--model-path artifacts/models/latest_model.zip
--episodes 50
--movement simple
--reward-mode progress
--no-progress-terminate-steps 300
--no-progress-terminate-penalty 10
--death-penalty -50
--stall-penalty 0.05
--stall-steps 40
--time-penalty -0.01
--random-noops 30
--epsilon 0.03