Files
frankenstallm/reports/2026-03-08_ORPO_SWEEP_DEBUG_REPORT.md
ModelHub XC d4abdb70fa 初始化项目,由ModelHub XC社区提供模型
Model: pathcosmos/frankenstallm
Source: Original Platform
2026-07-14 04:21:16 +08:00

7.2 KiB
Raw Permalink Blame History

ORPO HP Sweep 디버깅 및 체크포인트 수정 보고서

날짜: 2026-03-08 작성: Claude Opus 4.6 + ghong


1. 목표

SFT v2 best 체크포인트 기반 ORPO hyperparameter sweep (6개 조합, 각 200 steps)을 8×B200 GPU에서 실행하여 최적 HP 조합을 찾는다.

2. 발견된 문제 및 해결

2.1 [CRITICAL] 체크포인트 QKV Weight 누락

증상: 모델 로딩 시 28개 레이어의 self_attn.q_proj, k_proj, v_proj weight가 MISSING으로 표시. attention layer가 랜덤 초기화 상태로 학습됨.

원인: scripts/convert_to_hf.pyremap_weights() 함수가 fused QKV 프로젝션(attn.qkv_proj.weight)을 처리하지 못함. 원본 체크포인트(TransformerEngine FP8)는 Q+K+V를 하나의 qkv_proj로 저장하지만, 변환 스크립트는 q_proj, k_proj, v_proj를 개별 키로 찾았음.

체크포인트 구조:

원본 (TE FP8):  layers.0.attn.qkv_proj.weight  → shape [5120, 3072]
                                                   Q(3072) + K(1024) + V(1024) = 5120
변환 전 (HF):   self_attn.o_proj.weight만 존재  → 171 keys (QKV 84개 누락)
변환 후 (HF):   q_proj [3072,3072] + k_proj [1024,3072] + v_proj [1024,3072] → 255 keys

GQA 구조: heads=24, kv_heads=8, head_dim=128

  • Q: 24 × 128 = 3072
  • K: 8 × 128 = 1024
  • V: 8 × 128 = 1024

수정: scripts/convert_to_hf.py — fused qkv_proj를 감지하면 GQA 구조에 따라 Q/K/V로 분리:

qkv = src_state_dict[qkv_key].float()
dst["q_proj.weight"] = qkv[:q_dim]        # [3072, 3072]
dst["k_proj.weight"] = qkv[q_dim:q_dim+k_dim]  # [1024, 3072]
dst["v_proj.weight"] = qkv[q_dim+k_dim:]        # [1024, 3072]

검증: q_proj norm=73.54 (학습된 weight), 변환 후 255 keys 정상.

2.2 NCCL Timeout (1800s)

증상: torch.distributed.DistBackendError: wait timeout after 1800000ms

원인: ORPOTrainer 초기화 시 Rank 0이 649K 샘플 토크나이징에 ~30분 소요. 다른 rank들이 NCCL communicator setup을 기다리다 기본 timeout(1800s) 초과.

수정:

  • train/orpo.py: ddp_timeout=7200 (2시간)
  • configs/korean_3b_orpo.yaml: dataset_num_proc: 64 (토크나이징 ~10분으로 단축)
  • scripts/orpo_hp_sweep.sh: --dataset_num_proc 64 추가

2.3 TensorBoard Import 크래시

증상: AttributeError: module 'tensorflow' has no attribute 'io'

수정: report_to="none" (orpo.py, YAML config, sweep script 3곳)

2.4 TRL 0.29.0 API 변경

증상: from trl import ORPOTrainer → ImportError

수정: from trl.experimental.orpo import ORPOConfig, ORPOTrainer

2.5 load_best_model_at_end + save_steps 충돌

증상: ValueError: save_steps(9999) is not a round multiple of eval_steps(100)

수정:

  • orpo.py: --no_load_best CLI 인자 추가
  • sweep script: --no_load_best --save_steps 200 사용

2.6 포트 충돌 (EADDRINUSE)

증상: Run 1이 이전 프로세스의 port 29510 점유로 실패

원인: 이전 실행의 좀비 프로세스가 소켓을 점유

교훈: 실행 전 항상 pkill -f torchrun + sleep 2 로 정리 필요

2.7 TRL 0.29.0 ORPOTrainer 토크나이저 버그 (이전 세션)

증상: Korean tokenizer의 merge ops로 인한 prompt token 길이 불일치 → zip(strict=True) ValueError

수정: TRL 소스 패치 8건 (.029bak 백업):

  1. build_tokenized_answer length mismatch → graceful fallback
  2. chosen/rejected prompt tokens truncation
  3. zip(..., strict=True)zip(...) 변경
  4. prompt diff ValueError → pass (warn-and-continue)
  5. add_bos_token_if_needed args 통일
  6. evaluation_loop zip strict 제거

