Cerberus / docs /training-log.md
backseollgi's picture
Upload docs/training-log.md with huggingface_hub
c41ffc3 verified
|
Raw History Blame Contribute Delete
20.2 kB

CERBERUS Stage-1 โ€” Training Log & Decisions

Chunk-by-chunk history of the Stage-1 core pretrain (runs/core), and why the schedule was changed on 2026-08-09. Companion to training_plan.md (the plan) and MIGRATION.md (how to move servers).

Every relaunch appends provenance to runs/core/run_info.txt (git commit, dirty count, GPUs, resume source) and a git_diff_<ts>.patch. This file is the human-readable summary.


Chunk history

# Window Server GPUs eff. batch Epochs Ended by
1 2026-07-30 15:51 โ†’ 07-31 08:33 /data/pia (local disk) 2 (0,1) 8 0 โ†’ 25 host reboot
2 2026-08-03 12:02 โ†’ 08-04 07:16 /data/pia (local disk) 2 (0,1) 8 24 โ†’ 54* manual stop
3 2026-08-09 ~02:00 โ†’ Backend.AI container, /home/work/seoik (NFS) 3 (0,1,2) 12 53 โ†’ 107 (running)

* epoch 54 reached iter 1264/1500 and was discarded โ€” resume granularity is per-epoch, so checkpoint_53 is the real continuation point.

State at the end of chunk 2 (the resume point)

  • Total loss: 8.0 at start โ†’ ~2.9 plateau from ~epoch 10 onward (ep30 2.94, ep50 2.92, ep54 2.90 smoothed)
  • Complementarity LOSS terms middleloss (= 1 โˆ’ cos(z_a,z_m)) and middleloss_bg (= (1 + cos(z_m,z_b))/2) โ†’ โ‰ˆ 0 (converged, as designed). NOTE: these are losses, not cosines โ€” inverting them gives cos(z_a,z_m) โ†’ +1 (alignment) and cos(z_m,z_b) โ†’ โˆ’1 (anti-correlation). See base_task.py:264-270.
  • LR: 1e-5 โ†’ 8.53e-6 โ€” i.e. only 15% decayed after 53 epochs
  • Checkpoints: local 0..53; HF backup backseollgi/Cerberus/stage1_core/ 0..45 (+50)
  • Samples consumed: 79,500 step ร— 8 = 636,000

Decision (2026-08-09): max_epoch 200 โ†’ 107, GPUs 2 โ†’ 3

Why the plateau was not a convergence problem

hawk/common/optims.py:99 anneals cosine over max_epoch ร— iters_per_epoch total steps:

lr = (init_lr - min_lr) * 0.5 * (1 + cos(pi * total_step / (max_epoch * iters_per_epoch))) + min_lr

So max_epoch is the schedule length, not a harmless cap. It was set to 200 as a "generous cap โ€” stop anytime after ~3 days" (commits e11860c, 95eda28), which stretched the cosine over 300,000 steps. After 53 epochs we were only 26.5% into the schedule, LR was still 8.53e-6, and the late-cosine decay that actually drives convergence had not begun. Continuing under max_epoch: 200 meant 95 more hours at a near-constant high LR.

Why 107 specifically โ€” match the sample budget, not the epoch count

Epoch numbers are not comparable between HAWK and CERBERUS; the units differ:

original HAWK stage-1 CERBERUS (chunk 3)
iters_per_epoch 2,500 1,500
batch (per GPU) 1 4
GPUs 4 3
samples per "epoch" 10,000 18,000

Copying max_epoch: 160 from HAWK would therefore train 20% longer, not equally. Matching samples instead:

HAWK stage-1 plan  : 160 ep ร— 2500 it ร— 4  = 1.60M samples   (ran to checkpoint_127 = 1.27M)
CERBERUS target    : 107 ep ร— 1500 it ร— 12 = 1.60M samples   โ† equivalent budget

Consequences at resume:

under max_epoch: 200 under max_epoch: 107
position of checkpoint_53 26.5% of schedule 49.5%
LR on resume 8.53e-6 5.57e-6
remaining wall-clock 95.5 h (2 GPU) 34.6 h (3 GPU)
LR at finish ~5e-6 (never annealed) 1e-6 = min_lr

