LoRA와 QLoRA 파인튜닝
파인튜닝은 지식이 아니라 행동을 조율합니다. 모델이 소재는 알지만 잘못된 춤을 출 때의 올바른 도구입니다. 잘못된 출력 형식, 잘못된 톤, 잘못된 도메인 방언, 잘못된 거절 조준. "내 문서를 알게" 하는 데는 잘못된 도구입니다 — 그것은 검색입니다: RAG.
파인튜닝인가 아닌가
| 목표 | 손을 뻗을 것 |
|---|---|
| 내 문서에서 질문에 답하기 | RAG |
| 정확히 내 JSON/XML 형식을 항상 뱉기 | LoRA — 또는 문법-제약 디코딩 |
| 일관된 하우스 스타일로 쓰기 | LoRA |
| 정당한 도메인 요청에 대한 거절 멈추기 | LoRA, 데이터에 주의하여 |
| 내 도메인 방언 유창하게 말하기 | LoRA, 그 위에 RAG |
| 더 잘 추론하기 | 더 크거나 더 나은 베이스 모델 — 튜닝은 IQ를 더하지 않습니다 |
프롬프트나 스키마로 될 일이라면 프롬프트나 스키마를 선호하세요. 모든 호출에 같은 지시 300 토큰을 붙여넣는 자신을 발견할 때 튜닝하세요.
LoRA 한 문단으로
모든 베이스 가중치를 동결하세요. 각 대상 가중치 행렬에 작은 학습 가능 행렬 두 개 — A (r×d)와 B (d×r) — 를 더하고 그것만 학습합니다. 갱신은 저계급(low-rank)입니다:
W' = W + (alpha / r) · B·A # A is r×d, B is d×r, rank r << d
구체적으로: d = 4096 행렬에 랭크 r = 16이면 4096² ≈ 16.8M의 덴스 대신 2 × 4096 × 16 = 131k 어댑터 파라미터가 필요합니다 — 그 행렬의 0.8%. 7–8B 모델 전체에 걸쳐 어댑터는 ~40–80M 파라미터입니다. 베이스의 0.5–1%, 몇백 MB. 스타일과 형식을 세게 움직이기에 충분한 용량입니다. 그 행동들이 강하게 저계급 방향에 살기 때문입니다.
QLoRA: 소비자 카드 한 장
QLoRA는 학습 중 동결된 베이스를 4비트(NF4)로 유지하고 어댑터를 16비트로 돌립니다. 현재 스택의 실무 숫자: 7–8B 모델은 단일 24GB GPU에서 QLoRA-학습됩니다. 3B는 8GB에서 편안합니다. 그래디언트 체크포인팅과 페이징 옵티마이저는 도구가 처리합니다 — 당신이 대는 것은 예산 수학입니다: VRAM 계산.
데이터가 모든 것을 이깁니다
고품질 쌍 500–5,000개가 긁어모은 쌍 10만 개를 매번 이깁니다. 중요한 규칙들:
- 하나의 일관된 형식. 서빙에 쓸 바로 그 챗 템플릿을 쓰세요 — 학습/서빙 템플릿 불일치는 실행 전체를 무효로 만듭니다.
- 양보다 품질. 각 쌍은 모델에게서 받아도 될 출력이어야 합니다. 중복 제거. 대충 만든 예기는 버리세요.
- 커버리지. 모델이 거절하거나 특별히 다뤄야 할 사례를 포함하세요 — 그러지 않으면 새 행동을 모든 것에 과잉 일반화합니다.
- 오염 검사. 평가 질문이 학습 데이터에 없는지 확인하세요 — 그러지 않으면 암기를 채점하는 것입니다.
- 홀드아웃 평가 세트. 절대 학습하지 않는 50–100개 예제, 전과 후에 채점.
쌍의 실제 모습(대부분 도구가 소비하는 messages 형식):
{"messages": [{"role": "system", "content": "You are a 1998-era equipment manual assistant."},
{"role": "user", "content": "How do I reset the service counter?"},
{"role": "assistant", "content": "Press MENU and hold for 3 seconds..."}]}
도구
| 도구 | 고르는 이유 |
|---|---|
| Unsloth | 가장 빠른 단일-GPU 트레이너, 무료 커뮤니티 노트북 — 쉬운 시작 |
| Axolotl | 설정 기반, 넓은 데이터셋 형식 지원, 재현 가능한 레시피 |
| LLaMA-Factory | GUI + CLI, 강력한 다국어 데이터셋 생태계 |
집필 시점 기준 셋 다 활발히 유지됩니다: unsloth, axolotl, llama-factory.
실제로 중요한 하이퍼파라미터
영향 순서대로:
- 학습률 — QLoRA에 1e-4 ~ 2e-4가 분별 있는 밴드. 너무 높은 것이 흐물흐물해지는 흔한 원인.
- 에포크 — 1–3. 그 이상에서 예스맨이 나옵니다.
- 랭크 / alpha — 행동 조정 대부분은 r 8–32에 alpha 16–32. 도메인 무거운 이동에는 더 큰 랭크.
- 컨텍스트 길이 — 트레이너 기본값이 아니라 가장 긴 실제 예제에 맞추세요.
- 배치 크기 — 한 장 카드의 QLoRA에서 1–8이 정상. 품질이 아니라 처리량 노브입니다.
실행이 실망스러우면 데이터 먼저, 학습률 그다음, 랭크는 마지막에 고치세요.
시간과 비용
2,000쌍, 3에포크, 7–8B 모델의 QLoRA: RTX 3090/4090급 카드 한 장에서 1–3시간을 예상하세요. API 청구가 아니라 전기요금이고, 반복은 늦어도 하룻밤입니다. 그래서 로컬 파인튜닝은 조달 절차가 아니라 취미입니다.
반복을 예산에 넣으세요. 첫 실행은 데이터 문제를 가르쳐주고, 두 번째가 당신이 계속 쓸 것입니다.
출하 전에 평가하세요
고정 프롬프트 30–50개 — 홀드아웃 세트 포함 — 를 전과 후에 돌리고, 출력을 나란히 비교하세요. 그런 다음 범용 챗을 회귀 검사하세요. 고전적 실패는 모든 것을 버그-리포트 형식으로 답하는 도메인 튜닝 모델입니다. 범용 품질이 떨어졌으면 에포크를 줄이고, 학습률을 낮추거나, 실행에 일반 지시 데이터 10–30%를 섞으세요.
loss 곡선은 이탈을 찾는 것이지 채점을 위한 것이 아닙니다. 학습 loss는 떨어지다가 평평해져야 합니다. 심판은 평가 스위트입니다.
내보내기와 서빙
학습된 어댑터에서 나가는 길은 두 개:
- 머지. LoRA를 fp16에서 베이스에 합치고 GGUF로 변환해 llama.cpp에 — 포럼 친화적 산출물: 파일 하나, 어느 엔진이나: 모델 포맷, 양자화.
- 어댑터 분리 유지. transformers/vLLM용으로, 런타임에 베이스 + 어댑터를 로드합니다 — 반복이 싸고, 엔진 특정적입니다.
실패 양상
- 과적합 / "예스맨" — 프롬프트를 따라 하고 모든 것에 동의. 학습 loss 낮음, 평가 악화. 해결: 에포크 축소, LR 하향, 더 다양한 데이터.
- 치명적 망각 — 도메인 기술 상승, 범용 능력 하락. 해결: 일반 데이터 혼합; LR 하향.
- 템플릿 표류 — 한 챗 템플릿으로 학습하고 다른 것으로 서빙. 증상은 문제 해결의 고전들.
SFT 뒤의 DPO
형식은 맞는데 선호가 어긋날 때 — 너무 장황, 틀린 톤, 과잉 거절 — 선호 쌍(선택 대 기각 응답)에 대한 소규모 DPO 실행이 또 한 번의 SFT 패스 없이 행동을 조정합니다. 싸고, 안정적이고, SFT-그리고-DPO 레시피의 표준 2단계입니다.