Sigbjørn Skjæret compilade commited on
Commit
8b10f59
·
1 Parent(s): 30eb7bc

Fix conversion of unnormalized BF16->BF16 weights (llama/7843)

Browse files

* add truncate_bf16

* truncate intermediate fp32 if converting bf16 to bf16

* fix masking in __compute_fp32_to_bf16

* np.int16 no longer used

* missing cast and additional numpy 2.x fix

* ggml-impl : do not flush bf16 subnormals to zero

* ggml : add reference fp32 to bf16 conversion

The fast version is no longer equivalent for all platforms
because of the handling of subnormal values.

* gguf-py : remove flush to zero for bf16 subnormals

* gguf-py : remove float32 truncation to bf16

Rounding achieves the same thing in the cases where this was used.

* missed prototype update in merge

* merge cleanup

---------

Co-authored-by: Francis Couture-Harpin <[email protected]>

Files changed (3) hide show
  1. ggml/include/ggml.h +1 -0
  2. ggml/src/ggml-impl.h +3 -6
  3. ggml/src/ggml.c +9 -2
ggml/include/ggml.h CHANGED
@@ -349,6 +349,7 @@ extern "C" {
349
  GGML_API ggml_bf16_t ggml_fp32_to_bf16(float);
350
  GGML_API float ggml_bf16_to_fp32(ggml_bf16_t); // consider just doing << 16
351
  GGML_API void ggml_bf16_to_fp32_row(const ggml_bf16_t *, float *, int64_t);
 
352
  GGML_API void ggml_fp32_to_bf16_row(const float *, ggml_bf16_t *, int64_t);
353
 
354
  struct ggml_object;
 
349
  GGML_API ggml_bf16_t ggml_fp32_to_bf16(float);
350
  GGML_API float ggml_bf16_to_fp32(ggml_bf16_t); // consider just doing << 16
351
  GGML_API void ggml_bf16_to_fp32_row(const ggml_bf16_t *, float *, int64_t);
352
+ GGML_API void ggml_fp32_to_bf16_row_ref(const float *, ggml_bf16_t *, int64_t);
353
  GGML_API void ggml_fp32_to_bf16_row(const float *, ggml_bf16_t *, int64_t);
354
 
355
  struct ggml_object;
ggml/src/ggml-impl.h CHANGED
@@ -80,8 +80,9 @@ static inline float ggml_compute_bf16_to_fp32(ggml_bf16_t h) {
80
  /**
81
  * Converts float32 to brain16.
82
  *
83
- * This function is binary identical to AMD Zen4 VCVTNEPS2BF16.
84
- * Subnormals shall be flushed to zero, and NANs will be quiet.
 
85
  * This code should vectorize nicely if using modern compilers.
86
  */
87
  static inline ggml_bf16_t ggml_compute_fp32_to_bf16(float s) {
@@ -95,10 +96,6 @@ static inline ggml_bf16_t ggml_compute_fp32_to_bf16(float s) {
95
  h.bits = (u.i >> 16) | 64; /* force to quiet */
96
  return h;
97
  }
98
- if (!(u.i & 0x7f800000)) { /* subnormal */
99
- h.bits = (u.i & 0x80000000) >> 16; /* flush to zero */
100
- return h;
101
- }
102
  h.bits = (u.i + (0x7fff + ((u.i >> 16) & 1))) >> 16;
103
  return h;
104
  }
 
80
  /**
81
  * Converts float32 to brain16.
82
  *
83
+ * This is binary identical with Google Brain float conversion.
84
+ * Floats shall round to nearest even, and NANs shall be quiet.
85
+ * Subnormals aren't flushed to zero, except perhaps when used.
86
  * This code should vectorize nicely if using modern compilers.
87
  */
88
  static inline ggml_bf16_t ggml_compute_fp32_to_bf16(float s) {
 
96
  h.bits = (u.i >> 16) | 64; /* force to quiet */
97
  return h;
98
  }
 
 
 
 
99
  h.bits = (u.i + (0x7fff + ((u.i >> 16) & 1))) >> 16;
100
  return h;
101
  }
ggml/src/ggml.c CHANGED
@@ -483,9 +483,16 @@ void ggml_bf16_to_fp32_row(const ggml_bf16_t * x, float * y, int64_t n) {
483
  }
484
  }
485
 
 
 
 
 
 
 
486
  void ggml_fp32_to_bf16_row(const float * x, ggml_bf16_t * y, int64_t n) {
487
  int i = 0;
488
  #if defined(__AVX512BF16__)
 
489
  for (; i + 32 <= n; i += 32) {
490
  _mm512_storeu_si512(
491
  (__m512i *)(y + i),
@@ -965,7 +972,7 @@ static const ggml_type_traits_t type_traits[GGML_TYPE_COUNT] = {
965
  .is_quantized = false,
966
  .to_float = (ggml_to_float_t) ggml_bf16_to_fp32_row,
967
  .from_float = (ggml_from_float_t) ggml_fp32_to_bf16_row,
968
- .from_float_ref = (ggml_from_float_t) ggml_fp32_to_bf16_row,
969
  .vec_dot = (ggml_vec_dot_t) ggml_vec_dot_bf16,
970
  .vec_dot_type = GGML_TYPE_BF16,
971
  .nrows = 1,
@@ -20653,7 +20660,7 @@ size_t ggml_quantize_chunk(
20653
  case GGML_TYPE_BF16:
20654
  {
20655
  size_t elemsize = sizeof(ggml_bf16_t);
20656
- ggml_fp32_to_bf16_row(src + start, (ggml_bf16_t *)dst + start, n);
20657
  result = n * elemsize;
20658
  } break;
20659
  case GGML_TYPE_F32:
 
483
  }
484
  }
485
 
486
+ void ggml_fp32_to_bf16_row_ref(const float * x, ggml_bf16_t * y, int64_t n) {
487
+ for (int i = 0; i < n; i++) {
488
+ y[i] = ggml_compute_fp32_to_bf16(x[i]);
489
+ }
490
+ }
491
+
492
  void ggml_fp32_to_bf16_row(const float * x, ggml_bf16_t * y, int64_t n) {
493
  int i = 0;
494
  #if defined(__AVX512BF16__)
495
+ // subnormals are flushed to zero on this platform
496
  for (; i + 32 <= n; i += 32) {
497
  _mm512_storeu_si512(
498
  (__m512i *)(y + i),
 
972
  .is_quantized = false,
973
  .to_float = (ggml_to_float_t) ggml_bf16_to_fp32_row,
974
  .from_float = (ggml_from_float_t) ggml_fp32_to_bf16_row,
975
+ .from_float_ref = (ggml_from_float_t) ggml_fp32_to_bf16_row_ref,
976
  .vec_dot = (ggml_vec_dot_t) ggml_vec_dot_bf16,
977
  .vec_dot_type = GGML_TYPE_BF16,
978
  .nrows = 1,
 
20660
  case GGML_TYPE_BF16:
20661
  {
20662
  size_t elemsize = sizeof(ggml_bf16_t);
20663
+ ggml_fp32_to_bf16_row_ref(src + start, (ggml_bf16_t *)dst + start, n);
20664
  result = n * elemsize;
20665
  } break;
20666
  case GGML_TYPE_F32: