| # SFT ํ์ต ์์ธ ์ํฉ ํ๋ ์ด๋ถ |
|
|
| **ํ๋ก์ ํธ:** Korean 1B SFT ์ฌํ์ต |
| **์๋ฒ:** 8ร B200 183GB, Driver 580.95.05, CUDA 13.1, PyTorch 2.10 |
| **์์ฑ์ผ:** 2026-02-26 |
| **์ค์ :** bs=4 ร 8GPU ร grad_accum=2 = effective batch 64, max_steps=10000, lr=2e-5, FP8 |
|
|
| --- |
|
|
| ## ์๋๋ฆฌ์ค 1: Loss๊ฐ 0์ผ๋ก ๋จ์ด์ง๋ ๊ฒฝ์ฐ |
|
|
| ### ๊ฐ์ง ๊ธฐ์ค |
| - **์ฆ๊ฐ ๊ฒฝ๊ณ :** loss < 0.01์ด 3 step ์ฐ์ ๋ฐ์ |
| - **์ฃผ์:** loss < 0.1์ด 10 step ์ด์ ์ง์ |
| - **์ ์ ๋ฒ์:** 1B SFT์์ ์๋ ด ์ loss โ 1.5~2.0. 0์ ๊ฐ๊น์ฐ๋ฉด 100% ๋น์ ์ |
|
|
| ### ์ฆ๊ฐ ๋์ |
| 1. ํ์ต ์ฆ์ ์ค๋จ (Ctrl+C ๋๋ `kill -SIGINT <PID>`) |
| 2. ๊ฐ์ฅ ์ต๊ทผ ์ ์ ์ฒดํฌํฌ์ธํธ ํ์ธ: |
| ```bash |
| ls -lt checkpoints/korean_1b_sft/checkpoint-* | head -5 |
| ``` |
|
|
| ### ์์ธ๋ณ ์ง๋จ ๋ฐ ๋์ |
|
|
| #### 1-A. Labels Shift ๋ฒ๊ทธ ์ฌ๋ฐ |
| **ํ์ธ ๋ฐฉ๋ฒ:** |
| ```python |
| # ๋ฐ์ดํฐ์์ ์ํ ํ๋ ๋ก๋ ํ labels ๊ฒ์ฆ |
| from data.sft_dataset import SFTDataset |
| from tokenizers import Tokenizer |
| tok = Tokenizer.from_file("tokenizer/korean_sp/tokenizer.json") |
| ds = SFTDataset("data/sft/train.jsonl", tok, max_seq_len=4096) |
| ids, labels = ds[0] |
| # labels์์ -1์ด ์๋ ๋ถ๋ถ์ด input_ids์ ๋ค์ ํ ํฐ๊ณผ ์ผ์นํ๋์ง ํ์ธ |
| mask = labels != -1 |
| print(f"์ ํจ labels ์: {mask.sum()}") |
| print(f"์ฒซ ์ ํจ label ์์น: {mask.nonzero()[0].item() if mask.any() else 'NONE'}") |
| # labels[i]๋ input_ids[i+1]๊ณผ ๊ฐ์์ผ ํจ (autoregressive) |
| # ๋ง์ฝ labels == input_ids ์ด๋ฉด shift ์ ๋จ โ ๋ฒ๊ทธ |
| ``` |
| **์์ :** `sft_dataset.py`์์ `labels = input_ids[1:]`, `input_ids = input_ids[:-1]` shift ํ์ธ |
|
|
| #### 1-B. ๋ฐ์ดํฐ ์ค์ผ |
| **ํ์ธ ๋ฐฉ๋ฒ:** |
| ```python |
| # ๋๋ค ๋ฐฐ์น์์ ์ค์ ํ์ต ํ ํฐ ๊ฒ์ฌ |
| for batch in train_loader: |
| ids, labels, mask = batch |
| valid = (labels != -1) |
| print(f"์ ํจ ํ ํฐ ๋น์จ: {valid.float().mean():.4f}") |
| # ์ ํจ ํ ํฐ์ด 0์ด๋ฉด ๋ชจ๋ labels๊ฐ -1 โ loss=0 |
| if valid.sum() == 0: |
| print("๐ด ๋ชจ๋ labels๊ฐ ignore_index! ๋ฐ์ดํฐ ๋ฌธ์ ") |
| break |
| ``` |
| **๋์:** ๋ฐ์ดํฐ ์ฌ์์ฑ, `prepare_sft_data.py` ์ฌ์คํ |
|
|
| #### 1-C. Learning Rate ๋ฌธ์ |
| **ํ์ธ:** loss๊ฐ ๊ฐ์๊ธฐ 0์ด๋ฉด lr ๋ฌธ์ ๋ณด๋ค๋ labels ๋ฒ๊ทธ์ผ ๊ฐ๋ฅ์ฑ์ด ํจ์ฌ ๋์. ๊ทธ๋๋ ํ์ธ: |
| ```bash |
| grep "lr " checkpoints/korean_1b_sft/train.log | tail -20 |
| # lr์ด ๋น์ ์์ ์ผ๋ก ๋์ผ๋ฉด (>1e-3) ์์ |
| ``` |
|
|
| --- |
|
|
| ## ์๋๋ฆฌ์ค 2: Loss Spike (๊ธ๋ฑ) |
|
|
| ### ๊ฐ์ง ๊ธฐ์ค |
| - **Spike ์ ์:** ์ด์ log_interval ํ๊ท ๋๋น **3๋ฐฐ ์ด์** ๊ธ๋ฑ |
| - **์:** ํ๊ท loss 1.9์์ ๊ฐ์๊ธฐ 5.7 ์ด์ |
| - **GNorm ๊ธฐ์ค:** grad_norm > 10.0์ด๋ฉด ์ฃผ์, > 50.0์ด๋ฉด ์ฌ๊ฐ |
|
|
| ### ์์ธ๋ณ ๋์ |
|
|
| | ์์ธ | ์ง๋จ | ๋์ | |
| |------|------|------| |
| | Bad batch (์ด์ ๋ฐ์ดํฐ) | ํด๋น step์ ๋ฐฐ์น ๋ด์ฉ ํ์ธ | 1~2ํ spike ํ ์์ฐ ๋ณต๊ตฌ๋๋ฉด ๋ฌด์ | |
| | LR ๋ฌธ์ | warmup ์งํ spike โ lr ๋๋ฌด ๋์ | lr์ 1e-5๋ก ๋ฎ์ถ๊ณ ์ฌ์์ | |
| | GNorm ํญ๋ฐ | gnorm > 50 | max_grad_norm์ 0.5๋ก ๊ฐํ | |
| | FP8 ์์น ๋ถ์์ | FP8 ๊ด๋ จ warning ํ์ธ | `--use_fp8` ์ ๊ฑฐํ๊ณ BF16์ผ๋ก ์ ํ | |
|
|
| ### ๋์ ์ ์ฐจ |
| 1. **1ํ spike:** ๋ฌด์ (๋จ๋ฐ์ฑ bad batch). ๋ค์ log์์ ๋ณต๊ตฌ ํ์ธ |
| 2. **์ฐ์ 3ํ spike:** ํ์ต ์ค๋จ |
| 3. **๋ณต๊ตฌ ๋ฐฉ๋ฒ:** |
| ```bash |
| # ๋ง์ง๋ง ์ ์ ์ฒดํฌํฌ์ธํธ์์ ์ฌ์์, lr ๋ฎ์ถ๊ธฐ |
| bash scripts/launch_sft.sh --resume checkpoints/korean_1b_sft/checkpoint-XXXX --lr 1e-5 |
| ``` |
|
|
| ### ํ์ฌ ์ฝ๋์ ๋ณดํธ ์ฅ์น |
| - โ
`max_grad_norm=1.0` (gradient clipping ํ์ฑํ) |
| - โ
Non-finite loss ๊ฐ์ง โ RuntimeError ๋ฐ์ (trainer.py `_step()`) |
| - โ Loss spike ์๋ ๊ฐ์ง/skip์ ๋ฏธ๊ตฌํ โ `monitor_training.sh`๋ก ๋ณด์ |
|
|
| --- |
|
|
| ## ์๋๋ฆฌ์ค 3: ๊ณผ์ ํฉ (val_loss > train_loss ์ง์) |
|
|
| ### ๊ฐ์ง ๊ธฐ์ค |
| - **์ฃผ์:** val_loss - train_loss > 0.15 (์๋๊ฐญ 8% ์ด์) |
| - **์ฌ๊ฐ:** val_loss๊ฐ 3ํ ์ฐ์ eval์์ ์์น (train_loss๋ ํ๊ฐ ์ค) |
| - **eval_interval:** ํ์ฌ 250 steps โ ๋งค 250 step๋ง๋ค val_loss ๊ธฐ๋ก๋จ |
| |
| ### ํ์ฌ ์ฝ๋ ์ํ |
| - โ
`val_loader` ์ง์ (sft.py์์ `--val_data` ์ธ์ ์์) |
| - โ
`_run_validation()` ๊ตฌํ๋จ (trainer.py) |
| - โ
Best checkpoint ์๋ ์ ์ฅ (`val_loss < self._best_val_loss`) |
| - โ **Early stopping ๋ฏธ๊ตฌํ** โ val_loss๊ฐ ์ฌ๋ผ๋ max_steps๊น์ง ํ์ต ๊ณ์ |
|
|
| ### ๋์ |
|
|
| #### ์ฆ์ ๊ฐ๋ฅํ ์กฐ์น |
| 1. **์๋ early stop:** ๋ชจ๋ํฐ๋ง ์คํฌ๋ฆฝํธ๊ฐ ๊ฒฝ๊ณ โ ์๋ ์ค๋จ |
| 2. **Best checkpoint ์ฌ์ฉ:** `checkpoint-best` ๋๋ ํ ๋ฆฌ์ ์๋ ์ ์ฅ๋จ |
| ```bash |
| ls checkpoints/korean_1b_sft/checkpoint-best/ |
| ``` |
|
|
| #### ๊ณผ์ ํฉ ํด์ ๋ฐฉ๋ฒ (์ฌํ์ต ์) |
| | ๋ฐฉ๋ฒ | ์ค์ ๋ณ๊ฒฝ | |
| |------|-----------| |
| | LR ๋ฎ์ถ๊ธฐ | `--lr 1e-5` | |
| | Weight decay ๋์ด๊ธฐ | `--weight_decay 0.05` | |
| | ๋ฐ์ดํฐ augmentation | NEFTune ์ด๋ฏธ ํ์ฑํ (noise_alpha=10.0) โ
| |
| | Steps ์ค์ด๊ธฐ | `--max_steps 7000` (๊ณผ์ ํฉ ์์ ์ step์์ ๋ฉ์ถค) | |
| | Dropout | ๋ชจ๋ธ ๊ตฌ์กฐ ์์ ํ์ (ํ์ฌ ์ฝ๋์์ ์ฝ์ง ์์) | |
|
|
| #### Early Stopping ์ถ๊ฐ ๋ฐฉ๋ฒ (trainer.py ์์ ) |
| ```python |
| # trainer.py์ train() ๋ฉ์๋์์ validation ํ: |
| if val_loss > self._best_val_loss: |
| self._patience_counter += 1 |
| if self._patience_counter >= 5: # 5ํ ์ฐ์ ๊ฐ์ ์์ผ๋ฉด ์ค๋จ |
| self._log("Early stopping triggered") |
| break |
| else: |
| self._patience_counter = 0 |
| self._best_val_loss = val_loss |
| ``` |
|
|
| --- |
|
|
| ## ์๋๋ฆฌ์ค 4: OOM (Out of Memory) |
|
|
| ### ํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์ถ์ |
|
|
| | ํญ๋ชฉ | ์ถ์ | |
| |------|------| |
| | ๋ชจ๋ธ ํ๋ผ๋ฏธํฐ (1.19B, BF16) | ~2.4 GB | |
| | ์ตํฐ๋ง์ด์ ์ํ (AdamW, fp32) | ~9.5 GB | |
| | Gradient (BF16) | ~2.4 GB | |
| | Activation (bs=4, seq=4096, gradient checkpointing ON) | ~8-15 GB | |
| | **Peak ์ดํฉ (per GPU)** | **~25-35 GB** | |
| | **B200 ์ฌ์ ** | **183 - 35 = ~148 GB ์ฌ์ ** | |
|
|
| โ 1B ๋ชจ๋ธ์์ OOM ๊ฐ๋ฅ์ฑ **๊ทนํ ๋ฎ์** |
|
|
| ### ๋ง์ฝ ๋ฐ์ํ๋ค๋ฉด |
| 1. **์ฆ์:** `torch.cuda.OutOfMemoryError` โ trainer.py์์ ์ด๋ฏธ catchํ์ฌ ์์ธ ๋ฉ์์ง ์ถ๋ ฅ |
| 2. **์ฆ์ ๋์:** |
| ```bash |
| # batch_size ์ค์ด๊ธฐ (4โ2), grad_accum ๋๋ฆฌ๊ธฐ (2โ4) โ effective batch ๋์ผ |
| bash scripts/launch_sft.sh --batch_size 2 --grad_accum 4 --resume <last_ckpt> |
| ``` |
| 3. **Gradient checkpointing:** |
| - โ
**์ด๋ฏธ ํ์ฑํ๋จ** (sft.py์์ `model.gradient_checkpointing_enable()`) |
| 4. **์ถ๊ฐ ์กฐ์น:** |
| ```bash |
| # ๋ฉ๋ชจ๋ฆฌ fragmentation ๋ฐฉ์ง |
| export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True |
| ``` |
|
|
| ### ๋ฉ๋ชจ๋ฆฌ ๋ชจ๋ํฐ๋ง |
| ```bash |
| watch -n 5 nvidia-smi # ์ค์๊ฐ ํ์ธ |
| # ๋๋ monitor_training.sh ์ฌ์ฉ (์๋ ์ฐธ์กฐ) |
| ``` |
|
|
| --- |
|
|
| ## ์๋๋ฆฌ์ค 5: GPU Hang / NCCL ํต์ ์ฅ์ |
|
|
| ### ๊ฐ์ง ๋ฐฉ๋ฒ |
| - **์ฆ์:** ํ์ต ๋ก๊ทธ๊ฐ ๋ฉ์ถค (์ step์ด N๋ถ ์ด์ ์ ๋์ด) |
| - **NCCL timeout:** ๊ธฐ๋ณธ 30๋ถ ํ ์๋ฌ ๋ฐ์ |
| - `nvidia-smi`์์ ํน์ GPU utilization 0% |
|
|
| ### ์ง๋จ |
| ```bash |
| # 1. GPU ์ํ ํ์ธ |
| nvidia-smi |
| |
| # 2. NCCL ๋๋ฒ๊ทธ ํ์ฑํํ์ฌ ์ฌ์์ |
| export NCCL_DEBUG=INFO |
| export NCCL_DEBUG_SUBSYS=ALL |
| |
| # 3. ํ๋ก์ธ์ค ์ํ ํ์ธ |
| ps aux | grep torchrun |
| ``` |
|
|
| ### ๋ณต๊ตฌ ๋ฐฉ๋ฒ |
| ```bash |
| # 1. ๊ธฐ์กด ํ๋ก์ธ์ค ์ ๋ฆฌ |
| pkill -f torchrun |
| sleep 5 |
| |
| # 2. ๊ฐ์ฅ ์ต๊ทผ ์ฒดํฌํฌ์ธํธ ์๋ ๊ฐ์ง |
| LATEST_CKPT=$(ls -d checkpoints/korean_1b_sft/checkpoint-* 2>/dev/null \ |
| | grep -v best | sort -t- -k2 -n | tail -1) |
| echo "Latest checkpoint: ${LATEST_CKPT}" |
| |
| # 3. ์ฌ์์ |
| bash scripts/launch_sft.sh --resume "${LATEST_CKPT}" |
| ``` |
|
|
| ### ์ต๊ทผ ์ฒดํฌํฌ์ธํธ ์๋ ๊ฐ์ง ์คํฌ๋ฆฝํธ |
| ```bash |
| #!/bin/bash |
| # find_latest_checkpoint.sh |
| CKPT_DIR="${1:-checkpoints/korean_1b_sft}" |
| LATEST=$(ls -d "${CKPT_DIR}"/checkpoint-[0-9]* 2>/dev/null \ |
| | sort -t- -k2 -n | tail -1) |
| if [[ -z "$LATEST" ]]; then |
| echo "No checkpoint found in ${CKPT_DIR}" >&2 |
| exit 1 |
| fi |
| echo "$LATEST" |
| ``` |
|
|
| ### ์๋ฐฉ |
| - `save_interval=500` (ํ์ฌ ์ค์ ) โ ์ต๋ 500 step ์์ค |
| - NCCL timeout ์กฐ์ : `export NCCL_TIMEOUT=1800` (30๋ถ โ ํ์ ์ ์ค์ด๊ธฐ) |
|
|
| --- |
|
|
| ## ์๋๋ฆฌ์ค 6: ํ์ต ์๋ฃ ํ ๋ฐ๋ณต๋ฅ >15% |
|
|
| ### ํ๋จ ๊ธฐ์ค |
|
|
| | ๋ฐ๋ณต๋ฅ | ํ๋จ | ๋์ | |
| |--------|------|------| |
| | <5% (rep_penalty ์์ด) | โ
์ฑ๊ณต | ๋ฐฐํฌ ๊ฐ๋ฅ | |
| | 5-10% | ๐ก OK | rep_penalty=1.1๋ก ๋ฐฐํฌ | |
| | 10-20% | ๐ ๊ฒฝ๊ณ | ์๋ ํ๋ผ๋ฏธํฐ ์กฐ์ ์๋ | |
| | >20% | ๐ด ์คํจ | ์ฌํ์ต ํ์ | |
|
|
| ### ํ๋ผ๋ฏธํฐ ์กฐ์ ์ผ๋ก ํด๊ฒฐ ์๋ (์ฌํ์ต ์์ด) |
|
|
| ```python |
| # ์ถ๋ก ์ ์ ์ฉ |
| generate_kwargs = { |
| "repetition_penalty": 1.1, # 1.05~1.2 ๋ฒ์ ํ์ |
| "no_repeat_ngram_size": 3, # 3-gram ๋ฐ๋ณต ์ฐจ๋จ |
| "temperature": 0.7, # ์ฝ๊ฐ ๋ฎ์ถ๋ฉด ๋ฐ๋ณต ๊ฐ์ |
| "top_p": 0.9, |
| } |
| ``` |
|
|
| ### ์ฌํ์ต์ด ํ์ํ ๊ฒฝ์ฐ |
| - rep_penalty=1.2 + no_repeat_3gram์์๋ >10% |
| - ์์ธ ๋ถ์: |
| 1. **๋ฐ์ดํฐ ๋ด ๋ฐ๋ณต ํจํด:** `data_quality_audit.py`๋ก ์ฌํ์ธ |
| 2. **Epoch ๊ณผ๋ค:** 5+ epoch์ ๋ฐ๋ณต ํจํด ์๊ธฐ ์ ๋ฐ โ 3-4 epoch์ด ์ ์ |
| 3. **EOS ํ์ต ๋ถ์กฑ:** truncation ์ EOS ์์ค ์ฌ๋ถ ํ์ธ |
| |
| ### ๊ณ ๊ธ ๋์ (์ถ๊ฐ ํ์ต ๋ฐฉ๋ฒ) |
| | ๋ฐฉ๋ฒ | ์ค๋ช
| ์์ | |
| |------|------|------| |
| | ORPO | Preference optimization, ๋ฐ๋ณต ํจํด ์ง์ penalize | +3-6์๊ฐ | |
| | DPO | Chosen(๋น๋ฐ๋ณต) vs Rejected(๋ฐ๋ณต) ์ ํ์ | +4-8์๊ฐ | |
| | rep_penalty fine-tuning | ์ถ๋ก ์ penalty ๊ฒฐ๊ณผ๋ฅผ reward๋ก RL | ๋ณต์ก | |
|
|
| --- |
|
|
| ## ์๋๋ฆฌ์ค 7: ko_ifeval ๊ธฐ๋์น ๋ฏธ๋ฌ (<15%) |
| |
| ### ์์ธ ๋ถ์ ๋ฐฉ๋ฒ |
| |
| #### Step 1: ๋ชจ๋ธ ์ถ๋ ฅ ์ง์ ํ์ธ |
| ```bash |
| # ko_ifeval ์คํจ ์ํ ๋ถ์ |
| python -c " |
| # lm_eval ๊ฒฐ๊ณผ์์ ์คํจ ์ผ์ด์ค ์ถ์ถ |
| # ์ง์๋ฌธ ์ดํด ๋ถ์กฑ vs ํฌ๋งท ์ค๋ฅ vs ํ๊ตญ์ด ๋ฅ๋ ฅ ๋ถ์กฑ ๊ตฌ๋ถ |
| " |
| ``` |
| |
| #### Step 2: ์นดํ
๊ณ ๋ฆฌ๋ณ ๋ถ์ |
| | ์คํจ ์ ํ | ์๋ฏธ | ๋์ | |
| |-----------|------|------| |
| | ์ง์ ๋ฌด์ (wrong format) | instruction following ์ฝํจ | SFT ๋ฐ์ดํฐ์ format-constrained ์ํ ์ถ๊ฐ | |
| | ํ๊ตญ์ด ์ดํด ์คํจ | ํ๊ตญ์ด ๋ฅ๋ ฅ ๋ถ์กฑ | ํ๊ตญ์ด ๋น์จ ๋์ด๊ธฐ (ํ์ฌ ~70%) | |
| | ์ถ๋ก ์ค๋ฅ | 1B ๋ชจ๋ธ ํ๊ณ | ๋ชจ๋ธ ํฌ๊ธฐ ํ๊ณ โ 3B ์ ํ | |
| |
| #### Step 3: ๋ชจ๋ธ ํ๊ณ vs ๋ฐ์ดํฐ ๋ฌธ์ ๊ตฌ๋ถ |
| ``` |
| 1B ๋ชจ๋ธ ko_ifeval ํ์ค์ ๋ฒ์: 15-30% |
| - <15%: ๋ฐ์ดํฐ/ํ์ต ๋ฌธ์ ๊ฐ๋ฅ์ฑ ๋์ |
| - 15-25%: ์ ์ ๋ฒ์, ๋ฐ์ดํฐ๋ก ๊ฐ์ ์ฌ์ง ์์ |
| - 25-30%: 1B ํ๊ณ์ ๊ทผ์ , 3B ์ ํ ํ์ |
| - >30%: 1B์์ ๋ฌ์ฑํ๊ธฐ ์ด๋ ค์ |
| ``` |
| |
| ### ๋ฐ์ดํฐ ์ถ๊ฐ ์์ง ๋ฐฉํฅ |
| 1. **Korean instruction-following ๋ฐ์ดํฐ:** KoAlpaca, KULLM ๋ฑ์์ format-constrained ์ํ |
| 2. **Multi-turn ํ๊ตญ์ด ๋ํ:** ์ง์ ๋ฐ๋ฅด๊ธฐ ๋ฅ๋ ฅ ๊ฐํ |
| 3. **ko_ifeval๊ณผ ์ ์ฌํ ํฌ๋งท ๋ฐ์ดํฐ:** "~ํ์์ผ๋ก ๋ตํ์์ค" ์ ํ |
| |
| --- |
| |
| ## ์๋๋ฆฌ์ค 8: ๋์คํฌ ๊ณต๊ฐ ๋ถ์กฑ |
| |
| ### ํ์ฌ ์ํ |
| ``` |
| /PROJECT: 3.5TB ์ด, 1.4TB ์ฌ์ฉ, 2.2TB ๊ฐ์ฉ (39% ์ฌ์ฉ) |
| ``` |
| |
| ### ์ฒดํฌํฌ์ธํธ ํฌ๊ธฐ ์ถ์ |
| | ํญ๋ชฉ | ํฌ๊ธฐ | |
| |------|------| |
| | model.pt (1.19B BF16) | ~2.4 GB | |
| | optimizer.pt (AdamW states) | ~9.5 GB | |
| | scheduler + meta | ~1 MB | |
| | **์ฒดํฌํฌ์ธํธ 1๊ฐ** | **~12 GB** | |
| | 10,000 steps / 500 save = 20๊ฐ | **~240 GB** | |
| | + best checkpoint | +12 GB | |
| | + tensorboard logs | ~100 MB | |
| | **์ด ์์** | **~252 GB** | |
| |
| โ 2.2TB ๊ฐ์ฉ ๋๋น ์ถฉ๋ถํ์ง๋ง, ์ฌ๋ฌ ์คํ ์ ๋์ ์ฃผ์ |
| |
| ### ์ฒดํฌํฌ์ธํธ ๊ด๋ฆฌ ์ ๋ต |
| |
| #### ์ ์ฅ ์ฃผ๊ธฐ ์ต์ ํ |
| - **ํ์ฌ:** 500 step๋ง๋ค (์ถ์ฒ ์ ์ง) |
| - ๋์คํฌ ๋ถ์กฑ ์: 1000 step์ผ๋ก ๋ณ๊ฒฝ โ 120 GB๋ก ์ ๋ฐ ๊ฐ์ |
| - `train_config.save_interval = 1000` |
| |
| #### ์ค๋๋ ์ฒดํฌํฌ์ธํธ ์๋ ์ญ์ |
| ```bash |
| #!/bin/bash |
| # cleanup_checkpoints.sh โ ์ต์ N๊ฐ๋ง ์ ์ง, best๋ ํญ์ ๋ณด์กด |
| CKPT_DIR="${1:-checkpoints/korean_1b_sft}" |
| KEEP="${2:-5}" # ์ต์ 5๊ฐ ์ ์ง |
|
|
| CKPTS=$(ls -d "${CKPT_DIR}"/checkpoint-[0-9]* 2>/dev/null | sort -t- -k2 -n) |
| TOTAL=$(echo "$CKPTS" | wc -l) |
| DELETE=$((TOTAL - KEEP)) |
| |
| if [[ $DELETE -gt 0 ]]; then |
| echo "$CKPTS" | head -n "$DELETE" | while read ckpt; do |
| echo "Removing: $ckpt" |
| rm -rf "$ckpt" |
| done |
| echo "Kept latest $KEEP checkpoints + checkpoint-best" |
| else |
| echo "Only $TOTAL checkpoints, nothing to delete (keep=$KEEP)" |
| fi |
| ``` |
| |
| ### ๋์คํฌ ๋ชจ๋ํฐ๋ง |
| ```bash |
| # ํ์ต ์ค ์ฃผ๊ธฐ์ ํ์ธ |
| df -h /PROJECT | awk 'NR==2 {if ($5+0 > 80) print "๐ด DISK >80%: "$5}' |
| ``` |
| |
| --- |
| |
| ## ํ์ต ์ฌ์์ ๊ฐ์ด๋ |
| |
| ### ํ์ฌ ์ฝ๋์ Resume ์ง์ |
| |
| โ
**์์ ์ง์๋จ:** |
| - `sft.py`์ `--resume` ์ธ์ ์์ |
| - `load_checkpoint()`์ผ๋ก model, optimizer, scheduler ์ํ ๋ชจ๋ ๋ณต์ |
| - `start_step` ๋ฐํ โ ์ด์ด์ ํ์ต |
|
|
| ### ์ฌ์์ ๋ช
๋ น์ด |
| ```bash |
| # ๋ฐฉ๋ฒ 1: ์ต์ ์ฒดํฌํฌ์ธํธ์์ ์๋ ์ฌ์์ |
| LATEST=$(ls -d checkpoints/korean_1b_sft/checkpoint-[0-9]* 2>/dev/null \ |
| | sort -t- -k2 -n | tail -1) |
| bash scripts/launch_sft.sh --resume "${LATEST}" |
| |
| # ๋ฐฉ๋ฒ 2: ํน์ ์ฒดํฌํฌ์ธํธ ์ง์ |
| bash scripts/launch_sft.sh --resume checkpoints/korean_1b_sft/checkpoint-0003000 |
| |
| # ๋ฐฉ๋ฒ 3: LR ๋ณ๊ฒฝํ๋ฉฐ ์ฌ์์ (๊ณผ์ ํฉ/spike ๋์) |
| bash scripts/launch_sft.sh --resume "${LATEST}" --lr 1e-5 |
| ``` |
|
|
| ### ์ฃผ์์ฌํญ |
| - **cosine schedule:** resume ์ scheduler๊ฐ ์ค๊ฐ step์์ ๋ณต์๋จ โ LR์ด ์ฌ๋ฐ๋ฅธ ์์น์์ ์ฌ๊ฐ |
| - **max_steps ๋ณ๊ฒฝ ์:** ์๋ 5000 step ๊ธฐ์ค schedule์ธ๋ฐ 10000์ผ๋ก ๋ณ๊ฒฝํ๋ฉด LR curve๊ฐ ๋ฌ๋ผ์ง โ ์ฒ์๋ถํฐ ์ฌํ์ต ๊ถ์ฅ |
| - **DDP seed:** resume ์ ๋์ผ seed ์ฌ์ฉํด์ผ ๋ฐ์ดํฐ ์์ ์ฌํ (ํ์ฌ ์ฝ๋์์ ์๋ ์ฒ๋ฆฌ) |
| |
| --- |
| |
| ## ๋ชจ๋ํฐ๋ง ์๋ํ |
| |
| ๋ณ๋ ์คํฌ๋ฆฝํธ: `scripts/monitor_training.sh` ์ฐธ์กฐ |
| |
| ### ๊ฐ์ ํญ๋ชฉ ์์ฝ |
| |
| | ํญ๋ชฉ | ์๊ณ๊ฐ | ์๋ฏธ | |
| |------|--------|------| |
| | loss = 0.0000 (3 step ์ฐ์) | ๐ด Critical | Labels ๋ฒ๊ทธ | |
| | loss spike (3ร ํ๊ท ) | ๐ Warning | Bad batch / LR | |
| | gnorm > 10.0 | ๐ Warning | ๋ถ์์ | |
| | gnorm > 50.0 | ๐ด Critical | ๋ฐ์ฐ ์ง์ | |
| | GPU util < 50% | ๐ก Info | ๋ณ๋ชฉ (data loading?) | |
| | ๋ก๊ทธ 5๋ถ ์ด์ ๋ฉ์ถค | ๐ด Critical | Hang / NCCL ์ฅ์ | |
| | ๋์คํฌ ์ฌ์ฉ > 80% | ๐ Warning | ์ฒดํฌํฌ์ธํธ ์ ๋ฆฌ ํ์ | |
| |
| --- |
| |
| ## ์ํ๋ ์์ (๋์ โ ๋ฎ์) |
| |
| | ์์ | ์๋๋ฆฌ์ค | ์ํ๋ | ์๋ฐฉ | |
| |------|----------|--------|------| |
| | 1 | **Loss โ 0 (Labels ๋ฒ๊ทธ)** | ๐ด๐ด๐ด | ํ์ต ์ labels shift ๊ฒ์ฆ ์คํฌ๋ฆฝํธ ์คํ | |
| | 2 | **GPU Hang (NCCL)** | ๐ด๐ด | save_interval=500, NCCL ํ๊ฒฝ๋ณ์ ์ค์ | |
| | 3 | **๊ณผ์ ํฉ** | ๐ด | val_data ํ์, ๋ชจ๋ํฐ๋ง | |
| | 4 | **๋ฐ๋ณต๋ฅ >15%** | ๐ ๐ | ๊นจ๋ํ ๋ฐ์ดํฐ, ์ ์ epoch | |
| | 5 | **Loss Spike** | ๐ | grad_clip=1.0, ์ด๋ฏธ ์ค์ ๋จ | |
| | 6 | **ko_ifeval ๋ฏธ๋ฌ** | ๐ | 1B ํ๊ณ ์ธ์ง, ๋ฐ์ดํฐ ๋ค์์ฑ | |
| | 7 | **๋์คํฌ ๋ถ์กฑ** | ๐ก | 2.2TB ์ฌ์ , ์๋ ์ ๋ฆฌ | |
| | 8 | **OOM** | ๐ข | 183GB์ 1B ๋ชจ๋ธ, ๊ฑฐ์ ๋ถ๊ฐ๋ฅ | |
| |
| --- |
| |
| ## ํ์ต ์ ์ฒดํฌ๋ฆฌ์คํธ |
| |
| ``` |
| โก ๋ฐ์ดํฐ ํํฐ๋ง ์๋ฃ (data_quality_audit.py) |
| โก Val split ์์ฑ (90/10) |
| โก Labels shift ๊ฒ์ฆ (์ ์ฝ๋ ์ค๋ํซ ์คํ) |
| โก sft_dataset.py ์์ ํ์ธ (dynamic padding, EOS ๋ณด์กด) |
| โก launch_sft.sh ์ค์ ํ์ธ (max_steps, val_data, lr) |
| โก ๋์คํฌ ๊ณต๊ฐ ํ์ธ (df -h /PROJECT) |
| โก GPU ์ํ ํ์ธ (nvidia-smi) |
| โก monitor_training.sh ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํ |
| โก tensorboard ์คํ: tensorboard --logdir checkpoints/korean_1b_sft/tensorboard |
| ``` |
| |