Maison  >  Article  >  développement back-end  >  Quelle est la différence entre FP et BF Voici une bonne explication pour vous

Quelle est la différence entre FP et BF Voici une bonne explication pour vous

WBOY
WBOYoriginal
2024-07-30 00:03:43873parcourir

What is the difference between FPand BF Here a good explanation for you

Représentation à virgule flottante :

FP16 (Half Precision) : Dans FP16, un nombre à virgule flottante est représenté en utilisant 16 bits. Il se compose de 1 bit de signe, 5 bits pour l'exposant et 10 bits pour la fraction (mantisse). Ce format offre une plus grande précision pour représenter les valeurs fractionnaires dans sa plage.

BF16 (BFloat16) : BF16 utilise également 16 bits, mais avec une distribution différente. Il comporte 1 bit de signe, 8 bits pour l'exposant et 7 bits pour la mantisse. Ce format sacrifie une certaine précision dans la partie fractionnaire pour s'adapter à un plus large éventail d'exposants.

Plage numérique :

FP16 a une plage plus petite mais une précision plus élevée dans cette plage en raison de sa mantisse de 10 bits.
BF16 a une plage plus large mais une précision plus faible pour les valeurs fractionnaires en raison de son exposant de 8 bits et de sa mantisse de 7 bits.

Exemples :

Utilisons des exemples pour illustrer les différences entre FP16 et BF16 avec 3 exemples de cas. TensorFlow est utilisé pour rendre les tests et le code partagés en bas :

Valeur originale : 0,0001 — Les deux méthodes peuvent représenter
FP16 : 0,00010001659393 (binaire : 0|00001|1010001110, Hex : 068E) — 10 mantisses et 5 exposants
BF16 : 0,00010013580322 (binaire : 0|01110001|1010010, Hex : 38D2) — 7 mantisse et 8 exposant

Comme vous pouvez le voir, ils ont un exposant et une mantisse différents et sont donc capables de représenter différemment. Mais nous pouvons voir que le FP16 l'a représenté plus précisément avec une valeur plus proche.

Valeur originale : 1e-08 (0,00000001)
FP16 : 0,00000000000000 (binaire : 0|00000|0000000000, Hex : 0000)
BF16 : 0,00000001001 172 (binaire : 0|01100100| 0101100, Hex : 322C)

C'est un cas très intéressant. FP16 échoue et rend le résultat 0 mais BF16 est capable de le représenter avec un formatage spécial.

Valeur originale : 100000.00001
FP16 : inf (binaire : 0|11111|0000000000, Hex : 7C00)
BF16 : 99840.00000000000000 (binaire : 0|10001 111|1000011, Hex : 47C3 )

Dans le cas ci-dessus, FP16 échoue puisque tous les bits d'exposant deviennent pleins et pas assez pour représenter la valeur. Cependant BF16 fonctionne

Cas d'utilisation :

FP16 est couramment utilisé dans la formation et l'inférence en apprentissage profond, en particulier pour les tâches qui nécessitent une grande précision dans la représentation de petites valeurs fractionnaires dans une plage limitée.

BF16 devient populaire dans les architectures matérielles conçues pour les tâches d'apprentissage automatique qui bénéficient d'une gamme plus large de valeurs représentables, même au prix d'une certaine précision dans la partie fractionnaire. C'est particulièrement utile lorsqu'il s'agit de gradients importants ou lorsque la stabilité numérique sur une large plage est plus importante que la précision de petites valeurs.

En résumé

FP16 offre une plus grande précision pour les valeurs fractionnaires dans une plage plus petite, ce qui le rend adapté aux tâches nécessitant une représentation précise de petits nombres. BF16, en revanche, offre une plage plus large au détriment d'une certaine précision, ce qui le rend avantageux pour les tâches impliquant un spectre de valeurs plus large ou lorsque la stabilité numérique sur une large plage est cruciale. Le choix entre FP16 et BF16 dépend des exigences spécifiques de la tâche d'apprentissage automatique à accomplir.

Conclusion finale

Pour toutes les raisons ci-dessus, lors de l'entraînement Stable Diffusion XL (SDXL), FP16 et BF16 nécessitent des taux d'apprentissage légèrement différents et je trouve que BF16 fonctionne mieux.

Le code utilisé pour générer les exemples ci-dessus

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))

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn