FP16(반정밀도): FP16에서는 부동 소수점 숫자를 16비트로 표현합니다. 부호 비트 1개, 지수 5비트, 분수(가수) 10비트로 구성됩니다. 이 형식은 해당 범위 내에서 분수 값을 표현하는 데 더 높은 정밀도를 제공합니다.
BF16(BFloat16): BF16도 16비트를 사용하지만 배포 방식이 다릅니다. 부호비트 1개, 지수 8비트, 가수 7비트로 구성됩니다. 이 형식은 더 넓은 범위의 지수를 수용하기 위해 분수 부분의 정밀도를 어느 정도 희생합니다.
FP16은 범위가 더 작지만 10비트 가수로 인해 해당 범위 내 정밀도가 더 높습니다.
BF16은 8비트 지수와 7비트 가수로 인해 범위는 더 넓지만 분수 값에 대한 정밀도는 더 낮습니다.
예제를 사용하여 FP16과 BF16의 차이점을 3가지 사례로 설명하겠습니다. TensorFlow는 하단에서 테스트와 코드를 공유하는 데 사용됩니다.
원래 값: 0.0001 — 두 메서드 모두
FP16: 0.00010001659393(바이너리: 0|00001|1010001110, 16진수: 068E) — 10개의 가수와 5개의 지수를 나타낼 수 있습니다
BF16: 0.00010013580322(2진수: 0|01110001|1010010, 16진수: 38D2) — 가수 7개와 지수 8개
보시다시피 지수와 가수가 다르기 때문에 다르게 표현할 수 있습니다. 그런데 FP16이 더 가까운 값으로 더 정확하게 표현한 것을 확인할 수 있습니다.
원래 값: 1e-08(0.00000001)
FP16: 0.00000000000000(2진수: 0|00000|0000000000, 16진수: 0000)
BF16: 0.0000000 1001172(바이너리: 0|01100100| 0101100, 16진수: 322C)
매우 흥미로운 사례입니다. FP16이 실패하여 결과를 0으로 만들지만 BF16은 이를 특수한 형식으로 표현할 수 있습니다.
원래 값: 100000.00001
FP16: inf(바이너리: 0|11111|0000000000, 16진수: 7C00)
BF16: 99840.00000000000000(바이너리: 0|1 0001111|1000011, 16진수: 47C3 )
위의 경우 FP16이 실패합니다. 모든 지수 비트가 가득 차서 값을 표현할 만큼 충분하지 않기 때문입니다. 그러나 BF16은 작동합니다
FP16은 딥 러닝 훈련 및 추론에 일반적으로 사용되며, 특히 제한된 범위 내에서 작은 분수 값을 표현하는 데 높은 정밀도가 필요한 작업에 사용됩니다.
BF16은 분수 부분의 정밀도를 희생하더라도 더 넓은 범위의 표현 가능한 값을 활용하는 기계 학습 작업용으로 설계된 하드웨어 아키텍처에서 인기를 얻고 있습니다. 이는 큰 기울기를 처리할 때나 작은 값의 정밀도보다 넓은 범위의 수치적 안정성이 더 중요한 경우에 특히 유용합니다.
FP16은 더 작은 범위 내의 분수 값에 대해 더 높은 정밀도를 제공하므로 작은 숫자를 정확하게 표현해야 하는 작업에 적합합니다. 반면에 BF16은 약간의 정밀도를 희생하면서 더 넓은 범위를 제공하므로 더 넓은 범위의 값을 포함하거나 넓은 범위에 걸친 수치 안정성이 중요한 작업에 유리합니다. FP16과 BF16 중에서 선택하는 것은 현재 머신러닝 작업의 특정 요구 사항에 따라 다릅니다.
위의 모든 이유로 인해 SDXL(Stable Diffusion XL) 훈련을 수행할 때 FP16과 BF16은 약간 다른 학습률이 필요하며 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))
위 내용은 FP와 BF의 차이점은 무엇입니까? 여기에 좋은 설명이 있습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!