Quantizationgiáo trình tự học
Chương 25 phút đọcBiểu diễn số và lượng tử hoá

2Máy tính biểu diễn số như thế nào#

Để hiểu quantization làm gì, trước hết phải hiểu dữ liệu vốn được lưu thế nào.

2.1Số nguyên#

Với bb bit:

  • Không dấu (unsigned): biểu diễn [0,2b−1][0, 2^b - 1]. Ví dụ uint8: [0,255][0, 255].
  • Có dấu, dạng bù hai (two's complement): biểu diễn [−2b−1,2b−1−1][-2^{b-1}, 2^{b-1} - 1]. Ví dụ int8: [−128,127][-128, 127]; int4: [−8,7][-8, 7].

Các số nguyên liền kề cách nhau đúng 1 đơn vị ở mọi vị trí. Ta nói số nguyên có độ chính xác tuyệt đối đều.

2.2Số dấu phẩy động theo chuẩn IEEE 754#

Một số dấu phẩy động gồm ba trường: bit dấu ss, phần mũ ee (exponent) và phần định trị mm (mantissa). Với số chuẩn hóa (normal), giá trị là

x=(−1)s×(1.m)2×2 e−biasx = (-1)^s \times (1.m)_2 \times 2^{\,e - \text{bias}}

Chữ số 1 đứng trước dấu chấm là bit ẩn: nó không được lưu nhưng luôn có mặt, nên mantissa pp bit cho độ chính xác p+1p + 1 bit. Khi e=0e = 0 ta có số dưới chuẩn (subnormal) (−1)s×(0.m)2×21−bias(-1)^s \times (0.m)_2 \times 2^{1-\text{bias}}, cho phép biểu diễn các số rất gần 0.

Đoạn mã sau tách ba trường của một số FP32:

Python
import struct

def fp32_fields(x):
    bits = struct.unpack(">I", struct.pack(">f", x))[0]
    s = f"{bits:032b}"
    return s[0], s[1:9], s[9:], int(s[1:9], 2) - 127   # dấu, exponent, mantissa, số mũ thật

for x in [1993.0, 0.1, -6.5]:
    print(x, fp32_fields(x))
Kết quả chạy
1993.0 ('0', '10001001', '11110010010000000000000', 10)
0.1    ('0', '01111011', '10011001100110011001101', -4)
-6.5   ('1', '10000001', '10100000000000000000000', 2)

Diễn giải kết quả:

  • 1993=111110010012=1.11110010012×2101993 = 11111001001_2 = 1.1111001001_2 \times 2^{10}. Exponent lưu 10+127=137=10001001210 + 127 = 137 = 10001001_2; mantissa lưu 10 chữ số sau dấu chấm, phần còn lại là số 0. Như vậy không có "bit dành cho phần nguyên" hay "bit dành cho dấu phẩy": vị trí dấu chấm được mã hóa gián tiếp qua số mũ.
  • 0,10{,}1 có biểu diễn nhị phân vô hạn tuần hoàn (0,00011‾20{,}0\overline{0011}_2), nên FP32 chỉ lưu được một giá trị xấp xỉ. Bản thân FP32 đã là một phép lượng tử hóa của tập số thực.

2.3Các kiểu dữ liệu dùng trong deep learning#

Hình 2
Hình 2. Bố cục bit. Màu đỏ là bit dấu, xanh dương là exponent, xanh lá là mantissa, xám là số nguyên.
Kiểu Exp / Man Bias Giá trị lớn nhất Số chuẩn nhỏ nhất ε\varepsilon máy =2−p= 2^{-p}
FP32 8 / 23 127 ≈3,40×1038\approx 3{,}40 \times 10^{38} ≈1,18×10−38\approx 1{,}18 \times 10^{-38} 2−23≈1,19×10−72^{-23} \approx 1{,}19 \times 10^{-7}
FP16 5 / 10 15 65 50465\,504 ≈6,10×10−5\approx 6{,}10 \times 10^{-5} 2−10≈9,77×10−42^{-10} \approx 9{,}77 \times 10^{-4}
BF16 8 / 7 127 ≈3,39×1038\approx 3{,}39 \times 10^{38} ≈1,18×10−38\approx 1{,}18 \times 10^{-38} 2−7≈7,81×10−32^{-7} \approx 7{,}81 \times 10^{-3}
FP8 E4M3 (OCP) 4 / 3 7 448448 2−6≈0,01562^{-6} \approx 0{,}0156 2−3=0,1252^{-3} = 0{,}125
FP8 E5M2 5 / 2 15 57 34457\,344 2−14≈6,10×10−52^{-14} \approx 6{,}10 \times 10^{-5} 2−2=0,252^{-2} = 0{,}25

ε\varepsilon máy là khoảng cách từ 1 đến số biểu diễn được kế tiếp lớn hơn 1. Nó đo độ chính xác tương đối.

Nhận xét:

  • FP16 có dải hẹp (tối đa 65 504), dễ tràn số khi huấn luyện. BF16 giữ nguyên 8 bit exponent của FP32 nên có cùng dải, đổi lại mantissa ngắn hơn. Đây là lý do BF16 được ưa dùng để huấn luyện.
  • FP8 có hai biến thể (Micikevicius và cộng sự, 2022). E4M3 chính xác hơn, thường dùng cho trọng số và activation. E5M2 có dải rộng hơn, thường dùng cho gradient. Biến thể E4M3 của chuẩn OCP bỏ giá trị vô cực và chỉ giữ một mã NaN để nâng giá trị lớn nhất lên 448.

Có thể quan sát trực tiếp hiệu ứng làm tròn và tràn số của FP16:

Python
import numpy as np
print(np.float16(1993.0), np.float16(1993.5), np.float16(2049.0), np.float16(70000.0))
# 1993.0  1994.0  2048.0  inf

Trong khoảng [1024,2048)[1024, 2048), các số FP16 cách nhau 1, nên 1993,51993{,}5 được làm tròn về số chẵn gần nhất là 19941994. Trong khoảng [2048,4096)[2048, 4096) khoảng cách là 2, nên 2049→20482049 \to 2048. Còn 70 00070\,000 vượt quá 65 50465\,504 nên thành vô cực.

2.4Khác biệt cốt lõi: độ chính xác tương đối và tuyệt đối#

Hình 3
Hình 3. Các giá trị dương biểu diễn được trên đoạn [0,40][0, 40]: FP8 E4M3 (trên) và INT8 đối xứng có cùng giá trị lớn nhất 448 (dưới).

Số dấu phẩy động có lưới dày gần 0 và thưa dần khi ra xa: sai số tương đối xấp xỉ không đổi. Số nguyên có lưới cách đều: sai số tuyệt đối không đổi. Do đó, muốn dùng số nguyên để biểu diễn số thực, ta phải chọn khéo vị trí và độ rộng của lưới cách đều ấy sao cho khớp với dữ liệu. Đó chính là vai trò của hai tham số SS và ZZ trong chương sau.


Tự kiểm tra

3 câu. Chọn đáp án để xem ngay lời giải thích.

  1. 1Phát biểu nào đúng về cách FP32 lưu một số?

  2. 2Vì sao BF16 được ưa dùng để huấn luyện hơn FP16?

  3. 3Khác biệt cốt lõi giữa lưới của số dấu phẩy động và của số nguyên là gì?

Đã trả lời 0/3