Skip to content

Commit ab0d2c7

Browse files
committed
dynamic quant layernorm
Signed-off-by: charlifu <charlifu@amd.com>
1 parent aaf65de commit ab0d2c7

6 files changed

Lines changed: 43 additions & 32 deletions

File tree

csrc/ops.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ void rms_norm_dynamic_per_token_quant(torch::Tensor& out,
115115
torch::Tensor& scales,
116116
double const epsilon,
117117
std::optional<torch::Tensor> scale_ub,
118+
std::optional<torch::Tensor> residual_out,
118119
std::optional<torch::Tensor> residual);
119120

120121
void rotary_embedding(torch::Tensor& positions, torch::Tensor& query,

csrc/quantization/fused_kernels/fused_layernorm_dynamic_per_token_quant.cu

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

csrc/quantization/fused_kernels/layernorm_utils.cuh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ __device__ void norm_and_quant(scalar_out_t* __restrict__ output,
100100
scalar_t const* __restrict__ weight,
101101
float const rms, float const scale,
102102
int32_t const hidden_size,
103+
scalar_t* __restrict__ residual_out = nullptr,
103104
scalar_t* __restrict__ residual = nullptr) {
104105
int64_t const token_offset = blockIdx.x * static_cast<int64_t>(hidden_size);
105106
;
@@ -108,7 +109,7 @@ __device__ void norm_and_quant(scalar_out_t* __restrict__ output,
108109
float x = static_cast<float>(input[token_offset + i]);
109110
if constexpr (has_residual) {
110111
x += static_cast<float>(residual[token_offset + i]);
111-
residual[token_offset + i] = static_cast<scalar_t>(x);
112+
residual_out[token_offset + i] = static_cast<scalar_t>(x);
112113
}
113114
// Norm
114115
x = static_cast<float>(static_cast<scalar_t>(x * rms) * weight[i]);
@@ -268,6 +269,7 @@ __device__ void norm_and_quant(scalar_out_t* __restrict__ output,
268269
scalar_t const* __restrict__ weight,
269270
float const rms, float const scale,
270271
int32_t const hidden_size,
272+
scalar_t* __restrict__ residual_out = nullptr,
271273
scalar_t* __restrict__ residual = nullptr) {
272274
int64_t const token_offset = blockIdx.x * static_cast<int64_t>(hidden_size);
273275
;
@@ -279,8 +281,11 @@ __device__ void norm_and_quant(scalar_out_t* __restrict__ output,
279281
reinterpret_cast<vec4_t<scalar_t> const*>(weight);
280282
q8x4_t<scalar_out_t>* vec_output =
281283
reinterpret_cast<q8x4_t<scalar_out_t>*>(&output[token_offset]);
284+
vec4_t<scalar_t>* vec_residual_out = nullptr;
282285
vec4_t<scalar_t>* vec_residual = nullptr;
283286
if constexpr (has_residual) {
287+
vec_residual_out =
288+
reinterpret_cast<vec4_t<scalar_t>*>(&residual_out[token_offset]);
284289
vec_residual = reinterpret_cast<vec4_t<scalar_t>*>(&residual[token_offset]);
285290
}
286291

@@ -311,7 +316,7 @@ __device__ void norm_and_quant(scalar_out_t* __restrict__ output,
311316
for (int j = 0; j < VEC_SIZE; ++j) {
312317
r.val[j] = static_cast<scalar_t>(x.val[j]);
313318
}
314-
vec_residual[i] = r;
319+
vec_residual_out[i] = r;
315320
}
316321

317322
q8x4_t<scalar_out_t> out;

csrc/torch_bindings.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
199199
ops.def(
200200
"rms_norm_dynamic_per_token_quant(Tensor! result, Tensor input, "
201201
"Tensor weight, Tensor! scale, float epsilon, "
202-
"Tensor? scale_ub, Tensor!? residual) -> ()");
202+
"Tensor? scale_ub, Tensor!? residual_out, Tensor? residual) -> ()");
203203
ops.impl("rms_norm_dynamic_per_token_quant", torch::kCUDA,
204204
&rms_norm_dynamic_per_token_quant);
205205

vllm/compilation/fusion.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ def replacement(result: torch.Tensor, result_rms: torch.Tensor,
400400
scale=scale,
401401
epsilon=self.epsilon,
402402
scale_ub=None,
403+
residual_out=None,
403404
residual=None)
404405

405406
# result, scale
@@ -471,11 +472,14 @@ def __init__(self,
471472
def register(self, pm_pass: PatternMatcherPass,
472473
record_match: Callable[[MultiOutputMatch], bool]):
473474

474-
def pattern(result: torch.Tensor, input: torch.Tensor,
475+
def pattern(result: torch.Tensor, result_rms: torch.Tensor,
476+
input: torch.Tensor, residual_out: torch.Tensor,
475477
residual: torch.Tensor, weight: torch.Tensor,
476478
scale: torch.Tensor):
477479
at = auto_functionalized(RMS_ADD_OP,
480+
result=result_rms,
478481
input=input,
482+
residual_out=residual_out,
479483
residual=residual,
480484
weight=weight,
481485
epsilon=self.epsilon)
@@ -488,7 +492,8 @@ def pattern(result: torch.Tensor, input: torch.Tensor,
488492
# result, residual, scale
489493
return at1[1], at[2], at1[2]
490494

491-
def replacement(result: torch.Tensor, input: torch.Tensor,
495+
def replacement(result: torch.Tensor, result_rms: torch.Tensor,
496+
input: torch.Tensor, residual_out: torch.Tensor,
492497
residual: torch.Tensor, weight: torch.Tensor,
493498
scale: torch.Tensor):
494499
at = auto_functionalized(self.FUSED_OP,
@@ -498,14 +503,17 @@ def replacement(result: torch.Tensor, input: torch.Tensor,
498503
scale=scale,
499504
epsilon=self.epsilon,
500505
scale_ub=None,
506+
residual_out=residual_out,
501507
residual=residual)
502508

503509
# result, residual, scale
504510
return at[1], at[3], at[2]
505511

506512
inputs = [
507513
torch.empty(5, 4, device="cuda", dtype=self.quant_dtype), # result
514+
empty_bf16(5, 4), # result_rms
508515
empty_bf16(5, 4), # input
516+
empty_bf16(5, 4), # residual_out
509517
empty_bf16(5, 4), # residual
510518
empty_bf16(1, 5), # weight
511519
empty_fp32(1, 1) # scale

vllm/utils.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2415,31 +2415,13 @@ def memory_profiling(
24152415
result.weights_memory = weights_memory
24162416

24172417
result.before_profile.measure()
2418-
logger.info("Before Profiling:", "torch_peak:",
2419-
result.before_profile.torch_peak / GiB_bytes, "torch_mem:",
2420-
result.before_profile.torch_memory / GiB_bytes,
2421-
"non_torch_mem:",
2422-
result.before_profile.non_torch_memory / GiB_bytes,
2423-
"cuda_mem:", result.before_profile.cuda_memory / GiB_bytes,
2424-
"free_mem:", result.before_profile.free_memory / GiB_bytes,
2425-
"total_mem:", result.before_profile.total_memory / GiB_bytes)
2426-
torch.cuda.memory._record_memory_history()
24272418

24282419
yield result
24292420

24302421
gc.collect()
24312422
torch.cuda.empty_cache()
24322423

24332424
result.after_profile.measure()
2434-
logger.info("After Profiling: torch_peak:",
2435-
result.after_profile.torch_peak / GiB_bytes, "torch_mem:",
2436-
result.after_profile.torch_memory / GiB_bytes,
2437-
"non_torch_mem:",
2438-
result.after_profile.non_torch_memory / GiB_bytes, "cuda_mem:",
2439-
result.after_profile.cuda_memory / GiB_bytes, "free_mem:",
2440-
result.after_profile.free_memory / GiB_bytes, "total_mem:",
2441-
result.after_profile.total_memory / GiB_bytes)
2442-
24432425
diff_profile = result.after_profile - result.before_profile
24442426
diff_from_create = result.after_profile - result.before_create
24452427
result.torch_peak_increase = diff_profile.torch_peak

0 commit comments

Comments
 (0)