Why 3 GPUs actually saves time here (and why it isn't automatic)

iters_per_epoch is fixed at 1500, so an "epoch" is a 39-minute checkpoint interval, not a pass over the data (one real pass over 2.63M samples would be ~329k iters). Adding a GPU therefore does not shrink epoch wall-clock โ€” it raises samples/step from 8 to 12.

The speedup only materialises because we lowered max_epoch to match: reaching the same 1.60M-sample budget needs 133,333 steps at 12/step instead of 200,000 at 8/step.

2 GPU 3 GPU
steps to 1.60M samples 200,000 133,333
required max_epoch 133 107
remaining wall-clock 52.2 h 34.6 h

Known discontinuities at epoch 54 (expected, recorded here on purpose)

  1. LR steps down 8.53e-6 โ†’ 5.57e-6. Downward, so it does not fight the restored Adam moments (raising LR mid-run is the dangerous direction) and it helps leave the plateau.
  2. Effective batch 8 โ†’ 12. Gradients get less noisy from epoch 54 on. Report Stage-1 as "epochs 0โ€“53 at effective batch 8, 54โ€“107 at 12" rather than a single number.
  3. Both land at the same point on the curve, so a small step in the loss/TensorBoard trace at epoch 54 is expected and is not a bug.

init_lr, min_lr, warmup_steps, iters_per_epoch, batch_size_train and seed were left untouched, so the only intended changes are the two above.


Environment notes for chunk 3 (new server)

Moved from /data/pia (local disk) to a Backend.AI container with /home/work/seoik on NFS. Nothing else about the run changed. Gotchas hit during setup, recorded so they are not re-discovered:

  • /home/work/seoik is the only persistent volume. $HOME (/home/work) is container scratch and disappears with the session. Conda, caches and data must live under seoik/. train_run.sh now pins TORCH_HOME / HF_HOME there.
  • The container ships its own conda at /home/work/miniconda3, active as base, and its envs_dirs does not include ours โ€” so conda run -n cerberus silently resolves to the wrong prefix and fails with No module named 'torch'. train_run.sh now addresses the env by absolute prefix (conda run -p /home/work/seoik/miniconda3/envs/cerberus).
  • NFS is the throughput bottleneck, not CPU/RAM (83 cores, 676 GB idle). Measured: 25.8 MB/s sequential, 35 ms per small-file write, and saturated at ~50 files/s regardless of parallelism (8 / 32 / 64 workers all measured the same). Extracting 2.66M mp4 files took ~3 h; raising worker count does not help.
  • scripts/extract_all_webvid.py (new) replaces build_webvid_split.py here: one 9.1T volume means no big/small split or union symlinks are needed. It is resumable per shard via <out>/.done/<page_dir> markers.
  • TensorBoard is NOT a complete record of this run. chunk 1-2's event files stayed on the old server, so runs/core/main/tensorboard/ starts at step 81,005. train.log is the only source covering epoch 0 onward (it is appended across chunks and travelled via HF). Use scripts/plot_training_curves.py to rebuild the full curves + a CSV from the log; it handles the re-run epochs at the resume points (25, 54) by letting the later record win.
  • Model build verified before training with python scripts/smoke_test.py --cfg configs/train_configs/stage1_main.yaml โ†’ all three streams (appearance / motion / background) forward OK on H100 (sm_90), torch 2.11+cu128, transformers 4.28.

Stage-2 finetune (anomaly instruction tuning) โ€” ์ด ์„œ๋ฒ„, 2026-08-10 ์ฐฉ์ˆ˜

์„ค์ •๊ณผ ๊ทธ ๊ทผ๊ฑฐ

ํ•ญ๋ชฉ ๊ฐ’ ๊ทผ๊ฑฐ
ckpt runs/core/main/checkpoint_106.pth stage1 ์ตœ์ข… (LR์ด min_lr๊นŒ์ง€ annealing ์™„๋ฃŒ)
max_epoch 160 (์›๋ณธ ๊ทธ๋Œ€๋กœ) ์•„๋ž˜ ์˜ˆ์‚ฐ ๊ณ„์‚ฐ ์ฐธ์กฐ
batch_size_train 2 (์›๋ณธ 1) GPU๊ฐ€ 4์žฅโ†’2์žฅ์ด๋ผ effective batch๋ฅผ ๋งž์ถ”๊ธฐ ์œ„ํ•ด
iters_per_epoch 2500 (์›๋ณธ ๊ทธ๋Œ€๋กœ)
num_workers 8 (์›๋ณธ 16) ์‹ค์ธก data: ์ง€์—ฐ 0.0000 โ€” 8๋กœ ์ถฉ๋ถ„, NFS ๋ถ€ํ•˜ ์ ˆ๊ฐ
GPU H100 2์žฅ (stage1์€ 3์žฅ) ์„ธ์…˜ ์žฌํ• ๋‹น์œผ๋กœ ๋ณ€๊ฒฝ๋จ

์ƒ˜ํ”Œ ์˜ˆ์‚ฐ โ€” ์›๋ณธ๊ณผ ๋™์ผํ•˜๊ฒŒ ํ†ต์ œ:

์›๋ณธ HAWK stage2 : 160 ep x 2500 it x batch 1 x 4 GPU = 1.60M ์ƒ˜ํ”Œ (effective batch 4)
์ด ์„œ๋ฒ„           : 160 ep x 2500 it x batch 2 x 2 GPU = 1.60M ์ƒ˜ํ”Œ (effective batch 4)

GPU ์žฅ์ˆ˜๊ฐ€ ์ ˆ๋ฐ˜์ด ๋œ ๋งŒํผ batch๋ฅผ 2๋ฐฐ๋กœ ์˜ฌ๋ ค, ์ƒ˜ํ”Œ ์˜ˆ์‚ฐ๊ณผ effective batch๋ฅผ ๋‘˜ ๋‹ค ์›๋ณธ๊ณผ ์ผ์น˜์‹œ์ผฐ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ max_epoch์€ ์›๋ณธ ๊ฐ’ 160์„ ๊ทธ๋Œ€๋กœ ์“ธ ์ˆ˜ ์žˆ๋‹ค (stage1์—์„œ 107๋กœ ์žฌ๊ณ„์‚ฐํ•ด์•ผ ํ–ˆ๋˜ ๊ฒƒ๊ณผ ๋‹ค๋ฅธ ์  โ€” stage1์€ iters_per_epoch๋„ 1500์œผ๋กœ ๋ฐ”๊ฟจ๊ธฐ ๋•Œ๋ฌธ).

batch๋ฅผ ๋” ํ‚ค์šฐ์ง€ ์•Š์€ ์ด์œ  (2026-08-10 ์‹ค์ธก, 150 iter ๊ณต์ • ๋น„๊ต, H100 2์žฅ):

batch ์ •์ƒ์ƒํƒœ s/it max mem ์ฒ˜๋ฆฌ๋Ÿ‰ 1.6M ์ƒ˜ํ”Œ ์†Œ์š”
2 1.369 45.7 GB 2.92 samples/s 6.3์ผ
4 2.773 56.6 GB 2.89 samples/s 6.4์ผ
6 4.31 69.0 GB 2.78 samples/s 6.7์ผ
8 โ€” OOM (75.9 GB ํ• ๋‹น ํ›„ ์‹คํŒจ) โ€” โ€”

batch์— ๋น„๋ก€ํ•ด iter ์‹œ๊ฐ„์ด ๊ฐ™์ด ๋Š˜์–ด ์ฒ˜๋ฆฌ๋Ÿ‰์ด ํ‰ํ‰ํ•˜๋‹ค = 32ํ”„๋ ˆ์ž„ x 3์ŠคํŠธ๋ฆผ ์กฐํ•ฉ์ด ์ด๋ฏธ ์ƒ˜ํ”Œ๋‹น ์—ฐ์‚ฐ ํฌํ™”. VRAM์„ ๋” ์ฑ„์›Œ๋„ ์ด๋“์ด ์—†๊ณ  batch 6๋ถ€ํ„ฐ๋Š” ์˜คํžˆ๋ ค ์ €ํ•˜๋˜๋ฏ€๋กœ, ์—ฌ์œ  34GB๋ฅผ ๋‚จ๊ฒจ ๋‹ค์ผ ํ•™์Šต์˜ OOM ์œ„ํ—˜์„ ์ค„์ด๋Š” batch 2๋ฅผ ํƒํ–ˆ๋‹ค. data: ์ง€์—ฐ์€ ๋ชจ๋“  ์„ค์ •์—์„œ 0.0000์ด๋ผ NFS๋Š” ๋ณ‘๋ชฉ์ด ์•„๋‹ˆ๋‹ค. PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True๋„ batch 6์˜ ์ €ํ•˜๋ฅผ ํ•ด์†Œํ•˜์ง€ ๋ชปํ–ˆ๋‹ค(4.72 s/it) โ€” ๋‹จํŽธํ™”๊ฐ€ ์•„๋‹ˆ๋ผ ์—ฐ์‚ฐ ํ•œ๊ณ„๋ผ๋Š” ๊ทผ๊ฑฐ.

์ฐฉ์ˆ˜ ์ „ ์ฒ˜๋ฆฌํ•œ ์ด๊ด€ ๋ฌธ์ œ (๋‹ค๋ฅธ ์„œ๋ฒ„์—์„œ ์žฌํ˜„ํ•  ๋•Œ๋„ ํ•„์š”)

  1. annotation์˜ ๋น„๋””์˜ค ๊ฒฝ๋กœ๊ฐ€ ์›์ €์ž ์„œ๋ฒ„ ์ ˆ๋Œ€๊ฒฝ๋กœ์˜€๋‹ค. ๋ฐฐํฌ๋ณธ JSON์˜ video ํ•„๋“œ๊ฐ€ /remote-home/share/jiaqitang/Data/...์ธ๋ฐ, ๋กœ๋”๋Š” os.path.join(vis_root, sample['video']) (video_instruct_dataset.py:128)๋ฅผ ์“ด๋‹ค. ๋‘ ๋ฒˆ์งธ ์ธ์ž๊ฐ€ ์ ˆ๋Œ€๊ฒฝ๋กœ๋ฉด vis_root๊ฐ€ ํ†ต์งธ๋กœ ๋ฌด์‹œ๋˜๋ฏ€๋กœ config์˜ videos_dir๋ฅผ ๊ณ ์ณ๋„ ์†Œ์šฉ์ด ์—†๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ๋ฐ์ดํ„ฐ์…‹ ์ด๋ฆ„์ด ์‹ค์ œ ๋ฐฐํฌ๋ณธ ๋””๋ ‰ํ† ๋ฆฌ๋ช…๊ณผ ๋‹ค๋ฅด๋‹ค(UCF-Crimeโ†”UCF_Crime, avenue/avenue/โ†”CUHK_Avenue/, ped1/ped1/โ†”Ped1/, ShanghaiTechDatasetโ†”ShanghaiTech). โ†’ scripts/localize_anomaly_annotations.py๊ฐ€ videos_dir ๊ธฐ์ค€ ์ƒ๋Œ€๊ฒฝ๋กœ๋กœ ๋ณ€ํ™˜ํ•ด *.local.json์„ ๋งŒ๋“ ๋‹ค(์›๋ณธ ๋ณด์กด). train 7066 / test 786 / all 7852 ์ „๋ถ€ ๋งค์นญ ํ™•์ธ.
  2. config์— ๋‚จ์•„ ์žˆ๋˜ ์™ธ๋ถ€ ๊ฒฝ๋กœ 6๊ณณ(llama_model, tokenizer_name, prompt_path, ckpt, anno_dir, videos_dir)์„ ์ด ์„œ๋ฒ„ ๊ธฐ์ค€์œผ๋กœ ๊ต์ฒด. output_dir๋„ ๋ ˆํฌ ์•ˆ(output/)์„ ๊ฐ€๋ฆฌํ‚ค๋˜ ๊ฒƒ์„ runs/ ์ ˆ๋Œ€๊ฒฝ๋กœ๋กœ ์˜ฎ๊ฒผ๋‹ค(train_run.sh ์‚ฌ์šฉ ์‹œ์—๋Š” run๋ณ„๋กœ ๋ฎ์–ด์จ์ง).

stage2์˜ ์†์‹ค ๊ตฌ์กฐ๋Š” stage1๊ณผ ๋‹ค๋ฅด๋‹ค (๋…ผ๋ฌธ ์„œ์ˆ  ์‹œ ์ฃผ์˜)

instruct ๋ฐ์ดํ„ฐ๋Š” conv_type='multi' ๊ฒฝ๋กœ(video_llama.py:738-806)๋ฅผ ํƒ€๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ๋Š” ์„ธ ์ŠคํŠธ๋ฆผ์˜ ์ž„๋ฒ ๋”ฉ์„ ํ† ํฐ์œผ๋กœ concatํ•ด LLaMA๋ฅผ ํ•œ ๋ฒˆ๋งŒ ํ†ต๊ณผ์‹œํ‚ค๊ณ  loss_motionยทloss_background์— ๊ฐ™์€ loss ๊ฐ’์„ ๋ณต์‚ฌํ•ด ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ stage2 ์ด์†์‹ค์€ ์‹ค์งˆ์ ์œผ๋กœ

total = 1.2 x LM์†์‹ค + 0.1 x middleloss + 0.1 x middleloss_bg

์ด๋ฉฐ, stage1์ฒ˜๋Ÿผ ์ŠคํŠธ๋ฆผ๋ณ„ ๋…๋ฆฝ LM ์†์‹ค์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด๋Š” ์›๋ณธ HAWK ์„ค๊ณ„ ๊ทธ๋Œ€๋กœ์ด๊ณ  ๋ฒ„๊ทธ๊ฐ€ ์•„๋‹ˆ๋‹ค. ๋กœ๊ทธ์˜ motionloss/backgroundloss๊ฐ€ oriloss์™€ ๋™์ผํ•˜๊ฒŒ ์ฐํžˆ๋Š” ๊ฒƒ์€ ์ •์ƒ์ด๋‹ค.

๋…ผ๋ฌธ ์ž‘์„ฑ์— ํ•„์š”ํ•œ ์‚ฐ์ถœ๋ฌผ โ€” ํ•™์Šต ์™„๋ฃŒ ์‹œ ์•„๋ž˜๊ฐ€ ์ „๋ถ€ ์ˆ˜์ง‘๋˜์–ด์•ผ ํ•œ๋‹ค

train_run.sh๊ฐ€ runs/stage2/์— ์ž๋™์œผ๋กœ ๋‚จ๊ธฐ๋Š” ๊ฒƒ:

  • main/checkpoint_{0..159}.pth โ€” epoch๋ณ„ ์ฒดํฌํฌ์ธํŠธ (์•ฝ 2GB x 160 = 320GB)
  • main/tensorboard/ โ€” ์Šค์นผ๋ผ 7์ข…: Loss/total, Loss/ori, Loss/motion, Loss/background, Loss/middle, Loss/middle_bg, Learning Rate (global step = epoch x 2500 + i)
  • train.log โ€” ์ „ ๊ตฌ๊ฐ„ append. TB๋ณด๋‹ค ์ด์ชฝ์ด ๊ถŒ์œ„ ์žˆ๋Š” ๊ธฐ๋ก์ด๋‹ค(chunk ์žฌ๊ฐœ ์‹œ TB๋Š” ๋Š๊ธธ ์ˆ˜ ์žˆ์Œ)
  • run_info.txt โ€” chunk๋ณ„ provenance: config ๊ฒฝ๋กœ, GPU, git commit + dirty ์—ฌ๋ถ€, resume ์ง€์ 
  • config.yaml โ€” ์‹คํ–‰ ์‹œ์  config ์‚ฌ๋ณธ
  • git_diff_<ts>.patch โ€” ์‹คํ–‰ ์‹œ์  ์›Œํ‚นํŠธ๋ฆฌ diff

ํ•™์Šต ์™„๋ฃŒ ํ›„ ์ถ”๊ฐ€๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ๊ฒƒ:

  • scripts/plot_training_curves.py๋กœ stage2 ๊ณก์„  + CSV ์ƒ์„ฑ โ†’ figs/stage2_curves.{png,pdf,csv}
  • HF backseollgi/Cerberus/stage2_finetune/์— ์ฒดํฌํฌ์ธํŠธ(๋งˆ์ผ์Šคํ†ค+์ตœ์ข…)ยทtrain.logยทconfig.yamlยท ๊ณก์„  ๋ฐฑ์—… (stage1๊ณผ ๋™์ผํ•œ ๋ฐฉ์‹)
  • E1/E2 ์‹ค์ธก: scripts/extract_representations.py + experiments/disentanglement.py๋กœ CDS ์‚ฐ์ถœ. stage1 ์ฒดํฌํฌ์ธํŠธ์™€ stage2 ์ฒดํฌํฌ์ธํŠธ ์–‘์ชฝ์—์„œ ๋ฝ‘์•„์•ผ ๋ถ„๋ฆฌ๋„๊ฐ€ finetune์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋ณ€ํ–ˆ๋Š”์ง€ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Table-1์šฉ VAD ์ •๋Ÿ‰ ์ˆ˜์น˜ (scripts/run_eval.sh, test split์€ all_videos_test.local.json)

NaN epoch ํ‰๊ท ์˜ ์ •์ฒด (2026-08-12, ์‹ค์ธก)

abl_flow arm์˜ ๋กœ๊ทธ์—์„œ Averaged stats์˜ totalloss๊ฐ€ 28 epoch ์ค‘ 9ํšŒ nan ์œผ๋กœ ์ฐํ˜”๊ณ , 26โ€“28์—์„œ 3์—ฐ์†์œผ๋กœ ๋‚˜ํƒ€๋‚ฌ๋‹ค. ํ•™์Šต ์‹คํŒจ๋กœ ์ฝํž ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ์ด๋ฏ€๋กœ ์›์ธ์„ ํ™•์ •ํ–ˆ๋‹ค.

์‹ค์ธก. ์ถœ๋ ฅ๋œ iteration 7,032๊ฐœ ์ค‘ NaN์€ 1๊ฐœ(0.014%)๋‹ค. epoch ํ‰๊ท ์€ 2,500 iteration์˜ ํ‰๊ท ์ด๋ฏ€๋กœ NaN ํ•˜๋‚˜๊ฐ€ ์„ž์ด๋ฉด ํ‰๊ท  ์ „์ฒด๊ฐ€ NaN์ด ๋œ๋‹ค. ์ฆ‰ ๋กœ๊ทธ์˜ nan์€ "์ด epoch์ด ์‹คํŒจํ–ˆ๋‹ค"๊ฐ€ ์•„๋‹ˆ๋ผ "์ด epoch์— NaN iteration์ด ์ ์–ด๋„ ํ•˜๋‚˜ ์žˆ์—ˆ๋‹ค"๋Š” ๋œป์ด๋‹ค.

์‹ค์ œ ๋ฐœ์ƒ๋ฅ ์€ epoch๋‹น ์•ฝ 0.4ํšŒ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด P(epoch์— NaN โ‰ฅ 1) = 9/28 = 0.32์ด๊ณ , 3์—ฐ์†์ด ๋‚˜ํƒ€๋‚  ํ™•๋ฅ ์€ 28 epoch ๊ตฌ๊ฐ„์—์„œ ์•ฝ 60%๋‹ค. 3์—ฐ์†์€ ์•…ํ™”์˜ ์ฆ๊ฑฐ๊ฐ€ ์•„๋‹ˆ๋ผ ์ด ๋ฐœ์ƒ๋ฅ ์—์„œ ์˜ˆ์ƒ๋˜๋Š” ์‚ฌ๊ฑด์ด๋‹ค.

๊ฐ€์ค‘์น˜ ํ™•์ธ. checkpoint_27.pth์˜ ํ•™์Šต ํŒŒ๋ผ๋ฏธํ„ฐ 231๊ฐœ ์ „๋ถ€ NaN/Inf ์—†์Œ. AMP GradScaler๊ฐ€ NaN ์†์‹ค์—์„œ ์˜ตํ‹ฐ๋งˆ์ด์ € ์Šคํ…์„ ๊ฑด๋„ˆ๋›ฐ๋ฏ€๋กœ ๊ฐ€์ค‘์น˜๊ฐ€ ์˜ค์—ผ๋˜์ง€ ์•Š๋Š”๋‹ค. ์ •์ƒ epoch์˜ loss๋Š” ๋‹จ์กฐ ํ•˜๊ฐ•ํ•œ๋‹ค(1.537 โ†’ 0.983).

๊ฐ์‹œ ๊ธฐ์ค€ ๊ต์ฒด. "์—ฐ์† 3 epoch NaN"์€ ์ด ๋ฐœ์ƒ๋ฅ ์—์„œ ์šฐ์—ฐ๊ณผ ์•…ํ™”๋ฅผ ๊ตฌ๋ณ„ํ•˜์ง€ ๋ชปํ•˜๋ฏ€๋กœ ํ๊ธฐํ•œ๋‹ค.

ํ๊ธฐ ๋Œ€์ฒด
์—ฐ์† 3 epoch NaN ์ถœ๋ ฅ iteration์˜ NaN ๋น„์œจ > 1% (ํ˜„์žฌ 0.014%)
์ฒดํฌํฌ์ธํŠธ์— NaN/Inf ํŒŒ๋ผ๋ฏธํ„ฐ (ํ˜„์žฌ ์—†์Œ)
์ •์ƒ epoch loss๊ฐ€ 3ํšŒ ์—ฐ์† ์ƒ์Šน (ํ˜„์žฌ ๋‹จ์กฐ ํ•˜๊ฐ•)

๋…ผ๋ฌธ ํ‘œ๊ธฐ. arm๋ณ„ NaN epoch ์ˆ˜๋ฅผ ๋ณด๊ณ ํ•  ๋•Œ ์ด ๊ฐ์ฃผ๊ฐ€ ํ•จ๊ป˜ ๊ฐ€์•ผ ํ•œ๋‹ค. ์ˆ˜์น˜๋งŒ ์ œ์‹œํ•˜๋ฉด ์‹ฌ์‚ฌ์ž๊ฐ€ 9/28์„ ํ•™์Šต ๋ถˆ์•ˆ์ •์œผ๋กœ ์ฝ๋Š”๋‹ค. ๋ณด๊ณ  ํ˜•์‹์€ "NaN epoch 9/28 (iteration ์ˆ˜์ค€ NaN ๋น„์œจ 0.014%; epoch ํ‰๊ท ์€ ๋‹จ์ผ NaN์— ์˜ํ•ด ์˜ค์—ผ๋œ๋‹ค)"๋กœ ํ•œ๋‹ค.

์žฌํ˜„:

$CERBERUS_PY - <<'EOF'
import re, collections
tot = collections.Counter(); nan = collections.Counter()
for l in open('/home/work/seoik/runs/abl_flow/train.log', errors='ignore'):
    m = re.search(r'Train: data epoch: \[(\d+)\].*?totalloss: (nan|[0-9.]+)', l)
    if m:
        e = int(m.group(1)); tot[e] += 1
        if m.group(2) == 'nan': nan[e] += 1
print(f'์ถœ๋ ฅ {sum(tot.values())}๊ฐœ ์ค‘ NaN {sum(nan.values())}๊ฐœ')
EOF

random_mask arm ์ค‘๋‹จ๊ณผ ๋Ÿฌ๋„ˆ์˜ ์‹คํŒจ ๋ฏธ๊ฐ์ง€ (2026-08-13)

abl_random_mask ๊ฐ€ epoch 5, iteration 320 ๋ถ€๊ทผ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฃฝ์—ˆ๋‹ค.

RuntimeError: DataLoader worker (pid 3751766) is killed by signal: Killed.
[ablation] arm=random_mask ์ข…๋ฃŒ (exit 1)
[ablation] arm=duplicate ์‹œ์ž‘              โ† ๋Ÿฌ๋„ˆ๊ฐ€ ์‹คํŒจ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ์ง„ํ–‰

์ž์› ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค. ์‚ฌํ›„ ํ™•์ธ: RAM 2,015GB ์ค‘ 1,898GB ์—ฌ์œ , /dev/shm 64GB(์‚ฌ์šฉ 276KB), GPU 46.8/81.6GB. ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋กœ flow ๋Š” 40 epoch ์™„์ฃผํ–ˆ๊ณ  duplicate ๋Š” ๋ฌธ์ œ์—†์ด ์ง„ํ–‰ ์ค‘์ด๋‹ค. ์ผ์‹œ์  ๋ฉ”๋ชจ๋ฆฌ ์ŠคํŒŒ์ดํฌ๋กœ ๋ณด์ด๋ฉฐ ์žฌํ˜„๋˜์ง€ ์•Š์•˜๋‹ค.

๋ณต๊ตฌ ๊ฐ€๋Šฅ. checkpoint_4.pth ์— modelยทoptimizerยทscalerยทepoch ์ด ๋ชจ๋‘ ์žˆ์–ด epoch 5 ๋ถ€ํ„ฐ ์ด์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค(train_run.sh ๊ฐ€ ์ตœ์‹  ์ฒดํฌํฌ์ธํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์ฐพ์•„ resume_ckpt_path ๋กœ ๋„˜๊ธด๋‹ค).

๋Ÿฌ๋„ˆ์˜ ๊ฒฐํ•จ๊ณผ ๋Œ€์‘

run_ablation_arms.sh ๋Š” train_run.sh ์˜ ์ข…๋ฃŒ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜์ง€ ์•Š๋Š”๋‹ค. arm ํ•˜๋‚˜๊ฐ€ 5 epoch ์—์„œ ์ฃฝ์–ด๋„ ๋‹ค์Œ arm ์œผ๋กœ ๋„˜์–ด๊ฐ€๋ฏ€๋กœ, ๋™์ผ ์˜ˆ์‚ฐ ํ†ต์ œ๊ฐ€ ์กฐ์šฉํžˆ ๊นจ์ง„๋‹ค.

์‹คํ–‰ ์ค‘์ธ ์Šคํฌ๋ฆฝํŠธ๋Š” ํŽธ์ง‘ํ•˜์ง€ ์•Š์•˜๋‹ค โ€” bash ๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ฐ”์ดํŠธ ์˜คํ”„์…‹์œผ๋กœ ์ฝ์œผ๋ฏ€๋กœ ์ง„ํ–‰ ์ค‘ ํŒŒ์ผ์„ ๊ณ ์น˜๋ฉด ๋‚จ์€ ๋ถ€๋ถ„์„ ์ž˜๋ชป ํ•ด์„ํ•œ๋‹ค. ๋Œ€์‹  run_ablation_followup.sh ๋ฅผ ์ƒˆ๋กœ ๋‘๊ณ , ์™„๋ฃŒ epoch ์ˆ˜๋ฅผ ํ™•์ธํ•ด ๋ชฉํ‘œ์— ๋ชป ๋ฏธ์น˜๋ฉด ์žฌ์‹œ๋„ํ•˜๋„๋ก ํ–ˆ๋‹ค.

๊ฒ€์ฆํ•˜๋ ค๋‹ค ์‹ค์ œ ํ•™์Šต์„ ๋„์šด ์‚ฌ๊ณ 

ABL_ARMS="" bash scripts/run_ablation_followup.sh ๋กœ "arm ์—†์ด ์ƒํƒœ๋งŒ ๋ณด์ž"๊ณ  ์‹คํ–‰ํ–ˆ๋Š”๋ฐ ํ•™์Šต์ด ์‹œ์ž‘๋˜์–ด duplicate ์™€ GPU ๋ฅผ ๋‹คํˆฌ์—ˆ๋‹ค. ์›์ธ์€ ${ABL_ARMS:-๊ธฐ๋ณธ๊ฐ’} ์˜ :- ๊ฐ€ ๋นˆ ๋ฌธ์ž์—ด๋„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์น˜ํ™˜ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. ์ฆ‰์‹œ ์ข…๋ฃŒํ•˜์—ฌ ํ”ผํ•ด๋Š” ์—†์—ˆ๋‹ค(duplicate ์ •์ƒ ์ง„ํ–‰, random_mask ์ฒดํฌํฌ์ธํŠธยท๋กœ๊ทธ ๋ถˆ๋ณ€).

์„ธ ๊ฐ€์ง€ ์•ˆ์ „์žฅ์น˜๋ฅผ ๋„ฃ์—ˆ๋‹ค.

์žฅ์น˜ ํšจ๊ณผ
--check ํ”Œ๋ž˜๊ทธ ์ƒํƒœ๋งŒ ์ถœ๋ ฅํ•˜๊ณ  ์ข…๋ฃŒ. ๊ฒ€์ฆ ์‹œ ํ•™์Šต์ด ์‹œ์ž‘๋  ์ˆ˜ ์—†๋‹ค
${ABL_ARMS-...} (: ์ œ๊ฑฐ) ๋นˆ ๋ฌธ์ž์—ด์„ "arm ์—†์Œ"์œผ๋กœ ์กด์ค‘
์‹คํ–‰ ์ค‘ ํ”„๋กœ์„ธ์Šค ๊ฐ์ง€ ๋‹ค๋ฅธ ์ ˆ์ œ ํ•™์Šต์ด ์žˆ์œผ๋ฉด ๊ฑฐ๋ถ€(ABL_FORCE=1 ๋กœ๋งŒ ๋ฌด์‹œ)

๋‚จ์€ ์ผ์ •

flow          40/40  ์™„์ฃผ
random_mask    5/40  ์žฌ๊ฐœ ํ•„์š”
duplicate     12/40  ์ง„ํ–‰ ์ค‘
zero           0/40  ๋Œ€๊ธฐ
flow_reinit    0/40  ๋Œ€๊ธฐ

zero ์ข…๋ฃŒ ํ›„ bash scripts/run_ablation_followup.sh ๋กœ random_mask ์žฌ๊ฐœ + flow_reinit ์‹คํ–‰. ์•ฝ 144 epoch ร— 75๋ถ„ โ‰ˆ 7.5์ผ.


duplicate arm ๋ฐœ์‚ฐ (2026-08-13)

abl_duplicate ๊ฐ€ epoch 16, iteration 1430 ๋ถ€๊ทผ์—์„œ ๋ฐœ์‚ฐํ–ˆ๋‹ค. ์ด์ „์˜ ์‚ฐ๋ฐœ์  NaN ๊ณผ ์„ฑ๊ฒฉ์ด ์ „ํ˜€ ๋‹ค๋ฅด๋‹ค.

epoch 15 ๊นŒ์ง€ : middleloss 0.0001, ์ •์ƒ
epoch 16      : iteration ~1430 ์ดํ›„ totallossยทorilossยทmiddleloss ์ „๋ถ€ nan (์ถœ๋ ฅ 250 ์ค‘ 116)
epoch 17      : ์‹œ์ž‘๋ถ€ํ„ฐ ์ „๋ถ€ nan

๋ชจ๋ธ์ด ์ฃฝ์—ˆ๋‹ค. checkpoint_16.pth ์˜ ํ•™์Šต ํŒŒ๋ผ๋ฏธํ„ฐ 231๊ฐœ ์ค‘ 193๊ฐœ๊ฐ€ ๋น„์œ ํ•œ์ด๋‹ค (llama_proj_0.weight, video_query_tokens_* ๋“ฑ). ์ „์ˆ˜ ์Šค์บ” ๊ฒฐ๊ณผ epoch 15 ๊ฐ€ ๋งˆ์ง€๋ง‰ ์ •์ƒ ์ฒดํฌํฌ์ธํŠธ๋‹ค(13ยท14ยท15 ์ „๋ถ€ 0/231).

ํšŒ๋ณต ๋ถˆ๊ฐ€. AMP GradScaler ๋Š” NaN ์†์‹ค์—์„œ ์˜ตํ‹ฐ๋งˆ์ด์ € ์Šคํ…์„ ๊ฑด๋„ˆ๋›ฐ๋Š”๋ฐ, ๊ฐ€์ค‘์น˜๊ฐ€ ์ด๋ฏธ NaN ์ด๋ฉด ๋ชจ๋“  forward ๊ฐ€ NaN ์ด๊ณ  ๋ชจ๋“  ์Šคํ…์ด ๊ฑด๋„ˆ๋›ฐ์–ด์ง„๋‹ค. ์Šค์Šค๋กœ ๋น ์ ธ๋‚˜์˜ฌ ๊ฒฝ๋กœ๊ฐ€ ์—†๋‹ค. ๋”ฐ๋ผ์„œ ๊ณ„์† ๋‘๋Š” ๊ฒƒ์€ ์ˆœ์ˆ˜ํ•œ ๋‚ญ๋น„์ด๋ฉฐ(arm ๋‹น ์•ฝ 2์ผ), ์ค‘๋‹จํ–ˆ๋‹ค. ๋Ÿฌ๋„ˆ๋Š” ๋‹ค์Œ arm(zero)์œผ๋กœ ์ง„ํ–‰ํ–ˆ๋‹ค.

์ด์ „ NaN ๊ณผ์˜ ๊ตฌ๋ณ„

์‚ฐ๋ฐœ์  NaN (flow arm) ๋ฐœ์‚ฐ (duplicate arm)
iteration NaN ๋น„์œจ 0.014% (7,032 ์ค‘ 1) 46% (250 ์ค‘ 116), ์ดํ›„ 100%
์ง€์†์„ฑ ๋‹จ๋ฐœ, ๋‹ค์Œ iteration ์ •์ƒ ์‹œ์ž‘ ํ›„ ๋˜๋Œ์•„์˜ค์ง€ ์•Š์Œ
๊ฐ€์ค‘์น˜ ์ „๋ถ€ ์œ ํ•œ 193/231 ๋น„์œ ํ•œ
epoch ํ‰๊ท ์ด NaN ์ธ ์ด์œ  ๋‹จ์ผ NaN ์ด ํ‰๊ท ์„ ์˜ค์—ผ ์‹ค์ œ๋กœ ์ „๋ถ€ NaN

์ƒˆ ๊ฐ์‹œ ๊ธฐ์ค€์ด ์ด๊ฒƒ์„ ์žก์•˜๋‹ค. "์—ฐ์† 3 epoch NaN" ๊ธฐ์ค€์€ ๋‘ ๊ฒฝ์šฐ๋ฅผ ๊ตฌ๋ณ„ํ•˜์ง€ ๋ชปํ–ˆ์œผ๋‚˜, ๊ต์ฒดํ•œ ๊ธฐ์ค€(iteration NaN ๋น„์œจ > 1% ยท ์ฒดํฌํฌ์ธํŠธ ๋น„์œ ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ)์€ ๋ฐœ์‚ฐ๋งŒ ๋ฐœ๋™ํ–ˆ๋‹ค.

์›์ธ ๋ฏธํ™•์ •

epoch 16 ์ „๊นŒ์ง€ middleloss ๊ฐ€ 0.0001 โ†’ 0.0003 ์œผ๋กœ ์›€์ง์ด๊ธฐ ์‹œ์ž‘ํ–ˆ๊ณ (์ •๋ฅ˜์  ์ดํƒˆ์˜ ์ดˆ๊ธฐ ์‹ ํ˜ธ), ๊ทธ ์งํ›„ ๋ฐœ์‚ฐํ–ˆ๋‹ค. flow arm ์—์„œ๋„ epoch 28 ์— ์ดํƒˆ์ด ์žˆ์—ˆ์œผ๋‚˜ ๋ฐœ์‚ฐํ•˜์ง€ ์•Š๊ณ  ํšŒ๋ณตํ–ˆ๋‹ค. ๋‘ ์‚ฌ๊ฑด์ด ๊ฐ™์€ ๊ธฐ์ œ์ธ์ง€, duplicate ์˜ ์ •์  ์ž…๋ ฅ(์›๋ณธ ํ”„๋ ˆ์ž„ ๋ณต์ œ)์ด ์ดํƒˆ์„ ๋” ๋ถˆ์•ˆ์ •ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š”์ง€๋Š” ํ™•์ •ํ•˜์ง€ ๋ชปํ–ˆ๋‹ค.

ํ‘œํ˜„ ์†์‹ค์„ ๋„๋ฉด ์ด ์‹คํŒจ ์–‘์‹์ด ์‚ฌ๋ผ์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค. ๋…ผ๋ฌธ์€ L_simยทL_dis ๋ฅผ ๊ธฐ์—ฌ๋กœ ์ฃผ์žฅํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ t_1 = t_4 = 0 ์œผ๋กœ ๋‘๋Š” ๋ฐ ์†์‹ค์ด ์—†๊ณ , ํ†ต์ œ ์‹คํ—˜์—์„œ ์ผœ ๋‘˜ ์ด์œ ๋„ ์—†๋‹ค. ์žฌ์‹คํ–‰ ์‹œ ์ด ์„ค์ •์„ ๊ฒ€ํ† ํ•  ๊ฒƒ.

๋‚จ์€ ์ƒํƒœ

flow         40/40  ์™„์ฃผ
random_mask   5/40  OOM kill (checkpoint_4 ์—์„œ ์žฌ๊ฐœ ๊ฐ€๋Šฅ)
duplicate    17/40  ๋ฐœ์‚ฐ (checkpoint_15 ์—์„œ ์žฌ๊ฐœ ๊ฐ€๋Šฅ)
zero          0/40  ์ง„ํ–‰ ์‹œ์ž‘ 2026-08-13 22:23
flow_reinit   0/40  ๋Œ€๊ธฐ