Lee93whut commited on
Commit ·
b14b412
1
Parent(s): 18e19aa
docs(round4): finalize R4 Double DQN results — 78% Holdout, Grid-SPL clarification
Browse files- Fix Double DQN citation: van Hasselt et al. 2015 → 2016 AAAI
- Rename SPL → Grid-SPL, document wall-hit exclusion and HabitatAI incompatibility
- README: update success rate 74%→78%, add ±8–9pp CI disclaimer
- Rewrite Anti-Loop section: revisit_penalty deprecated (Markov violation),
replaced by 4th-channel visited_map; fix distance_shaping γ=1 approximation note
- hyperparameter_study: mark revisit_penalty as deprecated, fill R4 final metrics
- README.md +14 -25
- docs/hyperparameter_study.md +4 -4
- src/train.py +6 -4
README.md
CHANGED
|
@@ -10,7 +10,7 @@ license: mit
|
|
| 10 |
|
| 11 |
# RL Maze Navigator
|
| 12 |
|
| 13 |
-
### Benchmarking DQN variants on procedurally-generated mazes · SPL evaluation ·
|
| 14 |
|
| 15 |
[](https://github.com/Lee93whut/rl-maze/actions/workflows/test.yml)
|
| 16 |
[](https://www.python.org/)
|
|
@@ -22,22 +22,24 @@ license: mit
|
|
| 22 |
|
| 23 |
---
|
| 24 |
|
| 25 |
-
## 算法对比结果(Round
|
| 26 |
|
| 27 |
> Holdout 评估:100 张训练中**从未见过**的独立地图(seed+200000),ε=0 贪心推理。
|
| 28 |
> 指标:[SPL](https://arxiv.org/abs/1807.06757)(Anderson et al. 2018,导航领域标准评估指标)。
|
| 29 |
-
> Round
|
| 30 |
|
| 31 |
| 算法 | 成功率 | SPL | 峰值成功率 | 收敛 Episode |
|
| 32 |
|------|:------:|:---:|:---------:|:-----------:|
|
| 33 |
-
| **Double DQN** (
|
| 34 |
| Double DQN (R2) | 64.0% | 0.633 | 74.0% | 3300 |
|
| 35 |
| Vanilla DQN (R1) | 56.0% | 0.559 | — | 1921 |
|
| 36 |
| Double DQN (R1) | 61.0% | 0.605 | — | 948 |
|
| 37 |
| Dueling DQN (R1) | 45.0% | 0.445 | — | 759 |
|
| 38 |
| Double + Dueling (R1) | 43.0% | 0.425 | — | 1843 |
|
| 39 |
|
| 40 |
-
> R1 为随机起终点初版超参(训练量不足,供参考);R2/R3 为逐轮超参消融后的结果。完整演进见 [docs/experiment_log.md](docs/experiment_log.md)。
|
|
|
|
|
|
|
| 41 |
|
| 42 |
**R2 → R3 成功率对比(Double DQN)**:
|
| 43 |
|
|
@@ -96,29 +98,15 @@ if self.distance_shaping_alpha != 0.0:
|
|
| 96 |
reward += self.distance_shaping_alpha * (dist_before - dist_after)
|
| 97 |
```
|
| 98 |
|
| 99 |
-
撞墙步位置不变,不触发 shaping,避免撞墙获得零 shaping 奖励误导策略。`α=0.5` 使 shaping 幅度为基础奖励(-1)的 50%,提供方向感但不压过终点奖励(+100)。符合 Ng et al. (1999) 的势函数 shaping 理论,保证
|
| 100 |
|
| 101 |
-
### 5. Anti-Loop
|
| 102 |
|
| 103 |
-
|
| 104 |
|
| 105 |
-
```
|
| 106 |
-
if revisit_penalty != 0.0 and not info.get("hit_wall", False):
|
| 107 |
-
visit_cnt = ep_visited.get(cur_pos, 0)
|
| 108 |
-
if visit_cnt > 0:
|
| 109 |
-
reward += revisit_penalty * visit_cnt # 访问次数越多,惩罚越重
|
| 110 |
-
ep_visited[cur_pos] = visit_cnt + 1
|
| 111 |
-
```
|
| 112 |
-
|
| 113 |
-
**推理阶段**(Demo):对高频重复访问的格子施加 Q 值惩罚,作为额外安全网:
|
| 114 |
-
|
| 115 |
-
```python
|
| 116 |
-
visit_cnt = visited_count.get(cur_pos, 0)
|
| 117 |
-
if visit_cnt >= 2:
|
| 118 |
-
q_values[action] -= 3.0 * visit_cnt
|
| 119 |
-
```
|
| 120 |
|
| 121 |
-
|
| 122 |
|
| 123 |
### 6. BFS 连通性保证
|
| 124 |
|
|
@@ -262,7 +250,8 @@ rl-maze/
|
|
| 262 |
|------|---------|:--------------:|:---:|
|
| 263 |
| Round 1 | 初版(`ep=2000`, `decay=0.995`) | 61.0% | 0.605 |
|
| 264 |
| Round 2 | `ep=6000`, `decay=0.9985` | 64.0% | 0.633 |
|
| 265 |
-
| Round 3 | `buffer=80k`, `target_freq=1500`, `shaping=0.5` |
|
|
|
|
| 266 |
|
| 267 |
完整超参诊断与论文依据详见 [`docs/hyperparameter_study.md`](docs/hyperparameter_study.md)。
|
| 268 |
|
|
|
|
| 10 |
|
| 11 |
# RL Maze Navigator
|
| 12 |
|
| 13 |
+
### Benchmarking DQN variants on procedurally-generated mazes · SPL evaluation · 78% Holdout success rate
|
| 14 |
|
| 15 |
[](https://github.com/Lee93whut/rl-maze/actions/workflows/test.yml)
|
| 16 |
[](https://www.python.org/)
|
|
|
|
| 22 |
|
| 23 |
---
|
| 24 |
|
| 25 |
+
## 算法对比结果(Round 4,最终)
|
| 26 |
|
| 27 |
> Holdout 评估:100 张训练中**从未见过**的独立地图(seed+200000),ε=0 贪心推理。
|
| 28 |
> 指标:[SPL](https://arxiv.org/abs/1807.06757)(Anderson et al. 2018,导航领域标准评估指标)。
|
| 29 |
+
> Round 4 最终超参:`buffer=80000`、`target_update_freq=1500`、`distance_shaping_alpha=0.5`、visited_map 第四通道 + EVAL-based checkpoint,Double DQN。
|
| 30 |
|
| 31 |
| 算法 | 成功率 | SPL | 峰值成功率 | 收敛 Episode |
|
| 32 |
|------|:------:|:---:|:---------:|:-----------:|
|
| 33 |
+
| **Double DQN** (R4) | **78.0%** | **0.773** | **84.0%** | 3750 |
|
| 34 |
| Double DQN (R2) | 64.0% | 0.633 | 74.0% | 3300 |
|
| 35 |
| Vanilla DQN (R1) | 56.0% | 0.559 | — | 1921 |
|
| 36 |
| Double DQN (R1) | 61.0% | 0.605 | — | 948 |
|
| 37 |
| Dueling DQN (R1) | 45.0% | 0.445 | — | 759 |
|
| 38 |
| Double + Dueling (R1) | 43.0% | 0.425 | — | 1843 |
|
| 39 |
|
| 40 |
+
> R1 为随机起终点初版超参(训练量不足,供参考);R2/R3/R4 为逐轮超参消融后的结果。完整演进见 [docs/experiment_log.md](docs/experiment_log.md)。
|
| 41 |
+
>
|
| 42 |
+
> ⚠️ **统计说明**:Holdout 评估使用 100 张地图,单次跑点估计,95% CI ≈ ±8–9pp。相邻轮次间约 10pp 的提升处于置信区间边缘,不保证统计显著性。严格对比需多次独立运行取均值±标准差。
|
| 43 |
|
| 44 |
**R2 → R3 成功率对比(Double DQN)**:
|
| 45 |
|
|
|
|
| 98 |
reward += self.distance_shaping_alpha * (dist_before - dist_after)
|
| 99 |
```
|
| 100 |
|
| 101 |
+
撞墙步位置不变,不触发 shaping,避免撞墙获得零 shaping 奖励误导策略。`α=0.5` 使 shaping 幅度为基础奖励(-1)的 50%,提供方向感但不压过终点奖励(+100)。近似符合 Ng et al. (1999) 的势函数 shaping 理论。严格形式为 $r' = r + \gamma\Phi(s') - \Phi(s)$,代入 $\Phi(s)=-\alpha d$ 得 $\alpha d_{\text{before}} - \gamma\alpha d_{\text{after}}$;代码实现省略了 $\gamma$(即 $\gamma=1$ 近似),在 $\gamma=0.99$、迷宫路径较短的条件下误差约 1%,实践影响可忽略,但不严格保证策略不变性。
|
| 102 |
|
| 103 |
+
### 5. Anti-Loop:visited_map 第四通道
|
| 104 |
|
| 105 |
+
Round 3 曾使用 `revisit_penalty` 对重复访问格子施加递进奖励惩罚,但在 Round 4 中被诊断为**理论错误并彻底弃用**:该方案依赖 Episode 内状态(访问计数),违反马尔可夫性,导致相同状态对应不同 TD 目标,Q 值估计被系统性污染(experiment_log.md P9)。
|
| 106 |
|
| 107 |
+
**现行方案(Round 4)**:观测张量 `(4, N, N)` 第四通道为二值访问图(1=本 Episode 内到达过,0=未到达),将历史信息直接编码进状态,保持马尔可夫性。推理侧(`app.py`)执行裸 argmax,无需额外 Q 值修正。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
|
| 109 |
+
> 设计备注:曾考虑"访问次数归一化"(`count / max_steps`),但在 `max_steps=200` 的迷宫任务中,计数信号的高频区间几乎无训练样本覆盖,归一化后数值分布极度不均匀。二值图更简洁,Q 函数真正需要的信息是"去过/没去过"而非精确次数,与 Markov 状态表达的最小充分性原则一致。
|
| 110 |
|
| 111 |
### 6. BFS 连通性保证
|
| 112 |
|
|
|
|
| 250 |
|------|---------|:--------------:|:---:|
|
| 251 |
| Round 1 | 初版(`ep=2000`, `decay=0.995`) | 61.0% | 0.605 |
|
| 252 |
| Round 2 | `ep=6000`, `decay=0.9985` | 64.0% | 0.633 |
|
| 253 |
+
| Round 3 | `buffer=80k`, `target_freq=1500`, `shaping=0.5` | 74.0% | 0.735 |
|
| 254 |
+
| **Round 4** | visited_map 4th channel + EVAL-based checkpoint + terminated-only TD mask | **78.0%** | **0.773** |
|
| 255 |
|
| 256 |
完整超参诊断与论文依据详见 [`docs/hyperparameter_study.md`](docs/hyperparameter_study.md)。
|
| 257 |
|
docs/hyperparameter_study.md
CHANGED
|
@@ -13,8 +13,8 @@
|
|
| 13 |
| `epsilon_decay` | 0.995 | **0.9985** | 0.9985 | 0.9985 | van Hasselt et al. (2016):ε 应在训练期 10–25% 内衰减完;R1 ep≈800 触底,后 1200 ep 样本单一 |
|
| 14 |
| `buffer_capacity` | 20000 | 20000 | **80000** | 80000 | Lin (1992):ER 核心价值是保留稀有样本;Mnih et al. (2015) 原版 1M;20k≈250 局,成功样本快速消失 |
|
| 15 |
| `target_update_freq` | 500 | 500 | **1500** | 1500 | Mnih et al. (2015) 原版 10000 步;固定目标 $\theta^-$ 保证 TD 收敛性,过频同步等价于"移动靶"监督学习 |
|
| 16 |
-
| `distance_shaping_alpha` | 0 | 0 | **0.5** | 0.5 | Ng et al. (1999):势函数 shaping $r' = r + \gamma\Phi(s') - \Phi(s)$ 不
|
| 17 |
-
| `revisit_penalty` | 0 | 0 | 0 |
|
| 18 |
| checkpoint 保存策略 | 训练奖励触发 | 训练奖励触发 | 训练奖励触发 | **EVAL 最优触发** | R3 实测:训练奖励与 EVAL 成功率时序不对齐,导致 Holdout 74% vs EVAL 峰值 84%,差 10pp |
|
| 19 |
|
| 20 |
---
|
|
@@ -26,7 +26,7 @@
|
|
| 26 |
| R1 | 基线(随机起终点初版) | 61.0% | — | 诊断 P1(训练量)+ P2(探索)+ P3(buffer)+ P4(target)|
|
| 27 |
| R2 | `ep=6000` + `decay=0.9985` | 64.0% | 74.0% | P1/P2 消除;振荡周期 400–500 ep(P3 定量确认)|
|
| 28 |
| R3 | `buffer=80k` + `target=1500` + `shaping=0.5` | **74.0%** | **84.0%** | 峰值突破 80%;Holdout 低于峰值 10pp(P6:保存策略错位)|
|
| 29 |
-
| R4 | EVAL
|
| 30 |
|
| 31 |
---
|
| 32 |
|
|
@@ -36,7 +36,7 @@ Henderson et al. (2018) 实证结论:**RL 超参敏感度远高于监督学习
|
|
| 36 |
|
| 37 |
- R2:仅修复 P1+P2,验证收敛形状
|
| 38 |
- R3:同时修复 P3+P4+P5,验证振荡是否消除
|
| 39 |
-
- R4:修复保存策略(P6)+
|
| 40 |
|
| 41 |
---
|
| 42 |
|
|
|
|
| 13 |
| `epsilon_decay` | 0.995 | **0.9985** | 0.9985 | 0.9985 | van Hasselt et al. (2016):ε 应在训练期 10–25% 内衰减完;R1 ep≈800 触底,后 1200 ep 样本单一 |
|
| 14 |
| `buffer_capacity` | 20000 | 20000 | **80000** | 80000 | Lin (1992):ER 核心价值是保留稀有样本;Mnih et al. (2015) 原版 1M;20k≈250 局,成功样本快速消失 |
|
| 15 |
| `target_update_freq` | 500 | 500 | **1500** | 1500 | Mnih et al. (2015) 原版 10000 步;固定目标 $\theta^-$ 保证 TD 收敛性,过频同步等价于"移动靶"监督学习 |
|
| 16 |
+
| `distance_shaping_alpha` | 0 | 0 | **0.5** | 0.5 | Ng et al. (1999):势函数 shaping 标准形式 $r' = r + \gamma\Phi(s') - \Phi(s)$;代码实现省略 $\gamma$($\gamma=1$ 近似),在 $\gamma=0.99$ 下误差约 1%,实践可忽略,但不严格满足策略不变性定理 |
|
| 17 |
+
| `revisit_penalty` | 0 | 0 | 0 | ~~-1.0~~ → **弃用** | Round 4 实验后因违反马尔可夫性放弃,改用 visited_map 第四通道编码访问历史 |
|
| 18 |
| checkpoint 保存策略 | 训练奖励触发 | 训练奖励触发 | 训练奖励触发 | **EVAL 最优触发** | R3 实测:训练奖励与 EVAL 成功率时序不对齐,导致 Holdout 74% vs EVAL 峰值 84%,差 10pp |
|
| 19 |
|
| 20 |
---
|
|
|
|
| 26 |
| R1 | 基线(随机起终点初版) | 61.0% | — | 诊断 P1(训练量)+ P2(探索)+ P3(buffer)+ P4(target)|
|
| 27 |
| R2 | `ep=6000` + `decay=0.9985` | 64.0% | 74.0% | P1/P2 消除;振荡周期 400–500 ep(P3 定量确认)|
|
| 28 |
| R3 | `buffer=80k` + `target=1500` + `shaping=0.5` | **74.0%** | **84.0%** | 峰值突破 80%;Holdout 低于峰值 10pp(P6:保存策略错位)|
|
| 29 |
+
| R4 | EVAL-based checkpoint + visited_map 第四通道(revisit_penalty 因违反马尔可夫性弃用) | **78.0%** | **0.773** | |
|
| 30 |
|
| 31 |
---
|
| 32 |
|
|
|
|
| 36 |
|
| 37 |
- R2:仅修复 P1+P2,验证收敛形状
|
| 38 |
- R3:同时修复 P3+P4+P5,验证振荡是否消除
|
| 39 |
+
- R4:修复保存策略(P6)+ visited_map 第四通道(revisit_penalty 已弃用),Holdout 78.0%
|
| 40 |
|
| 41 |
---
|
| 42 |
|
src/train.py
CHANGED
|
@@ -148,7 +148,7 @@ def optimize_model(
|
|
| 148 |
if use_double:
|
| 149 |
# Double DQN:policy_net 选动作,target_net 估值
|
| 150 |
# 解耦"选哪个动作"与"该动作值多少",消除 max 算子的过估计偏差
|
| 151 |
-
# (van Hasselt et al.,
|
| 152 |
next_acts = policy_net(next_states).argmax(dim=1, keepdim=True) # (B,1)
|
| 153 |
q_next_max = target_net(next_states).gather(1, next_acts).squeeze(1)
|
| 154 |
else:
|
|
@@ -246,9 +246,11 @@ def run_evaluation(
|
|
| 246 |
使 TensorBoard 曲线的波动能真实反映 AI 能力变化,而非地图难度变化。
|
| 247 |
* random_start_goal=True 时,每张地图用派生种子从自由格中随机选取起终点,
|
| 248 |
与训练分布保持一致,避免 train/test 分布偏差。
|
| 249 |
-
* SPL(
|
| 250 |
SPL = (1/N) × Σ S_i × ℓ*_i / max(ℓ*_i, p_i)
|
| 251 |
-
其中
|
|
|
|
|
|
|
| 252 |
失败局 S_i=0,整项贡献 0,与主流导航论文定义一致。
|
| 253 |
"""
|
| 254 |
policy_net.eval()
|
|
@@ -312,7 +314,7 @@ def run_evaluation(
|
|
| 312 |
# 成功:S_i=1,贡献 ℓ*_i / max(ℓ*_i, p_i)
|
| 313 |
# 失败:S_i=0,整项贡献 0.0
|
| 314 |
hit_wall_count = info.get("hit_wall_count", 0)
|
| 315 |
-
actual_move_steps = ai_steps - hit_wall_count # p_i:
|
| 316 |
|
| 317 |
if success and actual_move_steps > 0:
|
| 318 |
bfs_result = _bfs(
|
|
|
|
| 148 |
if use_double:
|
| 149 |
# Double DQN:policy_net 选动作,target_net 估值
|
| 150 |
# 解耦"选哪个动作"与"该动作值多少",消除 max 算子的过估计偏差
|
| 151 |
+
# (van Hasselt et al., 2016, AAAI)
|
| 152 |
next_acts = policy_net(next_states).argmax(dim=1, keepdim=True) # (B,1)
|
| 153 |
q_next_max = target_net(next_states).gather(1, next_acts).squeeze(1)
|
| 154 |
else:
|
|
|
|
| 246 |
使 TensorBoard 曲线的波动能真实反映 AI 能力变化,而非地图难度变化。
|
| 247 |
* random_start_goal=True 时,每张地图用派生种子从自由格中随机选取起终点,
|
| 248 |
与训练分布保持一致,避免 train/test 分布偏差。
|
| 249 |
+
* Grid-SPL(改自 Anderson et al. 2018):
|
| 250 |
SPL = (1/N) × Σ S_i × ℓ*_i / max(ℓ*_i, p_i)
|
| 251 |
+
其中 p_i 为实际**移动**步数(撞墙原地步不计入),
|
| 252 |
+
与标准 SPL 的区别:排除撞墙步使 p_i 偏小、SPL 偏高,
|
| 253 |
+
不可与 HabitatAI 等连续导航 Benchmark 直接比较。
|
| 254 |
失败局 S_i=0,整项贡献 0,与主流导航论文定义一致。
|
| 255 |
"""
|
| 256 |
policy_net.eval()
|
|
|
|
| 314 |
# 成功:S_i=1,贡献 ℓ*_i / max(ℓ*_i, p_i)
|
| 315 |
# 失败:S_i=0,整项贡献 0.0
|
| 316 |
hit_wall_count = info.get("hit_wall_count", 0)
|
| 317 |
+
actual_move_steps = ai_steps - hit_wall_count # p_i:仅计移动步(Grid-SPL 变体)
|
| 318 |
|
| 319 |
if success and actual_move_steps > 0:
|
| 320 |
bfs_result = _bfs(
|