MCPcopy Create free account
hub / github.com/bitsandbytes-foundation/bitsandbytes / TestNonContiguousInputs

Class TestNonContiguousInputs

tests/test_ops.py:378–474  ·  view source on GitHub ↗

Regression tests for #1342 and #1690: quantization must handle non-contiguous tensors correctly.

Source from the content-addressed store, hash-verified

376
377
378class TestNonContiguousInputs:
379 """Regression tests for #1342 and #1690: quantization must handle non-contiguous tensors correctly."""
380
381 @pytest.mark.parametrize("device", get_available_devices())
382 @pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16, torch.float32], ids=id_formatter("dtype"))
383 @pytest.mark.parametrize("blocksize", [64, 128, 256])
384 def test_quantize_blockwise_non_contiguous(self, device, dtype, blocksize):
385 code = bitsandbytes.functional.create_dynamic_map().to(device)
386
387 # Create non-contiguous tensor via slicing
388 A_full = torch.randn(3, 4, 6, 256, dtype=dtype, device=device)
389 A_noncontig = A_full[:, ::2, :, :]
390 assert not A_noncontig.is_contiguous()
391
392 A_contig = A_noncontig.contiguous()
393
394 out_nc, absmax_nc = torch.ops.bitsandbytes.quantize_blockwise(A_noncontig, code, blocksize)
395 out_c, absmax_c = torch.ops.bitsandbytes.quantize_blockwise(A_contig, code, blocksize)
396
397 torch.testing.assert_close(absmax_nc, absmax_c)
398 torch.testing.assert_close(out_nc, out_c)
399
400 @pytest.mark.parametrize("device", get_available_devices())
401 @pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16, torch.float32], ids=id_formatter("dtype"))
402 @pytest.mark.parametrize("blocksize", [64, 128, 256])
403 def test_dequantize_blockwise_non_contiguous(self, device, dtype, blocksize):
404 code = bitsandbytes.functional.create_dynamic_map().to(device, dtype=torch.float32)
405
406 # Quantize a contiguous tensor, then create non-contiguous uint8 via transpose
407 A = torch.randn(1024, 1024, dtype=dtype, device=device)
408 quantized, absmax = torch.ops.bitsandbytes.quantize_blockwise(A, code, blocksize)
409
410 # Create non-contiguous uint8 tensor by transposing and transposing back
411 q_noncontig = quantized.t().t()
412 # If that's still contiguous, use a different approach
413 if q_noncontig.is_contiguous():
414 # Pad and slice to force non-contiguity
415 q_padded = torch.zeros(1024, 1025, dtype=torch.uint8, device=device)
416 q_padded[:, :1024] = quantized
417 q_noncontig = q_padded[:, :1024]
418
419 assert not q_noncontig.is_contiguous()
420 q_contig = q_noncontig.contiguous()
421
422 out_nc = torch.ops.bitsandbytes.dequantize_blockwise(q_noncontig, absmax, code, blocksize, dtype)
423 out_c = torch.ops.bitsandbytes.dequantize_blockwise(q_contig, absmax, code, blocksize, dtype)
424
425 torch.testing.assert_close(out_nc, out_c)
426
427 @pytest.mark.parametrize("device", get_available_devices())
428 @pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16, torch.float32], ids=id_formatter("dtype"))
429 @pytest.mark.parametrize("quant_type", ["fp4", "nf4"])
430 @pytest.mark.parametrize("blocksize", [64, 128, 256])
431 def test_quantize_4bit_non_contiguous(self, device, dtype, quant_type, blocksize):
432 if device not in ("cuda", "mps"):
433 pytest.skip("Non-contiguous input handling not implemented for this backend")
434
435 # Reproduce issue #1342: non-contiguous tensor from slicing

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected