Skip to content

Commit f25e6f0

Browse files
authored
Merge pull request #46 from TATP-233/feat/reward-config-injection
Feat/reward config injection
2 parents 4617837 + 0e716e1 commit f25e6f0

62 files changed

Lines changed: 2502 additions & 1739 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CLAUDE.md‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ make check # make format && make type
3535
make test # Run all non-slow tests (default)
3636
make test-cov # Run non-slow tests with coverage report
3737
make test-slow # Run slow integration tests (requires MuJoCo)
38+
make test-veryslow # Run full training iteration tests (minutes per test)
3839
make test-all # make check && make test-cov
3940
```
4041

@@ -56,7 +57,10 @@ uv run pytest -m "not slow"
5657
uv run pytest -m "not slow" --cov=unilab --cov-report=term-missing
5758

5859
# Slow integration tests (need MuJoCo installed)
59-
uv run pytest -m slow -v
60+
uv run pytest -m "slow and not veryslow" -v
61+
62+
# Very slow: full training iteration tests (minutes per test)
63+
uv run pytest -m veryslow -v
6064
```
6165

6266
## Test Structure
@@ -91,6 +95,9 @@ tests/
9195
Tests marked `@pytest.mark.slow` require a real MuJoCo environment and are excluded from CI
9296
by default. Run them locally when working on runner/learner code.
9397

98+
Tests marked `@pytest.mark.veryslow` run full training iterations (minutes per test). They are
99+
excluded by default even when running `make test-slow`. Run `make test-veryslow` explicitly.
100+
94101
## Testing
95102

96103
**New features must ship with tests.** When developing a new feature or refactoring, design and write comprehensive unit tests alongside the feature code — not as an afterthought. Tests should cover:
@@ -118,3 +125,23 @@ pre-commit install # Optional
118125
```
119126

120127
**Always run `make check` before committing.**
128+
129+
## Configuration System
130+
131+
UniLab uses **Hydra + dataclass** for type-safe, composable configs:
132+
133+
- **Structured configs**: `src/unilab/config/structured_configs.py` (typed dataclasses)
134+
- **YAML configs**: `conf/` directory (offpolicy/appo/ppo)
135+
- **CLI overrides**: `algo.num_envs=2048 training.device=cuda`
136+
137+
### Adding New Tasks
138+
139+
1. Create YAML file: `conf/{algo}/task/my_task.yaml`
140+
2. Use `# @package _global_` directive
141+
3. Override only deltas from base config
142+
143+
### Adding New Algorithms
144+
145+
1. Add dataclass to `structured_configs.py`
146+
2. Create `conf/{algo}/config.yaml` with defaults
147+
3. Update training script with `@hydra.main()`

‎CONTRIBUTING.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,13 @@ Push / PR 到 `main` 时自动触发三个 job:
110110
## 问题反馈
111111

112112
使用 GitHub Issues 报告 bug 或提出功能建议。
113+
114+
## 配置系统
115+
116+
UniLab 使用 Hydra + dataclass 配置系统:
117+
118+
- **添加新任务**:在 `conf/{algo}/task/` 创建 YAML,使用 `# @package _global_`
119+
- **修改超参数**:编辑对应 YAML 或使用 CLI 覆盖(`algo.num_envs=2048`)
120+
- **添加新算法**:在 `structured_configs.py` 添加 dataclass,创建对应 `conf/` 目录
121+
122+
详见 `CLAUDE.md` 配置系统章节。

‎Makefile‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ test-fast:
2929

3030
.PHONY: test-slow
3131
test-slow:
32-
uv run pytest -m "slow"
32+
uv run pytest -m "slow and not veryslow" -v
33+
34+
.PHONY: test-veryslow
35+
test-veryslow:
36+
uv run pytest -m "veryslow" -v
3337

3438
.PHONY: test-all
3539
test-all: check test-cov

‎README.md‎

Lines changed: 74 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -133,67 +133,84 @@ UniLab 支持两种仿真后端:
133133

134134
```bash
135135
# 训练
136-
uv run python scripts/train_rsl_rl.py --task Go1JoystickFlatTerrain --sim_backend motrix
136+
uv run python scripts/train_rsl_rl.py task=go1_joystick training.sim_backend=motrix
137137

138138
# 回放(交互式可视化)
139-
uv run python scripts/train_rsl_rl.py --task Go1JoystickFlatTerrain --sim_backend motrix --play_only
139+
uv run python scripts/train_rsl_rl.py task=go1_joystick training.sim_backend=motrix training.play_only=true
140140
```
141141

142142
## 训练与回放指南
143143

144144
### 1. 开始训练 (Training)
145145

