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

Files changed (3) hide show
  1. README.md +14 -25
  2. docs/hyperparameter_study.md +4 -4
  3. 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 · 74% Holdout success rate
14
 
15
  [![CI](https://github.com/Lee93whut/rl-maze/actions/workflows/test.yml/badge.svg)](https://github.com/Lee93whut/rl-maze/actions/workflows/test.yml)
16
  [![Python](https://img.shields.io/badge/python-3.10-blue)](https://www.python.org/)
@@ -22,22 +22,24 @@ license: mit
22
 
23
  ---
24
 
25
- ## 算法对比结果(Round 3,最终)
26
 
27
  > Holdout 评估:100 张训练中**从未见过**的独立地图(seed+200000),ε=0 贪心推理。
28
  > 指标:[SPL](https://arxiv.org/abs/1807.06757)(Anderson et al. 2018,导航领域标准评估指标)。
29
- > Round 3 超参:`buffer=80000`、`target_update_freq=1500`、`distance_shaping_alpha=0.5`,Double DQN 单算法验证
30
 
31
  | 算法 | 成功率 | SPL | 峰值成功率 | 收敛 Episode |
32
  |------|:------:|:---:|:---------:|:-----------:|
33
- | **Double DQN** (R3) | **74.0%** | **0.735** | **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 为逐轮超参消融后的结果。完整演进见 [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
- **训练阶段**:对重复访问格子施加递进奖励惩罚,导 Q 函数主动规避循环路径:
104
 
105
- ```python
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
- 两层机制职责分离训练层修改 reward shaping 使 Q 函数内化回避循环;推理层直接修Q 值作为兜底,不影响训练
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` | **74.0%** | **0.735** |
 
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
  [![CI](https://github.com/Lee93whut/rl-maze/actions/workflows/test.yml/badge.svg)](https://github.com/Lee93whut/rl-maze/actions/workflows/test.yml)
16
  [![Python](https://img.shields.io/badge/python-3.10-blue)](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 | **-1.0** | 训练时对重复访问格子施加递进惩罚引导 Q 函数内化回避循环路径 |
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 触发保存 + `revisit_penalty=-1.0` | 进行中 | | 预期 Holdout≈80–84%(消除 10pp 时序错位损失)|
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)+ revisit penalty,验证 Holdout 与峰值对齐
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., 2015)
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(Success-weighted Path Length,Anderson et al. 2018):
250
  SPL = (1/N) × Σ S_i × ℓ*_i / max(ℓ*_i, p_i)
251
- 其中 S_i∈{0,1} 为成功标志,ℓ*_i 为 BFS 最短步数,p_i 为实际移动步数
 
 
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(