# Vardist Transfer Learning — 历史归档分析

> **历史归档 / ARCHIVED TRANSFER ANALYSIS**
> 本文记录 2026-07-07 的 `_tr` 迁移实验及当时诊断，保留其科学内容作为历史记录；它不描述当前 active scratch workflow，不是模型发布或当前验证声明。当前规范见 `README.md`、`TRAIN_PIPELINE.md` 与 `DESIGN_DECISIONS.md`。
> 当前归档位置：迁移脚本在 `archive/scripts_deprecated/vardist_transfer.sh`；保留的 `_tr` 日志、校准副本和 metadata 在 `archive/transfer_instability/kar_d*_tr_seed*/`；旧校准在 `archive/calibrations_deprecated/kar_d*_tr/`。active case ID 不带 `_sc`，`_tr` 仅用于这些历史归档。

> 日期: 2026-07-07  
> 实验: 改变上游扰动圆柱尺寸 (0.75L / 1.5L / 2.0L)，从 re100 baseline 进行 transfer learning  
> 所有实验使用相同超参数和物理配置（仅 dist_radius 不同）

---

## 1. 实验配置总览

### 1.1 共享超参数

| 参数 | 值 |
|------|-----|
| PPO n_steps | 2048 |
| PPO batch_size | 64 |
| PPO n_epochs | 10 |
| Learning rate | 3e-4 |
| Gamma | 0.995 |
| Policy net_arch | [64, 64] |
| Activation | sin |
| Symmetry augmentation | prob=0.5 |
| Episode 数 | 200 (transfer) |
| 基座模型 | re100_karman_seed44 或 seed45 (500ep from scratch, best ≈ 0.92) |

### 1.2 校准参数差异

| 参数 | d075 (0.75L) | re100 (1.0L) | d15 (1.5L) | d2 (2.0L) |
|------|:-----------:|:------------:|:----------:|:---------:|
| **FORCE_SCALE** | 0.0018 | 0.0024 | 0.0036 | 0.0046 |
| **SENS_SCALE** | 0.84 | 0.75 | 0.75 | 0.77 |
| **dtw_norm_scale** | 0.146 | 0.204 | 0.307 | 0.393 |
| **SIM_BP[1]** (zero rot) | 0.25 | 0.32 | 0.30 | 0.30 |
| **SIM_BP[2]** (ref rot) | 0.79 | 0.82 | 0.65 | 0.65 |
| **SIM_BP gap** | **0.54** | 0.50 | **0.35** | **0.35** |
| **SIM_BP 来源** | 实测 | 实测 | generic 兜底 | generic 兜底 |
| **K_CD / K_CL** | 50/100 | 50/100 | 50/100 | 50/100 |

> **关键**: d075 的 SIM_BP 使用了实测值 (gap=0.54)，而 d15 和 d2 因为 `spread<0.10` 或 `better_sim<0.5` 触发了 calibrate.py 中的 generic fallback (gap=0.35)。

---

## 2. 训练结果

### 2.1 最终指标

| Case | Best Reward | Ep 1 Reward | Ep 1 r_sim | Ep 1 r_cd | 走势质量 |
|------|:-----------:|:-----------:|:----------:|:---------:|:--------:|
| **d15 (1.5L)** | **0.7265** (Ep 198) | 0.570 | 0.748 | 0.650 | ✅ 稳定单调上升 |
| **d2 (2.0L)** | **0.4696** (Ep 2!) | 0.301 | 0.455 | 0.288 | ❌ Ep 2 peak 后持续退化 |
| **d075 (0.75L)** | **0.4175** (Ep 153) | 0.023 | 0.053 | 0.012 | ❌ 持续 peak-crash 震荡 |

### 2.2 对比基线：跨 Re transfer (来自同一基座模型)

| Case | Best Reward | 走势 |
|------|:-----------:|:----:|
| re60 transfer | **0.724** | ✅ 稳定上升 |
| re200 transfer | **0.499** | ⚠️ 缓慢但稳定 |

