Repository navigation
ggml-cuda: fallback to F32 on device without BF16 hardware acceleration - #28846
Conversation
…on: (Nvidia >= AMPERE, AMD >= RDNA3 or = CDNA)
PerformanceTable generated with
I pushed the corresponding logic for NVIDIA as well. Unfortunately I don't have a Turing card so I'm using the logic I determined for Volta. |
IMbackK
left a comment
There was a problem hiding this comment.
Simple enough and logical change they put mutch more effort into tuning fp32 in the era these cards where made. I dont have any old enough hardware to add anything to the switchover parameters.
|
It would be great to make this change switchable via some environment variable, because, for example on my RDNA2 (RX6900XT) it drastically increases the memory requirements for loading models with BF16 layers and does not increase the prefill speed a lot. It is not a very advantageous exchange. |
I think you could do that with |
|
The default should remain the FP32 conversion where it is faster. It can be overridden via setting the environment variable |
|
Setting the compute type via GGML_CUDA_CUBLAS_COMPUTE_TYPE is not a good solution as well, because it leads to the forced layer type conversion, which definitely is not desirable in some cases. I just added the |
Upstream ggml-org#28846 only falls back when ne1 is large, so decode (ne1==1) stayed on software BF16 on Tesla P100. Always use F32 when the device has no BF16 tensor cores.
…on (ggml-org#28846) * ggml-cuda: fallback to F32 on device without BF16 hardware acceleration: (Nvidia >= AMPERE, AMD >= RDNA3 or = CDNA) * apply logic to NVIDIA as well --------- Co-authored-by: Johannes Gäßler <johannesg@5d6.de>
|
A P40 user mentioned this does increase the VRAM usage quite a bit, so it being togglable would be useful. |
|
The toggle already exists via setting |
|
@LostRuins @eliah @JohannesGaessler After some digging, I've managed to fix the high temporary-memory usage on model like: We are still getting a performance improvement over native bf16, but with a little performance drop compare to unchuncked.
The idea is to let the chunk size is configurable through The intresting thing is that it could also be useful in term of vram peak for F16->F32 conversations. |
…olta at all batch sizes The 2026-09-24 sync took upstream ggml-org#28846's batch thresholds, which put the n = 9..16 speculative verify batches (MMVF -> cuBLAS handoff) on the GTX 1070 and RDNA2 back on emulated BF16 compute -- the cliff the fork's unconditional F32 arm (4019c9a) fixed. Volta/Turing keep upstream's > 8 threshold. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P8PLP5mBrNxvCpwnd47qrk
Upstream ggml-org#28846 only falls back when ne1 is large, so decode (ne1==1) stayed on software BF16 on Tesla P100. Always use F32 when the device has no BF16 tensor cores.
…backend changes A quantized weight that takes the dequantize and hipBLAS path was dequantized to F16, so any activation past the F16 range came back as inf. On RDNA3 the 27B crosses into that path at 129 rows, which is why a long prompt returned NaN logits while a short one did not. Quantized types now dequantize to F32 on AMD; NVIDIA keeps F16 where its hardware is fast at it. The regression test added later in this series (activations in [-4000, 4000], both sides of the 128-row cutover) returned inf for Q2_K, Q6_K and Q8_0 before this change. The same commit carries the backend half of the upstream sync: the MMQ and vec-dot changes (ggml-org#28552, ggml-org#26705), fast_bf16_hardware_available and the BF16 fallback (ggml-org#28846), the GGML_CUDA_FA_QUANTS build option, and ggml-org#26308 and ggml-org#28897. The integrated-GPU host-buffer path stays disabled on HIP as well, because it corrupts output there (upstream ggml-org#26209, reverted in ggml-org#28604). MUL_MAT and MUL_MAT_ID pass on gfx1100 (1304/1304 and 892/892 at the tip of this series). Assisted-by: Claude Opus 5
Overview
Older AMD GPUs (pre-CDNA / pre-RDNA3) do not have native BF16 matrix acceleration, and rocBLAS has no tuned BF16 kernel for them. On these older card a BF16 GEMM can land on a 64x32x8 stub tile.
This PR add a fallback from BF16 to F32 on pre-CDNA / pre-RDNA3 AMD GPUs because rocBLAS does not provide a properly tuned BF16 GEMM path there.
Applies to UD/*_XL quants that keep BF16 tensors.
During testing on my gfx906 this gives large prefill improvements for sufficiently large GEMMs, but benchmarking showed that doing the conversion unconditionally introduces a significant regression for small
N.After some tests on multiple models (differents count of BF16 and different GEMM shapes
(M,N,K)) I added small check to keeps BF16 on AMD whenN <= 32and switches to F32 whenN > 32.src1->ne[1] > 32corresponds to the GEMM N dimension.I've only made the change for AMD. Nvidia GPU before Ampere does not have native BF16 matrix acceleration eather but I do not own a Nvidia card to test this. Feel free to complete/remove the todo if revelant.
Additional information
Why N > 32 ?
Whitout the thresold, on small N <=32 :
N=32 Seems to be the crossover. The generic HIP fallback library contains:
Cijk_Ailk_Bjlk_BSS_BH_MT64x32x8_...which seems to always fallback to the
64x32x8macro-tile and several other fallback solutions also use a free-dimension tile of 32. This does not necessarily mean that the 64x32x8 macro-tile alone causes the crossover: rocBLAS can select different solutions depending on the complete (M, N, K) shape. However, the exact 32 -> 33 transition was observed across models with very different shapes, which makes the N > 32 threshold a good fit.Tested models:
Overall results
Detailed threshold validation
RDNA1 and RDNA2 also lack native BF16 matrix acceleration, and rocBLAS appears to use the same generic HIP BF16 fallback family, which includes the 64x32x8, but I cannot confirm that the same N > 32 threshold is optimal there since I do not own an RDNA1/RDNA2 GPU.. If someone has an RDNA2/RDNA1 gpu could test if N>32 is still correct on thoses architecture ?
Requirements