QLoRA: 4비트 모델을 학습한다는 말에 숨은 정밀도의 역할
큰 언어 모델을 내 데이터에 맞추고 싶을 때, 첫 번째 장애물은 알고리즘보다 GPU 메모리일 때가 많다. 작은 어댑터만 학습하면 해결될 것 같지만, 기반 가중치 자체가 이미 너무 크다. QLoRA가 흥미로운 이유는 이 문제를 한 가지 트릭으로 풀지 않는다는 데 있다. 가중치를 보관하는 형식, 학습하는 부분, 양자화에 딸린 정보, 순간적인 메모리 사용을 함께 다룬다.
4비트로 저장하고, 다른 정밀도로 계산하기
QLoRA는 기반 모델을 4비트로 양자화해 고정한다. 학습 가능한 저랭크 어댑터를 붙이고, 양자화된 기반 모델을 통과하는 학습 신호로 그 어댑터를 갱신한다. 기반 모델의 4비트 값을 매번 직접 학습하는 방식은 아니다.
저장 형식과 계산 형식도 구별된다. 원문은 가중치를 낮은 비트로 보관하고, 행렬곱에 사용할 때 보통 bfloat16으로 복원하는 구성을 설명한다. 어댑터까지 전부 4비트로 학습하거나 모든 연산을 4비트로 수행한다는 뜻이 아니다. 복원은 압축 이전의 값을 완벽하게 되찾는 일이 아니라, 양자화 코드와 스케일로 근사값을 구성하는 일이다. QLoRA 원문
학습 메모리가 부족한 상황에서 이 구분은 실질적이다. 전체 가중치의 그래디언트와 옵티마이저 상태를 만들지 않아도 되고, 기반 가중치의 저장 공간도 줄어든다. 하지만 활성값, 어댑터 상태, 계산 중 작업 공간은 계속 필요하다. 파라미터 하나당 저장 비트만 보고 학습 가능한 배치 크기를 계산하면 쉽게 빗나간다.
숫자 16개를 어디에 놓을 것인가
4비트는 16개의 코드를 표현할 수 있다. 문제는 그 코드가 어떤 실수값에 대응하는가다. 값이 −1과 1 사이에 있다고 해서 같은 간격으로 16개를 배치하는 것이 모든 분포에 가장 좋은 선택은 아니다. 대부분의 값이 0 근처에 모여 있다면, 자주 나타나는 구간에 더 촘촘하게 표현 값을 배치할 이유가 있다.
NF4, 즉 4-bit NormalFloat는 이런 발상에서 출발한다. 정규분포의 분위수를 이용해 양자화 표현 값을 정하며 0을 표현할 수 있도록 설계한다. 가중치는 블록별로 스케일을 맞추어 이 표현에 대응시킨다. 원문이 말하는 최적성에는 정규분포라는 조건이 붙어 있다. 모든 신경망의 모든 값에 무조건 최적인 숫자 형식이라는 뜻으로 받아들이면 안 된다. 원문 양자화 설계
직접 만든 예로 눈금을 생각해 보자. 측정할 값 100개 중 90개가 −0.1에서 0.1 사이에 있고, 나머지만 넓게 흩어져 있다면 긴 꼬리에 많은 눈금을 써 버리는 것이 아쉬울 수 있다. 반대로 극단값이 결과에 아주 중요한 역할을 한다면 중심부를 촘촘하게 만드는 것만으로 충분하지 않을 수 있다. 실제 모델에서 양자화 형식의 효과를 비교해야 하는 이유가 여기 있다.
NF4의 설명이 정규분포와 닮았다고 해서 모델의 의미적 지식이 정규분포라는 뜻도 아니다. 대상은 가중치의 수치 분포다. 숫자를 효율적으로 근사하는 형식과, 모델이 어떤 사실을 알고 있는지는 서로 다른 층위의 이야기다.
압축 정보도 쌓이면 커진다
블록별 양자화를 하려면 각 블록의 스케일 같은 부가 정보를 저장해야 한다. 가중치 본체를 4비트로 줄였는데, 작은 블록마다 상대적으로 큰 스케일 값을 붙이면 그 정보도 무시하기 어려워진다. Double Quantization은 이 양자화 상수들까지 한 번 더 양자화하는 방법이다.
수백만 개의 작은 상자마다 큰 라벨을 붙이는 장면을 떠올릴 수 있다. 내용물을 줄여도 라벨이 많이 남는다. 라벨을 표현하는 방식까지 줄이면 추가 절감이 생긴다. 물론 실제 구현에서는 두 단계의 스케일과 복원 절차를 함께 관리해야 한다. 이 비유는 저장 비용을 설명하기 위한 것이며, 복원 오차나 커널 비용까지 동일하게 설명하지는 않는다.
다른 문제는 평균 사용량은 맞는데 가끔 학습이 멈추는 상황이다. 긴 시퀀스나 특정 학습 단계에서 메모리 사용이 순간적으로 올라갈 수 있다. 원문의 Paged Optimizer는 NVIDIA unified memory를 이용해 필요할 때 옵티마이저 상태의 페이지를 CPU와 GPU 사이에서 관리한다. 가중치 양자화가 저장의 바닥 비용을 낮춘다면, 이 장치는 일시적인 최고 사용량에 대응한다. 공식 구현과 설정
페이지를 옮길 수 있다고 해서 이동 비용이 없어지는 것은 아니다. 내가 적용한다면 '메모리 부족 없이 끝나는가'와 '시간이 얼마나 드는가'를 따로 보겠다. 작은 평균 메모리 수치보다 가장 긴 배치에서의 최고 사용량을 기록하고 싶은 이유도 같은 맥락이다.
65B를 한 GPU에 맞췄다는 결과 읽기
원문은 65B 모델을 48GB GPU 하나에서 미세조정할 수 있었음을 보고한다. 여러 모델 크기와 데이터셋에서 양자화 어댑터 학습을 16비트 방식과 비교하고, 해당 평가에서 경쟁력 있는 성능을 보인다. 동시에 어댑터를 어느 층에 붙이는지 같은 설정이 성능 복원에 중요하다고 분석한다. 논문 실험
이 결과는 접근성의 변화로 읽을 가치가 크다. 이전에는 실행할 수 없었던 크기의 실험을 작은 장비 구성에서 해 볼 수 있기 때문이다. 다만 같은 GPU 메모리가 있다고 모든 시퀀스 길이와 배치 크기의 65B 학습이 가능해지는 것은 아니다. 모델 구조, 활성값, 체크포인팅, 옵티마이저 설정이 함께 결정한다.
Guanaco의 챗봇 평가도 맥락이 필요하다. 원문은 사람과 GPT-4를 통한 비교 평가를 제시하면서, 평가자와 벤치마크의 불확실성도 논의한다. 특정 비교 점수를 '범용적으로 어떤 제품과 동등한 능력'이라고 옮겨 적고 싶지는 않다. 질문 집합과 채점 방식이 달라지면 순위의 의미도 달라지기 때문이다.
오히려 내 관심은 저렴한 학습 덕분에 데이터와 설정을 여러 번 바꾸어 볼 수 있다는 데 있다. 한 번의 거대한 실행보다 작은 실패를 빨리 발견하는 반복이 좋은 결과를 만들 수도 있다. 이는 논문 결과에서 얻은 실무적 해석이지, QLoRA만으로 데이터 품질이 개선된다는 주장과는 다르다.
내가 작은 팀에서 먼저 확인할 것
업무별 검증 질문을 먼저 만들겠다. 답의 형식과 말투를 맞추는지, 필요한 내용을 빠뜨리지 않는지, 낯선 사례에서 자신 있게 틀리지 않는지 살핀다. 그 다음 기반 모델 단독, 16비트 어댑터, 4비트 어댑터를 가능한 범위에서 비교하면 품질 손실과 업무 개선을 분리해서 볼 수 있다.
어댑터 파일에는 기반 모델의 버전과 양자화 설정도 함께 기록하고 싶다. 학습할 때 사용한 근사 기반 가중치가 달라지면 같은 어댑터의 동작도 달라질 수 있다. 배포 때 병합하거나 다시 양자화한다면 실제 배포 경로에서 다시 평가한다. 학습이 끝났다는 사실만으로 서비스 품질 확인까지 끝난 것은 아니다.
QLoRA를 읽고 남은 인상은 '4비트라서 작다'보다 더 세밀하다. 꼭 높은 정밀도로 남겨야 하는 값과, 작게 보관해도 되는 값을 나누고, 평균 비용과 순간 비용을 따로 관리한다. 큰 모델을 가까이 가져오는 데는 새로운 모델만큼 이런 실행 설계도 중요한 역할을 한다.
읽은 논문: Tim Dettmers, Artidoro Pagnoni, Ari Holtzman, Luke Zettlemoyer, QLoRA: Efficient Finetuning of Quantized LLMs, NeurIPS 2023. 논문 · 공식 코드