콘텐츠로 이동

05. 출력 해석하기#

📚 학습 목표: 학습 중 터미널에 나오는 숫자들을 제대로 읽기
⏱️ 읽는 시간: 20분


왜 출력 해석이 중요한가#

학습은 3-5시간 걸립니다. 그동안 "잘 되고 있는 건가?" 모니터링이 필요합니다.

틀린 판단의 비용: - 학습 잘못 가고 있는데 방치 → 5시간 날림 - 정상인데 Ctrl+C로 중단 → 5시간 날림

제대로 읽을 줄 알면 초기 10분 만에 판단 가능합니다.


1. 학습 시작 시점 출력#

======================================
MLX LoRA 학습 (Apple Silicon 로컬)
  Base Model:     google/gemma-4-E4B-it
  Iterations:     600
  Batch Size:     2
  LoRA r/α:       32 / 64
  Data:           data/processed
  Adapter 출력:   outputs/mlx_adapter
======================================

[1/5] 데이터 MLX 형식으로 준비
      → data/processed/mlx/{train,valid}.jsonl

[2/5] HF 모델 → MLX 변환
      → outputs/mlx_base 생성 완료

[3/5] 4-bit 양자화 (QLoRA)
      → outputs/mlx_base_4bit 생성 완료

체크 포인트#

  • Base Model: google/gemma-4-E4B-it (맞음)
  • Iterations: 600: 더미 데이터는 OK, 실제 데이터면 900-1500 필요
  • LoRA r/α: 32/64: 표준값
  • ⚠️ 경고 없는지 확인: 빨간 글씨 있으면 읽어보기

2. 학습 중 출력 (가장 중요)#

Iter 10: Train loss 2.451, Learning Rate 2.000e-04, It/sec 0.85, Tokens/sec 245.3, Trained Tokens 2860
Iter 20: Train loss 1.982, Learning Rate 2.000e-04, It/sec 0.92, Tokens/sec 268.5, Trained Tokens 5720
Iter 50: Val loss 1.672, Val took 3.142s
Iter 50: Train loss 1.435, Learning Rate 2.000e-04, It/sec 0.95, Tokens/sec 275.1, Trained Tokens 14300
Iter 100: Saved adapter weights to outputs/mlx_adapter/0000100_adapters.safetensors
...

용어 해석#

용어 의미 정상 범위
Iter 몇 번째 반복인지 1~600 (설정대로)
Train loss 학습 중 데이터 틀린 정도 2.5 → 0.8로 감소
Val loss 검증 데이터 틀린 정도 (진짜 실력) Train loss 근처
Learning Rate 한 번에 얼마나 바꾸는지 2e-4 고정 (cosine)
It/sec 초당 반복 횟수 0.5~1.5 (맥미니 M4 기준)
Tokens/sec 초당 처리 토큰 수 200-400 (정상)
Trained Tokens 총 학습한 토큰 수 누적값

3. Loss 변화 패턴 읽기#

패턴 A: 이상적 (성공)#

Iter 10:  Train loss 2.451
Iter 50:  Train loss 1.823  ← 꾸준히 감소
Iter 50:  Val loss 1.742    ← Train과 비슷
Iter 100: Train loss 1.421
Iter 100: Val loss 1.389
Iter 300: Train loss 0.921
Iter 300: Val loss 0.952
Iter 500: Train loss 0.756
Iter 500: Val loss 0.812   ← 더 이상 많이 안 내려감 (수렴)
Iter 600: Train loss 0.712
Iter 600: Val loss 0.798

해석: 매우 건강한 학습. 그대로 두면 됨.

패턴 B: Overfitting (경고)#

Iter 10:  Train loss 2.451
Iter 100: Train loss 1.200
Iter 100: Val loss 1.250     ← 아직 비슷
Iter 300: Train loss 0.450
Iter 300: Val loss 1.100     ⚠️ 격차 벌어짐
Iter 500: Train loss 0.180
Iter 500: Val loss 1.350     ⚠️ Val 오히려 상승
Iter 600: Train loss 0.120
Iter 600: Val loss 1.480     🚨 완전 overfitting

해석: 학습 데이터를 외워버림. 새 문제엔 약함.

대처: 1. 가장 좋았던 체크포인트로 롤백 (0000300_adapters.safetensors) 2. 다음엔 iter 줄이기 (600 → 300) 3. 데이터 더 모으기

패턴 C: 학습 안 됨 (문제)#

Iter 10:  Train loss 2.451
Iter 50:  Train loss 2.440
Iter 100: Train loss 2.438
Iter 300: Train loss 2.431   ← 거의 변화 없음
Iter 600: Train loss 2.425

해석: 뭔가 문제 있음.

원인 가능성: - Learning Rate 너무 낮음: 2e-4 → 5e-4로 증가 - 데이터 포맷 문제: JSONL 구조 확인 - 토크나이저 문제: 한국어 깨짐 확인 - 모델 너무 큼: E4B → E2B로 테스트

패턴 D: Loss 폭주 (즉시 중단)#

Iter 10:  Train loss 2.451
Iter 50:  Train loss 5.823   ⚠️ 오히려 증가
Iter 100: Train loss 12.4    🚨
Iter 150: Train loss NaN     💥 폭발

해석: 학습 실패. 즉시 Ctrl+C.

원인: - Learning Rate 너무 높음 (2e-4 → 1e-4 낮추기) - 데이터에 이상치 포함 (전처리 재검토) - 배치 사이즈 부적절


4. 학습 속도 해석#

It/sec (Iterations per Second)#

맥미니 M4 24GB에서 정상 범위:

설정 예상 It/sec
E4B, batch=2, 4bit 0.8-1.2
E4B, batch=4, 4bit 0.4-0.6
E2B, batch=4, 4bit 1.5-2.5

이상 신호: - 0.1 이하: 메모리 스와핑 발생 중 → 다른 앱 닫기 - 0.3 이하 (E4B batch=2): 뭔가 문제

전체 학습 시간 계산#

총 시간 = (총 Iter) / (It/sec)
예시 = 600 / 1.0 = 600초 × iter당 batch_size = ...

실제 경험: - 더미 250건 + 600 iter: 약 1-2시간 - 실제 1,500건 + 900 iter: 약 3-5시간 - 실제 5,000건 + 1500 iter: 약 6-10시간


5. 체크포인트 출력#

Iter 100: Saved adapter weights to outputs/mlx_adapter/0000100_adapters.safetensors
Iter 200: Saved adapter weights to outputs/mlx_adapter/0000200_adapters.safetensors
...

왜 좋은가: - 중간에 중단되도 복구 가능 - 각 시점 모델 비교 가능 - Overfitting 직전 체크포인트로 롤백

용량 주의: 체크포인트마다 300MB → 600 iter면 총 1.8GB

정리:

# 학습 완료 후 중간 체크포인트 정리
rm outputs/mlx_adapter/000*_adapters.safetensors  # 중간 것만
# adapters.safetensors (최종)만 남김


6. 메모리 사용량 해석#

다른 터미널에서:

# 실시간 모니터링
top -o mem

# 또는 Activity Monitor
open -a "Activity Monitor"

정상 범위#

단계 메모리 사용
데이터 준비 1-2 GB
MLX 변환 8-12 GB
4bit 양자화 6-8 GB
LoRA 학습 10-15 GB
GGUF 변환 8-10 GB
Ollama 추론 4-6 GB

맥미니 24GB: 시스템(5-8GB) + 학습(15GB) = 여유 있음

위험 신호: - 메모리 압박 (Memory pressure) 빨강 → 다른 앱 전부 닫기 - Swap used > 2GB → 디스크로 swap 나감, 속도 저하 - Pages swapped > 100,000 → 심각, 학습 멈출 수도


7. 학습 완료 후 출력#

[5/5] 학습된 어댑터로 추론 테스트
==========
Prompt: KPCS가 뭔가요?
Response: Korean Patient Classification System으로, 환자의 간호 요구도를 분류하는 체계...
==========

✅ MLX LoRA 학습 완료

다음 단계:
  1. 어댑터 병합:  bash scripts/03b_fuse_mlx.sh
  2. GGUF 변환:    bash scripts/04_convert_gguf.sh outputs/merged mediconsol-v1 Q4_K_M
  3. Ollama 등록:  bash scripts/05_create_ollama.sh mediconsol-v1

품질 체크#

첫 답변 평가 기준:

답변 특징 해석
도메인 용어 정확 사용 ✅ 학습됨
형식 (SOAP 등) 준수 ✅ 패턴 익힘
사실 관계 맞음 ✅ 지식 습득
자연스러운 한국어 ✅ 기본 유지
프롬프트 그대로 반복 ⚠️ 덜 학습됨
횡설수설 🚨 문제 있음
영어로 답변 🚨 데이터 문제

8. 병합/변환 단계 출력#

Fuse 출력#

[1/2] 어댑터 병합 중...
      ✅ 병합 완료: outputs/merged

[2/2] 병합 모델 검증
   디렉토리 크기:
    8.1G    outputs/merged
   포함 파일:
   -rw-r--r--  model-00001-of-00002.safetensors  4.3G
   -rw-r--r--  model-00002-of-00002.safetensors  3.8G
   -rw-r--r--  tokenizer.json                    17M
   ...

체크: - ✅ 약 8GB 내외 (E4B FP16) - ✅ model-*.safetensors 여러 파일 - ✅ tokenizer.json 있음