146146
```bash
147-
# PPO (RSL-RL)
148-
uv run python scripts/train_rsl_rl.py --task Go2JoystickFlatTerrain
147+
# PPO (RSL-RL) - 使用 Hydra 配置
148+
uv run python scripts/train_rsl_rl.py task=go2_joystick
149149

150150
# PPO (MLX - Apple Silicon)
151-
uv run python scripts/train_mlx_ppo.py --task Go2JoystickFlatTerrain
151+
uv run python scripts/train_mlx_ppo.py task=go2_joystick
152152

153153
# APPO(异步 PPO,CPU/GPU 并行)
154-
uv run python scripts/train_appo.py --task Go1JoystickFlatTerrain
154+
uv run python scripts/train_appo.py task=go1_joystick
155155

156-
# Unified OffPolicy entry (recommended)
157-
uv run python scripts/train_offpolicy.py --algo sac --task Go1JoystickFlatTerrain
158-
uv run python scripts/train_offpolicy.py --algo td3 --task Go1JoystickFlatTerrain
156+
# Off-Policy (SAC/TD3) - 推荐使用统一入口
157+
uv run python scripts/train_offpolicy.py algo=sac task=go1_joystick
158+
uv run python scripts/train_offpolicy.py algo=td3 task=go1_joystick
159159

160+
# CLI 覆盖配置参数
161+
uv run python scripts/train_offpolicy.py algo=sac task=g1_sac algo.num_envs=2048 algo.max_iterations=1000
160162
```
161163

162-
**注意**:训练脚本默认在训练完成后会进入回放阶段。`mujoco` 后端会导出 `play_video.mp4`,`motrix` 后端为交互式窗口渲染(不导出视频)。使用 `--no_play` 跳过自动回放。
164+
**注意**:训练脚本默认在训练完成后会进入回放阶段。`mujoco` 后端会导出 `play_video.mp4`,`motrix` 后端为交互式窗口渲染(不导出视频)。使用 `training.no_play=true` 跳过自动回放。
163165

164166
**日志目录命名**:训练 run 目录统一采用 `YYYY-MM-DD_HH-MM-SS_<sim_backend>`,例如 `2026-03-09_18-30-00_mujoco`。
165167

166168
### 2. 回放与渲染视频 (Play / Evaluation)
167169

168-
使用 `--play_only` 参数跳过训练,直接回放。脚本会加载最新 checkpoint;`mujoco` 回放生成 `play_video.mp4`,`motrix` 回放打开交互窗口。
170+
使用 `training.play_only=true` 参数跳过训练,直接回放。脚本会加载最新 checkpoint;`mujoco` 回放生成 `play_video.mp4`,`motrix` 回放打开交互窗口。
169171

170172
```bash
171173
# 回放最新训练结果
172-
uv run python scripts/train_rsl_rl.py --task Go2JoystickFlatTerrain --play_only
173-
uv run python scripts/train_offpolicy.py --algo sac --task Go2JoystickFlatTerrain --play_only
174+
uv run python scripts/train_rsl_rl.py task=go2_joystick training.play_only=true
175+
uv run python scripts/train_offpolicy.py algo=sac task=go2_joystick training.play_only=true
174176

175177
# 加载特定 checkpoint 回放
176-
uv run python scripts/train_offpolicy.py --algo td3 --task Go1JoystickFlatTerrain --play_only --load_run "2024-02-04_12-00-00"
178+
uv run python scripts/train_offpolicy.py algo=td3 task=go1_joystick training.play_only=true training.load_run="2024-02-04_12-00-00"
177179
```
178180

179181
### 3. 加载特定 Run 继续训练
180182

181183
```bash
182184
# PPO 继续训练
183-
uv run python scripts/train_rsl_rl.py --task Go2JoystickFlatTerrain --load_run "2024-02-04_12-00-00"
185+
uv run python scripts/train_rsl_rl.py task=go2_joystick training.load_run="2024-02-04_12-00-00"
184186

185187
# OffPolicy (SAC) 继续训练
186-
uv run python scripts/train_offpolicy.py --algo sac --task Go2JoystickFlatTerrain --load_run "2024-02-04_12-00-00"
188+
uv run python scripts/train_offpolicy.py algo=sac task=go2_joystick training.load_run="2024-02-04_12-00-00"
187189
```
188190

189191
### 通用参数说明
190192

