更新 .gitignore 和训练脚本,添加可视化脚本

This commit is contained in:
2026-01-17 20:24:02 +08:00
parent 4dbea5f0a6
commit 265b0eade1
6 changed files with 453 additions and 1718 deletions

113
scripts/README_visualize.md Normal file
View File

@@ -0,0 +1,113 @@
# 模型可视化脚本使用说明
## 功能
使用训练好的MAGAIL模型在环境中运行并生成俯瞰效果图top-down view
## 使用方法
### 基本用法
```bash
python scripts/visualize_trained_model.py \
--model_dir runs/magail_0113 \
--episode 1250 \
--data_dir data/exp_filtered \
--num_scenarios 1 \
--output_dir visualizations
```
### 参数说明
- `--model_dir`: 模型保存目录(例如:`runs/magail_0113`
- `--episode`: 要加载的episode编号例如`1250`
- `--data_dir`: Waymo数据目录默认`data/exp_filtered`
- `--start_index`: 起始场景索引(默认:`0`
- `--num_scenarios`: 要运行的场景数量(默认:`1`
- `--horizon`: 每个episode的最大步数默认`200`
- `--output_dir`: 输出图像保存目录(默认:`visualizations`
- `--save_all_frames`: 保存所有帧(否则按间隔保存)
- `--save_interval`: 保存帧的间隔,当不使用`--save_all_frames`时生效(默认:`10`
- `--gif_duration`: GIF每帧持续时间毫秒默认50ms20fps。值越小GIF播放越快
### 示例
#### 1. 查看最新训练的模型episode 1250
```bash
python scripts/visualize_trained_model.py \
--model_dir runs/magail_0113 \
--episode 1250 \
--num_scenarios 3 \
--output_dir visualizations/episode_1250
```
#### 2. 保存所有帧(用于制作视频)
```bash
python scripts/visualize_trained_model.py \
--model_dir runs/magail_0113 \
--episode 1250 \
--save_all_frames \
--output_dir visualizations/episode_1250_all_frames
```
#### 3. 每5步保存一帧
```bash
python scripts/visualize_trained_model.py \
--model_dir runs/magail_0113 \
--episode 1250 \
--save_interval 5 \
--output_dir visualizations/episode_1250_sparse
```
#### 4. 生成更快的GIF30fps
```bash
python scripts/visualize_trained_model.py \
--model_dir runs/magail_0113 \
--episode 1250 \
--gif_duration 33 \
--output_dir visualizations/episode_1250
```
## 输出
脚本会在指定的输出目录中创建以下文件:
- `scenario_{idx}.gif`: **场景动画GIF**(主要输出)
- `scenario_{idx}_step_{step:04d}.png`: 每个保存步骤的俯瞰图(可选)
- `scenario_{idx}_final.png`: 每个场景的最终状态图
### GIF格式
- 分辨率1600x900
- 格式GIF动画
- 包含完整的场景运行过程
- 显示场景编号、步数、智能体数量和奖励信息
- 默认帧率20fps可通过`--gif_duration`调整)
### 图像格式
- 分辨率1600x900
- 格式PNG
- 包含语义地图和车辆轨迹
## 注意事项
1. **GPU要求**: 脚本需要CUDA支持如果没有GPU会自动使用CPU速度较慢
2. **渲染模式**: 使用MetaDrive的top-down渲染模式会弹出窗口显示实时渲染
3. **内存占用**: 如果保存所有帧,会占用较多磁盘空间
4. **场景数据**: 确保`--data_dir`指向正确的Waymo数据目录
## 故障排除
### 模型文件不存在
```
FileNotFoundError: 模型文件不存在: runs/magail_0113/model_1250_actor.pth
```
**解决**: 检查模型目录和episode编号是否正确
### 场景数据不存在
```
ValueError: Data directory not found
```
**解决**: 确保`--data_dir`指向正确的数据目录
### 渲染失败
如果遇到渲染相关错误,可以尝试:
- 降低`film_size`参数(在脚本中修改)
- 使用无头模式(需要修改脚本)

View File

@@ -0,0 +1,18 @@
import sys
import types
import os
# Mock imghdr module for Python 3.13 compatibility
# TensorBoard depends on imghdr which was removed in Python 3.13
if sys.version_info >= (3, 13):
if 'imghdr' not in sys.modules:
imghdr_mock = types.ModuleType('imghdr')
imghdr_mock.what = lambda filename, h=None: None
# Mock tests list which tensorboard appends to
imghdr_mock.tests = []
sys.modules['imghdr'] = imghdr_mock
from tensorboard import main as tb_main
if __name__ == '__main__':
sys.exit(tb_main.run_main())

View File

@@ -0,0 +1,143 @@
import argparse
import os
import sys
import torch
import numpy as np
import time
# Add project root to Python path
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if project_root not in sys.path:
sys.path.insert(0, project_root)
from train_magail import Actor, MAGAILScenarioEnv
from metadrive.engine.engine_utils import close_engine
def visualize_model(args):
# 1. Load Environment
data_path = os.path.abspath(args.data_dir)
env_config = {
"data_directory": data_path,
"is_multi_agent": True,
"num_controlled_agents": 3,
"horizon": args.horizon,
"use_render": True, # Visualisation enabled
"sequential_seed": True,
"start_scenario_index": args.start_index,
"num_scenarios": args.num_scenarios,
"log_level": 40,
}
print("Initializing MAGAILScenarioEnv...")
try:
env = MAGAILScenarioEnv(config=env_config, agent2policy={})
except Exception as e:
print(f"Error init env: {e}. Trying to close lingering engine...")
try:
close_engine()
except:
pass
env = MAGAILScenarioEnv(config=env_config, agent2policy={})
# 2. Load Model
state_dim = 45
action_dim = 2
actor = Actor(state_dim, action_dim).cuda()
model_path = args.model_path
if not os.path.exists(model_path):
# Try to find it in runs/
potential_path = os.path.join("runs", "magail_production", model_path)
if os.path.exists(potential_path):
model_path = potential_path
else:
# Try appending _actor.pth
potential_path = model_path + "_actor.pth"
if os.path.exists(potential_path):
model_path = potential_path
else:
raise ValueError(f"Model path {args.model_path} not found.")
print(f"Loading model from {model_path}...")
actor.load_state_dict(torch.load(model_path))
actor.eval()
# 3. Run Loop
try:
for i in range(args.start_index, args.start_index + args.num_scenarios):
print(f"\n--- Playing Scenario {i} ---")
# Reset
try:
# Use sequential seed logic or specific seed?
# ExpertReplayEnv/ScenarioEnv logic: seed matches scenario index if configured right
obs_dict = env.reset(seed=i)
except Exception as e:
print(f"Error resetting {i}: {e}. Skipping.")
# Try soft reset
try:
close_engine()
env = MAGAILScenarioEnv(config=env_config, agent2policy={})
except:
pass
continue
print(f"Scenario loaded. Controlled agents: {len(obs_dict)}")
step_count = 0
while True:
actions = {}
# Inference
for agent_id, obs in obs_dict.items():
# Preprocess obs: (45,) -> (1, 45) tensor
obs_tensor = torch.FloatTensor(obs).unsqueeze(0).cuda()
with torch.no_grad():
dist = actor(obs_tensor)
# Deterministic action for viz? Or sample?
# Usually deterministic (mean) is better for checking performance
# But training uses sample.
if args.deterministic:
action = torch.tanh(dist.mean) # Use mean of Gaussian
else:
pre_tanh = dist.sample()
action = torch.tanh(pre_tanh)
actions[agent_id] = action.cpu().numpy().flatten()
# Step
obs_dict, rewards, dones, infos = env.step(actions)
# Render
env.render(
mode="top_down",
text={
"Scenario": i,
"Step": step_count,
"Agents": len(obs_dict)
}
)
step_count += 1
# time.sleep(0.02) # Slow down if needed
if dones["__all__"] or step_count >= args.horizon:
print(f"Scenario finished at step {step_count}")
break
except KeyboardInterrupt:
print("Interrupted.")
finally:
env.close()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--model_path", type=str, required=True, help="Path to actor model pth (e.g. runs/magail_production/model_50_actor.pth)")
parser.add_argument("--data_dir", type=str, default="data/exp_filtered")
parser.add_argument("--start_index", type=int, default=0)
parser.add_argument("--num_scenarios", type=int, default=1)
parser.add_argument("--horizon", type=int, default=200)
parser.add_argument("--deterministic", action="store_true", help="Use mean action instead of sampling")
args = parser.parse_args()
visualize_model(args)