bfloat16
더 많은 작업
- bfloat16, BF16, brain floating point; bfloat16
- FP32의 지수 8비트를 그대로 두고 가수만 7비트로 줄인 16비트 부동소수점 형식. 딥 러닝 학습용으로 구글 브레인이 만들었다.
bfloat16(brain floating point 16, 줄여서 BF16)은 IEEE 754 단정밀도(FP32) 32비트에서 가수(유효숫자) 아래 16비트를 잘라 낸 모양의 16비트 수 형식이다. 부호 1비트, 지수 8비트, 가수 7비트로 이루어져 FP32와 표현 범위가 같고 정밀도만 낮다. 이름은 이 형식을 고안한 구글 브레인(Google Brain)에서 왔다.[1]
같은 16비트인 IEEE 반정밀도(FP16)는 가수를 10비트로 더 정밀하게 두는 대신 지수가 5비트라 65504보다 큰 수와 약 보다 작은 수를 표현하지 못한다. 구글은 신경망이 가수 크기보다 지수 크기에 훨씬 민감하다는 경험에서 지수를 FP32와 맞췄고, 덕분에 BF16은 FP16에 필요한 손실 스케일링 없이 FP32를 거의 그대로 대체할 수 있다고 설명했다.[1] 대형 언어 모델의 학습과 추론에 쓰이며, 혼합 정밀도 학습의 핵심 재료다. 이 문서는 BF16을 중심으로 딥 러닝에서 쓰는 저정밀도 수 형식(FP16, TF32, FP8, FP6, FP4, MX, NVFP4)을 함께 비교한다. 부동소수점 일반은 부동소수점 표현 (IEEE 754 규격) 문서 참고.
| 형식 | 부호 | 지수 | 가수 | 전체 |
|---|---|---|---|---|
| FP32 (binary32) | 1 | 8 | 23 | 32 |
| BF16 | 1 | 8 | 7 | 16 |
| FP16 (binary16) | 1 | 5 | 10 | 16 |
정규수의 값은 다른 IEEE 형식과 같은 방식으로 계산한다. 지수 바이어스는 FP32와 같은 127이다. 지수 필드가 0이면 0과 비정규수, 255면 무한대와 NaN이다. 가장 작은 양의 정규수는 , 가장 큰 수는 이다. 가수가 7비트(숨은 비트 포함 8비트 정밀도)라 십진수로 2~3자리만 정확하다. 예를 들어 BF16에서는 1과 2 사이의 수 간격이 이므로 은 1로 반올림되고, 256 이상에서는 정수 1 차이도 표현하지 못한다(256 + 1 = 256).
BF16은 FP32 비트 패턴의 위쪽 16비트와 같으므로 변환이 아주 싸다. BF16에서 FP32로는 아래에 0 16개를 붙이면 끝이고, FP32에서 BF16으로는 아래 16비트를 버리는 버림(truncation, 0 쪽 반올림) 또는 최근접 짝수 반올림(round to nearest even, RNE)을 쓴다. 인텔과 페이스북 연구진의 BF16 학습 연구는 RNE로 반올림했다.[2]
import torch
x = torch.tensor([3.14159265, 1/3, 131000.0, 1e-30], dtype=torch.float32)
bits = x.view(torch.int32)
truncated = (bits & ~0xFFFF).view(torch.float32) # 아래 16비트 버림
print(truncated.tolist()) # [3.140625, 0.33203125, 130560.0, 9.98e-31]
print(x.to(torch.bfloat16).float().tolist()) # RNE: [3.140625, 0.333984375, 131072.0, 9.98e-31]
print(x.to(torch.float16).float().tolist()) # FP16: [3.140625, 0.33325..., inf, 0.0]
같은 수를 FP16으로 바꾸면 131000은 범위를 넘어 무한대가, 은 0이 된다. BF16은 둘 다 근삿값을 유지하지만 1/3처럼 일반적인 수의 정밀도는 FP16보다 낮다.
아래 값은 각 형식의 정의에서 계산한 것이다(PyTorch torch.finfo로 FP32·FP16·BF16·FP8 값을 확인). ε은 1 바로 다음 수와 1의 차이(기계 엡실론)다.
| 형식 | 비트(부호·지수·가수) | 지수 바이어스 | 최대값 | 최소 양의 정규수 | ε | 주요 쓰임 |
|---|---|---|---|---|---|---|
| FP32 | 1·8·23 | 127 | 약 | 마스터 가중치, 옵티마이저 상태, 누산 | ||
| TF32 | 1·8·10 (19비트) | 127 | FP32와 같음 | 엔비디아 텐서 코어 내부 연산 전용 | ||
| FP16 | 1·5·10 | 15 | 65504 | 혼합 정밀도(손실 스케일링 필요), 추론 | ||
| BF16 | 1·8·7 | 127 | 약 | 학습·추론의 기본 16비트 형식 | ||
| FP8 E4M3 | 1·4·3 | 7 | 448 | 순전파 가중치·활성값 | ||
| FP8 E5M2 | 1·5·2 | 15 | 57344 | 역전파 기울기 | ||
| FP6 E2M3 | 1·2·3 | 1 | 7.5 | MXFP6 원소 | ||
| FP6 E3M2 | 1·3·2 | 3 | 28 | MXFP6 원소 | ||
| FP4 E2M1 | 1·2·1 | 1 | 6 | MXFP4·NVFP4 원소 |
FP8 두 형식은 2022년 엔비디아·Arm·인텔 연구진이 함께 제안했다. E5M2는 IEEE 관례대로 무한대와 NaN을 모두 두지만, E4M3는 무한대를 없애고 NaN 비트 패턴을 하나만 남겨 최대값을 240에서 448로 넓혔다.[3] PyTorch에서는 torch.float8_e4m3fn과 torch.float8_e5m2라는 자료형 이름을 쓴다(fn은 finite, 즉 무한대가 없다는 뜻). TF32는 저장 형식이 아니라 엔비디아 A100(암페어)부터 텐서 코어가 FP32 입력을 곱할 때 내부에서 쓰는 형식으로, FP32의 8비트 지수와 FP16의 10비트 가수를 합친 것이다.[4]
8비트 이하 형식은 표현 범위가 너무 좁아 원소 하나하나만으로는 텐서를 담지 못한다. 그래서 작은 블록마다 공통 스케일을 하나 두는 블록 부동소수점 방식이 쓰인다.
| 형식 | 블록 크기 | 블록 스케일 | 원소 형식 | 추가 스케일 |
|---|---|---|---|---|
| MXFP8 | 32 | E8M0 (2의 거듭제곱) | FP8 E4M3 또는 E5M2 | 없음 |
| MXFP6 | 32 | E8M0 | FP6 E2M3 또는 E3M2 | 없음 |
| MXFP4 | 32 | E8M0 | FP4 E2M1 | 없음 |
| MXINT8 | 32 | E8M0 | INT8 | 없음 |
| NVFP4 | 16 | FP8 E4M3 (소수 배율 가능) | FP4 E2M1 | 텐서당 FP32 스케일 하나 |
MX(마이크로스케일링) 형식은 마이크로소프트·AMD·인텔·메타·엔비디아·퀄컴 연구진이 2023년 OCP(Open Compute Project) 규격으로 내놓은 것이다. 블록 값은 로, 는 블록 공통 스케일(8비트 지수만 있는 E8M0), 는 각 원소다. 연구진은 MXFP8로 FP32 사전 학습 모델을 보정 없이 바로 변환해 추론해도 정확도가 거의 같고, MXFP6로 가중치·활성값·기울기를 모두 8비트 미만으로 둔 채 학습 레시피를 바꾸지 않고 FP32에 맞먹는 생성형 언어 모델을 학습했다고 보고했다.[5]
NVFP4는 엔비디아가 블랙웰 GPU와 함께 내놓은 4비트 형식이다. MXFP4와 원소 형식(E2M1, 표현 가능한 크기 0, 0.5, 1, 1.5, 2, 3, 4, 6)은 같지만 블록을 16개로 줄이고, 블록 스케일을 2의 거듭제곱으로 묶인 E8M0 대신 소수 배율을 표현할 수 있는 FP8 E4M3로 둔다. E4M3 스케일은 범위가 좁으므로 텐서 전체에 FP32 스케일을 하나 더 곱하는 2단계 구조다. 엔비디아는 FP16 대비 약 3.5배, FP8 대비 약 1.8배 메모리를 줄인다고 밝혔다.[6]
학습 중 수치의 크기 분포는 텐서마다, 단계마다 크게 다르다. 기울기는 아래까지 내려가고, 어텐션 로짓이나 손실 합은 수천을 넘기도 한다. FP16은 이 범위를 한 번에 담지 못해 손실 스케일링으로 분포를 옮겨야 하고, 스케일이 맞지 않으면 기울기가 0이 되거나 inf가 된다. BF16은 범위가 FP32와 같아 이 관리가 필요 없다. 정밀도가 낮은 문제는 곱셈은 BF16으로 하되 누산(덧셈 누적)은 FP32로 하는 방식으로 대부분 해결된다. 구글 TPU v2·v3의 행렬 곱 장치(MXU)는 곱셈을 BF16으로, 누산을 FP32로 한다.[1]
인텔·페이스북 연구진은 BF16 연산을 소프트웨어로 흉내 내어 이미지 분류(AlexNet, ResNet-50), 음성 인식(DeepSpeech2), 번역(GNMT), 생성 신경망(DC-GAN, SR-GAN), 산업용 추천 모델을 학습했고, BF16 혼합 정밀도가 FP32와 같은 반복 횟수, 같은 하이퍼파라미터로 같은 최고 수준 결과를 낸다고 보고했다. 이 연구는 FP16은 하이퍼파라미터 조정이 필요하지만 BF16은 FP32와 범위가 같아 그럴 필요가 없다는 점을 강조했다.[2] 구글은 클라우드 TPU 참조 모델 대부분을 BF16 혼합 정밀도로 바꿔 4~47%(기하 평균 13.9%) 성능 향상을 얻었다고 밝혔다.[1]
- 작은 갱신량이 사라진다. 가중치를 BF16으로만 들고 있으면 학습률 × 기울기가 가중치의 배쯤보다 작을 때 덧셈 결과가 원래 값으로 반올림된다. 그래서 보통 FP32 마스터 가중치를 따로 두거나, 확률적 반올림(stochastic rounding)·카한 합산(Kahan summation) 같은 보정을 쓴다.
- FP16 모델과 서로 바꿔 쓰기 어렵다. BF16으로 학습한 모델은 활성값이 65504를 넘는 경우가 있어 FP16 추론에서 오버플로가 날 수 있다. PyTorch 문서도 BF16 사전 학습 모델 대부분이 FP16 범위에서 동작하지 못할 수 있다고 경고한다.[7] 반대로 FP16 모델을 BF16으로 돌리는 것은 범위 문제는 없지만 정밀도가 낮아진다.
- 비정규수 처리. 구글은 TPU의 BF16이 비정규수를 0으로 내린다(flush to zero)고 밝혔다.[1] 하드웨어마다 다를 수 있다.
- 합산과 정규화는 FP32로. 소프트맥스, 레이어 정규화, 손실, 큰 합산은 BF16으로 하면 오차가 커진다. PyTorch autocast는 이런 연산을 자동으로 FP32로 올린다.[7]
- 정수 표현. 256을 넘는 정수는 정확히 표현되지 않으므로 토큰 ID나 위치 인덱스를 BF16 텐서에 담으면 안 된다.
import torch
print(torch.finfo(torch.bfloat16)) # eps=0.0078125, max=3.39e+38, tiny=1.18e-38
print(torch.cuda.is_bf16_supported())
# 1) 혼합 정밀도: 가중치는 FP32, 연산만 BF16
with torch.autocast(device_type="cuda", dtype=torch.bfloat16):
y = model(x)
# 2) 모델 전체를 BF16으로 (추론, 또는 별도 보정과 함께 하는 학습)
model = model.to(torch.bfloat16)
# 3) FP8 자료형은 저장·변환용이다. 행렬 곱은 스케일과 함께 전용 커널로 한다.
w8 = (w / w.abs().max() * 448).to(torch.float8_e4m3fn)
CPU에서 autocast의 기본 자료형은 BF16이다.[7] 허깅 페이스 Transformers에서는 모델을 불러올 때 자료형을 torch.bfloat16으로 지정할 수 있다.
- ↑ 1.0 1.1 1.2 1.3 1.4 Shibo Wang, Pankaj Kanwar, 〈BFloat16: The secret to high performance on Cloud TPUs〉, Google Cloud 블로그, 2019. cloud.google.com
- ↑ 2.0 2.1 Dhiraj Kalamkar 외, 〈A Study of BFLOAT16 for Deep Learning Training〉, 2019. arXiv:1905.12322
- ↑ Paulius Micikevicius 외, 〈FP8 Formats for Deep Learning〉, 2022. arXiv:2209.05433
- ↑ NVIDIA, 〈NVIDIA Ampere Architecture In-Depth〉, 2020. developer.nvidia.com
- ↑ Bita Darvish Rouhani 외, 〈Microscaling Data Formats for Deep Learning〉, 2023. arXiv:2310.10537
- ↑ 6.0 6.1 NVIDIA, 〈Introducing NVFP4 for Efficient and Accurate Low-Precision Inference〉, 2025. developer.nvidia.com
- ↑ 7.0 7.1 7.2 PyTorch, 〈Automatic Mixed Precision package - torch.amp〉, 2.14 문서. docs.pytorch.org
- ↑ NVIDIA, 〈NVIDIA Hopper Architecture In-Depth〉, 2022. developer.nvidia.com