191-
* `--task`: 任务名称(如 `Go2JoystickFlatTerrain`、`Go1JoystickFlatTerrain`)
192-
* `--play_only`: 仅回放模式,跳过训练
193-
* `--no_play`: 训练后跳过自动回放
194-
* `--load_run`: 指定加载的运行 ID,默认 `-1`(最新)
195-
* `--play_env_num`: 回放时的环境数量(默认 16)
196-
* `--logger`: 日志后端(`tensorboard` / `wandb` / `none`)
193+
所有训练脚本使用 Hydra 配置系统,支持 CLI 覆盖:
194+
195+
```bash
196+
# 基本格式
197+
uv run python scripts/train_*.py [config_group=value] [key.subkey=value]
198+
199+
# 示例
200+
task=go1_joystick # 选择任务配置
201+
algo=sac # 选择算法配置(offpolicy)
202+
training.play_only=true # 仅回放模式
203+
training.no_play=true # 训练后跳过回放
204+
training.load_run="-1" # 加载运行 ID(-1=最新)
205+
training.logger=tensorboard # 日志后端(tensorboard/wandb/none)
206+
algo.num_envs=2048 # 覆盖环境数量
207+
algo.max_iterations=1000 # 覆盖迭代次数
208+
```
209+
210+
查看完整配置:
211+
```bash
212+
uv run python scripts/train_offpolicy.py --cfg job
213+
```
197214

198215
---
199216

@@ -215,45 +232,44 @@ uv run python scripts/train_offpolicy.py --algo sac --task Go2JoystickFlatTerrai
215232

216233
```bash
217234
# 默认参数训练
218-
uv run python scripts/train_appo.py --task Go1JoystickFlatTerrain
235+
uv run python scripts/train_appo.py task=go1_joystick
219236

220237
# 指定环境数量和迭代次数
221-
uv run python scripts/train_appo.py --task Go2JoystickFlatTerrain --total_envs 2048 --max_iterations 300
238+
uv run python scripts/train_appo.py task=go2_joystick algo.num_envs=2048 algo.max_iterations=300
222239

223240
# 自定义 replay queue 深度(越大 staleness 越高,但 GPU 利用率更稳定)
224-
uv run python scripts/train_appo.py --task Go1JoystickFlatTerrain --replay_queue_size 2
241+
uv run python scripts/train_appo.py task=go1_joystick training.replay_queue_size=2
225242

226243
# 跳过训练后的自动 play
227-
uv run python scripts/train_appo.py --task Go1JoystickFlatTerrain --no_play
244+
uv run python scripts/train_appo.py task=go1_joystick training.no_play=true
228245
```
229246

230247
### 回放
231248

232249
```bash
233250
# 仅回放(加载最新 checkpoint)
234-
uv run python scripts/train_appo.py --task Go1JoystickFlatTerrain --play_only
251+
uv run python scripts/train_appo.py task=go1_joystick training.play_only=true
235252

236253
# 加载特定 checkpoint 回放
237-
uv run python scripts/train_appo.py --task Go1JoystickFlatTerrain --play_only --load_run "2026-03-16_01-35-12_mujoco"
238-
uv run python scripts/train_appo.py --task Go1JoystickFlatTerrain --play_only --load_run "/abs/path/to/model_150.pt"
254+
uv run python scripts/train_appo.py task=go1_joystick training.play_only=true training.load_run="2026-03-16_01-35-12_mujoco"
239255
```
240256

241257
### 参数说明
242258

243259
| 参数 | 默认值 | 说明 |
244260
|------|--------|------|
245-
| `--task` | `Go2JoystickFlatTerrain` | 任务名称 |
246-
| `--max_iterations` | 配置文件值 | 最大训练迭代次数 |
247-
| `--total_envs` | 配置文件值(2048) | 并行环境数量 |
248-
| `--steps_per_env` | 配置文件值(24) | 每条 rollout 的步数 |
249-
| `--replay_queue_size` | 3 | Learner 端 rollout 重放队列深度 |
250-
| `--device` | 自动检测 | Learner 设备(`cuda` / `mps` / `cpu`) |
251-
| `--collector_device` | `cpu` | Collector 设备(`cpu` 或 `gpu`) |
252-
| `--logger` | `tensorboard` | 日志后端(`tensorboard` / `wandb` / `none`) |
253-
| `--play_only` | False | 仅回放,跳过训练 |
254-
| `--no_play` | False | 训练后跳过自动回放 |
255-
| `--load_run` | `-1`(最新) | 指定 run 目录名或 checkpoint 路径 |
256-
| `--save_interval` | 配置文件值 | 每隔多少次迭代保存一次 checkpoint |
261+
| `task` | `go2_joystick` | 任务配置名称 |
262+
| `algo.max_iterations` | 150 | 最大训练迭代次数 |
263+
| `algo.num_envs` | 2048 | 并行环境数量 |
264+
| `algo.steps_per_env` | 24 | 每条 rollout 的步数 |
265+
| `training.replay_queue_size` | 3 | Learner 端 rollout 重放队列深度 |
266+
| `training.device` | 自动检测 | Learner 设备(`cuda` / `mps` / `cpu`) |
267+
| `training.collector_device` | `cpu` | Collector 设备 |
268+
| `training.logger` | `tensorboard` | 日志后端(`tensorboard` / `wandb` / `none`) |
269+
| `training.play_only` | false | 仅回放,跳过训练 |
270+
| `training.no_play` | false | 训练后跳过自动回放 |
271+
| `training.load_run` | `-1` | 指定 run 目录名或 checkpoint 路径 |
272+
| `algo.save_interval` | 50 | 每隔多少次迭代保存一次 checkpoint |
257273

