import pytest import torch from lmdeploy.utils import is_bf16_supported def _bf16_mark(): return pytest.mark.skipif(not is_bf16_supported(), reason='bf16 not supported.') class TestMultinomialSampling: @pytest.fixture def num_tokens(self, request): yield request.param @pytest.fixture def select_ids(self, request): yield request.param @pytest.fixture def batch_size(self, select_ids): yield len(select_ids) @pytest.fixture def dtype(self, request): yield request.param @pytest.fixture def scores(self, num_tokens, batch_size, select_ids, dtype): ret = torch.zeros(batch_size, num_tokens).cuda() batch_ids = torch.arange(batch_size).cuda() ret[batch_ids, select_ids] = 1 ret = ret.to(dtype) yield ret @pytest.fixture def seeds(self, batch_size): yield torch.randint(1000, 2000, (batch_size, )).cuda() @pytest.fixture def offsets(self, batch_size): yield torch.randint(1000, 2000, (batch_size, )).cuda() @pytest.fixture def indices(self, scores): num_tokens = scores.size(1) ret = [torch.randperm(num_tokens) for _ in scores] ret = torch.stack(ret, 0).cuda() yield ret @pytest.fixture def gt(self, batch_size, select_ids, indices): batch_ids = torch.arange(batch_size).cuda() yield indices[batch_ids, select_ids] @pytest.mark.parametrize('dtype', [torch.float32, torch.half, pytest.param(torch.bfloat16, marks=_bf16_mark())]) @pytest.mark.parametrize(['num_tokens', 'select_ids'], [ (8, (4, 2) * 30), (2000, (500, 1500)), ], indirect=True) def test_multinomial_sampling(self, scores, seeds, offsets, indices, gt): from lmdeploy.pytorch.kernels.cuda import multinomial_sampling output = multinomial_sampling(scores, seeds, offsets, indices) torch.testing.assert_close(output, gt)