연구 동기
- LLM을 미세 조정할 때 메모리를 많이 사용하기에, GPU 클러스터 없이 단일 GPU로 LLM을 미세 조정하기 어려움
- 이유 1: 파라미터 수가 많고 파라미터를 표현하는 자료형이 큼
- 이유 2: backpropagation 때 계산량을 줄이기 위해, activation을 저장
- batch 사이즈가 커지면 activation을 저장하는 데 사용하는 공간도 커짐
- 이유 3: Optimizer 상태를 저장해야 함
- QLoRA는 양자화를 통해 모델 파라미터가 차지하는 공간의 크기를 줄이고 LoRA를 통해 필요한 Optimizer state의 수를 줄임
- 파라미터를 4bit 정수형으로 저장하고 계산은 bfloat16으로 수행하기 때문에, activation을 저장하기 위해 사용하는 메모리 용량을 줄이지는 않는 듯
양자화 방법
- 파라미터를 4-bit NormalFloat로 저장하고 forward/backward propagation 때 Bfloat16으로 바꾸어 계산함
- 4-bit NormalFloat:
- 파라미터가 가우스 분포를 가질 때 적합한 방법
- 파라미터를 N 개의 블록으로 나눔. 각 블록을 해당 블록의 최댓값으로 나눠서 [-1,1] 범위에 놓이도록 정규화함.
- 아래의 값 중에서 제일 가까운 값의 인덱스가 양자화 결과가 됨.
- [-1.0, -.6961928009986877, -0.39491748809814453, -0.28444138169288635, -0.18477343022823334, -0.09105003625154495, 0.0 0.07958029955625534, 0.16093020141124725, 0.24611230194568634, 0.33791524171829224, 0.44070982933044434, 0.5626170039176941, 0.7229568362236023, 1.0]
- 양자화 상수를 양자화하는 "Double Quantization"도 제시하는데, 이를 통해 얻는 메모리 절약이 크지 않기에 이 글에서는 이를 생략함.
Paged Optimizer
- 그래픽카드의 메모리 용량을 초과할 경우, RAM에 데이터를 일부분 로드하여, 메모리 부족으로 인한 에러 발생을 방지함
아쉬운 부분
- Batch가 커짐에 따라 activation을 로드하는 데 사용하는 메모리 용량이 커진다. 하지만 QLoRA는 activation을 bfloat16으로 로드하기에, batch를 조금만 증가시켜도 activation으로 인한 메모리 사용량이 파라미터로 인한 메모리 사용량을 초과할 수 있다.
- 물론 이는 더 공격적인 gradient checkpointing과 gradient accumulation을 통해 해결할 수 있다. 하지만 gradient checkpointing으로 인해 계산량이 늘어나거나, gradient accumulation으로 인해, 한 번에 계산하는 행렬의 크기가 작아지면서 GPU의 병렬성을 충분히 활용하지 못할 수 있다.
- 모델의 파라미터 수가 330억 개 이상일 때, QLoRA가 16비트 미세 조정과 비슷한 성능을 내는지 확인하지 않음