둘 다 아닙니다. 시간축으로는 KL 학습이 추론(수리) 전에 오프라인으로 끝나고 매퍼 θ만 넘어갑니다. 그런데 학습 forward 안에서는 수리가 별도 단계가 아니라 층마다 끼어들어 있습니다 — 층 ℓ의 어텐션이 K/V를 읽는 순간, S 자리만 "이 패스에서 방금 계산한 값"으로 갈아 끼우는 식입니다. 그래서 "전/후"가 아니라 "층 단위로 교차(interleaved)"가 정확한 답입니다.
토이 설정: 프리픽스 T=16, S={2,3,9,13} (ρ≈25%로 과장), 꼬리 R=4, 층 4개. 팔을 바꾸고 층을 넘겨 보세요.
| 팔 | run_readside.py 인자 | full_prefix_read 안에서 층 ℓ마다 |
|---|---|---|
| plain KL | --mode kl (preserve_frac 0) | k = cache.layers[ℓ].keys — 모든 u가 번역값 |
| oracle | --preserve-rule spec --preserve-source native | k = where(mask, native_k, k) — S는 상수(기울기 없음) |
| consistent | --preserve-rule spec --preserve-source self | ks_ = k_norm(k_proj(input_layernorm(h_in))) → k = where(mask, ks_, k). detach 없음 |
| 추론 ICR | RECOV_SPEC_DIRECT=1 (+RUNS, MERGE) | S 토큰만 forward. 어텐션 op이 S 슬롯에 K/V를 쓴 뒤 위치 <u 전체를 읽음(seq_len=pos+1, 원래 슬롯) |
왜 self가 추론과 "정확히 같은가": S 토큰 u의 K/V는 h(ℓ)u에서 나오고, h(ℓ)u는 위치 <u의 K/V(비-S는 번역값, S는 같은 층에서 방금 쓴 self 값)만 읽어 만들어진다. 학습에서 비-S 위치도 질의로 돈다는 점은 다르지만, 비-S 위치의 hidden은 어디에도 K/V로 써지지 않으므로 S의 값에 영향이 없다. 유일한 차이는 학습에서 마스크가 문서마다 spec_select_positions로 새로 뽑히는 것과, 손실이 꼬리 R에서 잰다는 것.