LLM 양자화에 대한 비쥬얼 가이드
(newsletter.maartengrootendorst.com)- 대규모 언어 모델(LLM)은 일반 하드웨어에서 실행하기에는 너무 크고, 보통 매개변수 수십억 개를 가져서 대량의 VRAM을 가진 GPU들이 필요
- 따라서 개선된 훈련, 어댑터 등을 통해 이러한 모델을 더 작게 만드는 데 점점 더 많은 연구가 집중되고 있으며, 이 분야의 주요 기술 중 하나는 양자화(Quantization)
Part 1: 대규모 언어 모델의 "문제"
- LLM(Large Language Model)은 포함된 매개변수의 수에 따라 이름이 붙여졌음
- 이런 모델에는 일반적으로 수십억 개의 매개변수(대부분 가중치)가 포함되어 저장 비용이 상당히 많이 들 수 있음
- 추론 중에 활성화는 입력과 가중치의 곱으로 생성되며, 마찬가지로 상당히 클 수 있음
- 따라서 주어진 값을 저장하는 데 필요한 공간을 최소화하면서 수십억 개의 값을 최대한 효율적으로 표현하려고 시도함
수치 값을 표현하는 방법
- 주어진 값은 부동 소수점 숫자(실수)로 표현되는 경우가 많음
- 이 값들은 "비트"로 표현되며, IEEE-754 표준은 비트가 값을 표현하기 위해 기호, 지수, 가수(fraction) 중 하나의 기능을 나타내는 방법을 설명
- 값을 표현하는 데 사용되는 비트가 많을수록 일반적으로 더 정밀해짐
- 사용 가능한 비트가 많을수록 표현 가능한 값의 범위가 커짐
메모리 제약
- 700억 개의 매개변수를 가진 모델을 가정할 때, FP32(full-precision)를 사용한다면 모델을 로드하는 데만 280GB의 메모리가 필요
- 따라서 모델의 매개변수를 나타내는 비트 수를 최소화하는 것이 매우 중요하지만, 정밀도가 감소하면 모델의 정확도도 일반적으로 감소
- 정확도를 유지하면서 값을 표현하는 비트 수를 줄이는 것이 목표이며, 이것이 바로 양자화(quantization)가 등장하는 부분
Part 2: 양자화 소개
- 양자화는 모델 매개변수의 정밀도를 높은 비트 폭(예: 32비트 부동 소수점)에서 낮은 비트 폭(예: 8비트 정수)으로 줄이는 것을 목표로 함
- 비트 수를 줄일 때마다 원래 매개변수를 저비트 표현으로 "압축"하기 위한 매핑이 수행됨
일반적인 데이터 유형
FP16
- FP32에서 FP16(half precision)으로 가면 FP16이 취할 수 있는 값의 범위가 FP32보다 상당히 작아짐
BF16
- FP32와 유사한 값 범위를 얻기 위해 "잘린 FP32"의 일종인 bfloat 16이 도입됨
- BF16은 FP16과 동일한 양의 비트를 사용하지만 더 넓은 값 범위를 가질 수 있으며 딥러닝 응용 프로그램에서 자주 사용됨
INT8
- 비트 수를 더 줄이면 부동 소수점 표현 대신 정수 기반 표현에 가까워짐
대칭 양자화
- 원래 부동 소수점 값의 범위가 양자화된 공간에서 0을 중심으로 대칭 범위에 매핑됨
- 부동 소수점 공간에서 0의 양자화된 값은 양자화된 공간에서 정확히 0임
비대칭 양자화
- 대칭 양자화와 달리 0을 중심으로 대칭이 아님
- 최소값(β)과 최대값(α)을 부동 소수점 범위에서 양자화된 범위의 최소값과 최대값으로 매핑
- 영점(zero-point) 양자화라고 불리는 방법 중 하나
범위 매핑 및 클리핑
- 벡터의 전체 범위를 매핑하면 이상치로 인해 모든 작은 값이 동일한 저비트 표현에 매핑되어 차별화 요소를 잃게 됨
- 대신 특정 값을 클리핑(clipping)하도록 선택할 수 있음
- 클리핑은 모든 이상치가 동일한 값을 갖도록 원래 값의 다른 동적 범위를 설정하는 것
- 이상치가 아닌 값의 양자화 오차는 크게 줄어들지만 이상치의 양자화 오차는 증가
보정(Calibration)
가중치(및 편향)
- 가중치와 편향은 모델을 실행하기 전에 알려진 정적 값으로 간주할 수 있음
- 편향은 가중치보다 훨씬 적기 때문에 더 높은 정밀도(예: INT16)로 유지되며 양자화의 주요 노력은 가중치로 향함
- 정적이고 알려진 가중치의 보정 기법에는 입력 범위의 백분위수를 수동으로 선택하거나, 원래 가중치와 양자화된 가중치 사이의 평균 제곱 오차(MSE)를 최적화하거나, 원래 값과 양자화된 값 사이의 엔트로피(KL 발산)를 최소화하는 것 등이 있음
활성화
- 입력은 LLM 전체에서 지속적으로 업데이트되며 일반적으로 "활성화"라고 함
- 이 값은 각 입력 데이터가 추론 중에 모델에 공급될 때마다 달라지므로 정확하게 양자화하기 어려움
- 이 값은 각 은닉층 후에 업데이트되므로 입력 데이터가 모델을 통과할 때만 추론 중에 무엇이 될지 알 수 있음
Part 3: 사후 훈련 양자화(PTQ - Post-Training Quantization)
동적 양자화
- 데이터가 은닉층을 통과한 후 활성화가 수집됨
- 이 활성화 분포는 출력을 양자화하는 데 필요한 영점(z)과 스케일 팩터(s) 값을 계산하는 데 사용됨
- 데이터가 새 층을 통과할 때마다 프로세스가 반복됨. 따라서 각 층은 고유한 z와 s 값을 가지며 서로 다른 양자화 체계를 가짐
정적 양자화
- 추론 중이 아니라 미리 영점(z)과 스케일 팩터(s)를 계산
- 이러한 값을 찾기 위해 보정 데이터 세트가 사용되어 모델에 제공되어 이러한 잠재적 분포를 수집
- 실제 추론을 수행할 때 s와 z 값은 재계산되지 않고 모든 활성화에 대해 전역적으로 사용되어 양자화됨
- 일반적으로 동적 양자화가 각 은닉층마다 s와 z 값을 계산하려고 하기 때문에 약간 더 정확하지만, 계산 시간이 늘어날 수 있음
- 반면에 정적 양자화는 덜 정확하지만 이미 s와 z 값을 알고 있기 때문에 더 빠름
4비트 양자화의 영역
- 8비트 미만으로 내려가는 것은 비트를 잃을 때마다 양자화 오차가 증가하기 때문에 어려운 작업으로 판명됨
- HuggingFace에서 일반적으로 공유되는 두 가지 방법인 GPTQ와 GGUF 탐색
GPTQ
- 4비트로 양자화하기 위해 실제로 가장 잘 알려진 방법 중 하나
- 비대칭 양자화를 사용하고 각 층이 독립적으로 처리된 후 다음으로 계속되도록 층별로 수행
- 층별 양자화 프로세스 중에 먼저 층의 가중치를 역 Hessian으로 변환하며, 이는 모델 손실 함수의 2차 도함수이며 각 가중치의 변화에 모델 출력이 얼마나 민감한지 알려줌
- 간단히 말해서 층에서 각 가중치의 (역)중요도를 보여줌
- Hessian 행렬에서 값이 작은 가중치는 이러한 가중치의 작은 변화가 모델 성능에 큰 변화를 초래할 수 있기 때문에 더 중요함
GGUF
- GPTQ는 전체 LLM을 GPU에서 실행하기에 좋은 양자화 방법이지만 항상 그런 용량을 가지고 있지는 않음
- 대신 LLM의 모든 층을 CPU로 오프로드하기 위해 GGUF를 사용할 수 있음
- 충분한 VRAM이 없을 때 CPU와 GPU를 모두 사용할 수 있게 해줌
Part 4: 양자화 인식 훈련(QAT - Quantization Aware Training)
- 3부에서 훈련 후 모델을 양자화하는 방법을 살펴봤지만, 이 양자화는 실제 훈련 프로세스를 고려하지 않는다는 단점이 있음
- 이것이 바로 양자화 인식 훈련(QAT)이 등장하는 부분. PTQ와 달리 QAT는 훈련 중에 양자화 절차를 학습하는 것을 목표로 함
- QAT는 훈련 중에 양자화가 이미 고려되었기 때문에 PTQ보다 더 정확한 경향이 있음
1비트 LLM의 시대: BitNet
- BitNet은 모델의 가중치를 단일 1비트, -1 또는 1로 표현
- 트랜스포머 아키텍처에 양자화 프로세스를 직접 주입하여 수행
- 트랜스포머 아키텍처는 대부분의 LLM의 기반으로 사용되며 선형 레이어를 포함하는 계산으로 구성됨
- BitNet은 이러한 선형 레이어를 BitLlinear라고 하는 것으로 대체
가중치 양자화
- 훈련 중에 가중치는 INT8에 저장된 다음 기본 전략인 부호 함수를 사용하여 1비트로 양자화됨
- 본질적으로 가중치 분포를 0을 중심으로 이동시킨 다음 0의 왼쪽에 있는 모든 것을 -1로, 오른쪽에 있는 모든 것을 1로 할당
활성화 양자화
- 활성화를 양자화하기 위해 BitLinear는 행렬 곱셈(×)에 더 높은 정밀도가 필요하기 때문에 활성화를 FP16에서 INT8로 변환하기 위해 absmax 양자화를 사용
역양자화
- α(활성화의 절대값 중 가장 큰 값)와 β(가중치의 평균 절대값)를 추적했는데, 이 값들은 나중에 활성화를 FP16으로 역양자화하는 데 도움이 될 것임
- 출력 활성화는 {α, γ}로 재조정되어 원래 정밀도로 역양자화됨
모든 대규모 언어 모델은 1.58비트 이다
- BitNet 1.58b는 이전에 언급된 스케일링 문제를 개선하기 위해 도입됨
- 이 새로운 방법에서는 모델의 모든 단일 가중치가 -1 또는 1뿐만 아니라 이제 0도 값으로 취할 수 있어 삼진(ternary)이 됨
- 흥미롭게도 0만 추가해도 BitNet이 크게 개선되고 계산 속도가 훨씬 빨라짐
0의 힘
- 0을 추가하는 것이 왜 그렇게 큰 개선인가? 이는 행렬 곱셈과 모두 관련이 있음
- 1.58비트로 양자화된 가중치가 있으면 곱셈만 수행하면 되기 때문에 계산 속도를 크게 높일 수 있을 뿐만 아니라 특성 필터링도 가능
양자화
- 가중치 양자화를 수행하기 위해 BitNet 1.58b는 이전에 보았던 absmax 양자화의 변형인 absmean 양자화를 사용
- 단순히 가중치 분포를 압축하고 절대 평균(α)을 사용하여 값을 양자화하며, 이들은 -1, 0 또는 1로 반올림됨
- BitNet와 비교하여 활성화 양자화는 한 가지를 제외하고는 동일함. 활성화를 [0, 2ᵇ⁻¹] 범위로 조정하는 대신 이제 absmax 양자화를 사용하여 [-2ᵇ⁻¹, 2ᵇ⁻¹]로 조정됨
- 1.58비트 양자화에는 (주로) 두 가지 트릭이 필요했음:
- 삼진 표현 [-1, 0, 1]을 만들기 위해 0 추가
- 가중치에 대한 absmean 양자화
-
"13B BitNet b1.58은 지연 시간, 메모리 사용량 및 에너지 소비 측면에서 3B FP16 LLM보다 더 효율적"
- 따라서 계산적으로 효율적인 1.58비트만 있기 때문에 경량 모델을 얻을 수 있음