@@ -15,6 +15,7 @@ __device__ void rms_norm_dynamic_per_token_quant_vec(
1515 scalar_t const * __restrict__ input, // [..., hidden_size]
1616 scalar_t const * __restrict__ weight, // [hidden_size]
1717 float const * scale_ub, float const var_epsilon, int32_t const hidden_size,
18+ scalar_t * __restrict__ residual_out = nullptr ,
1819 scalar_t * __restrict__ residual = nullptr ) {
1920 float rms = 0 .0f ;
2021 float token_scale = 0 .0f ;
@@ -33,12 +34,14 @@ __device__ void rms_norm_dynamic_per_token_quant_vec(
3334 if constexpr (std::is_same_v<scalar_out_t , int8_t >) {
3435 vllm::vectorized::norm_and_quant<scalar_t , scalar_out_t , true ,
3536 has_residual>(
36- out, input, weight, rms, 1 .0f / token_scale, hidden_size, residual);
37+ out, input, weight, rms, 1 .0f / token_scale, hidden_size, residual_out,
38+ residual);
3739 } else {
3840 // FP8 - Do not invert token_scale for exact match with FBGemm
3941 vllm::vectorized::norm_and_quant<scalar_t , scalar_out_t , false ,
40- has_residual>(
41- out, input, weight, rms, token_scale, hidden_size, residual);
42+ has_residual>(out, input, weight, rms,
43+ token_scale, hidden_size,
44+ residual_out, residual);
4245 }
4346}
4447
@@ -50,6 +53,7 @@ __global__ void rms_norm_dynamic_per_token_quant_kernel(
5053 scalar_t const * __restrict__ input, // [..., hidden_size]
5154 scalar_t const * __restrict__ weight, // [hidden_size]
5255 float const * scale_ub, float const var_epsilon, int32_t const hidden_size,
56+ scalar_t * __restrict__ residual_out = nullptr ,
5357 scalar_t * __restrict__ residual = nullptr ) {
5458 // For vectorization, token_input and token_output pointers need to be
5559 // aligned at 8-byte and 4-byte addresses respectively.
@@ -76,11 +80,13 @@ __global__ void rms_norm_dynamic_per_token_quant_kernel(
7680 // RMS Norm + Quant
7781 if constexpr (std::is_same_v<scalar_out_t , int8_t >) {
7882 vllm::norm_and_quant<scalar_t , scalar_out_t , true , has_residual>(
79- out, input, weight, rms, 1 .0f / token_scale, hidden_size, residual);
83+ out, input, weight, rms, 1 .0f / token_scale, hidden_size, residual_out,
84+ residual);
8085 } else {
8186 // FP8 - Do not invert s_token_scale for exact match with FBGemm
8287 vllm::norm_and_quant<scalar_t , scalar_out_t , false , has_residual>(
83- out, input, weight, rms, token_scale, hidden_size, residual);
88+ out, input, weight, rms, token_scale, hidden_size, residual_out,
89+ residual);
8490 }
8591}
8692} // namespace vllm
@@ -94,6 +100,7 @@ void rms_norm_dynamic_per_token_quant_dispatch(
94100 torch::Tensor& scales, // [num_tokens]
95101 double const var_epsilon, // Variance epsilon used in norm calculation
96102 std::optional<at::Tensor> const & scale_ub,
103+ std::optional<at::Tensor>& residual_out,
97104 std::optional<at::Tensor>& residual) {
98105 int32_t hidden_size = input.size (-1 );
99106 auto num_tokens = input.numel () / hidden_size;
@@ -112,7 +119,9 @@ void rms_norm_dynamic_per_token_quant_dispatch(
112119 out.data_ptr <scalar_t >(), scales.data_ptr <float >(),
113120 input.data_ptr <scalar_in_t >(), weight.data_ptr <scalar_in_t >(),
114121 scale_ub.has_value () ? scale_ub->data_ptr <float >() : nullptr ,
115- var_epsilon, hidden_size, residual->data_ptr <scalar_in_t >());
122+ var_epsilon, hidden_size,
123+ residual_out->data_ptr <scalar_in_t >(),
124+ residual->data_ptr <scalar_in_t >());
116125 });
117126
118127 } else {
@@ -124,7 +133,7 @@ void rms_norm_dynamic_per_token_quant_dispatch(
124133 out.data_ptr <scalar_t >(), scales.data_ptr <float >(),
125134 input.data_ptr <scalar_in_t >(), weight.data_ptr <scalar_in_t >(),
126135 scale_ub.has_value () ? scale_ub->data_ptr <float >() : nullptr ,
127- var_epsilon, hidden_size, nullptr );
136+ var_epsilon, hidden_size, nullptr , nullptr );
128137 });
129138 }
130139}
@@ -135,13 +144,18 @@ void rms_norm_dynamic_per_token_quant(
135144 torch::Tensor const & weight, // [hidden_size]
136145 torch::Tensor& scales, // [num_tokens]
137146 double const var_epsilon, // Variance epsilon used in norm calculation
138- std::optional<at::Tensor> scale_ub, std::optional<at::Tensor> residual) {
147+ std::optional<at::Tensor> scale_ub, std::optional<at::Tensor> residual_out,
148+ std::optional<at::Tensor> residual) {
139149 static c10::ScalarType kFp8Type = is_fp8_ocp ()
140150 ? c10::ScalarType::Float8_e4m3fn
141151 : c10::ScalarType::Float8_e4m3fnuz;
142152 TORCH_CHECK (out.dtype () == kFp8Type || out.dtype () == torch::kInt8 );
143153 TORCH_CHECK (out.is_contiguous () && input.is_contiguous ());
144154
155+ if (residual.has_value ()) {
156+ TORCH_CHECK (residual_out.has_value ());
157+ }
158+
145159 if (scale_ub.has_value ()) {
146160 TORCH_CHECK (out.dtype () == kFp8Type );
147161 }
@@ -150,6 +164,7 @@ void rms_norm_dynamic_per_token_quant(
150164 VLLM_DISPATCH_FLOATING_TYPES (
151165 input.scalar_type (), " rms_norm_dynamic_per_token_quant_dispatch" , [&] {
152166 rms_norm_dynamic_per_token_quant_dispatch<scalar_t >(
153- out, input, weight, scales, var_epsilon, scale_ub, residual);
167+ out, input, weight, scales, var_epsilon, scale_ub, residual_out,
168+ residual);
154169 });
155170}
0 commit comments