main
py 212 lines 5.28 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
5 import pytest
6 import torch
7
8 from tests.kernels.allclose_default import get_default_atol, get_default_rtol
9 from tests.kernels.utils import opcheck
10 from vllm.platforms import CpuArchEnum, current_platform
11 from vllm.utils.torch_utils import set_random_seed
12
13 if not current_platform.is_cpu():
14 pytest.skip("skipping CPU-only tests", allow_module_level=True)
15
16 from vllm.model_executor.layers.activation import (
17 GELU,
18 FastGELU,
19 GeluAndMul,
20 NewGELU,
21 QuickGELU,
22 SiluAndMul,
23 )
24
25 DTYPES = [torch.bfloat16, torch.float32]
26 NUM_TOKENS = [7, 83]
27 D = [512, 2048]
28 SEEDS = [0]
29
30
31 @pytest.mark.parametrize(
32 ("activation_cls", "fn"),
33 [
34 (SiluAndMul, torch.ops._C.silu_and_mul),
35 (GeluAndMul, torch.ops._C.gelu_and_mul),
36 (GeluAndMul, torch.ops._C.gelu_tanh_and_mul),
37 ],
38 )
39 @pytest.mark.parametrize("num_tokens", NUM_TOKENS)
40 @pytest.mark.parametrize("d", D)
41 @pytest.mark.parametrize("dtype", DTYPES)
42 @pytest.mark.parametrize("seed", SEEDS)
43 @torch.inference_mode()
44 def test_cpu_act_and_mul(
45 default_vllm_config,
46 activation_cls: type[torch.nn.Module],
47 fn: object,
48 num_tokens: int,
49 d: int,
50 dtype: torch.dtype,
51 seed: int,
52 ) -> None:
53 set_random_seed(seed)
54 x = torch.randn(num_tokens, 2 * d, dtype=dtype)
55
56 layer = activation_cls()
57 out = layer(x)
58 ref_out = layer.forward_native(x)
59
60 torch.testing.assert_close(
61 out, ref_out, atol=get_default_atol(out), rtol=get_default_rtol(out)
62 )
63
64 output_shape = x.shape[:-1] + (x.shape[-1] // 2,)
65 raw_out = torch.empty(output_shape, dtype=x.dtype, device=x.device)
66 opcheck(fn, (raw_out, x))
67
68
69 @pytest.mark.parametrize(
70 ("activation_cls", "fn", "op_args"),
71 [
72 (NewGELU, torch.ops._C.gelu_new, ()),
73 (FastGELU, torch.ops._C.gelu_fast, ()),
74 (QuickGELU, torch.ops._C.gelu_quick, ()),
75 pytest.param(
76 GELU,
77 getattr(torch.ops._C, "activation_lut_bf16", None),
78 ("gelu",),
79 marks=pytest.mark.skipif(
80 current_platform.get_cpu_architecture() != CpuArchEnum.ARM,
81 reason="activation_lut_bf16 is only built on Arm CPU",
82 ),
83 ),
84 ],
85 )
86 @pytest.mark.parametrize("num_tokens", NUM_TOKENS)
87 @pytest.mark.parametrize("d", D)
88 @pytest.mark.parametrize("dtype", DTYPES)
89 @pytest.mark.parametrize("seed", SEEDS)
90 @torch.inference_mode()
91 def test_cpu_unary_activation(
92 default_vllm_config,
93 activation_cls: type[torch.nn.Module],
94 fn: object,
95 op_args: tuple[str, ...],
96 num_tokens: int,
97 d: int,
98 dtype: torch.dtype,
99 seed: int,
100 ) -> None:
101 set_random_seed(seed)
102 x = torch.randn(num_tokens, d, dtype=dtype)
103 layer = activation_cls()
104 out = layer(x)
105 ref_out = layer.forward_native(x)
106 torch.testing.assert_close(
107 out, ref_out, atol=get_default_atol(out), rtol=get_default_rtol(out)
108 )
109 # gelu with activation_lut_bf16 only makes sense for BF16
110 if not (activation_cls is GELU and dtype != torch.bfloat16):
111 raw_out = torch.empty_like(x)
112 opcheck(fn, (raw_out, x, *op_args))
113
114
115 @pytest.mark.parametrize("dtype", DTYPES)
116 @torch.inference_mode()
117 def test_cpu_gelu_tanh_and_mul(
118 default_vllm_config,
119 dtype: torch.dtype,
120 ) -> None:
121 gate = torch.tensor(
122 [
123 [
124 -12.0,
125 -10.0,
126 -9.01,
127 -5.0,
128 -2.0,
129 -1.0,
130 -0.0,
131 0.0,
132 0.5,
133 1.0,
134 2.0,
135 5.0,
136 9.01,
137 10.0,
138 12.0,
139 11.0,
140 ],
141 [
142 -7.5,
143 -4.5,
144 -3.0,
145 -1.5,
146 -0.75,
147 -0.25,
148 0.25,
149 0.75,
150 1.5,
151 3.0,
152 4.5,
153 7.5,
154 -11.0,
155 11.0,
156 8.75,
157 -8.75,
158 ],
159 ],
160 dtype=dtype,
161 )
162 val = torch.tensor(
163 [
164 [
165 0.25,
166 -0.5,
167 0.75,
168 -1.0,
169 1.25,
170 -1.5,
171 1.75,
172 -2.0,
173 2.25,
174 -2.5,
175 2.75,
176 -3.0,
177 3.25,
178 -3.5,
179 3.75,
180 -4.0,
181 ],
182 [
183 -0.4,
184 0.6,
185 -0.8,
186 1.0,
187 -1.2,
188 1.4,
189 -1.6,
190 1.8,
191 -2.0,
192 2.2,
193 -2.4,
194 2.6,
195 -2.8,
196 3.0,
197 -3.2,
198 3.4,
199 ],
200 ],
201 dtype=dtype,
202 )
203
204 x = torch.cat((val, gate), dim=-1).contiguous()
205 kernel_out = torch.empty_like(val)
206 torch.ops._C.gelu_tanh_and_mul(kernel_out, x)
207
208 torch_ref = torch.nn.functional.gelu(val, approximate="tanh") * gate
209
210 atol = get_default_atol(kernel_out)
211 rtol = get_default_rtol(kernel_out)
212 torch.testing.assert_close(kernel_out, torch_ref, atol=atol, rtol=rtol)