FP16 (Half Precision): In FP16 wird eine Gleitkommazahl mit 16 Bit dargestellt. Es besteht aus 1 Vorzeichenbit, 5 Bits für den Exponenten und 10 Bits für den Bruch (Mantisse). Dieses Format bietet eine höhere Präzision für die Darstellung von Bruchwerten innerhalb seines Bereichs.
BF16 (BFloat16): BF16 verwendet ebenfalls 16 Bit, jedoch mit einer anderen Verteilung. Es verfügt über 1 Vorzeichenbit, 8 Bits für den Exponenten und 7 Bits für die Mantisse. Dieses Format opfert etwas Genauigkeit im Bruchteil, um einen größeren Bereich von Exponenten zu berücksichtigen.
FP16 hat einen kleineren Bereich, aber eine höhere Präzision innerhalb dieses Bereichs aufgrund seiner 10-Bit-Mantisse.
BF16 hat einen größeren Bereich, aber eine geringere Präzision für Bruchwerte aufgrund seines 8-Bit-Exponenten und seiner 7-Bit-Mantisse.
Veranschaulichen wir anhand von Beispielen die Unterschiede zwischen FP16 und BF16 anhand von drei Beispielfällen. TensorFlow wird verwendet, um die Tests und den unten geteilten Code durchzuführen:
Ursprünglicher Wert: 0,0001 – Beide Methoden können darstellen
FP16: 0,00010001659393 (Binär: 0|00001|1010001110, Hex: 068E) – 10 Mantissen und 5 Exponenten
BF16: 0,00010013580322 (Binär: 0|01110001|1010010, Hex: 38D2) – 7 Mantisse und 8 Exponenten
Wie Sie sehen können, haben sie unterschiedliche Exponenten und Mantissen und können daher unterschiedlich dargestellt werden. Aber wir können sehen, dass FP16 es genauer und näher dargestellt hat.
Ursprünglicher Wert: 1e-08 (0,00000001)
FP16: 0,00000000000000 (Binär: 0|00000|0000000000, Hex: 0000)
BF16: 0,0000000100117 2 (Binär: 0|01100100| 0101100, Hex: 322C)
Das ist ein sehr interessanter Fall. FP16 schlägt fehl und ergibt das Ergebnis 0, aber BF16 kann es mit einer speziellen Formatierung darstellen.
Ursprünglicher Wert: 100000,00001
FP16: inf (Binär: 0|11111|0000000000, Hex: 7C00)
BF16: 99840,00000000000000 (Binär: 0|1000111 1|1000011, Hex: 47C3 )
Im obigen Fall schlägt FP16 fehl, da alle Exponentenbits voll werden und nicht ausreichen, um den Wert darzustellen. Allerdings funktioniert BF16
FP16 wird häufig im Deep-Learning-Training und in der Inferenz verwendet, insbesondere für Aufgaben, die eine hohe Präzision bei der Darstellung kleiner Bruchwerte innerhalb eines begrenzten Bereichs erfordern.
BF16 erfreut sich zunehmender Beliebtheit in Hardwarearchitekturen, die für maschinelle Lernaufgaben entwickelt wurden und von einem größeren Bereich darstellbarer Werte profitieren, selbst auf Kosten einer gewissen Präzision im Bruchteil. Dies ist besonders nützlich, wenn es um große Gradienten geht oder wenn numerische Stabilität über einen weiten Bereich wichtiger ist als die Präzision kleiner Werte.
FP16 bietet eine höhere Präzision für Bruchwerte innerhalb eines kleineren Bereichs und eignet sich daher für Aufgaben, die eine genaue Darstellung kleiner Zahlen erfordern. BF16 hingegen bietet einen größeren Bereich auf Kosten einer gewissen Präzision, was es für Aufgaben vorteilhaft macht, die ein breiteres Wertespektrum umfassen oder bei denen numerische Stabilität über einen weiten Bereich von entscheidender Bedeutung ist. Die Wahl zwischen FP16 und BF16 hängt von den spezifischen Anforderungen der jeweiligen maschinellen Lernaufgabe ab.
Aus allen oben genannten Gründen erfordern FP16 und BF16 beim Stable Diffusion XL (SDXL)-Training leicht unterschiedliche Lernraten und ich finde, dass BF16 besser funktioniert.
Der Code, der zum Generieren der obigen Beispiele verwendet wird
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))
Das obige ist der detaillierte Inhalt vonWas ist der Unterschied zwischen FP und BF? Hier eine gute Erklärung für Sie. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!