FP16(半精度):在 FP16 中,浮點數使用 16 位元表示。它由 1 個符號位、5 位指數和 10 位分數(尾數)組成。此格式提供了更高的精度來表示其範圍內的小數值。
BF16 (BFloat16):BF16 也使用 16 位,但分佈不同。它有 1 個符號位、8 位指數、7 位尾數。這種格式犧牲了小數部分的一些精確度以適應更廣泛的指數。
FP16 由於其 10 位元尾數而具有較小的範圍,但在該範圍內精度較高。
BF16 由於其 8 位指數和 7 位尾數而具有較寬的範圍,但小數值的精度較低。
以下透過3個案例來說明FP16和BF16的差異。使用TensorFlow來做測試和程式碼共享在底層:
原始值:0.0001 — 兩種方法都可以表示
FP16: 0.00010001659393 (二進位:0|00001|1010001110,十六進位:0|00001|1010001110,十六進位:68E) —個尾數和5 個指數
BF16: 0.00010013580322 (二進位: 0|01110001|1010010, 十六進位: 38D2) — 7 個尾數和8 個指數
正如您所看到的,它們具有不同的指數和尾數,因此能夠以不同的方式表示。 但是我們可以看到FP16更準確地表達了它,並且值更接近。
原始值:1e-08 (0.00000001)
FP16:0.00000000000000(二進位:0|00000|0000000000, :0 |01100100| 0101100,十六進位:322C)
FP16 失敗 並使結果為 0,但 BF16 能夠以特殊格式表示它。
原始值:100000.00001FP16:inf(二進位:0|11111|0000000000,十六進位:7C00)
BF16:99840.000001000 011,十六進位:47C3 )
FP16 失敗,因為所有指數位都已滿且不足以表示該值。然而 BF16 有效
BF16 在專為機器學習任務設計的硬體架構中變得越來越流行,這些任務受益於更廣泛的可表示值,即使是以犧牲小數部分的一些精度為代價。當處理大梯度或當大範圍內的數值穩定性比小值的精確度更重要時,它特別有用。
用於產生上述範例的程式碼
將張量流導入為 tf 導入結構體 def float_to_binary(f): return ''.join(f'{b:08b}' for b in struct.pack('>f', f)) def display_fp16(值): fp16 = tf.cast(tf.constant(值, dtype=tf.float32), tf.float16) fp32 = tf.cast(fp16, tf.float32) 二進位 = 格式(int.from_bytes(fp16.numpy().tobytes(), '大'), '016b') 符號=二進位[0] 指數 = 二進位[1:6] 分數 = 二進位[6:] return f"FP16: {fp32.numpy():14.14f} (二進位: {sign}|{exponent}|{fraction}, 十六進位: {fp16.numpy().view('uint16'):04X })" def display_bf16(值): bf16 = tf.cast(tf.constant(值, dtype=tf.float32), tf.bfloat16) bf32 = tf.cast(bf16, tf.float32) 二進位 = 格式(int.from_bytes(bf16.numpy().tobytes(), '大'), '016b') 符號=二進位[0] 指數 = 二進位[1:9] 分數 = 二進位[9:] return f"BF16: {bf32.numpy():14.14f} (二進位: {sign}|{exponent}|{fraction}, 十六進位: {bf16.numpy().view('uint16'):04X })" 值 = [0.0001, 0.00000001, 100000.00001] 對於值中的值: print(f"\n原始值: {value}") 列印(display_fp16(值)) 列印(display_bf16(值))
import tensorflow as tf import struct def float_to_binary(f): return ''.join(f'{b:08b}' for b in struct.pack('>f', f)) def display_fp16(value): fp16 = tf.cast(tf.constant(value, dtype=tf.float32), tf.float16) fp32 = tf.cast(fp16, tf.float32) binary = format(int.from_bytes(fp16.numpy().tobytes(), 'big'), '016b') sign = binary[0] exponent = binary[1:6] fraction = binary[6:] return f"FP16: {fp32.numpy():14.14f} (Binary: {sign}|{exponent}|{fraction}, Hex: {fp16.numpy().view('uint16'):04X})" def display_bf16(value): bf16 = tf.cast(tf.constant(value, dtype=tf.float32), tf.bfloat16) bf32 = tf.cast(bf16, tf.float32) binary = format(int.from_bytes(bf16.numpy().tobytes(), 'big'), '016b') sign = binary[0] exponent = binary[1:9] fraction = binary[9:] return f"BF16: {bf32.numpy():14.14f} (Binary: {sign}|{exponent}|{fraction}, Hex: {bf16.numpy().view('uint16'):04X})" values = [0.0001, 0.00000001, 100000.00001] for value in values: print(f"\nOriginal value: {value}") print(display_fp16(value)) print(display_bf16(value))
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3