"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 다이어그램

diagram-1

5.8 한계

  • 큰 분포 변화에는 약하다. 사전학습 분포에서 멀리 떨어진 도메인(예: 단백질 시퀀스)에는 full FT가 여전히 우세.
  • rank \(r\)·target module 선택이 적지 않은 휴리스틱.
  • LoRA만으로 catastrophic forgetting을 완전히 피하지는 못한다(완화일 뿐).

5.9 실습 과제

  1. LoRALinear에서 \(B = 0\) 초기화를 \(B \sim \mathcal{N}(0, 0.01)\)으로 바꿔 학습 첫 스텝의 출력 분산을 비교한다(=무엇이 깨지는지 본다).
  2. 같은 베이스 모델 위에 두 개의 LoRA를 학습한 뒤, \(W = W_0 + \Delta W^{(1)} + \Delta W^{(2)}\)로 합쳐 본다. 두 태스크 성능이 어떻게 변하는지 측정.
  3. 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 학습 흐름

  1. 베이스 \(W_0\)을 NF4 + double-quant로 양자화해 GPU에 적재(읽기 전용).
  2. forward 시 4-bit 가중치를 BF16으로 디코딩 후 행렬곱. 그래디언트는 4-bit를 거치지 않는다.
  3. LoRA 어댑터(BF16)만 학습. 옵티마이저 상태도 LoRA 파라미터에 한정.
  4. 추론 시 양자화 베이스 + 풀-정밀 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 실습 과제

  1. bitsandbytes 라이브러리로 7B 모델을 NF4 적재한 뒤, GPU 메모리 사용량을 BF16 적재와 비교한다.
  2. 동일 데이터셋에 LoRA(BF16 베이스) vs QLoRA(NF4 베이스) 학습을 돌려 perplexity와 학습 시간을 측정한다.
  3. 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 실습 과제

  1. 같은 모델로 (a) full FT, (b) LoRA로 한국어 데이터를 학습시키고, 학습 전후 영어 MMLU 점수 차이를 비교한다.
  2. 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 실습 과제

  1. 작은 분류 데이터셋에서 (a) one-hot CE만, (b) \(T = 4\) KD를 사용해 학생 모델을 학습하고 일반화 격차를 비교한다.
  2. \(\alpha\)와 \(T\)를 같은 격자에서 바꿔가며 검증 성능 등고선을 그린다.

9. 어휘 관리 — 파인튜닝의 잊혀진 함정

새 도메인 토큰이 자주 등장하지만 어휘에 없으면 매번 여러 서브워드로 쪼개진다(예: 특정 약품명). 두 가지 선택지:

  1. 어휘 확장. 새 토큰을 어휘에 추가하고 임베딩 행에 추가. 추가 행은 평균 임베딩으로 초기화하는 것이 흔한 휴리스틱. 단, 모델은 이 토큰이 어떻게 행동해야 하는지를 처음부터 학습해야 한다.
  2. 유지. 기존 토크나이저로 잘리는 것을 감수. 입력·출력 토큰 수가 늘어나 비용은 증가하지만 모델 가중치는 그대로.

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. 추가 학습


이 글은 LLM 핵심 학습 시리즈의 2/6 편이다. 다음 편(3/6)은 디코딩과 생성 — Greedy·Beam·Top-p·Speculative로 이어진다.

시리즈 전체 안내: 시리즈 목차

댓글

이 블로그의 인기 게시물

"LLM 핵심 학습 (1/6) — 기본: 토큰화·임베딩·어텐션·위치 인코딩"

"ML 기초 학습 (1/9) — 머신러닝과 sklearn: 학습의 좌표계"