diff --git a/tests/test-dt3-gpu.cpp b/tests/test-dt3-gpu.cpp index 6a21a2278..54bc17f72 100644 --- a/tests/test-dt3-gpu.cpp +++ b/tests/test-dt3-gpu.cpp @@ -379,50 +379,67 @@ static int test_mul_mat(ggml_backend_t backend, ggml_type type, const std::vecto // tensor holding fp16(dequant(block))": running the same GEMM with an // F16 src0 built from the fp16-rounded reference weights must give a // bit-identical result. This isolates our (already bit-validated) - // dequantization from cuBLAS numerics. + // dequantization from cuBLAS numerics. The backend may run the DT3 + // fallback at a different accumulator precision than its default F16 + // GEMM (Vulkan forces fp32 accumulators for DT3), so the F16 control is + // run at both the default and the F32-forced precision and bit-identity + // with either one passes. if (strict) { - ggml_init_params params = { - /*.mem_size =*/ ggml_tensor_overhead()*8 + ggml_graph_overhead(), - /*.mem_buffer =*/ nullptr, - /*.no_alloc =*/ true, - }; - ggml_context * ctx = ggml_init(params); + int n_mismatch_best = -1; + double max_diff_best = 0.0; - ggml_tensor * a16 = ggml_new_tensor_2d(ctx, GGML_TYPE_F16, NCOLS, NROWS); - ggml_tensor * b = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, NCOLS, 16); - ggml_tensor * out = ggml_mul_mat(ctx, a16, b); + for (int force_f32_prec = 0; force_f32_prec < 2; ++force_f32_prec) { + ggml_init_params params = { + /*.mem_size =*/ ggml_tensor_overhead()*8 + ggml_graph_overhead(), + /*.mem_buffer =*/ nullptr, + /*.no_alloc =*/ true, + }; + ggml_context * ctx = ggml_init(params); - ggml_backend_buffer_t buf = ggml_backend_alloc_ctx_tensors(ctx, backend); - GGML_ASSERT(buf != nullptr); - - std::vector w16(ref_w.size()); - for (size_t i = 0; i < ref_w.size(); ++i) { - w16[i] = ggml_fp32_to_fp16(ref_w[i]); - } - ggml_backend_tensor_set(a16, w16.data(), 0, w16.size()*sizeof(ggml_fp16_t)); - ggml_backend_tensor_set(b, y.data(), 0, (size_t)NCOLS*16*sizeof(float)); - - std::vector gpu16((size_t)NROWS*16); - compute_graph(backend, ctx, out, gpu16.data()); - - const std::vector & gemm = results[4]; // n = 16 - int n_mismatch = 0; - double max_diff = 0.0; - for (size_t i = 0; i < gemm.size(); ++i) { - const double diff = fabs((double)gemm[i] - (double)gpu16[i]); - max_diff = diff > max_diff ? diff : max_diff; - if (gemm[i] != gpu16[i]) { - n_mismatch++; + ggml_tensor * a16 = ggml_new_tensor_2d(ctx, GGML_TYPE_F16, NCOLS, NROWS); + ggml_tensor * b = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, NCOLS, 16); + ggml_tensor * out = ggml_mul_mat(ctx, a16, b); + if (force_f32_prec) { + ggml_mul_mat_set_prec(out, GGML_PREC_F32); } + + ggml_backend_buffer_t buf = ggml_backend_alloc_ctx_tensors(ctx, backend); + GGML_ASSERT(buf != nullptr); + + std::vector w16(ref_w.size()); + for (size_t i = 0; i < ref_w.size(); ++i) { + w16[i] = ggml_fp32_to_fp16(ref_w[i]); + } + ggml_backend_tensor_set(a16, w16.data(), 0, w16.size()*sizeof(ggml_fp16_t)); + ggml_backend_tensor_set(b, y.data(), 0, (size_t)NCOLS*16*sizeof(float)); + + std::vector gpu16((size_t)NROWS*16); + compute_graph(backend, ctx, out, gpu16.data()); + + const std::vector & gemm = results[4]; // n = 16 + int n_mismatch = 0; + double max_diff = 0.0; + for (size_t i = 0; i < gemm.size(); ++i) { + const double diff = fabs((double)gemm[i] - (double)gpu16[i]); + max_diff = diff > max_diff ? diff : max_diff; + if (gemm[i] != gpu16[i]) { + n_mismatch++; + } + } + if (n_mismatch_best < 0 || n_mismatch < n_mismatch_best) { + n_mismatch_best = n_mismatch; + max_diff_best = max_diff; + } + + ggml_backend_buffer_free(buf); + ggml_free(ctx); } - printf("%s: %s GEMM path vs F16 GEMM on fp16-rounded weights: %d mismatches, max |diff| = %g\n", - n_mismatch == 0 ? "OK" : "FAILED", ggml_type_name(type), n_mismatch, max_diff); - if (n_mismatch != 0) { + + printf("%s: %s GEMM path vs F16 GEMM on fp16-rounded weights (best of default/F32 prec): %d mismatches, max |diff| = %g\n", + n_mismatch_best == 0 ? "OK" : "FAILED", ggml_type_name(type), n_mismatch_best, max_diff_best); + if (n_mismatch_best != 0) { num_failed++; } - - ggml_backend_buffer_free(buf); - ggml_free(ctx); } // manual sum over the trits stored by the test for row 0, column 0 —