Files
super-mario/mario-rl-mvp/README.md
ROOG 2960ac1df5 - Implemented policy_utils.py with helper functions for action selection, including epsilon-greedy support.
- Updated `requirements.txt` to relax PyTorch version constraint for better GPU compatibility.
- Added detailed GPU setup instructions, new device fallback options, and command examples to `README.md`.
- Developed a new script `plot_model_max_x_trend.py` for visualizing training trends, generating HTML/Markdown reports.
2026-02-13 16:11:38 +08:00

526 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Mario RL MVP (macOS Apple Silicon)
最小可运行工程:使用像素输入 + 传统 CNN policy`stable-baselines3` PPO训练 `gym-super-mario-bros / nes-py` 智能体,不使用大语言模型。
## 1. 项目结构
```text
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` 即可)。
```bash
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` 创建环境并安装依赖:
```bash
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`,先安装:
```bash
sudo apt-get update
sudo apt-get install -y python3.10-venv python3-pip
```
### RTX 50 系列(如 RTX 5080GPU 说明
如果你看到类似:
```text
... CUDA capability sm_120 is not compatible with the current PyTorch installation ...
```
说明当前 torch wheel 不包含 `sm_120` 内核。可直接升级到 `cu128` nightly
```bash
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
```bash
.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 兼容):
```bash
brew install ffmpeg sdl2
```
## 3. 一条命令开始训练
默认 `--device auto` 训练(优先 CUDA其次 MPS最后 CPU
```bash
python -m src.train_ppo
```
显式指定 `--device cuda``--device mps` 时,如果该设备不可用,脚本会默认报错(避免静默回退到 CPU
若你明确接受回退,可加:
```bash
python -m src.train_ppo --device cuda --allow-device-fallback
```
常用覆盖参数:
```bash
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`
```bash
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`),可用部分加载:
```bash
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_kl``policy_gradient_loss` 长期接近 0希望从已有模型继续探索。
- 注意:这不是“热更新”,仍然需要停止当前训练进程后用新命令重启。
```bash
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 训练日志
- TensorBoard`artifacts/logs/<run_name>/tb/`
- checkpoint`artifacts/models/<run_name>/ppo_mario_ckpt_*.zip`
- final model`artifacts/models/<run_name>/final_model.zip`
- latest 指针:`artifacts/models/latest_model.zip` + `LATEST_MODEL.txt`
启动 TensorBoard
```bash
tensorboard --logdir artifacts/logs --port 6006
```
## 3.2 训练日志字段速查PPO
训练时你会看到类似:
```text
| 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_range`PPO 的 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输出平均指标
```bash
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
```
可指定模型:
```bash
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_rate``flag_get=True` 的比例)
查看步数
```php
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/`
```bash
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
```
或者稳定版本
```bash
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
```
可选:
```bash
--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 报告。
默认命令:
```bash
python -m src.plot_model_max_x_trend
```
默认输出:
- `artifacts/reports/model_max_x_trend.html`
输出 Markdown 报告:
```bash
python -m src.plot_model_max_x_trend --format markdown
```
Markdown 默认输出:
- `artifacts/reports/model_max_x_trend.md`
可选参数(自定义目录/输出):
```bash
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`(动作更丰富):
```bash
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`
使用裁剪奖励:
```bash
python -m src.train_ppo --reward-mode clip
```
针对“卡在固定位置(如 x=314 撞蘑菇)”的推荐续训命令:
```bash
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 编译问题)
先安装工具链并重试:
```bash
xcode-select --install
brew install cmake swig sdl2
pip install --upgrade pip setuptools wheel
pip install -r requirements.txt
```
### 8.2 MPS 不稳定或报错
强制 CPU
```bash
python -m src.train_ppo --device cpu
```
说明:脚本会先做一次 MPS 张量 sanity check失败自动回退 CPU。
### 8.3 视频写入失败ffmpeg/codec
1) 安装系统 ffmpeg
```bash
brew install ffmpeg
```
2) 已降级保存帧序列时,手动转码:
```bash
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 问题,可显式设置:
```bash
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 一致的动作空间:
```bash
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
```
2) 若你确实要切动作空间,用部分初始化(跳过不兼容动作头):
```bash
python -m src.train_ppo --init-model-path artifacts/models/latest_model.zip --movement simple --allow-partial-init
```
3) 或者直接不加载旧模型,从头训练新动作空间。
### 8.6 `cudaGetDeviceCount ... Error 304`WSL 下 CUDA 初始化失败)
如果训练启动时看到:
```text
[device] cpu | CUDA unavailable, using CPU.
[device_diag] ... torch.cuda.is_available()=False ... Error 304 ...
```
说明不是 `device` 参数没传,而是 CUDA 运行时在当前环境初始化失败。
先做两步确认:
```bash
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
```bash
python -m src.train_ppo --device cpu
```
## 9. 最小 smoke test按顺序执行
```bash
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/` 帧序列)