
8-bit Adam 특집: 옵티마이저 메모리를 75% 줄인 블록별 양자화의 비밀
Adam 옵티마이저의 상태만 84GB — 모델보다 6배 크다. 2021년, Tim Dettmers는 옵티마이저 상태를 8비트로 압축해 75%를 절약하면서도 32비트와 동일한 학습 품질을 유지하는 방법을 발견했다. 블록별 양자화와 동적 트리 양자화의 원리를 파헤친다.

Adam 옵티마이저의 상태만 84GB — 모델보다 6배 크다. 2021년, Tim Dettmers는 옵티마이저 상태를 8비트로 압축해 75%를 절약하면서도 32비트와 동일한 학습 품질을 유지하는 방법을 발견했다. 블록별 양자화와 동적 트리 양자화의 원리를 파헤친다.
7B 모델의 가중치는 FP16으로 ~14GB다. 그런데 AdamW 옵티마이저의 상태(1차 모멘텀 m + 2차 모멘텀 v + FP32 마스터 가중치)는 ~84GB. 모델 자체보다 6배 더 크다.
이것이 대규모 모델 학습의 숨은 병목이다. GPU 메모리의 대부분을 옵티마이저가 잡아먹고, 정작 모델과 활성화에 쓸 공간이 부족하다.
2021년, Tim Dettmers는 이 문제를 정면으로 해결했다 — 옵티마이저 상태를 FP32(4바이트) 대신 INT8(1바이트) 로 저장하면서도, 32비트와 동일한 학습 품질을 유지하는 방법을 만든 것이다. 비결은 세 가지: 블록별 양자화, 동적 트리 양자화, 안정 임베딩 레이어.
옵티마이저 상태(특히 Adam의 2차 모멘트 v)는 극도로 불균일한 분포를 갖는다. 대부분의 값은 작지만, 극소수의 이상값이 수백~수천 배 크다.
동적 양자화는 최댓값으로 나눠 [-1, 1] 범위로 정규화한다. 문제는 이상값 하나가 전체 텐서의 양자화를 망친다는 것이다:
이것이 단순 양자화가 실패하는 이유다. 100만 개 원소 중 1% 미만이 [3, ∞) 범위를 차지하는데, 이 극소수가 나머지 99%의 정밀도를 파괴한다.
핵심 아이디어: 텐서를 2048개 원소 블록으로 나눠, 각 블록을 독립적으로 양자화한다.
이상값이 한 블록에 격리되면, 그 블록만 영향을 받고 나머지 블록은 온전한 정밀도를 유지한다. GPU의 병렬 처리와도 자연스럽게 호환된다 — 각 블록이 독립적이므로 코어 간 동기화가 불필요하다.
일반적인 선형 양자화는 값의 범위를 균등하게 나눈다. 하지만 옵티마이저 상태는 작은 값이 훨씬 많으므로, 작은 값에는 높은 정밀도, 큰 값에는 넓은 범위가 필요하다.
동적 트리 양자화의 8비트 구조:
| 비트 | 역할 |
|---|---|
| 1번째 | 부호 비트 (+/-) |
| 이후 0 비트들 | 지수 크기를 나타냄 |
| 처음 나오는 1 비트 | 지수와 가수를 구분하는 인디케이터 |
| 나머지 비트 | 선형 양자화를 위한 가수(fraction) |
인디케이터 비트의 위치를 이동시키면 10⁻⁷까지의 극소값부터 큰 값까지 ~7자릿수의 동적 범위를 커버한다. 양의 정수만 저장하는 2차 모멘트에서는 부호 비트를 추가 범위로 전용한다.
NLP에서 단어 임베딩은 희소 레이어다 — 배치마다 일부 토큰만 업데이트되어, 기울기 분포가 극도로 불균일하다. 최대 기울기가 다른 레이어의 100배에 달할 수 있다.
해법: 임베딩 레이어에 세 가지 안정화를 적용한다:
핵심: 이 변환이 GPU 레지스터에서 원소별로 일어난다. 글로벌 메모리에 임시 FP32 복사본을 만들지 않으므로, 추가 메모리가 필요 없고, 메모리 대역폭 병목도 없다.
이 덕분에 8비트 Adam은 32비트보다 오히려 더 빠르다 — FP32 상태를 읽고 쓸 때의 메모리 대역폭이 75% 감소하기 때문이다.
4096개 미만의 원소를 가진 텐서(편향, 레이어 정규화 등)는 32비트로 유지한다. 절약되는 메모리가 미미하고, 이런 파라미터는 변동성이 크거나 높은 정밀도가 필요한 경우가 많다. 임계값은 min_8bit_size로 설정 가능하다.
| GPU 메모리 | FP32 Adam 최대 모델 | 8-bit Adam 최대 모델 |
|---|---|---|
| 6 GB | RoBERTa-base (110M) | RoBERTa-large (355M) |
| 11 GB | mT5-small (300M) | mT5-base (580M) |
| 24 GB | mT5-base (580M) | mT5-large (1.2B) |
1.3B+ 규모에서는 동적 양자화만으로는 100% 발산, 블록별 추가 시 80% 불안정, 세 가지 모두 적용 시 0% 불안정.
| 과제 | 32-bit Adam | 8-bit Adam |
|---|---|---|
| Transformer-1.5B (PPL) | 9.0 | 9.0 |
| RoBERTa-Base (PPL) | 3.49 | 3.48 |
| GLUE (RoBERTa-Large) | 88.6 | 88.7 |
| ImageNet (ResNet-50) | 77.1% | 77.2% |
| WMT'14 번역 (BLEU) | 29.0 | 29.1 |
| MoCo v2 (Top-1) | 67.3% | 67.4% |
모든 벤치마크에서 32비트와 동일하거나 미세하게 우수. 하이퍼파라미터 변경 없이 드롭인 교체.
| 옵티마이저 | 시간 |
|---|---|
| 32-bit PyTorch Adam | 145ms |
| 32-bit Apex Adam | 63ms |
| 8-bit Adam (bitsandbytes) | 47ms |
8비트가 32비트보다 3배 빠르다 — 메모리 접근량이 줄었기 때문이다.
8-bit Adam은 이 여정의 첫 번째 디딤돌이었다. 옵티마이저 양자화에서 시작해 추론 양자화(LLM.int8())를 거쳐 QLoRA의 4비트 파인튜닝까지 — 일관된 주제는 "더 적은 비트로 같은 일을 하자" 다.
Tim Dettmers가 만든 bitsandbytes는 8-bit Adam의 공식 구현체이자, QLoRA, LLM.int8() 등을 포함하는 메모리 효율적 딥러닝 도구 모음이다.
| 지표 | 수치 |
|---|---|
| 월간 다운로드 | ~540만 회 (PyPI) |
| 사용 프로젝트 | 35,800+ (GitHub) |
| GitHub 스타 | 8,100+ |
| 지원 백엔드 | CUDA, ROCm, Intel XPU, Gaudi, CPU, Apple Silicon (실험적) |
import bitsandbytes as bnb
# 8-bit Adam (드롭인 교체)
optimizer = bnb.optim.Adam8bit(model.parameters(), lr=1e-3)
# 또는 Hugging Face Transformers에서
from transformers import TrainingArguments
args = TrainingArguments(optim="adamw_bnb_8bit", ...)
핵심 장점: 하이퍼파라미터 변경 없이 torch.optim.AdamW를 bnb.optim.AdamW8bit로 교체하면 끝이다.
8-bit Adam의 독특한 강점: 알고리즘 자체를 바꾸지 않는다. Adam의 수학적 동작을 그대로 유지하면서 저장 형식만 변경한다. 이것이 드롭인 교체와 하이퍼파라미터 호환성을 가능하게 한다.
GaLore와의 조합은 특히 흥미롭다 — 기울기를 저랭크로 투영하고, 그 위의 옵티마이저 상태를 8비트로 양자화하면 두 가지 절감을 동시에 얻는다.
8-bit Adam의 교훈은 단순하면서 깊다:
32비트의 정밀도 중 24비트는 불필요했다.
옵티마이저 상태의 75%가 "낭비"였다는 뜻이 아니다. 저장 시 8비트면 충분하고, 계산 시 FP32로 잠깐 올렸다 다시 내리면 된다는 것이다. 이 발상의 전환이 동일한 GPU에서 학습 가능한 모델의 크기를 약 2배 키웠다.
그리고 이 발상은 멈추지 않았다:
Tim Dettmers의 연구가 증명한 것은, AI의 진정한 혁신이 항상 더 큰 모델, 더 많은 GPU에서 오는 것은 아니라는 것이다. 때로는 같은 비트를 더 현명하게 쓰는 것이 더 큰 변화를 만든다.