Exploring Quantization Backends in Diffusers
Quick Summary
Diffusers는 Flux의 핵심 구성 요소를 여러 백엔드로 양자화해 이미지 품질을 크게 훼손하지 않으면서 메모리 사용량을 줄일 수 있으며, 정밀도와 백엔드에 따라 속도·메모리·사용 편의성의 차이가 뚜렷하다.
🖼️ 인포그래픽
🖼️ 4컷 인포그래픽
💡 한 줄 요약
Diffusers는 Flux의 핵심 구성 요소를 여러 백엔드로 양자화해 이미지 품질을 크게 훼손하지 않으면서 메모리 사용량을 줄일 수 있으며, 정밀도와 백엔드에 따라 속도·메모리·사용 편의성의 차이가 뚜렷하다.
📌 핵심 요약
- Flux-dev 전체 모델을 BF16으로 불러오면 약 31.447GB가 필요하며, 특히 23.8GB의 Transformer와 9.52GB의 T5 텍스트 인코더가 주요 양자화 대상이다.
- bitsandbytes의 4비트 NF4는 로딩 후 메모리를 12.584GB까지 줄이면서 BF16과 같은 12초의 추론 시간을 기록했고, 8비트는 19.273GB와 27초를 기록했다.
- torchao와 Quanto의 INT4는 약 10~12GB 수준까지 메모리를 줄였지만 추론 시간이 모두 109초로 늘었고, INT8과 FP8 계열은 약 15~16초의 상대적으로 빠른 결과를 보였다.
- GGUF는 사전 양자화 파일을 불러오는 방식으로 Q2_k, Q4_1, Q8_0을 지원하며, 정밀도가 높아질수록 메모리 사용량이 증가하는 대신 추론 시간이 단축되는 결과를 보였다.
- PipelineQuantizationConfig를 이용하면 Transformer와 T5에 서로 다른 라이브러리의 양자화 설정을 연결할 수 있지만, 백엔드별 설정 클래스·장치 배치·버전 제약을 정확히 구분해야 한다.
🧩 주요 포인트
- Flux-dev 전체 모델을 BF16으로 불러오면 약 31.447GB가 필요하며, 특히 23.8GB의 Transformer와 9.52GB의 T5 텍스트 인코더가 주요 양자화 대상이다.
- bitsandbytes의 4비트 NF4는 로딩 후 메모리를 12.584GB까지 줄이면서 BF16과 같은 12초의 추론 시간을 기록했고, 8비트는 19.273GB와 27초를 기록했다.
- torchao와 Quanto의 INT4는 약 10~12GB 수준까지 메모리를 줄였지만 추론 시간이 모두 109초로 늘었고, INT8과 FP8 계열은 약 15~16초의 상대적으로 빠른 결과를 보였다.
- GGUF는 사전 양자화 파일을 불러오는 방식으로 Q2_k, Q4_1, Q8_0을 지원하며, 정밀도가 높아질수록 메모리 사용량이 증가하는 대신 추론 시간이 단축되는 결과를 보였다.
- PipelineQuantizationConfig를 이용하면 Transformer와 T5에 서로 다른 라이브러리의 양자화 설정을 연결할 수 있지만, 백엔드별 설정 클래스·장치 배치·버전 제약을 정확히 구분해야 한다.
🧠 상세 정리
1. 대형 확산 모델과 양자화의 목적
Flux와 같은 대형 텍스트-이미지 생성 모델은 뛰어난 이미지를 만들 수 있지만, 모델의 크기 때문에 많은 메모리와 연산 자원을 요구한다. 글은 양자화를 모델 접근성을 높이는 핵심 수단으로 제시하며, 성능을 크게 훼손하지 않고 모델 크기와 메모리 부담을 줄일 수 있는지를 살펴본다. 기술적인 수치만 비교하는 데 그치지 않고, 사용자가 고정밀 모델과 양자화 모델이 만든 이미지를 실제로 구별할 수 있는지도 중요한 판단 기준으로 삼는다. 이를 위해 BF16 원본과 bitsandbytes 4비트·8비트 결과를 함께 제시하고 어떤 이미지가 양자화 모델에서 생성됐는지 맞히는 실험을 제공한다. 특히 8비트 양자화의 차이는 자세히 살펴보지 않으면 알아보기 어려운 경우가 많으며, 4비트 이하에서는 차이가 더 드러날 수 있지만 큰 메모리 절감량을 고려하면 여전히 양호한 결과를 얻을 수 있다고 설명한다.
2. FluxPipeline의 구성과 주요 양자화 대상
비교에는 black-forest-labs/FLUX.1-dev 체크포인트를 사용하는 FluxPipeline이 활용되며, 전체 모델을 BF16 정밀도로 불러올 때 필요한 메모리는 약 31.447GB로 제시된다. 텍스트 프롬프트를 처리하는 인코더는 CLIP과 T5로 구성되며, CLIP은 초기 이해를 담당하고 더 큰 T5는 세밀한 문맥 이해와 텍스트 표현 개선에 사용된다. BF16 기준 메모리는 T5가 9.52GB, CLIP이 246MB이고, 이미지의 잠재 표현을 생성하는 핵심 MMDiT Transformer는 23.8GB를 차지한다. 픽셀 공간과 잠재 공간 사이를 변환하고 최종 이미지를 복원하는 VAE는 168MB로 상대적으로 작다. 따라서 예제들은 가장 큰 절감 효과를 얻기 위해 주로 Transformer와 text_encoder_2에 해당하는 T5를 함께 양자화하며, 바로크 궁전·미래형 우주항·누아르 골목이라는 세 종류의 프롬프트로 결과를 비교한다.
3. bitsandbytes의 4비트·8비트 양자화
bitsandbytes는 LLM과 QLoRA 미세조정에 널리 사용되는 8비트·4비트 양자화 라이브러리이며, Transformer 기반 확산 모델과 흐름 기반 모델에도 적용할 수 있다. NVIDIA H100 80GB GPU 한 장에서 측정한 결과, BF16은 로딩 후 약 31.447GB와 최대 36.166GB를 사용하고 추론에 12초가 걸렸다. BnB 4비트는 로딩 후 12.584GB, 최대 17.281GB로 메모리를 크게 줄이면서도 추론 시간은 BF16과 같은 12초를 기록했다. 반면 BnB 8비트는 로딩 후 19.273GB와 최대 24.432GB를 사용했지만 추론 시간은 27초로 늘어났다. 글은 공격적인 저비트 양자화에서 시각적 차이가 더 나타날 가능성을 인정하면서도, NF4가 이미지 품질과 메모리 절감 사이에서 흔히 가장 좋은 절충점을 제공한다고 평가한다.
4. PipelineQuantizationConfig 설정 방식과 주의점
BnB 4비트 예제는 PipelineQuantizationConfig의 quant_mapping을 사용해 Transformer와 T5 텍스트 인코더에 각각 양자화 설정을 연결한다. 두 구성 요소에는 모두 4비트 로딩, NF4 양자화 형식, BF16 연산 자료형이 지정되며, 파이프라인 자체도 BF16으로 불러온 뒤 CUDA 장치로 이동한다. 생성 설정은 1024×1024 해상도, guidance scale 3.5, 50단계 추론, 최대 시퀀스 길이 512이며, 동일한 결과를 얻기 위해 수동 시드 0을 사용한다. 중요한 점은 Transformer용 BitsAndBytesConfig를 diffusers에서, T5용 BitsAndBytesConfig를 transformers에서 각각 가져와야 한다는 것이다. 이름이 같더라도 구성 요소가 서로 다른 라이브러리에서 유래하기 때문에 설정 클래스를 구분해야 하며, 이 import 관리를 피하고 싶다면 Diffusers 문서에 소개된 다른 파이프라인 수준 양자화 방식을 사용할 수 있다.
5. torchao의 PyTorch 네이티브 최적화
torchao는 양자화뿐 아니라 희소화와 사용자 정의 자료형을 제공하는 PyTorch 네이티브 아키텍처 최적화 라이브러리이며, torch.compile 및 FSDP와의 호환성을 목표로 한다. Diffusers는 torchao의 다양한 자료형을 지원해 int4_weight_only, int8_weight_only, float8_weight_only 같은 방식을 선택할 수 있게 한다. H100 기준 int4_weight_only는 로딩 후 10.635GB와 최대 14.654GB로 비교 대상 중 매우 낮은 메모리 사용량을 보였지만, 추론에는 109초가 걸렸다. int8_weight_only는 17.020GB·최대 21.482GB·15초였고, float8_weight_only는 17.016GB·최대 21.488GB·15초로 두 방식의 측정값이 유사했다. INT4 예제에서는 Diffusers와 Transformers의 TorchAoConfig를 각각 지정하고 device_map을 balanced로 설정하며, 파이프라인 전체를 명시적으로 CUDA로 옮기는 기존 호출은 제거한다.
6. Quanto의 INT4·INT8·FP8 지원
Quanto는 optimum 라이브러리를 통해 Hugging Face 생태계와 통합되는 양자화 라이브러리로, 글에서는 INT4·INT8·FP8 결과를 비교한다. INT4는 로딩 후 12.254GB와 최대 16.139GB를 사용해 메모리를 크게 절감했지만 추론 시간은 torchao INT4와 같은 109초였다. INT8은 17.330GB·최대 21.814GB·15초였고, FP8은 16.395GB·최대 20.898GB·16초로 측정되어 저비트 INT4보다 더 많은 메모리를 쓰는 대신 훨씬 빠른 추론을 보였다. INT8 예제는 Transformer와 T5에 각각 DiffusersQuantoConfig와 TransformersQuantoConfig를 연결하고 weights_dtype을 int8로 지정한다. FP8은 작성 시점에 optimum-quanto 0.2.5 미만 버전과 Quanto 직접 사용이 필요하며, text_encoder_2와 Transformer를 별도로 불러온 뒤 qfloat8로 양자화하고 freeze한 다음 FluxPipeline에 주입하는 방식이 제시된다.
7. GGUF 사전 양자화 모델 활용
GGUF는 llama.cpp 커뮤니티에서 양자화 모델을 저장하는 용도로 널리 쓰이는 파일 형식이며, Diffusers에서는 사전 양자화된 Flux Transformer 파일을 불러오는 방식으로 활용된다. 비교 대상인 Q2_k는 로딩 후 13.264GB와 최대 17.752GB를 사용하고 추론에 26초가 걸렸으며, Q4_1은 16.838GB·최대 21.326GB·23초를 기록했다. 정밀도가 더 높은 Q8_0은 로딩 후 21.502GB와 최대 25.973GB로 메모리 사용량이 가장 컸지만 추론 시간은 15초로 세 GGUF 형식 중 가장 짧았다. Q4_1 예제에서는 Hugging Face에 공개된 사전 양자화 GGUF 파일의 경로를 지정하고, FluxTransformer2DModel.from_single_file과 GGUFQuantizationConfig를 사용해 BF16 연산 자료형으로 Transformer를 불러온다. 이후 원래 모델 ID에서 나머지 FluxPipeline 구성 요소를 불러오되 해당 Transformer를 교체해 넣고, 완성된 파이프라인을 CUDA 장치로 이동한다.
8. 백엔드별 절충점과 FP8 계층별 캐스팅
전체 벤치마크는 양자화 비트 수가 낮아진다고 해서 메모리·속도·시각 품질이 단순히 같은 방향으로 변하지는 않는다는 점을 보여준다. bitsandbytes 4비트는 12.584GB의 로딩 메모리와 12초의 추론 시간을 함께 달성한 반면, torchao와 Quanto의 INT4는 더 낮거나 비슷한 메모리를 사용하지만 각각 109초가 필요했다. torchao의 INT8·float8과 Quanto의 INT8·FP8은 약 16~17GB의 로딩 메모리와 15~16초의 추론 시간을 기록했고, GGUF는 Q2_k에서 Q8_0으로 갈수록 메모리는 증가하지만 측정된 추론 시간은 짧아졌다. 따라서 선택은 가장 낮은 비트 수만을 기준으로 하기보다 사용 가능한 메모리, 허용 가능한 생성 시간, 설정 방식과 최종 이미지의 체감 차이를 함께 고려해야 한다. 원문은 이어서 enable_layerwise_casting을 이용한 FP8 계층별 캐스팅을 메모리 최적화 기법으로 소개하고, 모델 가중치를 더 작은 FP8 형식으로 저장한다는 설명을 시작하지만 제공된 본문은 그 지점에서 끝난다.
🧾 핵심 주장 / 시사점
- 동일한 4비트 양자화라도 BnB는 12초, torchao와 Quanto는 109초를 기록했으므로 비트 수만으로 실제 추론 성능을 판단할 수 없다.
- Flux에서 메모리 절감 효과를 크게 얻으려면 상대적으로 작은 CLIP이나 VAE보다 23.8GB의 Transformer와 9.52GB의 T5를 우선 양자화하는 구성이 핵심이다.
- 실용적인 백엔드 선택에는 이미지의 체감 품질뿐 아니라 로딩 메모리, 최대 메모리, 추론 시간, 사전 양자화 파일 사용 여부, 라이브러리별 설정 및 버전 제약을 함께 비교해야 한다.
✅ 액션 아이템
- BF16 기준치(31.447GB)와 Transformer 23.8GB, T5 9.52GB를 근거로 양자화 우선순위를 정한다.
- bitsandbytes의 NF4(12.584GB, 12초)와 8비트(19.273GB, 27초)를 대조해 메모리 절감 우선 시나리오를 정리한다.
- torchao·Quanto INT4(약10~12GB, 109초)와 INT8/FP8(15~16초) 조합을 지연 요구별로 분기해 적용 계획을 잡는다.
❓ 열린 질문
- BF16 대비 추론시간 손실을 제한하면서도 메모리를 줄이려면 NF4, INT4, INT8·FP8 중 어떤 정밀도가 적합한가?
- GGUF에서 Q2_k·Q4_1·Q8_0 정밀도별로 메모리 증가와 추론 단축의 균형점은 대상 하드웨어에서 어디에 위치하는가?
- PipelineQuantizationConfig로 Transformer와 T5를 분리 적용할 때 설정 클래스·장치 배치·버전 제약은 어떻게 분리해 충돌을 방지할 것인가?