Skip to content

Warn once, and only when it matters, for unaligned gemm_4bit - #2031

Open
guptaishaan wants to merge 1 commit into
bitsandbytes-foundation:mainfrom
guptaishaan:fix-2027
Open

Warn once, and only when it matters, for unaligned gemm_4bit#2031
guptaishaan wants to merge 1 commit into
bitsandbytes-foundation:mainfrom
guptaishaan:fix-2027

Conversation

@guptaishaan

Copy link
Copy Markdown

Fixes #2027

In the CUDA gemm_4bit dispatch the K % blocksize != 0 check sat in an elif ahead of the kernel-selection heuristic, so any call with M <= _gemm_4bit_custom_max_m (1536) and a misaligned K warned, even though the heuristic caps the fused kernel at M <= 512 and would have taken the dequant + F.linear fallback anyway. That is why the warning shows up during training, where M is batch * seq_len. On top of that it was emitted per call, so a model whose K is inherently misaligned (Qwen2.5-VL vision tower, K = 3420) got one warning per forward.

Changes:

  • backends/cuda/ops.py: run the heuristic first and warn only when misalignment is what actually cost us the fused kernel.
  • backends/utils.py: the warning body moves into a functools.cached _warn_gemm_4bit_unaligned(K, blocksize), so it fires at most once per shape per process.
  • backends/xpu/ops.py: calls the same helper. The warning text there was a verbatim copy.

No behaviour change beyond the warning. Every call that used to warn took the fallback then and takes it now, so numerics are identical.

Verified on an A40 (sm_86), CUDA 12.6, torch 2.13.0+cu126. With the issue's repro (K = 3420, blocksize = 64, 10 calls) the counts go from 10/10/10 to 1/0/0 for M=1 inference, batched, and a Linear4bit training forward+backward. New test tests/test_ops.py::Test4bitBlockwiseQuantOps::test_gemm_4bit_unaligned_warning fails on CUDA before the patch and passes after. tests/test_ops.py and the 4-bit subset of tests/test_functional.py pass, and the pre-commit hooks pass on the changed files.

Not verified on hardware I do not have: the XPU change (mechanical substitution, no control-flow change) and ROCm, which shares the CUDA dispatch and can only see fewer warnings after this. Arch coverage is sm_86 only. The fix keys on the heuristic's return value rather than any threshold, so it is arch-independent, but the exact M at which warnings stop is not.

Thanks to @albertvillanova for the report and the precise diagnosis.

The CUDA gemm_4bit dispatch checked K % blocksize in an elif ahead of
the kernel-selection heuristic, so any call with M <= 1536 and a
misaligned K warned. The heuristic caps the fused kernel at M <= 512, so
for larger M the dequant + F.linear fallback was the intended path all
along and the warning was noise. This is what made it show up during
training, where M is batch * seq_len.

Run the heuristic first and warn only when misalignment is what actually
cost us the fused kernel. Move the warning into a functools.cache'd
_warn_gemm_4bit_unaligned(K, blocksize) in backends/utils.py so it fires
at most once per shape per process, which matters for architectures whose
K cannot be aligned (Qwen2.5-VL vision tower has K=3420). The XPU backend
had a verbatim copy of the warning and now calls the same helper.

No numerical change: every call that used to warn took the fallback then
and takes it now.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gemm_4bit: blocksize-alignment warning emitted on every call, and now also during training (new in 0.50.0)

1 participant