"LLM 핵심 학습 (2/6) — 파인튜닝: LoRA·QLoRA·증류·Adapter"
사전학습된 LLM을 내 데이터에 적응시키는 방법을 비용·메모리·일반화 관점에서 정리한다. Full FT의 한계 → Adapter → LoRA → QLoRA → Distillation 순으로 같은 그림을 점점 확대해 본다.
0. 학습 목표
- Full fine-tuning의 메모리 병목을 옵티마이저 상태·그래디언트·가중치·활성화의 4분할로 설명한다.
- Adapter(Houlsby 2019)와 LoRA(Hu 2021)의 식 차이를 한 줄로 적는다.
- LoRA의 \(A, B\) 행렬이 왜 저랭크이고, rank \(r\) 선택이 무엇을 결정하는지 답한다.
- QLoRA(Dettmers 2023)의 NF4·double-quant·paged optimizer를 분리해서 설명한다.
- Catastrophic Forgetting을 분포 시프트 관점에서 정의하고 완화 기법을 두 개 이상 든다.
- Hinton 2015의 Knowledge Distillation 식을 손으로 유도한다.
1. 핵심 요약
- Full FT는 메모리/디스크/시간 모두 비싸다. 7B 모델 full FT는 V100 8장 + A100 1장으로도 큰 부담이다.
- PEFT(파라미터 효율 파인튜닝) 일가족은 극히 일부 파라미터만 학습해 같은 효과를 얻는다.
- LoRA: \(\Delta W = BA\) (rank \(r \ll \min(d_{\text{in}}, d_{\text{out}})\))로 가중치 업데이트를 저랭크 분해.
- QLoRA: 베이스 모델을 4-bit(NF4)로 양자화한 채 LoRA만 풀-정밀(BF16)으로 학습.
- Catastrophic Forgetting: 새 분포에 적응하느라 이전 능력이 무너지는 현상. PEFT 자체가 부분 완화책.
- Distillation: 큰 교사 모델의 soft target을 학습 신호로 써서 작은 학생 모델을 만든다.
2. 직관: 왜 사전학습만으로는 부족한가
사전학습은 일반 텍스트 분포에서 다음 토큰을 잘 예측하도록 가중치를 잡는다. 사용처가 (a) 도메인 특화 문체(법률, 의료), (b) 특정 형식(JSON 출력), (c) 안전·정책(거부 행동) 같은 좁은 분포라면, 사전학습 모델은 평균적으로 똑똑할 뿐 그 분포에 조정된 적이 없다. 파인튜닝은 이 좁은 분포에 가중치를 다시 옮기는 행위다.
문제는 비용이다. 7B 모델의 BF16 파라미터 1개 = 2바이트. 가중치만 14 GB. Adam 옵티마이저는 추가로 \(m, v\) 모멘트 텐서 두 개를 FP32로 보관해야 하니 8 GB × 2 = 16 GB. 그래디언트도 가중치만큼. 활성화는 시퀀스 길이 × 배치 × 레이어 수에 비례. 합하면 단일 GPU 80 GB도 빠듯하다. PEFT는 "학습 대상을 1%로 줄여 옵티마이저 상태·그래디언트를 1%로 줄이자"는 단순하고 강력한 아이디어다.
3. Full Fine-Tuning — 메모리 분해와 손실
3.1 식
손실은 보통 다음 토큰 cross-entropy다.
$$ \mathcal{L}(\theta) = -\sum_{t=1}^{T} \log P_\theta(x_t \mid x_{<t}). $$
\(\theta\) 전체를 학습하는 것이 full FT. 업데이트는 표준 AdamW:
$$ m_t = \beta_1 m_{t-1} + (1-\beta_1) g_t,\ \ v_t = \beta_2 v_{t-1} + (1-\beta_2) g_t^2, $$ $$ \theta_t = \theta_{t-1} - \eta \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} - \eta \lambda \theta_{t-1}. $$
3.2 메모리 분해
| 항목 | 7B 모델 BF16 기준 | 메모리 |
|---|---|---|
| 가중치 \(\theta\) | \(7 \times 10^9 \times 2\)B | 14 GB |
| 그래디언트 \(g\) | \(7 \times 10^9 \times 2\)B (BF16 mixed-precision 시) | 14 GB |
| AdamW m, v (FP32) | \(7 \times 10^9 \times 4\)B × 2 | 56 GB |
| 활성화 (gradient checkpointing 없이) | 시퀀스 4K · BS 1 · L=32 | 10~30 GB |
| 합계 | 94~114 GB |
→ 단일 A100 80 GB로는 부족. ZeRO-3 / FSDP로 GPU 여러 대에 분산하거나, gradient checkpointing으로 활성화 메모리를 줄여야 한다. 학습 비용의 큰 부분이 가중치 자체가 아니라 옵티마이저 상태와 활성화에 있다는 점이 PEFT의 출발점이다.
3.3 한계
- 비용. 작은 데이터셋에 full FT는 과잉.
- Catastrophic Forgetting 위험. 다음 절에서 정의.
- 배포. 도메인마다 7 GB짜리 가중치 사본을 따로 저장.
4. Adapter — PEFT의 원조
Houlsby et al., 2019는 트랜스포머 블록 안에 작은 다운-업 projection 모듈을 끼워 넣는 방법을 제안했다.
$$ h \leftarrow h + W_{\text{up}} \, \sigma(W_{\text{down}} h), $$
여기서 \(W_{\text{down}} \in \mathbb{R}^{r \times d}, W_{\text{up}} \in \mathbb{R}^{d \times r}\)이고 \(r \ll d\). 사전학습 가중치는 동결하고 어댑터만 학습한다. 학습 파라미터를 1~5%로 줄이면서 BERT 계열에서 거의 동등한 성능을 보였다.
단점은 추론 지연. 어댑터는 forward에 추가 연산을 더한다(블록당 2개의 추가 행렬곱). 양자화/배포 관점에서 거추장스럽다는 비판이 LoRA의 동기를 낳았다.
5. LoRA (Low-Rank Adaptation, Hu 2021)
5.1 식
기존 선형층 \(y = W_0 x\) (\(W_0 \in \mathbb{R}^{d_{\text{out}} \times d_{\text{in}}}\))에 덧셈 형태로 업데이트를 추가한다.
$$ y = W_0 x + \Delta W \, x,\ \ \Delta W = B A,\ \ A \in \mathbb{R}^{r \times d_{\text{in}}}, B \in \mathbb{R}^{d_{\text{out}} \times r}. $$
- \(r \ll \min(d_{\text{in}}, d_{\text{out}})\). 보통 \(r \in \{4, 8, 16, 32, 64\}\).
- \(W_0\)은 동결. \(A, B\)만 학습.
- 초기화: \(A \sim \mathcal{N}(0, \sigma^2)\), \(B = 0\). 초기 출력이 정확히 \(W_0 x\)와 같아 학습 시작 시 모델 동작이 바뀌지 않는다.
- 스케일 하이퍼파라미터 \(\alpha\): 실무에서 \(\Delta W = (\alpha / r) B A\) 형태로 적용. \(r\)을 바꿔도 그래디언트 스케일이 안정.
5.2 왜 저랭크인가
가설은 사전학습 모델은 이미 풍부한 표현을 갖고 있어서, 특정 태스크 적응에 필요한 가중치 차이 \(\Delta W\)는 매우 저랭크 구조를 띤다는 것이다. Hu et al., 2021은 GPT-3 175B에서 \(r=1\)조차 일부 태스크에서 작동하는 것을 보였다. 적정 \(r\)은 태스크 난이도에 따라 \(8 \sim 64\) 범위가 흔하다.
5.3 추론 시 병합 가능
학습이 끝나면 \(W = W_0 + (\alpha/r) B A\)를 미리 계산해 베이스에 합칠 수 있다. 추론에는 어댑터 같은 추가 연산이 없다(이것이 LoRA가 Adapter보다 선호된 결정적 이유). 여러 LoRA를 동시에 베이스 위에 합쳐 멀티태스크 라우팅을 만들 수도 있다.
5.4 파라미터·메모리 절감
기존 \(W_0\)의 파라미터: \(d_{\text{in}} \cdot d_{\text{out}}\). LoRA의 추가 파라미터: \(r (d_{\text{in}} + d_{\text{out}})\). 예: \(d=4096, r=8\)이면 추가 = \(8 \times 8192 = 65{,}536\) vs 기존 \(16{,}777{,}216\). 0.4%.
옵티마이저 상태도 LoRA 파라미터에만 잡히므로 AdamW의 \(m, v\) 메모리도 1% 미만으로 감소.
5.5 어디에 끼워 넣는가
원논문은 트랜스포머의 attention의 \(W^Q, W^V\)에만 LoRA를 붙여도 충분하다고 보고했다. 후속 실험은 \(W^K, W^O\) 그리고 MLP 층(\(W_1, W_2\))까지 확장하는 것이 더 강하다고 보였다. 어느 층에 어떤 rank를 줄지가 LoRA 튜닝의 주된 결정 사항.
5.6 PyTorch 미니 구현
import torch
import torch.nn as nn
class LoRALinear(nn.Module):
def __init__(self, base: nn.Linear, r: int = 8, alpha: float = 16.0):
super().__init__()
self.base = base
for p in self.base.parameters():
p.requires_grad = False
in_f, out_f = base.in_features, base.out_features
self.A = nn.Parameter(torch.randn(r, in_f) * 0.01)
self.B = nn.Parameter(torch.zeros(out_f, r))
self.scale = alpha / r
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.base(x) + (x @ self.A.T @ self.B.T) * self.scale
if __name__ == '__main__':
base = nn.Linear(4096, 4096, bias=False)
layer = LoRALinear(base, r=8, alpha=16.0)
x = torch.randn(2, 16, 4096)
y = layer(x)
print(y.shape, sum(p.numel() for p in layer.parameters() if p.requires_grad))
# torch.Size([2, 16, 4096]) 65536
5.7 다이어그램
5.8 한계
- 큰 분포 변화에는 약하다. 사전학습 분포에서 멀리 떨어진 도메인(예: 단백질 시퀀스)에는 full FT가 여전히 우세.
- rank \(r\)·target module 선택이 적지 않은 휴리스틱.
- LoRA만으로 catastrophic forgetting을 완전히 피하지는 못한다(완화일 뿐).
5.9 실습 과제
LoRALinear에서 \(B = 0\) 초기화를 \(B \sim \mathcal{N}(0, 0.01)\)으로 바꿔 학습 첫 스텝의 출력 분산을 비교한다(=무엇이 깨지는지 본다).- 같은 베이스 모델 위에 두 개의 LoRA를 학습한 뒤, \(W = W_0 + \Delta W^{(1)} + \Delta W^{(2)}\)로 합쳐 본다. 두 태스크 성능이 어떻게 변하는지 측정.
- rank \(r \in \{1, 4, 8, 32\}\)로 같은 데이터에 학습해 perplexity 곡선을 비교한다.
6. QLoRA — 4-bit 베이스 + LoRA
6.1 동기
LoRA는 학습 대상 파라미터를 줄이지만, 베이스 가중치 14 GB는 그대로 GPU에 올라가야 한다. Dettmers et al., 2023의 QLoRA는 베이스를 4-bit로 양자화해 메모리를 더 줄이고도 16-bit full FT급 성능을 보였다.
6.2 NF4 (NormalFloat 4-bit)
가중치 분포가 평균 0 정규분포에 가깝다는 관찰에서 출발해, 표준정규 분포의 분위수 16개로 4-bit 값을 정의한다. 일반 4-bit 정수 양자화(INT4)는 등간격이지만 NF4는 분포에 최적 적합된 분위수다. 양자화 오차가 낮은 동시에 \(2^4 = 16\) 코드를 사용하므로 메모리는 동일하게 4-bit/파라미터.
7B 모델 가중치: \(7 \times 10^9 \times 0.5\)B = 3.5 GB. 양자화 상수까지 포함해도 약 4 GB.
6.3 Double Quantization
각 텐서를 블록(예: 64개 가중치) 단위로 양자화하고, 그 블록별 스케일도 한 번 더 양자화한다. 추가 메모리는 파라미터당 평균 0.5 bit 미만으로 줄어든다.
6.4 Paged Optimizer
장문/긴 시퀀스에서 활성화·옵티마이저 상태가 일시적으로 부풀어 OOM이 나는 것을 막기 위해, NVIDIA Unified Memory(통합 메모리)로 옵티마이저 상태를 CPU/GPU 페이지 단위로 스왑한다. 학습 중 메모리 스파이크를 안전하게 흡수.
6.5 학습 흐름
- 베이스 \(W_0\)을 NF4 + double-quant로 양자화해 GPU에 적재(읽기 전용).
- forward 시 4-bit 가중치를 BF16으로 디코딩 후 행렬곱. 그래디언트는 4-bit를 거치지 않는다.
- LoRA 어댑터(BF16)만 학습. 옵티마이저 상태도 LoRA 파라미터에 한정.
- 추론 시 양자화 베이스 + 풀-정밀 LoRA를 결합.
6.6 결과 (논문 기준)
LLaMA-65B를 단일 48 GB GPU에서 QLoRA로 학습 가능. Guanaco 모델은 동일 자원으로 만든 모델 중 당시 1위 chat 성능을 보였다. 4-bit가 성능 손실이 없다는 결론은 양자화 방식(NF4) + 적절한 LoRA 결합이 함께 작동했기 때문이다.
6.7 한계와 주의
- 추론 시 양자화 베이스를 그대로 쓰면 처리량이 좋지만, 합쳐서 BF16으로 재배포하려면 다시 BF16으로 디코딩해 LoRA를 합쳐야 한다.
- 4-bit는 가중치만. KV 캐시·활성화는 별도 양자화가 필요(GPTQ, AWQ 등 별도 기법).
6.8 실습 과제
bitsandbytes라이브러리로 7B 모델을 NF4 적재한 뒤, GPU 메모리 사용량을 BF16 적재와 비교한다.- 동일 데이터셋에 LoRA(BF16 베이스) vs QLoRA(NF4 베이스) 학습을 돌려 perplexity와 학습 시간을 측정한다.
- NF4 양자화의 절대 오차(원본 가중치와 디코딩 후 가중치의 L2 차)를 텐서별로 측정해 분포를 그린다.
7. Catastrophic Forgetting
7.1 정의
이전에 학습한 분포 \(\mathcal{D}_A\)에서 잘 작동하던 모델이, 새 분포 \(\mathcal{D}_B\)로 추가 학습되면 \(\mathcal{D}_A\)의 성능이 급격히 떨어지는 현상. 연속 학습(continual learning)의 핵심 난제이며, 1989년 McCloskey & Cohen이 처음 명명했다.
7.2 LLM에서의 발현
- 영어로 사전학습된 모델을 한국어로 파인튜닝하면 영어 능력이 떨어진다.
- 코드 생성에 특화 파인튜닝하면 일반 대화 능력이 떨어진다.
- 안전 행동(거부 응답) 파인튜닝 후 일반 능력이 약화될 수 있다.
7.3 완화 기법
- PEFT 자체가 부분 완화. LoRA는 베이스 가중치를 건드리지 않아 원 능력 손실이 작다. 단, LoRA를 합쳐서 배포하면 효과는 사라진다.
- Replay. 사전학습 분포에서 샘플을 섞어 학습. 효과 강력하나 데이터 접근 필요.
- Elastic Weight Consolidation (EWC, Kirkpatrick 2017). 사전학습 시 중요했던 파라미터에 대한 변화에 패널티를 추가.
$$ \mathcal{L}_{\text{EWC}} = \mathcal{L}_{\text{new}}(\theta) + \frac{\lambda}{2} \sum_i F_i (\theta_i - \theta_i^A)^2, $$
\(F_i\)는 Fisher 정보(파라미터 \(i\)의 중요도 근사). 구현 복잡도가 높아 LLM 스케일에서 보편화되지는 못했다.
- Curriculum / Mixed Data. 새 태스크 데이터에 사전학습 분포 데이터를 비율로 섞는다(예: 70:30). 가장 실무적인 완화.
7.4 실습 과제
- 같은 모델로 (a) full FT, (b) LoRA로 한국어 데이터를 학습시키고, 학습 전후 영어 MMLU 점수 차이를 비교한다.
- Replay 비율을 0%, 10%, 30%로 바꿔 가며 새 태스크와 이전 태스크의 성능 트레이드오프 곡선을 그린다.
8. Knowledge Distillation (Hinton 2015)
8.1 식
큰 교사(teacher) 모델의 출력 분포 \(P_T(y \mid x)\)를 학생(student) 모델 \(P_S(y \mid x; \theta)\)가 모사하도록 학습한다.
$$ \mathcal{L}_{\text{KD}} = \alpha \cdot \mathcal{L}_{\text{CE}}(P_S, y_{\text{true}}) + (1-\alpha) \cdot T^2 \cdot \mathrm{KL}(P_T^{(T)} \,\|\, P_S^{(T)}). $$
여기서 \(P_T^{(T)}\)는 온도 \(T\)로 부드럽게 한 softmax:
$$ P^{(T)}(y \mid x) = \frac{\exp(z_y / T)}{\sum_{y'} \exp(z_{y'} / T)},\ \ T > 1. $$
온도가 크면 분포가 평평해져 teacher가 알고 있는 클래스 간 유사도 정보(dark knowledge)가 풍부해진다. 마지막 \(T^2\) 배율은 그래디언트 스케일 보정.
8.2 왜 작동하는가
- One-hot 정답은 어떤 오답이 더 가까운지 알려주지 않는다("강아지" 정답일 때 "고양이"와 "트럭" 모두 0).
- 교사의 soft target은 "강아지에 가깝지만 약간은 고양이 같다" 같은 클래스 간 거리를 전달.
- 학생은 적은 데이터로도 더 일반화 잘 되는 것을 학습.
8.3 LLM에서의 응용
- DistilBERT (Sanh 2019): BERT 대비 40% 작고 60% 빠르며 성능 97% 유지.
- TinyLlama, Llama-3.2-1B 같은 소형 모델은 같은 패밀리의 대형 모델 출력에서 distillation 신호를 받는다.
- 생성 모델에서는 단순 KL 외에 sequence-level distillation(학생이 교사의 생성 시퀀스를 모사) 변형이 흔하다.
8.4 실습 과제
- 작은 분류 데이터셋에서 (a) one-hot CE만, (b) \(T = 4\) KD를 사용해 학생 모델을 학습하고 일반화 격차를 비교한다.
- \(\alpha\)와 \(T\)를 같은 격자에서 바꿔가며 검증 성능 등고선을 그린다.
9. 어휘 관리 — 파인튜닝의 잊혀진 함정
새 도메인 토큰이 자주 등장하지만 어휘에 없으면 매번 여러 서브워드로 쪼개진다(예: 특정 약품명). 두 가지 선택지:
- 어휘 확장. 새 토큰을 어휘에 추가하고 임베딩 행에 추가. 추가 행은 평균 임베딩으로 초기화하는 것이 흔한 휴리스틱. 단, 모델은 이 토큰이 어떻게 행동해야 하는지를 처음부터 학습해야 한다.
- 유지. 기존 토크나이저로 잘리는 것을 감수. 입력·출력 토큰 수가 늘어나 비용은 증가하지만 모델 가중치는 그대로.
LoRA 학습 시 어휘 확장은 임베딩 행 + LM 헤드 행 두 곳에 영향이 있어 적용이 까다롭다. 보통은 기존 어휘 유지 + 충분한 학습 데이터로 우회한다.
10. 정리된 결론 — 보지 않고 답해 보라
이 글이 답한 핵심 질문 5개. 먼저 답을 가린 채로 한 줄로 답해 본 뒤 정답과 비교.
Q1. AdamW의 옵티마이저 상태가 가중치 대비 몇 배 메모리를 잡나?
정답 약 4배. 가중치 1× + 1차 모멘트 1× + 2차 모멘트 1× + gradients 1× ≈ 4×. 7B fp16이면 14GB → 풀 파인튜닝 56GB. 왜 풀 파인튜닝의 메모리 천장이 모델 크기 가 아니라 옵티마이저 상태 에 있다는 직관. 그래서 LoRA + QLoRA가 등장 — 7B 모델 풀 파인튜닝 56GB → QLoRA 6GB. (본문 §3 Full Fine-Tuning)
Q2. LoRA의 \(A\)와 \(B\)는 어떤 모양이고 왜 그렇게 초기화되나?
정답 \(A \in \mathbb{R}^{r \times d}\) 표준정규 초기화, \(B \in \mathbb{R}^{d \times r}\) 영행렬 초기화. 학습 시작 시 \(BA = 0\)이라 베이스 모델과 동일 한 상태에서 출발. 왜 "처음에는 베이스를 망치지 않는다"는 보장. 학습 중에만 \(B\)가 0에서 떨어져 가중치 보정 추가. ResNet의 identity 기본 패턴과 같은 발상. (본문 §5 LoRA)
Q3. LoRA를 추론 시 베이스에 합치면 무엇이 이득인가?
정답 \(W + BA\)를 미리 계산해 하나의 W'로 저장 → 추론 시 추가 행렬 곱이 없음 → 베이스 모델과 동일한 latency. 왜 학습 시점에는 \(BA\)가 분리되어 메모리 절감, 추론 시점에는 합쳐서 속도 절감. LoRA가 학습 + 추론 양쪽에서 모두 표준이 된 이유. (본문 §5)
Q4. QLoRA의 NF4가 INT4와 다른 점은?
정답 NF4 (Normal Float 4)는 정규분포 가정 에 최적화된 4-bit 양자화. INT4는 균등 분포 가정. LLM 가중치는 정규분포에 가깝다 → NF4가 INT4보다 정보 손실 적음. 왜 Dettmers 2023 QLoRA. NF4 + Double Quantization (양자화 상수도 다시 양자화) + Paged Optimizer 세 기법으로 65B 모델을 단일 48GB GPU에서 LoRA 학습 가능. (본문 §6 QLoRA)
Q5. Catastrophic Forgetting의 정의를 분포 시프트 관점으로 한 줄로 말하면? Distillation에서 \(T^2\)가 곱해진 이유는?
정답 Forgetting: 새 도메인에 fine-tune하면 기존 분포에서 학습한 지식 이 가중치 갱신으로 손실됨. \(T^2\): 손실의 스케일을 보존 하기 위함 — soft target은 \(T\)로 나뉘어 정보가 평탄해진 상태라 그래디언트 크기가 \(1/T^2\)배 작아짐. 왜 Forgetting: 분포 시프트 관점에서 과거 분포에서 best fit이었던 가중치 가 새 분포 best fit으로 이동. EWC (Kirkpatrick 2017) · LoRA 가 부분 답. Distillation \(T^2\): Hinton 2015. 같은 학습률로 hard target과 soft target을 결합 할 수 있게 함. (본문 §7 Forgetting, §8 Distillation)
5개를 한 줄로 답할 수 있었다면 파인튜닝의 메모리 분해 → LoRA → QLoRA → 분포 보존 흐름이 자리잡은 것이다.
11. 추가 학습
- Hu et al., 2021, LoRA. arXiv:2106.09685.
- Dettmers et al., 2023, QLoRA. arXiv:2305.14314.
- Houlsby et al., 2019, Parameter-Efficient Transfer Learning. arXiv:1902.00751.
- Hinton et al., 2015, Distilling the Knowledge in a Neural Network. arXiv:1503.02531.
- Sanh et al., 2019, DistilBERT. arXiv:1910.01108.
- Kirkpatrick et al., 2017, EWC. PNAS.
- HF PEFT 라이브러리: github.com/huggingface/peft.
bitsandbytes: github.com/TimDettmers/bitsandbytes.
이 글은 LLM 핵심 학습 시리즈의 2/6 편이다. 다음 편(3/6)은 디코딩과 생성 — Greedy·Beam·Top-p·Speculative로 이어진다.
시리즈 전체 안내: 시리즈 목차
댓글
댓글 쓰기