3. 수정된 파일 목록

파일 변경 내용
scripts/convert_to_hf.py fused QKV → separate Q/K/V 분리 로직 추가
train/orpo.py TRL 0.29.0 import, ddp_timeout, dataset_num_proc, 예외처리/로깅 강화, --no_load_best
configs/korean_3b_orpo.yaml dataset_num_proc: 64, report_to: none
scripts/orpo_hp_sweep.sh --dataset_num_proc 64, --no_load_best, set +e, FAILED_RUNS 추적
eval/outputs/hf_3b_sft_best/ 재변환 완료 (171→255 keys)

4. Sweep 설정

Run Name Beta LR Max Length Effective BS
1 baseline_b015_lr8e6 0.15 8e-6 1536 128
2 baseline_b025_lr8e6 0.25 8e-6 1536 128
3 strong_b035_lr8e6 0.35 8e-6 1536 128
4 fast_b025_lr12e6 0.25 1.2e-5 1536 128
5 conserv_b025_lr5e6 0.25 5e-6 1536 128
6 short_b025_lr8e6 0.25 8e-6 1024 128

각 run: 200 steps, eval_steps=100, 8×B200 DDP

5. 하드웨어 최적화 설정

# NCCL (NVSwitch mesh — auto-detect)
NCCL_IB_DISABLE=1
NCCL_BUFFSIZE=134217728
NCCL_P2P_LEVEL=NVL

# CPU
OMP_NUM_THREADS=9    # 72 cores / 8 GPUs
MKL_NUM_THREADS=9
dataset_num_proc=64  # 토크나이징 병렬화

# GPU
bf16=true
flash_attention_2
gradient_checkpointing=true
dataloader_pin_memory=true
ddp_find_unused_parameters=false
ddp_timeout=7200

6. 현재 상태

  • 체크포인트 재변환 완료 (QKV 정상)

7. Sweep 실행 이력

시도 1 — NCCL Timeout (이전 세션)

  • 시각: ~03:00
  • 결과: Rank 0이 토크나이징(649K, num_proc=8)에 30분 소요 → 나머지 rank NCCL 1800s timeout
  • 교훈: ddp_timeout=7200 + dataset_num_proc=64 필요

시도 2 — save_steps/eval_steps 충돌

  • 시각: 03:28
  • 결과: ValueError: save_steps(9999) not a multiple of eval_steps(100)
  • 6개 run 전부 즉시 실패 (ORPOConfig 생성 단계)
  • 수정: --save_steps 200, --no_load_best 추가

시도 3 — 포트 충돌 + 깨진 체크포인트

  • 시각: 03:45
  • 결과:
    • Run 1: port 29510 EADDRINUSE (이전 좀비 프로세스) → 2초 만에 실패
    • Run 2~6: 모델 로딩 성공하나 q_proj/k_proj/v_proj MISSING (랜덤 초기화)
    • GPU 0만 100% utilization, 나머지 7개 0% → DDP 비정상
  • 근본 원인 발견: convert_to_hf.py가 fused qkv_proj [5120, 3072]를 분리 안 함
  • 수정: QKV split 로직 추가, 체크포인트 재변환 (171→255 keys)

시도 4 — 정상 실행 중 (현재)

  • 시각: 04:20
  • 사전 정리: pkill -9 + 포트 해제 + sweep 디렉토리 초기화
  • 상태: Run 1/6 baseline_b015_lr8e6 토크나이징 진행 중 (Map 69%, num_proc=64)
  • 확인 사항:
    • 모델 255 keys 정상 로딩 (MISSING 경고 없음)
    • 8 GPU 모두 모델 로드 (726MB/GPU)
    • utilization 0% = 정상 (CPU 토크나이징 단계)
  • 대기 중: 토크나이징 완료 → NCCL init → 8 GPU DDP 학습 시작 확인 필요

GPU 1개만 사용 문제 설명

  • 현상: 시도 3에서 GPU 0만 100%, 나머지 0%
  • 원인: 깨진 체크포인트(attention 랜덤 초기화)로 인해 DDP 동기화 실패. Rank 0만 학습 진입, 나머지 rank는 NCCL communicator 대기 상태
  • 현재: 아직 토크나이징 단계라 GPU utilization 0%는 정상. 토크나이징 완료 후 8 GPU 학습 진입 확인 필요

8. 다음 단계

  1. 토크나이징 완료 후 8 GPU DDP 학습 정상 진입 확인
  2. 6개 HP 조합 결과 비교 (eval_loss, margin 기준)
  3. 최적 HP로 본 학습 (full epochs)
  4. 학습 후 6차원 평가 재실행