| import pytest |
| import torch |
| from torch.nn.utils.rnn import pad_sequence |
| from kernels.varlen_packing import pack_varlen_batch, unpack_varlen_batch, packed_to_padded |
|
|
|
|
| def test_roundtrip(device): |
| torch.manual_seed(42) |
| D = 768 |
| lens = [160, 80, 90, 110, 140, 70, 130, 100] |
| toks = [torch.randn(L, D, device=device) for L in lens] |
| packed, cu = pack_varlen_batch(toks) |
| recovered = unpack_varlen_batch(packed, cu) |
| for i, (orig, rec) in enumerate(zip(toks, recovered)): |
| assert torch.allclose(orig, rec), f"Mismatch at item {i}" |
|
|
|
|
| def test_cu_seqlens(device): |
| D = 64 |
| lens = [10, 20, 15] |
| toks = [torch.randn(L, D, device=device) for L in lens] |
| _, cu = pack_varlen_batch(toks) |
| expected = torch.tensor([0, 10, 30, 45], dtype=torch.int32, device=device) |
| assert torch.equal(cu, expected) |
|
|
|
|
| def test_less_memory_than_padded(device): |
| D = 768 |
| lens = [196, 40, 50, 60] |
| toks = [torch.randn(L, D, device=device) for L in lens] |
| packed, _ = pack_varlen_batch(toks) |
| padded = pad_sequence(toks, batch_first=True) |
| assert packed.numel() < padded.numel() |
|
|
|
|
| def test_attention_mask(device): |
| D = 64 |
| lens = [5, 3, 4] |
| toks = [torch.randn(L, D, device=device) for L in lens] |
| packed, cu = pack_varlen_batch(toks) |
| padded, mask = packed_to_padded(packed, cu) |
| assert padded.shape == (3, 5, D) |
| assert mask[0].all() |
| assert mask[1, :3].all() |
| assert not mask[1, 3:].any() |
|
|
|
|
| def test_single_item(device): |
| D = 256 |
| toks = [torch.randn(100, D, device=device)] |
| packed, cu = pack_varlen_batch(toks) |
| assert packed.shape == (100, D) |
| assert cu.tolist() == [0, 100] |
|
|