Quantization concepts
Blog

Quantization concepts

2026.04.14
·Hugging Face·by 배레온/부산/개발자
#Deep Learning#Inference Optimization#LLM#Model Compression#Quantization

핵심 포인트

  • 1Quantization은 float32 대신 int8과 같은 저정밀도 데이터 타입을 사용하여 모델 크기를 줄이고, 추론 속도를 높이며, 에너지 소비를 줄이는 기술이지만, 정확도 손실이 발생할 수 있습니다.
  • 2Quantization은 주로 scale(S) 및 zero-point(Z) 파라미터를 사용하는 affine quantization 방식을 통해 float32 값을 int8 범위로 매핑하며, int4 및 FP8과 같은 다양한 데이터 타입으로도 적용됩니다.
  • 3Quantization은 모델 훈련 후에 적용하는 PTQ와 훈련 중에 시뮬레이션하는 QAT 기술로 나뉘며, Hugging Face Transformers 라이브러리는 `BitsAndBytesConfig`를 포함한 다양한 백엔드를 통해 이를 통합 지원합니다.

본 문서는 트랜스포머 모델과 같은 대규모 머신러닝 모델의 메모리 사용량과 연산 비용을 줄이기 위한 양자화(Quantization) 개념을 설명합니다. 양자화는 모델의 가중치(weights)와 활성화(activations)를 float32와 같은 표준 부동 소수점(floating-point) 대신 8비트 정수(int8)와 같은 낮은 정밀도의 데이터 타입으로 표현하여 이를 달성합니다.

양자화의 주요 이점은 다음과 같습니다:

  • 모델 크기 감소: int8 모델은 float32 모델에 비해 약 4배 작습니다.
  • 추론 속도 향상: 낮은 정밀도 데이터 타입, 특히 정수 연산은 호환 가능한 하드웨어(CPU 및 GPU)에서 훨씬 빠르며, 이는 대기 시간(latency)을 줄입니다.
  • 에너지 소비 감소: 빠른 연산과 작은 메모리 전송은 전력 소모를 줄입니다.

주요 절충점은 *효율성* 대 *정확도*입니다. 정밀도 감소는 필연적으로 작은 오류(quantization noise)를 도입하므로, 목표는 적절한 스킴(scheme), 세분성(granularity), 및 기법(technique)을 사용하여 오류를 최소화하는 것입니다.

1. 양자화 스킴 (Quantization schemes)

핵심 아이디어는 float32 값의 범위를 int8(일반적으로 [128,127][-128, 127])로 매핑하는 것입니다.

  • 아핀 양자화 (Affine Quantization):
가장 일반적인 방법으로, float32 텐서의 최솟값 valminval_{min}과 최댓값 valmaxval_{max}를 찾아 int8 범위 [qmin,qmax][q_{min}, q_{max}]로 매핑합니다.
  • 대칭 양자화 (Symmetric Quantization):
원본 float32 범위가 0을 중심으로 대칭이라고 가정합니다(예: [a,a][-a, a]). 이 범위는 int8 범위(예: [127,127][-127, 127])로 대칭적으로 매핑되며, float32 값 0.00.0은 int8 값 00에 직접 매핑됩니다. 이는 하나의 파라미터인 scale (SS)만 필요로 하며, 연산을 단순화할 수 있지만 데이터 분포가 0을 중심으로 하지 않으면 정확도가 떨어질 수 있습니다. 양자화 및 역양자화는 다음과 같습니다:
q=round(x/S)q = \text{round}(x / S)
xSqx \approx S \cdot q
  • 비대칭 양자화 (Asymmetric Quantization / Affine Quantization):
데이터가 0을 중심으로 한다는 가정을 하지 않습니다. float32의 정확한 범위 [valmin,valmax][val_{min}, val_{max}]를 int8의 전체 범위(예: [128,127][-128, 127])로 매핑합니다. 이를 위해서는 두 개의 파라미터인 scale (SS)과 zero-point (ZZ)가 필요합니다.
scale (SS)은 float32와 int8 범위 간의 비율을 나타내는 양수 float32 값입니다.
S=valmaxvalminqmaxqminS = \frac{val_{max} - val_{min}}{q_{max} - q_{min}}
zero-point (ZZ)는 float32 값 0.00.0에 해당하는 int8 값입니다.
Z=qminround(valminS)Z = q_{min} - \text{round}\left(\frac{val_{min}}{S}\right)
float32 값 xx를 int8 qq로 양자화하는 공식은 다음과 같습니다:
q=round(xS+Z)q = \text{round}\left(\frac{x}{S} + Z\right)
int8 값 qq를 근사적인 float32로 역양자화하는 공식은 다음과 같습니다:
xS(qZ)x \approx S \cdot (q - Z)
추론 중에는 int8 값 qq를 사용하여 행렬 곱셈과 같은 연산을 수행하며, 결과는 다음 레이어로 전달되기 전에 float32로 역양자화됩니다(종종 int32와 같은 더 높은 정밀도 축적 타입을 내부적으로 사용).

  • int4 및 가중치 패킹 (int4 and weight packing):
int4 양자화는 모델 크기와 메모리 사용량을 int8에 비해 절반으로 줄입니다. 동일한 아핀 또는 대칭 양자화 원리가 적용되며, float32 범위를 int4가 표현할 수 있는 16개의 값(예: 부호 있는 int4의 경우 [8,7][-8, 7])으로 매핑합니다. 하드웨어에서 4비트 데이터 타입을 직접 처리할 수 없으므로, 두 개의 int4 값을 하나의 int8 바이트로 패킹하여 저장하고 전송합니다.

  • FP8 (8-bit floating-point):
8비트 부동 소수점(FP8)은 int8보다 더 높은 정확도를 유지하면서 정밀도를 줄이는 또 다른 방법입니다. FP8은 부동 소수점 구조(sign, exponent, mantissa)를 유지하지만 더 적은 비트를 사용합니다.
  • E4M3: 1비트 부호, 4비트 지수, 3비트 가수. 높은 정밀도를 제공하지만 동적 범위가 작습니다.
  • E5M2: 1비트 부호, 5비트 지수, 2비트 가수. 더 넓은 동적 범위를 제공하지만 정밀도가 낮습니다.
FP8은 활성화(A)와 가중치(W)를 모두 8비트 정밀도로 양자화하는 *A8W8* 양자화 스킴에서 사용됩니다. FP8 연산은 NVIDIA H100/H200/B100 및 AMD Instinct MI300 시리즈와 같은 최신 GPU의 특정 하드웨어 기능이 필요합니다.

2. 세분성 (Granularity)

양자화 파라미터(SSZZ)는 두 가지 방식으로 계산될 수 있습니다:

  • 텐서별 (Per-Tensor): 전체 텐서에 대해 하나의 SSZZ 세트를 사용합니다. 단순하지만 텐서 내에서 데이터 값이 크게 다를 경우 정확도가 떨어질 수 있습니다.
  • 채널별/그룹별 (Per-Channel / Per-Group/Block): 각 채널 또는 그룹에 대해 별도의 SSZZ를 사용합니다. 약간 더 복잡하고 메모리를 더 사용하지만 더 정확하고 성능이 좋습니다.

3. 양자화 기법 (Quantization techniques)

주요 양자화 기법은 두 가지입니다:

  • 학습 후 양자화 (Post-Training Quantization, PTQ): 모델이 완전히 학습된 *후*에 양자화를 적용합니다.
  • 양자화 인지 학습 (Quantization-Aware Training, QAT): "가짜 양자화(fake quantization)" 연산을 삽입하여 학습 *중에* 양자화의 반올림 오류를 시뮬레이션합니다. 이를 통해 모델이 양자화에 적응할 수 있게 하며, 특히 낮은 비트폭에서 더 나은 정확도를 얻는 경우가 많습니다.

4. Transformers에서의 양자화 (Quantization in Transformers)

Transformers 라이브러리는 bitsandbytes, torchao, compressed-tensors와 같은 여러 양자화 백엔드를 통합합니다. 모든 백엔드는 HfQuantizer API와 관련 QuantizationConfig 클래스 아래에서 통일됩니다. 일반적인 워크플로우는 하드웨어와 사용 사례에 적합한 양자화 방법을 선택한 다음, Hugging Face Hub에서 사전 양자화된 모델을 로드하거나 float32/float16/bfloat16 모델을 로드하고 QuantizationConfig로 특정 양자화 방법을 적용하는 것입니다.

예시 코드는 BitsAndBytesConfig를 사용하여 8B 파라미터 모델을 4비트로 양자화하는 방법을 보여줍니다.

pythonimport torch from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig model_id = "meta-llama/Llama-3.1-8B-Instruct" quantization_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16 ) model = AutoModelForCausalLM.from_pretrained( model_id, quantization_config=quantization_config, dtype=torch.bfloat16, device_map="auto" )

이 코드는 meta-llama/Llama-3.1-8B-Instruct 모델을 4비트 양자화로 로드하며, 계산 데이터 타입으로는 torch.bfloat16을 사용하도록 설정합니다.