전통적인 미세 조정(Fine-tuning)은 사전 학습된 모델의 가중치 행렬 를 새로운 가중치 로 업데이트하는 과정입니다. 이 과정은 다음과 같이 표현할 수 있습니다.
- : 사전 학습된 원래 가중치 (Pre-trained Weights)
- : 미세 조정을 통해 학습된 가중치 변화량 (Weight Update)
- : 최종적으로 업데이트된 가중치
여기서 와 는 대규모 언어 모델에서는 매우 큰 행렬(예: 4096×4096)입니다. 따라서 전체를 학습하고 저장하는 것은 비효율적일 수 있습니다.
LoRA(Low-Rank Adaptation)는 “대규모 언어 모델을 미세 조정할 때, 는 실제로 매우 낮은 랭크(intrinsic rank)를 가진다” 는 점에 착안합니다. 즉, 고차원 공간에 존재하더라도 그 변화를 표현하는 데 필요한 차원이 훨씬 적다는 의미입니다.
LoRA에서는 이 거대한 행렬을 두 개의 작은 저랭크(low-rank) 행렬인 와 의 곱으로 근사합니다.
- : 차원을 축소하는 역할을 하는 작은 행렬 ()
- : 다시 원래 차원으로 복원하는 역할을 하는 작은 행렬 ()
- : LoRA의 랭크(rank). 일반적으로 , 보다 훨씬 작은 값(예: 8, 16, 64)이며, 성능과 파라미터 수 사이의 트레이드오프를 결정하는 핵심 하이퍼파라미터입니다.
이제 순전파(forward pass) 계산 과정을 비교해 보겠습니다.
1. 기존 모델의 계산 (특정 레이어에서)
- : 출력 벡터
- : 원래 가중치 행렬 ()
- : 입력 벡터 ()
2. LoRA 적용 시 계산
LoRA에서는 기존의 를 직접 업데이트하지 않고, BA의 결과만을 더해줍니다.
여기서 중요한 점은 학습 내내 는 동결(frozen)되고 오직 A와 B만 학습된다는 것입니다.
파라미터 효율성 비교
- 기존 방식에서 파라미터 수:
- LoRA(A와 B)의 파라미터 수:
이 , 보다 훨씬 작으므로 는 에 비해 매우 적습니다. 예를 들어, , , 일 때:
- : 4096 × 4096 = 16,777,216개 파라미터
- LoRA: (4096 × 8) + (8 × 4096) = 32,768 + 32,768 = 65,536개 파라미터
즉, 약 256배나 파라미터가 줄어듭니다.
A.1) Alpha( 스케일링
실제 구현에서는 BA에 스케일링 상수 (알파)를 곱해 사용하기도 합니다. 보통 로 설정하여 랭크() 값을 바꿀 때마다 학습률을 따로 조정할 필요가 없도록 합니다.
B) LoRA 가중치 병합(Merging)
LoRA의 큰 장점 중 하나는 학습이 끝난 뒤 A와 B 행렬을 원래 가중치인 ${W}_0에 병합하여 추론 시 추가적인 연산 오버헤드를 없앨 수 있다는 점입니다. 병합 과정은 다음과 같습니다:
- 학습된 LoRA 어댑터 행렬 A와 B를 가져옵니다.
- 두 행렬을 곱하여 를 얻습니다. 이 행렬은 크기로 원래 와 동일한 차원을 갖습니다.
- 이 를 동결되어 있던 ${W}_0에 더합니다.
즉,
이렇게 하면 새로운 가중치 행렬 ${W}_{\text{merged}}를 얻게 되며, 병합 후에는 모델 구조가 기존과 완전히 동일해집니다. A와 B는 더 이상 필요하지 않습니다.
B.1) 병합(Merging)의 장점
-
추론 속도: 이제 연산은 한 번만 이루어집니다.
-
기존:
-
병합 후:
따라서 추론 시 지연(latency)이 전혀 증가하지 않습니다.
-
-
배포 용이성: LoRA 어댑터 없이 병합된 단일 체크포인트만 배포하면 되므로 운영 및 관리가 간편합니다.
C) Alpha와 Rank의 관계
LoRA에서 (알파)와 rank()는 성능 조정에 핵심적인 역할을 합니다. 이 둘의 관계를 이해하면 LoRA를 더 효과적이고 안정적으로 적용할 수 있습니다.
C.1) 각 변수의 의미
- Rank (): LoRA 어댑터의 **표현력(복잡도)**을 결정합니다. 이 높을수록 LoRA가 더 복잡하고 다양한 변화를 학습할 수 있습니다.
- Alpha (): LoRA 어댑터가 만들어내는 변화량(업데이트)의 강도 또는 영향력을 조절하는 스케일링 상수입니다.
C.2) LoRA 공식에서 나타나는 관계
LoRA의 주요 계산식은 다음과 같습니다.
여기서 는 LoRA 어댑터가 학습한 변화량이고, 이 변화량에 얼마나 강하게 가중치를 줄지가 바로 로 정해집니다.
C.3) 실전 활용: Alpha와 Rank 조합 방식
C.3.1) 일반적 설정:
대부분의 경우, 를 과 동일하게 설정합니다. 예를 들어 이면 으로 두는 식입니다. 이렇게 하면 스케일링 팩터가 항상 1로 고정되어 공식은 다음처럼 단순해집니다.
장점
- 실험 시 하이퍼파라미터 탐색을 단순화할 수 있습니다.
- 값을 바꿔도, 스케일링 팩터()는 항상 1이므로 LoRA 업데이트의 강도가 변하지 않습니다.
- 따라서 rank()만 바꿨을 때, 실제로는 오직 표현력(복잡도)에만 영향을 주게 되어 부수 효과 없이 실험할 수 있습니다.
만약 를 고정한 채 만 바꾸면, 이 커질수록 스케일링 팩터가 작아져서 의도하지 않게 업데이트 영향력이 줄어듭니다. 이런 현상을 방지하기 위한 관행입니다.
C.3.2) 의도적 조절:
특정 상황에서는 와 을 다르게 설정하여 LoRA 업데이트의 강도를 조절하기도 합니다.
- :
-
예시: ,
-
스케일링 팩터 =
-
계산식:
-
즉, LoRA 어댑터가 만드는 변화량을 두 배로 증폭해서 원래 모델보다 훨씬 더 적극적으로 반영합니다.
-
이렇게 하면 원본 모델과 성격이 크게 다른 작업이나, 새로운 스타일/패턴을 강하게 주입하고 싶을 때 유용합니다.
-
- :
-
예시: ,
-
스케일링 팩터 =
-
계산식:
-
즉, LoRA 어댑터의 영향력을 절반으로 줄여 보다 미세하고 부드러운 변화를 유도할 수 있습니다.
-
D) QLoRA (Quantized LoRA): 메모리 한계를 극복한 혁신
기존 LoRa 방식은 ‘훈련 가능한 파라미터’의 수를 줄여주지만, 추론과 훈련을 위해서는 여전히 16비트 부동소수점(FP16) 정밀도의 전체 기본 모델(W)을 GPU 메모리에 로드해야 합니다. 70B(700억) 파라미터 모델이라면 이것만으로도 140GB 이상의 VRAM이 필요합니다.
QLoRA는 “어떻게 하면 기본 모델(W) 자체를 메모리에 올리는 부담까지 줄일 수 있을까?”라는 질문에서 출발합니다. LoRA의 파라미터 효율적인 훈련 방식은 그대로 유지하면서, 메모리 사용량을 극한으로 줄이는 기술입니다.
QLoRA의 핵심 아이디어: 기본 모델(W)을 4비트로 양자화(quantize)하여 메모리에 로드하고, LoRA 어댑터(A, B)는 여전히 16비트로 훈련하여 성능 손실을 최소화하는 것입니다.
이 아이디어를 구현하기 위해 QLoRA는 다음 세 가지 핵심 기술을 도입했습니다.
D.1) 4비트 NormalFloat (NF4): 더 똑똑한 4비트 양자화
일반적인 4비트 정수(INT4)로 양자화하면 정보 손실이 커서 모델 성능이 크게 저하될 수 있습니다. 특히 LLM의 가중치는 평균이 0인 정규분포를 따르는데, INT4는 이 분포의 특성을 잘 살리지 못합니다.
- NF4의 접근법: NF4는 ‘분위수 양자화(Quantile Quantization)‘라는 기법을 사용합니다. 데이터의 분포를 미리 가정(정규분포)하고, 각 분위수에 해당하는 값을 4비트(16개 레벨)의 양자화 지점으로 설정합니다.
- 쉬운 비유: 데이터가 많이 몰려있는 구간(정규분포의 중앙)에는 양자화 지점을 촘촘하게 배치하고, 데이터가 드문 구간(꼬리 부분)에는 듬성듬성 배치하는 것입니다. 이렇게 하면 동일한 4비트를 사용하더라도 원본 데이터의 정보를 훨씬 더 잘 보존할 수 있습니다.
- 결과: 기본 모델을 FP16에서 NF4로 압축하면, 모델을 로드하는 데 필요한 메모리가 단순 계산으로 1/4로 줄어듭니다. (16비트 -> 4비트)
D.2) 이중 양자화 (Double Quantization, DQ)
4비트로 양자화하더라도, 양자화를 수행하기 위한 ‘양자화 상수(quantization constants)‘(예: 스케일링 팩터)들은 여전히 메모리를 차지합니다. 이 상수들은 보통 32비트 부동소수점(FP32)으로 저장되어, 이것만 모아도 수백 MB에 달하는 추가적인 메모리 오버헤드가 발생합니다.
-
DQ의 접근법: 이 양자화 상수들 자체를 다시 한번 양자화하는 것입니다.
-
동작 방식:
- 첫 번째 양자화: 가중치(W)를 작은 블록으로 나누고, 각 블록마다 하나의 FP32 양자화 상수(c1)를 계산합니다.
- 두 번째 양자화: 이 FP32 상수들(c1)의 묶음을 다시 8비트 등으로 양자화하고, 이 두 번째 양자화를 위한 또 다른 상수(c2)를 계산합니다.
-
결과: 양자화 상수에 대한 메모리 오버헤드를 파라미터당 약 0.5비트 수준으로 줄여, 메모리를 추가로 절약합니다.
D.3) 페이징된 옵티마이저 (Paged Optimizers)
GPU 메모리는 가끔 특정 데이터(예: 긴 시퀀스) 처리 시 순간적으로 사용량이 급증하여 ‘메모리 부족(Out of Memory)’ 오류를 일으키며 훈련이 중단될 수 있습니다.
- 페이징의 접근법: NVIDIA의 통합 메모리(Unified Memory) 기능을 활용하여, GPU 메모리가 꽉 찰 경우 사용량이 적은 옵티마이저 상태(optimizer states)를 자동으로 CPU RAM으로 옮기고(page out), 필요할 때 다시 GPU VRAM으로 가져오는(page in) 기술입니다.
- 쉬운 비유: 컴퓨터의 RAM이 부족할 때 하드디스크를 가상 메모리로 사용하는 것과 비슷한 원리입니다.
- 결과: 갑작스러운 메모리 스파이크로 인한 훈련 중단을 방지하여 훈련 안정성을 크게 높입니다.
D.4) LoRA Vs QLoRA: 결정적 차이점 비교표
| 구분 | 일반 LoRA | QLoRA |
|---|---|---|
| 기본 모델(W) 정밀도 | FP16 (16비트) | NF4 (4비트) |
| LoRA 어댑터(A,B) 정밀도 | FP16 (16비트) | FP16 (16비트) |
| 양자화 기법 | 사용 안 함 | 4-bit NormalFloat (NF4) + 이중 양자화 (DQ) |
| 메모리 요구량 | 높음 (전체 모델을 FP16으로 로드) | 매우 낮음 (전체 모델을 4비트로 로드) |
| 옵티마이저 | 표준 AdamW | 페이징된 AdamW (안정성 향상) |
| 핵심 목표 | 파라미터 효율적 미세조정 (훈련 파라미터 수 감소) | 메모리 효율적 미세조정 (GPU 메모리 사용량 감소) |
결론적으로, QLoRA는 일반 LoRA의 파라미터 효율성은 그대로 가져오면서, 4비트 양자화(NF4), 이중 양자화(DQ), 페이징된 옵티마이저라는 강력한 기술들을 결합하여 기본 모델을 로드하는 데 필요한 메모리 자체를 극단적으로 줄인 혁신적인 기술입니다. 이 덕분에 이전에는 수백 GB의 VRAM을 가진 전문가용 GPU에서만 가능했던 65B급 거대 모델의 미세조정을, 이제는 단일 소비자용 GPU(예: 24GB VRAM)에서도 수행할 수 있게 되었습니다.