# Plan: JAX PPO Model-Size A/B

**Status:** Ready to execute
**Priority:** Low — 진단상 용량은 병목이 아닐 가능성이 높다. 그러나 PPO 스택에서
한 번도 측정된 적이 없어 정황증거뿐이다. 이 A/B의 목적은 **스케일링 라인을 열지,
닫을지 확정**하는 것이다.
**Background:** [docs/reports/jax-ppo-model-capacity-2026-07-12.md](../reports/jax-ppo-model-capacity-2026-07-12.md)

> 이 계획은 은퇴한 Deep CFR/PyTorch 스택용
> [model_size_experiment.md](archive/model_size_experiment.md)를 **대체하지 않는다** —
> 그쪽은 다른 스택(`input_dim=365`, `legacy/deep-cfr/configs/`) 이야기다. 서로 무관하다.

## 가설

`hidden_size=512, num_layers=3` (808K 파라미터)은 구 스택에서 복사돼 온 상속값이며
PPO에서 검증된 적이 없다. 셀프플레이 샘플:파라미터 비가 약 2,028:1이므로
용량을 키우면 **응수 품질(expert 앵커)은 오르지만, exploitability 바닥(~0.54)은
움직이지 않을 것**이다.

이 예측이 맞으면 → 병목은 용량이 아니라 셀프플레이 스킴이며, 스케일링 라인을
닫고 리그/착취 구조 쪽에 투자한다.
틀리면 (exploitability가 유의하게 내려가면) → 스케일링이 열린다.

## 실험 설계

**2점 A/B. 그리드 아님.** 그리드는 이 우선순위에 비해 과하다.

| 이름 | hidden_size | num_layers | 파라미터 |
| --- | ---: | ---: | ---: |
| `size-512x3` (baseline) | 512 | 3 | 808,033 |
| `size-1024x4` (treatment) | 1024 | 4 | 3,714,145 |

- 두 config는 `network` 블록과 `run.experiment_name`만 다르고 **나머지는
  final candidate와 byte-identical**이어야 한다. 기준 config:
  `/mnt/2tbhdd/coolrl-lost-cities-artifacts/final-cycles/2026-07-05/main_ppo_config.json`
- **같은 `run.seed`**, 순차 실행 (AGENTS.md "Comparing two runs" 규약).
  같은 GPU에서 두 학습을 병렬로 돌리지 말 것.
- 리그 **1 사이클**, 500 updates.

## 판정 기준 (중요)

**H2H로 판정하지 말 것.** 더 큰 모델이 더 작은 모델을 이기는 건 거의 자명하고,
그건 우리가 알고 싶은 게 아니다. 두 축으로만 본다:

1. **Expert 앵커** — `heuristic_expert` 상대 duplicate 평가
   (shuffle bank seed 20260704, 2,000쌍). *응수 품질*을 본다.
2. **Exploitability** — 각 체크포인트에 대해 exploiter를 새로 학습시켜 승률 측정.
   `long_random_shaping` 프로토콜(1200 updates, shaping anneal, warm start
   `random`) 하나로 충분하다.
   [diminishing-returns-2026-07-05.md](../reports/diminishing-returns-2026-07-05.md)의
   기존 측정과 **같은 프로토콜 안에서만** 비교할 것 — 프로토콜이 다르면 섞지 않는다.

### 결정 트리

| Expert 앵커 | Exploiter 승률 | 결론 | 조치 |
| --- | --- | --- | --- |
| 유의하게 상승 | **변화 없음** (~0.54 유지) | **예측대로.** 용량은 병목이 아니다 | 스케일링 라인 종료. 리그/착취 구조로 이동. 1024×4를 default로 올릴지는 비용 대비 선택 사항 |
| 유의하게 상승 | **유의하게 하락** | 가설 기각. 용량이 실제로 제약이었다 | `network` default를 1024×4로 올리고, 2048×4까지 한 점 더 확장 |
| 변화 없음 | 변화 없음 | 용량 무관 확정 | 스케일링 라인 종료 |
| 하락 | — | 최적화 문제 (LR/KL 등이 큰 모델에 안 맞음) | default 유지. 스케일 재시도 전에 하이퍼파라미터 점검 |

"유의하게"는 Wilson CI(승률) / score CI(점수차) 비중첩 기준. 기존 리포트들이
쓰는 것과 동일하다.

## 비용

리포트 기준 리그 1사이클 ≈ 1.5시간 GPU (512×3). 1024×4는 파라미터 4.6배이나
병목이 롤아웃(엔진 시뮬)이라 학습 시간이 4.6배가 되지는 않는다.
exploiter 학습이 별도로 붙는다.

`.compute.lock`을 잡고 돌릴 것 (AGENTS.md "Compute Lock"):

```bash
flock -n .compute.lock <train command>
```

## Non-goals

- 그리드 스윕(768×4, 1536×8 등) — 2점으로 충분하다. 결과가 애매할 때만 확장.
- 아키텍처 변경 (residual, transformer, per-color 공유 인코더 등) — 별도 주제.
- 인코딩 변경 (`OBS_DIM=454` 고정).
- 하이퍼파라미터 동시 변경 — 한 번에 하나만 바꾼다.

## Definition of done

산출될 파일 (아직 존재하지 않음):

```text
configs/jax_ppo/size-512x3.yaml
configs/jax_ppo/size-1024x4.yaml
docs/reports/jax-ppo-model-size-ab-<YYYY-MM-DD>.md
```

- [ ] 위 두 config 추가 (final candidate config 기준, `network` /
      `run.experiment_name`만 차이)
- [ ] 두 학습 순차 실행, 같은 seed, `.compute.lock` 사용
- [ ] 두 체크포인트 expert 앵커 duplicate 평가
- [ ] 두 체크포인트 exploiter 학습 + 승률 측정 (`long_random_shaping`)
- [ ] 결과표 + 결정 트리 적용 결과를 위 dated 리포트에 기록
- [ ] 결정 트리에 따라: `network` default 갱신 **또는** 스케일링 라인 종료를 문서화