### 2.3 Reward 走势图 (定性)

```
d15:  ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄  ───→ 0.727  (稳步爬坡)
d2:   ▄▀▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄  ───→ 0.470  (Ep2 昙花一现，后再未超越)
d075: ▁▁▁▁▂▁▂▁▂▁▂▁▁▂▁▁▁▂  ───→ 0.418  (震荡不止，末班 0.053)
```

---

## 3. 诊断分析

### 3.1 ✅ d15 (1.5L) — 成功案例

**为什么成功：**
1. 上游圆柱放大 → 1.0L 的专家策略"不够用但方向对"，可以在此基础上升级
2. SIM_BP 使用 generic mapping (gap=0.35)，reward 梯度均匀且有意义
3. Ep 1 r_sim=0.748 说明初始策略在 1.5L 尾流下已经有相当不错的信号重建能力
4. r_cd 从 0.65 涨到 0.92，r_cl 从 0.27 涨到 0.48，三个 reward 分量协作上升

### 3.2 ❌ d075 (0.75L) — 最差案例

**根因 1 — SIM_BP 映射问题 (最主要)**

d075 是唯一一个使用实测 SIM_BP 的 case。测得的 zero-rotation similarity=0.25，reference rotation=0.79，gap=0.54。

这意味着 reward 映射中 SIM_VAL 从 0.2→0.5 覆盖了 0.54 的真实 similarity 跨度，梯度被显著摊薄。当 PPO 在 reward 空间中观测到的改进信号极小时，policy 更新方向近乎随机——这完美解释了反复的 peak-crash 行为。

**根因 2 — 物理域不匹配**

0.75L 扰动圆柱产生的卡门涡街更弱更窄（FORCE_SCALE=0.0018，比 1.0L 低 25%）。而 pinball 圆柱仍是 1.0L 固定尺寸，它们的旋转对弱流场的控制可能"过强"——类似于用力关门但门很轻。1.0L 的专家策略不适用于小扰动场景。

**根因 3 — 基座策略已接近局部最优**

reference rotation 在 0.75L 场景下已给出 similarity=0.79（接近 re100 baseline 的 0.82）。DRL 要超越一个已经很接近 1.0L baseline 水平的开环策略，且 reward 梯度又被摊薄，双重不利。

**证据 — Ep 1 collapse**

Ep 1 reward=0.023，r_cd=0.012，r_sim=0.053。这说明 1.0L 的 expert policy 在 0.75L 场景下几乎完全不适用，不是在微调而是在重新学习。

### 3.3 ❌ d2 (2.0L) — 早期 peak 后退化

**根因 1 — 几何差异导致初始 mismatch**

2.0L 圆柱是 1.0L 的两倍，FORCE_SCALE=0.0046（近乎翻倍）。Ep 1 r_sim=0.455（vs d15 的 0.748），说明在如此大差异下 transfer 效果甚微，几乎从接近 scratch 的状态开始。

**根因 2 — Ep 2 的 0.470 是偶发性好运**

```
Ep  2: 0.470 BEST
Ep 50: 0.138
Ep 125: 0.299 (轻微恢复)
Ep 200: 0.246
```

在独占 GPU 又跑了 150ep 后，从未超越 Ep 2 的 0.470。"早期 peak 后持续退化"的模式说明 Ep 2 的高 reward 是一次偶然发现的好策略，PPO 之后的探索却撞进了 reward 更低的方向且无力返回。

---

## 4. Ep 1 Metrics 作为先行指标的发现

| Case | Ep 1 r_sim | Ep 1 r_cd | 最终 Best | Transfer 成功? |
|------|:----------:|:---------:|:---------:|:--------------:|
| d15 | 0.748 | 0.650 | 0.727 | ✅ |
| d2 | 0.455 | 0.288 | 0.470 | ❌ |
| d075 | 0.053 | 0.012 | 0.417 | ❌ |
| re60 | 0.236 | 0.793 | 0.724 | ✅ |