GGUF 변환 출력#

[1/3] FP16 → GGUF (F16) 변환
INFO:hf-to-gguf:Loading model: merged
...
Writing: 100%|████████████| 8.14G/8.14G [05:12<00:00, 28.4MB/s]
INFO:hf-to-gguf:Model successfully exported

[2/3] Q4_K_M 양자화
main: quantizing 'mediconsol-v1.F16.gguf' to 'mediconsol-v1.Q4_K_M.gguf'
...
main: model size = 7811.26 MB
main: quant size = 2387.85 MB

[3/3] 검증
-rw-r--r--  mediconsol-v1.Q4_K_M.gguf  2.4G

체크: - ✅ F16 GGUF: 약 8GB - ✅ Q4_K_M: 약 2.4-3GB (1/3로 압축) - ✅ 압축률 75% 정상


9. Ollama 배포 출력#

[1/3] Modelfile 생성
[2/3] Ollama 모델 등록
creating model...
transferring model data
converting model
using existing layer sha256:...
using existing layer sha256:...
creating new layer sha256:...
success

[3/3] 태그 설정
copying 'mediconsol-v1:1.0.0' to 'mediconsol-v1:latest'

✅ Ollama 등록 완료

  ollama list
  NAME                    ID          SIZE      MODIFIED
  mediconsol-v1:latest    abc123      2.4 GB    1 min ago
  mediconsol-v1:1.0.0     abc123      2.4 GB    1 min ago

체크: - ✅ "success" 메시지 - ✅ latest와 버전 태그 모두 있음 - ✅ 크기 2.4GB (GGUF와 동일)


10. 평가 출력 상세#

make evaluate
==========================================
평가 실행: mediconsol-v1
==========================================

[1/5] 카테고리: nursing
  Q1: "다음 음성을 SOAP로 정리: 환자 김○○ 무릎 통증..."
     Expected keywords: ['SOAP', '통증', '사정']
     Response: "S: 환자는 무릎 통증 호소. O: 혈압 140/90..."
     Match: 3/3 (100%)
  Q2: ...
  Q3: ...
  Q4: ...
  [nursing] Score: 65% (13/20)

[2/5] 카테고리: management
  ...
  [management] Score: 55% (11/20)

...

==========================================
종합 결과
==========================================
카테고리          키워드 매칭   답변 품질
nursing          65%          양호
management       55%          보통
medical_terms    70%          좋음
consulting       50%          보통
communication    60%          양호
------------------------------------------
종합 점수:       60%

저장: outputs/eval_report.json

해석#

카테고리별 목표 점수:

카테고리 더미 데이터 실제 데이터 MVP 프로덕션 목표
nursing 50-70% 75%+ 85%+
management 40-60% 70%+ 80%+
medical_terms 60-80% 80%+ 90%+
consulting 40-60% 65%+ 75%+
communication 50-70% 75%+ 85%+

점수 해석: - 30% 이하: 거의 학습 안 됨 - 30-50%: 데이터 부족 또는 학습 부족 - 50-70%: 더미 데이터 기준 정상 ⭐ - 70-85%: 실제 데이터로 좋은 결과 - 85%+: 우수 (또는 overfitting 의심)


11. 막힐 때 자가진단 플로우#

Loss 감소 안 됨?
├── 데이터 양 충분? → 250건 이하면 문제
├── LR 적절? → 2e-4가 표준
└── 포맷 맞음? → JSONL 구조 확인

Loss 폭주 NaN?
└── 즉시 중단 → LR 낮추기 (1e-4)

Val loss >> Train loss?
└── Overfitting → iter 줄이기

학습 너무 느림?
├── It/sec 0.5 이하? → 메모리 확인
├── 다른 앱 실행 중? → 닫기
└── CPU 80%+? → 정상

답변이 영어?
├── 데이터에 영어 섞임 → 전처리 재검토
└── 시스템 프롬프트 확인

답변 품질 나쁨?
├── 더미라서 그럼 → 정상 (실제 데이터 필요)
├── 실제 데이터인데 나쁨? → Bad case 분석
└── 완전 엉뚱? → 학습 실패

✅ 자가 체크#

  • Loss 정상/비정상 패턴 구분 가능
  • It/sec 정상 범위 알고 있음
  • 메모리 사용량 정상/이상 구분 가능
  • 평가 점수 해석 가능
  • 문제 발생 시 초기 대응 가능

다음 단계#

출력 해석이 되면, 이제 문제 대처법입니다.

다음 문서: 06_TROUBLESHOOTING.md - 막힐 때 대처법


💡 핵심 요약#

Loss 2.5 → 0.8: 정상
Train << Val: Overfitting
Loss NaN: 즉시 중단
It/sec 1.0 근처: M4 정상
메모리 15GB 이하: 여유 있음