LoRA는 실제로 어떻게 작동하는가: 저랭크 분해, 가중치 병합 및 내부 메모리 구조 분석
요약
본 문서는 LoRA(Low-Rank Adaptation)가 메모리 효율성을 극대화하는 원리를 깊이 있게 분석합니다. 표준 미세 조정 시 발생하는 막대한 GPU 메모리 요구량 문제를 지적하고, LoRA가 기본 가중치를 고정하여 옵티마이저 상태와 기울기를 제거함으로써 메모리 사용량을 획기적으로 줄이는 과정을 설명합니다.
핵심 포인트
- LoRA는 전체 파라미터 미세 조정 대비 메모리 사용량을 크게 절감한다.
- 표준 학습 방식은 모델 가중치 외에도 옵티마이저 상태, 기울기 등으로 인해 막대한 VRAM을 요구한다.
- LoRA는 기본 가중치를 고정하고 저랭크 분해를 활용하여 효율성을 확보한다.
LoRA는 실제로 어떻게 작동하는가: 저랭크 분해(Low-Rank Decomposition), 가중치 병합(Weight Merging) 및 내부 메모리 구조 분석
만약 80억 개의 파라미터를 가진 언어 모델을 16비트 정밀도로 전체 파라미터(full-parameter) 미세 조정(fine-tune)하려고 시도한다면, GPU 메모리 요구 사항은 즉시 80GB를 초과하여 폭발합니다.
원래 모델 가중치만으로도 VRAM의 16GB($8 \times 10^9 \text{ 파라미터} \times 2 \text{ 바이트}$)가 필요합니다. 그런데 표준 학습 방식으로는 단일 80GB A100 또는 H100에서도 충돌이 발생합니다.
그렇다면 사라진 64GB 이상의 VRAM은 어디로 가는 것일까요? 그리고 Low-Rank Adaptation (LoRA)은 파라미터의 0.1% 미만을 업데이트하면서도 전체 미세 조정 성능의 99%를 유지하고, 메모리 사용량을 70% 이상 줄이는 것이 어떻게 가능할까요?
여기서는 LoRA 미세 조정 및 추론 과정에서 수학적, 기계적, 그리고 물리적인 GPU 메모리 상에서 실제로 무슨 일이 일어나는지 설명합니다.
1. 실제 메모리 문제의 원인: 전체 미세 조정이 폭발하는 이유
표준 AdamW 옵티마이저를 사용하여 신경망을 학습할 때, 모델 가중치는 메모리 소비량에서 아주 작은 부분만을 차지합니다.
훈련 가능한 모든 파라미터에 대해 시스템은 다음 사항들을 추적해야 합니다:
- FP16 / BF16 모델 가중치: 2 바이트
- FP16 / BF16 기울기(Gradients): 2 바이트
- FP32 마스터 가중치 (수치적 안정성을 위해): 4 바이트
- FP32 첫 번째 모멘텀 ($m_t$): 4 바이트
- FP32 두 번째 모멘텀 ($v_t$): 4 바이트
$$\text{훈련 가능한 파라미터당 총 메모리} = 2 + 2 + 4 + 4 + 4 = 16 \text{ 바이트}$$
+-------------------------------------------------------------+
| 전체 파라미터 훈련 (파라미터당 16 바이트) |
+-------------------------------------------------------------+
...
8B 파라미터 모델의 경우:
- 옵티마이저 상태(Optimizer States): $8\text{B} \times 12 \text{ 바이트} = 96 \text{ GB}$
- 기울기(Gradients): $8\text{B} \times 2 \text{ 바이트} = 16 \text{ GB}$
- 모델 가중치(Model Weights): $8\text{B} \times 2 \text{ 바이트} = 16 \text{ GB}$
- 기준 총합 (활성화 메모리 및 KV 캐시 제외): $\approx 128 \text{ GB}$
이것이 바로 전체 미세 조정(full fine-tuning)에 다중 GPU 분산 클러스터(DeepSpeed ZeRO 또는 FSDP)가 필요한 이유입니다.
LoRA는 이 문제를 근본적으로 해결합니다. 기본 가중치(base weights)를 고정함으로써, 모델의 99.9%에 달하는 옵티마이저 상태와 기울기(gradients)를 제거하기 때문입니다.
2. 본질적 순위 가설 (The Intrinsic Rank Hypothesis)
모델을 고정하는 것이 왜 효과적인가요?
트랜스포머의 표준 선형 레이어는 다음을 계산합니다:
$$h = W_0 x$$
여기서 $W_0 \in \mathbb{R}^{d \times k}$, $x \in \mathbb{R}^{k}$, 그리고 $h \in \mathbb{R}^{d}$입니다. Llama 3 8B의 경우, 은닉 차원(hidden dimension) $d = 4096$입니다. 각 가중치 행렬은 최대 $4096 \times 4096 \approx 16.7\text{M}$개의 파라미터를 가지며, 전체 수학적 순위는 4096입니다.
2021년, Edward Hu 외 연구진은 LoRA의 기반이 되는 가설을 발표했습니다:
사전 학습된 언어 모델(pre-trained language model)을 특정 작업이나 지침 형식에 적응시킬 때, 가중치 업데이트 행렬 $\Delta W$는 극도로 낮은 '본질적 순위'(intrinsic rank, $r \ll d$)를 갖습니다.
사전 학습된 모델은 이미 구문론(syntax), 세상의 사실(world facts), 언어 논리 등을 알고 있습니다. 미세 조정은 단순히 주의력(attention)을 유도하고 특징 선택(feature selection)을 조정하는 것에 불과합니다. 행렬당 1600만 개의 자유도를 업데이트할 필요가 없으며, 차원 $r$의 아주 작은 부분 공간(일반적으로 $r = 8, 16, \text{ 또는 } 32$)만 업데이트하면 됩니다.
3. 수학적 원리: 저순위 행렬 분해 (Low-Rank Matrix Factorization)
LoRA는 전체 $d \times k$ 행렬 $\Delta W$를 직접 학습하는 대신, 두 개의 작고 낮은 순위의 행렬 곱으로 분해합니다:
$$\Delta W = B \cdot A$$
여기서:
- $A \in \mathbb{R}^{r \times k}$ (다운 프로젝션, down-projection)
- $B \in \mathbb{R}^{d \times r}$ (업 프로젝션, up-projection)
- $r \ll \min(d, k)$
전체 업데이트 행렬 $\Delta W$ ($d \times k$) LoRA 분해
+---------------------------+ +-------+
| | | | +---------------------------+
...
파라미터 감소 수학 (The Parameter Reduction Math)
만약 $d = 4096, k = 4096$이고 순위(rank) $r = 16$을 선택한다고 가정해 봅시다:
- 전체 행렬 파라미터 (Full matrix parameters): $4096 \times 4096 = 16,777,216$
- 행렬 A 파라미터 (Matrix A parameters): $16 \times 4096 = 65,536$
- 행렬 B 파라미터 (Matrix B parameters): $4096 \times 16 = 65,536$
- 총 LoRA 파라미터 (Total LoRA parameters): $65,536 + 65,536 = 131,072$
$$\text{축소 계수} = \frac{16,777,216}{131,072} = 128\times \text{ 적은 파라미터 (99.2% 감소)}$$
이것을 트랜스포머 레이어 32개에 걸쳐 곱하면, 학습 가능한 파라미터가 80억 개에서 약 2천만 개로 줄어듭니다.
4. 초기화 및 스케일링 계수 $\alpha$
LoRA를 안정적이고 실용적으로 만드는 두 가지 중요한 구현 세부 사항이 있습니다:
상세 A: 행렬 B의 영(Zero) 초기화
학습 시작 시 무작위 노이즈가 사전 학습된 모델을 망치는 것을 어떻게 방지할까요?
- **행렬 $A$**는 $\mathcal{N}(0, \sigma^2)$ 또는 Kaiming uniform의 무작위 가우시안 값으로 초기화됩니다.
- **행렬 $B$**는 정확히 0(영)으로 초기화됩니다 ($B = 0$).
학습 단계 0에서:
$$\Delta W = B \cdot A = 0 \cdot A = 0$$
어댑터는 처음에 정확한 영 벡터를 생성합니다. 모델은 사전 학습된 기본 모델의 정확한 출력을 가지고 학습을 시작하므로, 부드럽고 안정적인 경사 하강(gradient descent)이 보장됩니다.
상세 B: 스케일링 계수 $\frac{\alpha}{r}$
LoRA를 적용한 수정된 순전파(forward pass)에는 상수 스케일링 승수 $\frac{\alpha}{r}$가 포함됩니다:
$$h = W_0 x + \frac{\alpha}{r} (B \cdot A) x$$
- $r$은 선택된 랭크(rank)입니다.
- $\alpha$는 상수 스케일링 하이퍼파라미터이며 (보통 $2r$로 설정하거나 $r$과 같습니다).
왜 $\frac{\alpha}{r}$가 존재할까요?
다양한 랭크($r=8$에서 $r=64$로 점프하는 경우 등)를 실험하면, 행렬 곱셈 $BAx$의 크기는 자연스럽게 $r$에 비례하여 조정됩니다. $\frac{\alpha}{r}$ 항은 어댑터 업데이트의 크기를 정규화(normalizes)합니다. 이를 통해 학습률을 처음부터 다시 조정할 필요 없이 랭크 $r$을 변경할 수 있습니다.
5. 순전파 및 역전파 (Forward and Backward Pass): GPU가 실제로 계산하는 것
학습 중, 계산은 두 개의 병렬 경로로 분기됩니다:
입력 $x$
/
/
순전파 계산 (Forward Computation)
- 기저(Base) 경로: 입력 벡터 $x$는 고정된 사전 학습 가중치 $W_0$와 곱해집니다 ($W_0 x$). (QLoRA를 사용하는 경우, $W_0$는 4비트 NormalFloat에서 16비트 float로 실시간 디양자화됩니다).
- 어댑터(Adapter) 경로: 입력 벡터 $x$는 먼저 행렬 $A$와 곱해져 (벡터의 크기를 $r$로 줄인 후), 이어서 행렬 $B$와 곱해져 (다시 차원 $d$로 확장한 후), 마지막으로 $\frac{\alpha}{r}$를 곱합니다.
- 결합: 두 출력은 요소별(element-wise)로 합산됩니다: $h = W_0 x + \frac{\alpha}{r} BAx$.
역전파 계산 (Backward Computation)
역전파 과정 동안:
- 기울기 $\frac{\partial \mathcal{L}}{\partial A}$와 $\frac{\partial \mathcal{L}}{\partial B}$가 계산되어 메모리에 저장됩니다.
- 옵티마이저는 오직 작은 행렬 $A$와 $B$만 업데이트합니다.
- $W_0$에 대한 옵티마이저 상태는 할당되지 않습니다. $W_0$에 대한 기울기는 저장되지 않습니다.
6. 제로 레이턴시 서빙: 가중치 병합 (Weight Merging)
LoRA가 이전의 어댑터 아키텍처(예: Houlsby adapters 또는 prompt tuning)보다 가장 큰 장점 중 하나는 추론 시 추가적인 지연 시간(latency)을 발생시키지 않는다는 것입니다.
실제 서비스 배포 환경에서는 두 개의 별도 행렬 곱셈 경로를 메모리에 유지하지 않습니다. 행렬 곱셈은 분배 법칙(distributive)을 따르기 때문입니다:
$$h = W_0 x + \Delta W x = (W_0 + \Delta W) x$$
모델을 배포용으로 내보내기 전에, 어댑터 가중치를 단일 행렬 덧셈을 통해 기저 가중치에 직접 병합합니다:
$$W_{\text{serving}} = W_0 + \frac{\alpha}{r} (B \cdot A)$$
한 번 더해지면, 어댑터 행렬 $A$와 $B$는 폐기됩니다. 최종 서빙 모델은 원래의 기저 모델과 정확히 동일한 아키텍처, 텐서 개수, 그리고 지연 시간을 가집니다.
+----------------------------------------------------------+
| 기저 가중치 $W_0$ LoRA 가중치 ($B \times A$) |
| [ 4096 × 4096 ] + [ 4096 × 4096 ] |
...```
동적으로 태스크를 전환해야 하는 경우(멀티테넌트 서빙), **S-LoRA**나 **vLLM Multi-LoRA** 같은 시스템은 기본 모델을 VRAM에 고정하고, 사용자 정의 배치형 GEMM 커널(예: Punica)을 사용하여 개별 요청마다 작은 $BAx$ 브랜치를 즉석에서 계산합니다.
## 7. 처음부터 구현하는 최소한의 PyTorch 코드
메커니즘이 얼마나 간단한지 보여주기 위해, 순수 PyTorch로 구현된 완전하고 작동하는 LoRA 선형 레이어를 소개합니다:
import math
import torch
import torch.nn as nn
...
## 8. 메모리 분석: 전체 파인튜닝 vs LoRA vs QLoRA
80억 개의 매개변수를 가진 모델(배치 크기 2, 시퀀스 길이 2048)에서 메모리 사용량을 비교한 표입니다:
| 구성 요소 | 전체 파인튜닝 (BF16) | LoRA ($r=16$, 모든 선형 레이어) | QLoRA (4비트 기본 모델 + LoRA) |
| :--- | :--- | :--- | :--- |
| **기본 모델 가중치** | 16.0 GB (BF16) | 16.0 GB (BF16) | 4.5 GB (NF4) |
| ... |
## 9. 개발자가 흔히 저지르는 네 가지 LoRA 실수
### 1. 어텐션 프로젝션($q_proj, v_proj$)만 대상으로 삼기
원래의 2021년 LoRA 논문은 Query와 Value 프로젝션에만 어댑터를 연결하여 개념 증명(proof-of-concept) 결과를 보여주었습니다. 하지만 Dettmers 등이 발표한 QLoRA를 포함한 여러 경험적 연구들은 **모든 선형 레이어**($q, k, v, o$뿐만 아니라 MLP 레이어의 $gate, up, down_proj$)를 대상으로 하는 것이 $r=8$ 또는 $r=16$과 같은 더 작은 랭크에서도 훨씬 높은 정확도와 표현 능력을 제공한다는 것을 입증합니다.
### 2. 알파($ ext{Alpha}$) 값을 임의로 설정하기
일반적인 관행은 $\alpha = 2 \times r$ 또는 $\alpha = r$로 설정하는 것입니다. 만약 랭크 $r$을 16에서 32로 두 배 늘렸지만 $\alpha$를 32로 변경하지 않으면, 어댑터의 유효 학습률($\frac{\alpha}{r}$)이 의도치 않게 절반으로 줄어듭니다(2.0에서 1.0으로 하락). 랭크 값을 스윕할 때 $\frac{\alpha}{r}$ 비율을 일관되게 유지하세요.
### 3. 병합 없이 배포하기
### 3. 병합 없이 배포하기
프로덕션 환경에서 단일 특화 모델을 배포하는 경우, LoRA를 별도의 브랜치로 유지하면 불필요한 커널 호출(kernel launches)과 메모리 대역폭 오버헤드(memory bandwidth overhead)가 발생합니다. Hugging Face PEFT에서 항상 `.merge_and_unload()`를 호출하거나, 배포 아티팩트(deployment artifact)를 저장하기 전에 가중치를 수동으로 병합(fold weights)해야 합니다.
### 4. 과도하게 높은 랭크($r > 64$)로 인한 과적합(Overfitting)
$r=128$ 또는 $r=256$으로 설정하는 것은 명령어 미세 조정(instruction fine-tuning)의 다운스트림 작업 정확도를 개선하는 경우가 거의 없지만, 메모리 소비를 급격히 증가시키고 치명적인 망각(catastrophic forgetting)의 위험을 높입니다. 표준 명령어 튜닝 및 분류(classification)의 경우, $r \in [8, 32]$가 경험적으로 가장 적절한 지점(empirical sweet spot)인 경우가 거의 항상 해당합니다.
## 요약 정신 모델 (Summary Mental Model)
- **전체 미세 조정(Full fine-tuning)**은 AdamW 최적화기 상태(optimizer states)가 가중치와 기울기 외에 파라미터당 12바이트를 요구하기 때문에 비용이 많이 듭니다.
- **LoRA**는 가중치 업데이트 $\Delta W$를 두 개의 저랭크 행렬 $B \times A$로 분해하여, 학습 가능한 파라미터와 최적화기 상태를 99% 이상 절감합니다.
- **초기화(Initialization)** ($B=0$)는 학습이 사전 훈련된 기본 모델과 동일하게 시작하도록 보장합니다.
- **서빙(Serving)**은 저랭크 행렬이 간단한 덧셈을 통해 기본 가중치($W_0 + \frac{\alpha}{r} BA$)에 직접 병합되므로 추가 지연 시간(latency)이 없습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기