1111namespace vllm {
1212
1313template <typename scalar_t , scalar_t (*ACT_FN )(const scalar_t &),
14- bool act_first>
14+ bool act_first, bool HAS_CLAMP >
1515__device__ __forceinline__ scalar_t compute (const scalar_t & x,
16- const scalar_t & y) {
17- return act_first ? ACT_FN (x) * y : x * ACT_FN (y);
16+ const scalar_t & y,
17+ const float limit) {
18+ if constexpr (act_first) {
19+ scalar_t gate = x;
20+ scalar_t up = y;
21+ if constexpr (HAS_CLAMP ) {
22+ gate = (scalar_t )fminf ((float )gate, limit);
23+ up = (scalar_t )fmaxf (fminf ((float )up, limit), -limit);
24+ }
25+ return ACT_FN (gate) * up;
26+ } else {
27+ scalar_t gate = x;
28+ scalar_t up = y;
29+ if constexpr (HAS_CLAMP ) {
30+ gate = (scalar_t )fmaxf (fminf ((float )gate, limit), -limit);
31+ up = (scalar_t )fminf ((float )up, limit);
32+ }
33+ return gate * ACT_FN (up);
34+ }
1835}
1936
2037template <typename packed_t , packed_t (*PACKED_ACT_FN )(const packed_t &),
21- bool act_first>
38+ bool act_first, bool HAS_CLAMP >
2239__device__ __forceinline__ packed_t packed_compute (const packed_t & x,
23- const packed_t & y) {
24- return act_first ? packed_mul (PACKED_ACT_FN (x), y)
25- : packed_mul (x, PACKED_ACT_FN (y));
40+ const packed_t & y,
41+ const float limit) {
42+ if constexpr (act_first) {
43+ packed_t gate = x;
44+ packed_t up = y;
45+ if constexpr (HAS_CLAMP ) {
46+ float2 g = cast_to_float2 (gate);
47+ float2 u = cast_to_float2 (up);
48+ g.x = fminf (g.x , limit);
49+ g.y = fminf (g.y , limit);
50+ u.x = fmaxf (fminf (u.x , limit), -limit);
51+ u.y = fmaxf (fminf (u.y , limit), -limit);
52+ gate = cast_to_packed<packed_t >(g);
53+ up = cast_to_packed<packed_t >(u);
54+ }
55+ return packed_mul (PACKED_ACT_FN (gate), up);
56+ } else {
57+ packed_t gate = x;
58+ packed_t up = y;
59+ if constexpr (HAS_CLAMP ) {
60+ float2 g = cast_to_float2 (gate);
61+ float2 u = cast_to_float2 (up);
62+ g.x = fmaxf (fminf (g.x , limit), -limit);
63+ g.y = fmaxf (fminf (g.y , limit), -limit);
64+ u.x = fminf (u.x , limit);
65+ u.y = fminf (u.y , limit);
66+ gate = cast_to_packed<packed_t >(g);
67+ up = cast_to_packed<packed_t >(u);
68+ }
69+ return packed_mul (gate, PACKED_ACT_FN (up));
70+ }
2671}
2772
2873// Activation and gating kernel template.
2974template <typename scalar_t , typename packed_t ,
3075 scalar_t (*ACT_FN )(const scalar_t &),
3176 packed_t (*PACKED_ACT_FN )(const packed_t &), bool act_first,
32- bool use_vec, bool use_256b = false >
77+ bool use_vec, bool HAS_CLAMP , bool use_256b = false >
3378__global__ void act_and_mul_kernel (
3479 scalar_t * __restrict__ out, // [..., d]
3580 const scalar_t * __restrict__ input, // [..., 2, d]
36- const int d) {
81+ const int d, const float limit ) {
3782 const scalar_t * x_ptr = input + blockIdx .x * 2 * d;
3883 const scalar_t * y_ptr = x_ptr + d;
3984 scalar_t * out_ptr = out + blockIdx .x * d;
@@ -58,8 +103,9 @@ __global__ void act_and_mul_kernel(
58103 }
59104#pragma unroll
60105 for (int j = 0 ; j < pvec_t ::NUM_ELTS ; j++) {
61- x.elts [j] = packed_compute<packed_t , PACKED_ACT_FN , act_first>(
62- x.elts [j], y.elts [j]);
106+ x.elts [j] =
107+ packed_compute<packed_t , PACKED_ACT_FN , act_first, HAS_CLAMP >(
108+ x.elts [j], y.elts [j], limit);
63109 }
64110 if constexpr (use_256b) {
65111 st256 (x, &out_vec[i]);
@@ -72,7 +118,8 @@ __global__ void act_and_mul_kernel(
72118 for (int64_t idx = threadIdx .x ; idx < d; idx += blockDim .x ) {
73119 const scalar_t x = VLLM_LDG (&x_ptr[idx]);
74120 const scalar_t y = VLLM_LDG (&y_ptr[idx]);
75- out_ptr[idx] = compute<scalar_t , ACT_FN , act_first>(x, y);
121+ out_ptr[idx] =
122+ compute<scalar_t , ACT_FN , act_first, HAS_CLAMP >(x, y, limit);
76123 }
77124 }
78125}
@@ -151,8 +198,11 @@ packed_gelu_tanh_kernel(const packed_t& val) {
151198
152199// Launch activation and gating kernel.
153200// Use ACT_FIRST (bool) indicating whether to apply the activation function
154- // first.
155- #define LAUNCH_ACTIVATION_GATE_KERNEL (KERNEL, PACKED_KERNEL, ACT_FIRST ) \
201+ // first. HAS_CLAMP (bool) enables pre-activation clamping: gate input is
202+ // clamped (max only) and up input is clamped (both sides) before the
203+ // activation function is applied.
204+ #define LAUNCH_ACTIVATION_GATE_KERNEL (KERNEL , PACKED_KERNEL , ACT_FIRST , \
205+ HAS_CLAMP , LIMIT ) \
156206 auto dtype = input.scalar_type(); \
157207 int d = input.size(-1 ) / 2 ; \
158208 int64_t num_tokens = input.numel() / input.size(-1 ); \
@@ -177,17 +227,17 @@ packed_gelu_tanh_kernel(const packed_t& val) {
177227 scalar_t , typename vllm::PackedTypeConverter<scalar_t >::Type, \
178228 KERNEL <scalar_t >, \
179229 PACKED_KERNEL <typename vllm::PackedTypeConverter<scalar_t >::Type>, \
180- ACT_FIRST , true , true ><<<grid, block, 0 , stream>>> ( \
181- out.data_ptr <scalar_t >(), input.data_ptr <scalar_t >(), d); \
230+ ACT_FIRST , true , HAS_CLAMP , true ><<<grid, block, 0 , stream>>> ( \
231+ out.data_ptr <scalar_t >(), input.data_ptr <scalar_t >(), d, LIMIT ); \
182232 }); \
183233 } else { \
184234 VLLM_DISPATCH_FLOATING_TYPES (dtype, " act_and_mul_kernel" , [&] { \
185235 vllm::act_and_mul_kernel< \
186236 scalar_t , typename vllm::PackedTypeConverter<scalar_t >::Type, \
187237 KERNEL <scalar_t >, \
188238 PACKED_KERNEL <typename vllm::PackedTypeConverter<scalar_t >::Type>, \
189- ACT_FIRST , true , false ><<<grid, block, 0 , stream>>> ( \
190- out.data_ptr <scalar_t >(), input.data_ptr <scalar_t >(), d); \
239+ ACT_FIRST , true , HAS_CLAMP , false ><<<grid, block, 0 , stream>>> ( \
240+ out.data_ptr <scalar_t >(), input.data_ptr <scalar_t >(), d, LIMIT ); \
191241 }); \
192242 } \
193243 } else { \
@@ -197,16 +247,23 @@ packed_gelu_tanh_kernel(const packed_t& val) {
197247 scalar_t , typename vllm::PackedTypeConverter<scalar_t >::Type, \
198248 KERNEL <scalar_t >, \
199249 PACKED_KERNEL <typename vllm::PackedTypeConverter<scalar_t >::Type>, \
200- ACT_FIRST , false ><<<grid, block, 0 , stream>>> ( \
201- out.data_ptr <scalar_t >(), input.data_ptr <scalar_t >(), d); \
250+ ACT_FIRST , false , HAS_CLAMP ><<<grid, block, 0 , stream>>> ( \
251+ out.data_ptr <scalar_t >(), input.data_ptr <scalar_t >(), d, LIMIT ); \
202252 }); \
203253 }
204254
205255void silu_and_mul (torch::Tensor& out, // [..., d]
206256 torch::Tensor& input) // [..., 2 * d]
207257{
208258 LAUNCH_ACTIVATION_GATE_KERNEL (vllm::silu_kernel, vllm::packed_silu_kernel,
209- true );
259+ true , false , 0 .0f );
260+ }
261+
262+ void silu_and_mul_clamp (torch::Tensor& out, // [..., d]
263+ torch::Tensor& input, // [..., 2 * d]
264+ double limit) {
265+ LAUNCH_ACTIVATION_GATE_KERNEL (vllm::silu_kernel, vllm::packed_silu_kernel,
266+ true , true , (float )limit);
210267}
211268
212269void mul_and_silu (torch::Tensor& out, // [..., d]
@@ -215,21 +272,21 @@ void mul_and_silu(torch::Tensor& out, // [..., d]
215272 // The difference between mul_and_silu and silu_and_mul is that mul_and_silu
216273 // applies the silu to the latter half of the input.
217274 LAUNCH_ACTIVATION_GATE_KERNEL (vllm::silu_kernel, vllm::packed_silu_kernel,
218- false );
275+ false , false , 0 . 0f );
219276}
220277
221278void gelu_and_mul (torch::Tensor& out, // [..., d]
222279 torch::Tensor& input) // [..., 2 * d]
223280{
224281 LAUNCH_ACTIVATION_GATE_KERNEL (vllm::gelu_kernel, vllm::packed_gelu_kernel,
225- true );
282+ true , false , 0 . 0f );
226283}
227284
228285void gelu_tanh_and_mul (torch::Tensor& out, // [..., d]
229286 torch::Tensor& input) // [..., 2 * d]
230287{
231- LAUNCH_ACTIVATION_GATE_KERNEL (vllm::gelu_tanh_kernel,
232- vllm::packed_gelu_tanh_kernel, true );
288+ LAUNCH_ACTIVATION_GATE_KERNEL (
289+ vllm::gelu_tanh_kernel, vllm::packed_gelu_tanh_kernel, true , false , 0 . 0f );
233290}
234291
235292namespace vllm {
0 commit comments