FP16 (Half Precision): No FP16, um número de ponto flutuante é representado usando 16 bits. Consiste em 1 bit de sinal, 5 bits para o expoente e 10 bits para a fração (mantissa). Este formato fornece maior precisão para representar valores fracionários dentro de seu intervalo.
BF16 (BFloat16): BF16 também usa 16 bits, mas com uma distribuição diferente. Possui 1 bit de sinal, 8 bits para o expoente e 7 bits para a mantissa. Este formato sacrifica alguma precisão na parte fracionária para acomodar uma gama mais ampla de expoentes.
FP16 tem um intervalo menor, mas maior precisão dentro desse intervalo devido à sua mantissa de 10 bits.
BF16 tem um intervalo mais amplo, mas menor precisão para valores fracionários devido ao seu expoente de 8 bits e mantissa de 7 bits.
Vamos usar exemplos para ilustrar as diferenças entre FP16 e BF16 com 3 casos de exemplo. O TensorFlow é usado para fazer os testes e o código compartilhados na parte inferior:
Valor original: 0,0001 — Ambos os métodos podem representar
FP16: 0,00010001659393 (Binário: 0|00001|1010001110, Hex: 068E) — 10 mantissas e 5 expoentes
BF16: 0,00010013580322 (Binário: 0|01110001|1010010, Hex: 38D2) — 7 mantissa e 8 expoentes
Como você pode ver, eles têm expoentes e mantissa diferentes e, portanto, são capazes de representar de forma diferente. Mas podemos ver que o FP16 representou isso com mais precisão e com um valor mais próximo.
Valor original: 1e-08 (0,00000001)
FP16: 0,00000000000000 (Binário: 0|00000|0000000000, Hex: 0000)
BF16: (Binário: 0|01100100| 0101100, hexadecimal: 322C)
Este é um caso muito interessante. FP16 falha e torna o resultado 0, mas BF16 é capaz de representá-lo com uma formatação especial.
Valor original: 100000,00001
FP16: inf (Binário: 0|11111|0000000000, Hex: 7C00)
BF16: 99840.0000000000000 (Binário: 0|10001111 |1000011, hexadecimal: 47C3 )
No caso acima, FP16 falha pois todos os bits do expoente ficam cheios e não são suficientes para representar o valor. Mas BF16 funciona
FP16 é comumente usado em treinamento e inferência de aprendizado profundo, especialmente para tarefas que exigem alta precisão na representação de pequenos valores fracionários dentro de um intervalo limitado.
BF16 está se tornando popular em arquiteturas de hardware projetadas para tarefas de aprendizado de máquina que se beneficiam de uma gama mais ampla de valores representáveis, mesmo ao custo de alguma precisão na parte fracionária. É particularmente útil ao lidar com gradientes grandes ou quando a estabilidade numérica em uma ampla faixa é mais importante do que a precisão de valores pequenos.
FP16 oferece maior precisão para valores fracionários dentro de uma faixa menor, tornando-o adequado para tarefas que exigem representação precisa de números pequenos. O BF16, por outro lado, oferece uma faixa mais ampla ao custo de alguma precisão, tornando-o vantajoso para tarefas que envolvem um espectro mais amplo de valores ou onde a estabilidade numérica em uma ampla faixa é crucial. A escolha entre FP16 e BF16 depende dos requisitos específicos da tarefa de aprendizado de máquina em questão.
Devido a todas as razões acima, ao fazer o treinamento Stable Diffusion XL (SDXL), FP16 e BF16 requerem taxas de aprendizagem ligeiramente diferentes e acho que BF16 funciona melhor.
O código usado para gerar os exemplos acima
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))
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3