Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 45 additions & 9 deletions ggml/src/ggml-quants.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,50 @@ void quantize_row_mxfp4_ref(const float * GGML_RESTRICT x, block_mxfp4 * GGML_RE
}
}

// Find the optimal UE4M3 micro-scale for a sub-block: starting from E2M1 max,
// iterate over the adjacent codes to minimize the squared reconstruction error.
static inline uint8_t best_scale_nvfp4(const float * GGML_RESTRICT xb, int n) {
static const int try_offsets[3] = { 0, -1, 1 };

// largest absolute input value
float amax = 0.0f;
for (int j = 0; j < n; j++) {
if (amax < fabsf(xb[j])) {
amax = fabsf(xb[j]);
}
}

// UE4M3 scale: amax / 6.0 maps the max E2M1 value (6.0) to amax
const int first_code = (int) ggml_fp32_to_ue4m3(amax / 6.0f);

// best sum of squared errors
float best_sse = FLT_MAX;
int best_code = 0;
for (int t = 0; t < 3; t++) {
const int code = first_code + try_offsets[t];

// skip underflow/overflow scale codes
if (code < 0 || code > 0x7E) {
continue;
}
const float d = ggml_ue4m3_to_fp32((uint8_t) code);

float sse = 0.0f;
for (int j = 0; j < n; j++) {
// find the best code, reconstruct, collect the squared error
const int l = best_index_mxfp4(xb[j], d);
const float diff = xb[j] - d*kvalues_mxfp4[l];
sse += diff*diff;
}
if (sse < best_sse) {
best_sse = sse;
best_code = code;
}
}

return (uint8_t) best_code;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CUDA counterpart:

static constexpr int test_offsets[5] = { 0, -1, 1, -2, 2 };
const int first_fp8_code = (int) ggml_cuda_fp32_to_ue4m3(amax_sub / 6.0f);
uint8_t fp8_code = (uint8_t) first_fp8_code;
float subblock_scale = ggml_cuda_ue4m3_to_fp32(fp8_code);
float inv_scale_err = subblock_scale > 0.0f ? 0.5f / subblock_scale : 0.0f;
#if CUDART_VERSION >= 12080
float best_err = nvfp4_native_scale_error(vals, inv_col_scale, inv_scale_err, subblock_scale);
#else
float best_err = 0.0f;
#pragma unroll
for (int k = 0; k < QK_NVFP4_SUB; ++k) {
const float v = vals[k] * inv_col_scale;
const uint8_t q = ggml_cuda_float_to_fp4_e2m1(v, inv_scale_err);
const float err_diff = fabsf(v) - fabsf(kvalues_fp4[q & 0x7]) * subblock_scale;
best_err = fmaf(err_diff, err_diff, best_err);
}
#endif // CUDART_VERSION >= 12080
#pragma unroll
for (int i = 1; i < 5; ++i) {
const int test_code = first_fp8_code + test_offsets[i];
if (test_code < 0 || test_code > 0x7e) {
continue;
}
const float test_scale = ggml_cuda_ue4m3_to_fp32((uint8_t) test_code);
const float test_inv_scale = test_scale > 0.0f ? 0.5f / test_scale : 0.0f;
#if CUDART_VERSION >= 12080
const float cur_err = nvfp4_native_scale_error(vals, inv_col_scale, test_inv_scale, test_scale);
#else
float cur_err = 0.0f;
#pragma unroll
for (int k = 0; k < QK_NVFP4_SUB; ++k) {
const float v = vals[k] * inv_col_scale;
const uint8_t q = ggml_cuda_float_to_fp4_e2m1(v, test_inv_scale);
const float err_diff = fabsf(v) - fabsf(kvalues_fp4[q & 0x7]) * test_scale;
cur_err = fmaf(err_diff, err_diff, cur_err);
}
#endif // CUDART_VERSION >= 12080
if (cur_err < best_err) {
best_err = cur_err;
fp8_code = (uint8_t) test_code;
subblock_scale = test_scale;
}
}

@sanmai sanmai Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As updated in #25730 and added in #21896


void quantize_row_nvfp4_ref(const float * GGML_RESTRICT x, block_nvfp4 * GGML_RESTRICT y, int64_t k) {
static const int qk = QK_NVFP4;
static const int qk_sub = QK_NVFP4_SUB;
Expand All @@ -394,15 +438,7 @@ void quantize_row_nvfp4_ref(const float * GGML_RESTRICT x, block_nvfp4 * GGML_RE
for (int s = 0; s < n_sub; s++) {
const float * xb = x + i*qk + s*qk_sub;

float amax = 0.0f;
for (int j = 0; j < qk_sub; j++) {
if (amax < fabsf(xb[j])) {
amax = fabsf(xb[j]);
}
}

// UE4M3 scale: amax / 6.0 maps the max E2M1 value (6.0) to amax
const uint8_t ue = ggml_fp32_to_ue4m3(amax / 6.0f);
const uint8_t ue = best_scale_nvfp4(xb, qk_sub);
y[i].d[s] = ue;
const float d = ggml_ue4m3_to_fp32(ue);

Expand Down