**推论**: Ep 1 r_sim 是预测 transfer 能否成功的强信号。r_sim≥0.5 的 case 最终都达到了 0.7+，r_sim<0.5 的 case 均未超过 0.47。例外是 re60 —— 虽然 r_sim 不高 (0.236)，但几何不变，PPO 可以快速"调回"相似度。

---

## 5. 改进建议

### 5.1 针对 d075 (0.75L)

| 优先级 | 方案 | 原理 |
|:------:|------|------|
| **P0** | 强制使用 generic SIM_BP mapping | 消除 SIM_BP gap=0.54 导致的平坦梯度问题 (即修改 calibrate.py 或手动替换 calibration.json 中 SIM_BP 为 [0, 0.30, 0.65, 0.79, 0.89, 1.0]) |
| **P1** | 降低 learning rate 至 1e-4 | 减少 PPO 在高方差环境中的 over-shoot，缓解 peak-crash |
| **P2** | 增加 episode 数至 500 | 当前 200ep 明显不足以收敛 |
| **P3** | 不 transfer，from scratch | 因为 Ep 1 已证明 re100 policy 对 d075 高度不适配 (reward=0.023)，scratch 训练可能更稳定 |

### 5.2 针对 d2 (2.0L)

| 优先级 | 方案 | 原理 |
|:------:|------|------|
| **P0** | 不 transfer，from scratch + 500ep | Ep 1 初始 mismatch 太大，从头学习可能更高效 |
| **P1** | transfer 但降低 lr=1e-4 + 更多 episode | 如果仍用 transfer，更保守的更新速率有助于保持策略稳定 |
| **P2** | 加强 symmetry augmentation (prob=0.7) | 2.0L 尾流更宽，采样空间更大，更强的对称正则化可能帮助泛化 |
| **P3** | 调整 K_CD/K_CL 以匹配 2.0L 的力尺度 | FORCE_SCALE 翻倍但 K 值不变，reward 的分量权重可能已不平衡 |

### 5.3 通用改进

| 优先级 | 方案 | 适用范围 |
|:------:|------|---------|
| **P0** | 给 calibrate.py 的 generic SIM_BP 兜底条件加宽阈值 | 所有 future case，避免 d075 式的 SIM_BP gap 问题再次出现 |
| **P1** | 观察 Ep 1 metrics 作为 transfer 可行性的先行判断 | 如果 Ep 1 r_sim<0.5，建议直接 from scratch 而非 transfer |
| **P2** | 对不同直径使用不同的 K_CD/K_CL 缩放 | FORCE_SCALE 变化时，reward 中 drag/lift 贡献的比例可能需要调整 |
| **P3** | 启用 VecNormalize reward normalization | 当前 `norm_reward=False`，对小 reward 场景可能会让 PPO 的信号强度不足 |

---

## 6. 关键文件索引

| 文件 | 路径 |
|------|------|
| 训练脚本 | `train_karman.py` |
| 环境 | `env_karman.py` |
| 校准脚本 | `calibrate.py` (generic SIM_BP 兜底逻辑在第 526-535 行) |
| Transfer 启动脚本 | `archive/scripts_deprecated/vardist_transfer.sh` |
| d075 校准 | `archive/transfer_instability/kar_d075_tr_seed44/calibration.json` |
| d15 校准 | `archive/transfer_instability/kar_d15_tr_seed45/calibration.json` |
| d2 校准 | `archive/transfer_instability/kar_d2_tr_seed45/calibration.json` |
| re100 基线校准 | `calibrations/re100/calibration.json` |
| d075 训练日志 | `archive/transfer_instability/kar_d075_tr_seed44/train.log` |
| d15 训练日志 | `archive/transfer_instability/kar_d15_tr_seed45/train.log` |
| d2 训练日志 | `archive/transfer_instability/kar_d2_tr_seed45/train.log` |
