Mixed Precision
Huấn luyện độ chính xác hỗn hợp sử dụng phép toán 16 bit và trọng số chính FP32 cho mạng nơ-ron, giúp giảm mức sử dụng bộ nhớ và thời gian huấn luyện. Nội dung bao gồm loss scaling, BF16 và AMP.
Mixed precision là kỹ thuật huấn luyện thực hiện phần lớn phép tính của mạng nơ-ron bằng định dạng dấu phẩy động 16-bit, gồm FP16 (độ chính xác half) hoặc BF16, đồng thời giữ bản sao master 32-bit (FP32) của trọng số model và thực hiện các phép toán nhạy cảm về số học bằng FP32. Giá trị 16-bit chỉ chiếm một nửa bộ nhớ và băng thông so với FP32, còn Tensor Core trên các GPU hiện đại nhân chúng nhanh hơn nhiều; nhờ đó mixed precision rút ngắn thời gian huấn luyện và cho phép chứa batch size lớn hơn trong bộ nhớ mà vẫn đạt độ chính xác tương đương FP32. Quy trình do Micikevicius và cộng sự mô tả năm 2018, gồm trọng số master FP32, phép toán FP16 và loss scaling, hiện được các framework deep learning tự động hóa dưới tên Automatic Mixed Precision (AMP).
Cách thức hoạt động của độ chính xác hỗn hợp#
Ba thành phần giúp backpropagation và cập nhật trọng số trong quá trình huấn luyện 16-bit đạt độ chính xác tương đương huấn luyện FP32:
- Trọng số master FP32: Optimizer áp dụng từng lần cập nhật lên bản sao FP32 của trọng số. Một cập nhật rất nhỏ cộng trực tiếp vào trọng số FP16 thường bị làm tròn mất, vì FP16 chỉ giữ khoảng ba chữ số thập phân có nghĩa.
- Độ chính xác theo từng phép toán: Context autocast thực hiện phép nhân ma trận và tích chập ở 16-bit, nơi Tensor Core đem lại mức tăng tốc lớn nhất, đồng thời giữ các phép tính tổng hợp, softmax và loss ở FP32.
- Loss scaling: FP16 không thể biểu diễn các giá trị nhỏ hơn khoảng 6 × 10⁻⁸, vì vậy nhiều gradient nhỏ sẽ bị underflow thành 0. Nhân loss với một hệ số tỷ lệ trước khi backpropagation sẽ dịch chuyển mọi gradient vào phạm vi biểu diễn của FP16; sau đó, các gradient được chia cho cùng hệ số trước khi cập nhật trọng số.
Trong PyTorch AMP, torch.autocast xử lý việc chuyển kiểu dữ liệu theo từng phép toán, còn GradScaler xử lý loss scaling:
import torch
from torch import nn
# Use FP16 on an NVIDIA GPU and BF16 on CPU
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.float16 if device == "cuda" else torch.bfloat16
model = nn.Linear(512, 10).to(device) # master weights stay in FP32
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
scaler = torch.amp.GradScaler(device, enabled=dtype == torch.float16) # loss scaling for FP16 only
x = torch.randn(64, 512, device=device)
with torch.autocast(device_type=device, dtype=dtype):
out = model(x) # the matrix multiply runs in 16-bit
loss = out.float().pow(2).mean()
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
print(f"Output: {out.dtype}, weights: {model.weight.dtype}, gradients: {model.weight.grad.dtype}")Trên CPU, đoạn mã in torch.bfloat16 cho đầu ra của layer và torch.float32 cho cả trọng số lẫn gradient; trên GPU NVIDIA, đầu ra là torch.float16. Phép toán 16-bit và trọng số master FP32 cùng tồn tại trong một bước huấn luyện.
GradScaler của PyTorch điều chỉnh scale theo cách linh hoạt. Scale bắt đầu ở 65,536; scale sẽ giảm một nửa và bỏ qua bước cập nhật bất cứ khi nào các gradient đã scale chứa giá trị inf hoặc NaN, rồi tăng gấp đôi sau 2,000 bước liên tiếp không bị tràn số; nhờ đó hệ số ổn định ngay dưới ngưỡng khiến gradient bị tràn.
FP16, BF16 và các độ chính xác thấp hơn#
FP16 dành 5 bit cho số mũ và 10 bit cho phần định trị, nên có độ chính xác cao nhưng bị tràn số trên 65,504. BF16 giữ 8 bit số mũ như FP32, bao phủ cùng phạm vi đến khoảng 3.4 × 10³⁸, nhưng chỉ có 7 bit phần định trị; vì vậy BF16 không cần loss scaling, đổi lại độ làm tròn thô hơn. BF16 chạy được trên GPU NVIDIA từ thế hệ Ampere trở đi, trên TPU của Google và trên nhiều CPU đời mới; đây là định dạng huấn luyện phổ biến cho mô hình ngôn ngữ lớn. Ý tưởng tương tự được áp dụng cho FP8 trên GPU Hopper và Blackwell thông qua Transformer Engine của NVIDIA, cũng như cho các định dạng FP4 như NVFP4 trên Blackwell.
Mixed precision trong thực tế#
Rủi ro thực tế chính của AMP là model hoặc GPU tạo ra loss NaN khi chạy ở 16-bit. Quá trình huấn luyện Ultralytics YOLO26 bật AMP theo mặc định bằng amp=True, trước tiên so sánh dự đoán FP32 và AMP từ model YOLO26n trên GPU CUDA, rồi chuyển về FP32 nếu hai kết quả không khớp hoặc GPU thuộc dòng đã biết là tạo ra loss NaN khi dùng AMP, chẳng hạn dòng GTX 16. Thiết lập amp="bf16" chuyển sang autocast BF16 và tắt loss scaling.
Mixed precision được sử dụng rộng rãi trong các tình huống huấn luyện bị giới hạn bởi bộ nhớ hoặc thời gian. Các nhóm phát triển xe tự hành huấn luyện model phát hiện đối tượng trên hàng triệu khung hình độ phân giải cao; việc giảm một nửa bộ nhớ activation cho phép dùng ảnh và batch lớn hơn. Trong phân tích ảnh y tế, ảnh chụp CT và MRI 3D thường vượt quá dung lượng bộ nhớ GPU khi dùng FP32, còn activation 16-bit giúp huấn luyện các model phân đoạn trên toàn bộ thể tích ảnh.
Mixed Precision và các khái niệm liên quan#
- Lượng tử hóa model: Lượng tử hóa chuyển model đã huấn luyện sang số nguyên độ chính xác thấp như INT8 để suy luận nhanh hơn, còn mixed precision tăng tốc quá trình huấn luyện và giữ trọng số ở dạng dấu phẩy động.
- Huấn luyện có nhận biết lượng tử hóa: QAT mô phỏng việc làm tròn số nguyên trong quá trình huấn luyện để model giữ được độ chính xác sau khi triển khai INT8.
- Độ chính xác half: Độ chính xác half là tên gọi của chính định dạng số FP16, còn mixed precision là kỹ thuật huấn luyện kết hợp FP16 với FP32. Huấn luyện hoàn toàn bằng FP16 mà không có trọng số master FP32 hoặc loss scaling sẽ làm mất các cập nhật nhỏ do làm tròn và làm gradient nhỏ bị underflow, khiến quá trình hội tụ thường thất bại.










