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 TestRMSNorm: @pytest.fixture(autouse=True, scope='class') def initialize(self): seed = 42 torch.manual_seed(seed) torch.cuda.manual_seed(seed) yield @pytest.fixture(scope='class') def dtype(self, request): yield request.param @pytest.fixture(scope='class') def input_shape(self, request): yield request.param @pytest.fixture(scope='class') def hidden_size(self, input_shape): yield input_shape[-1] @pytest.fixture(scope='class') def input(self, dtype, input_shape): yield torch.randn(input_shape, dtype=dtype, device='cuda') @pytest.fixture(scope='class') def weight(self, dtype, hidden_size): yield torch.randn(hidden_size, dtype=dtype, device='cuda') @pytest.fixture(scope='class') def eps(self): yield 1e-6 @pytest.fixture(scope='class') def gt(self, input, weight, eps): input_dtype = input.dtype input = input.to(torch.float32) variance = (input * input).mean(-1, keepdim=True) input = input * torch.rsqrt(variance + eps) return weight * input.to(input_dtype) @pytest.mark.parametrize('input_shape', [(2, 4, 4096), (4, 4096), (4096, )], indirect=True) @pytest.mark.parametrize('dtype', [pytest.param(torch.bfloat16, marks=_bf16_mark()), torch.float16], indirect=True) def test_rms_norm(self, input, weight, eps, gt): from lmdeploy.pytorch.kernels.cuda import rms_norm out = rms_norm(input, weight, eps) torch.testing.assert_close(out, gt) @pytest.fixture(scope='class') def residual(self, dtype, input_shape): yield torch.randn(input_shape, dtype=dtype, device='cuda') @pytest.fixture(scope='class') def gt_residual(self, input, residual, weight, eps): input = input + residual out_res = input input_dtype = input.dtype input = input.to(torch.float32) variance = (input * input).mean(-1, keepdim=True) input = input * torch.rsqrt(variance + eps) return weight * input.to(input_dtype), out_res @pytest.mark.parametrize('input_shape', [(2, 4, 4096), (4, 4096), (4096, )], indirect=True) @pytest.mark.parametrize('dtype', [pytest.param(torch.bfloat16, marks=_bf16_mark()), torch.float16], indirect=True) def test_rms_norm_residual(self, input, residual, weight, eps, gt_residual): from lmdeploy.pytorch.kernels.cuda import rms_norm out, out_res = rms_norm(input, weight, eps, residual=residual) gt, gt_res = gt_residual torch.testing.assert_close(out, gt) torch.testing.assert_close(out_res, gt_res)