258274
### 与 PPO 的对比
259275

@@ -282,37 +298,38 @@ uv run python scripts/train_appo.py --task Go1JoystickFlatTerrain --play_only --
282298
### 训练
283299

284300
```bash
285-
# Unified entry
286-
uv run python scripts/train_offpolicy.py --algo sac --task Go2JoystickFlatTerrain
287-
uv run python scripts/train_offpolicy.py --algo td3 --task Go1JoystickFlatTerrain
301+
# 基本训练
302+
uv run python scripts/train_offpolicy.py algo=sac task=go2_joystick
303+
uv run python scripts/train_offpolicy.py algo=td3 task=go1_joystick
288304

289305
# 异步模式(更高吞吐量)
290-
uv run python scripts/train_offpolicy.py --algo sac --task Go2JoystickFlatTerrain --no_sync_collection
306+
uv run python scripts/train_offpolicy.py algo=sac task=go2_joystick training.no_sync_collection=true
291307

292308
# 跳过训练后的自动 play
293-
uv run python scripts/train_offpolicy.py --algo td3 --task Go1JoystickFlatTerrain --no_play
309+
uv run python scripts/train_offpolicy.py algo=td3 task=go1_joystick training.no_play=true
294310
```
295311

296312
### 回放
297313

298314
```bash
299315
# 仅回放模式
300-
uv run python scripts/train_offpolicy.py --algo sac --task Go2JoystickFlatTerrain --play_only
316+
uv run python scripts/train_offpolicy.py algo=sac task=go2_joystick training.play_only=true
301317

302318
# 加载特定 checkpoint
303-
uv run python scripts/train_offpolicy.py --algo td3 --task Go1JoystickFlatTerrain --play_only --load_run "2024-02-04_12-00-00"
319+
uv run python scripts/train_offpolicy.py algo=td3 task=go1_joystick training.play_only=true training.load_run="2024-02-04_12-00-00"
304320
```
305321

306322
### 参数说明
307323

308324
| 参数 | 默认值 | 说明 |
309325
|------|--------|------|
310-
| `--max_iterations` | 1500 (SAC) / 5000 (TD3) | 最大训练迭代次数 |
311-
| `--num_envs` | 4096 | 并行环境数量 |
312-
| `--device` | 自动检测 | Learner 设备 (`cuda` / `mps` / `cpu`) |
313-
| `--collector_device` | `cpu` | Collector 设备(默认 `cpu`,可手动设为 `mps`/`cuda`) |
314-
| `--sim_backend` | `mujoco` | 仿真后端(`mujoco` / `motrix`) |
315-
| `--no_sync_collection` | False | 启用异步收集模式 |
316-
| `--env_steps_per_sync` | 1 | 同步模式下每次收集的步数 |
317-
| `--play_only` | False | 仅回放,跳过训练 |
318-
| `--no_play` | False | 训练后跳过自动回放 |
326+
| `algo` | `sac` | 算法选择(`sac` / `td3`) |
327+
| `task` | `go1_joystick` | 任务配置名称 |
328+
| `algo.max_iterations` | 500 (SAC) / 5000 (TD3) | 最大训练迭代次数 |
329+
| `algo.num_envs` | 4096 | 并行环境数量 |
330+
| `training.device` | 自动检测 | Learner 设备 (`cuda` / `mps` / `cpu`) |
331+
| `training.sim_backend` | `mujoco` | 仿真后端(`mujoco` / `motrix`) |
332+
| `training.no_sync_collection` | false | 启用异步收集模式 |
333+
| `training.env_steps_per_sync` | 1 | 同步模式下每次收集的步数 |
334+
| `training.play_only` | false | 仅回放,跳过训练 |
335+
| `training.no_play` | false | 训练后跳过自动回放 |

0 commit comments

Comments
 (0)