Skip to content

Commit 45336da

Browse files
Add a flag to support computing zero-centered gamma in weight dtype or compute dtype for CuDNN
Signed-off-by: Jeremy Berchtold <jberchtold@nvidia.com>
1 parent 48f3ca9 commit 45336da

6 files changed

Lines changed: 283 additions & 226 deletions

File tree

‎tests/cpp/operator/test_normalization.cu‎

Lines changed: 22 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -18,159 +18,16 @@
1818
#include <transformer_engine/normalization.h>
1919
#include <transformer_engine/transformer_engine.h>
2020
#include "../test_common.h"
21+
#include "test_normalization.h"
2122

2223
using namespace transformer_engine;
2324
using namespace test;
2425

2526
namespace {
2627

27-
enum NormType {
28-
LayerNorm,
29-
RMSNorm
30-
};
31-
32-
std::map<NormType, std::string> normToString = {
33-
{NormType::LayerNorm, "LayerNorm"},
34-
{NormType::RMSNorm, "RmsNorm"}
35-
};
36-
37-
template <typename InputType>
38-
void compute_ref_stats(NormType norm_type,
39-
const InputType *data, float *mu, float *rsigma,
40-
const size_t N, const size_t H, const double epsilon){
41-
using compute_t = float;
42-
compute_t current, m;
43-
for (size_t i = 0; i < N; ++i) {
44-
compute_t sum = 0;
45-
for (size_t j = 0; j < H; ++j) {
46-
sum += static_cast<compute_t>(data[i * H + j]);
47-
}
48-
if (norm_type == LayerNorm){
49-
mu[i] = sum / H;
50-
m = mu[i];
51-
} else { m = 0;}
52-
53-
compute_t sum_sq = 0;
54-
for (size_t j = 0; j < H; ++j) {
55-
current = static_cast<compute_t>(data[i * H + j]);
56-
sum_sq += (current - m) * (current - m);
57-
}
58-
rsigma[i] = rsqrtf((sum_sq / H) + epsilon);
59-
}
60-
}
61-
62-
// For now, cudnn does static_cast<compute_t>(gamma + static_cast<input_t>(1.0))
63-
// This will be changed in the future release
64-
template <typename InputType>
65-
inline auto compute_gamma(InputType gamma, const bool zero_centered_gamma, const bool use_cudnn){
66-
67-
using compute_t = float;
68-
if constexpr (std::is_same_v<InputType, fp8e5m2> || std::is_same_v<InputType, fp8e4m3>){
69-
compute_t g = static_cast<compute_t>(gamma);
70-
if (zero_centered_gamma) {
71-
g += static_cast<compute_t>(1.f);
72-
}
73-
return g;
74-
} else {
75-
if (use_cudnn){
76-
compute_t g = static_cast<compute_t>(0.f);
77-
InputType gi = gamma;
78-
if (zero_centered_gamma) {
79-
gi = gi + static_cast<InputType>(1.f);
80-
}
81-
g = static_cast<compute_t>(gi);
82-
return g;
83-
} else {
84-
compute_t g = static_cast<compute_t>(gamma);
85-
if (zero_centered_gamma) {
86-
g += static_cast<compute_t>(1.f);
87-
}
88-
return g;
89-
}
90-
}
91-
}
92-
93-
template <typename InputType, typename OutputType>
94-
void compute_ref_output(NormType norm_type,
95-
const InputType *data, const InputType *gamma, const InputType *beta,
96-
OutputType* output,
97-
const float *mu, const float *rsigma,
98-
const size_t N, const size_t H,
99-
float *amax, float scale, const bool zero_centered_gamma, const bool use_cudnn) {
100-
using compute_t = float;
101-
compute_t current_max = -1e100;
102-
for (size_t i = 0; i < N; ++i) {
103-
for (size_t j = 0; j < H; ++j) {
104-
compute_t current = static_cast<compute_t>(data[i * H + j]);
105-
compute_t g = compute_gamma(gamma[j], zero_centered_gamma, use_cudnn);
106-
107-
compute_t tmp;
108-
if (norm_type == LayerNorm) {
109-
tmp = (current - mu[i]) * rsigma[i] * g + static_cast<compute_t>(beta[j]);
110-
} else { // RMSNorm
111-
tmp = current * rsigma[i] * g;
112-
}
113-
114-
output[i * H + j] = static_cast<OutputType>(tmp * scale);
115-
current_max = fmaxf(current_max, fabsf(tmp));
116-
}
117-
}
118-
*amax = current_max;
119-
}
120-
121-
122-
template <typename InputType, typename OutputType>
123-
void compute_ref_backward(const NormType norm_type, const OutputType *output_grad, const InputType *data,
124-
const float *mu, const float *rsigma,
125-
const InputType *gamma,
126-
InputType *data_grad,
127-
InputType *gamma_grad, InputType *beta_grad,
128-
const size_t N, const size_t H,
129-
const bool zero_centered_gamma, const bool use_cudnn) {
130-
using compute_t = float;
131-
std::vector<compute_t> dgamma(H, 0.f);
132-
std::vector<compute_t> dbeta(H, 0.f);
133-
134-
for (size_t i = 0 ; i < N; ++i) {
135-
// Reductions
136-
auto local_mu = (norm_type == LayerNorm) ? mu[i] : 0.;
137-
compute_t mdy = 0, mdyy = 0;
138-
for (size_t j = 0; j < H; ++j) {
139-
const compute_t x = static_cast<compute_t>(data[i * H + j]);
140-
const compute_t y = (x - local_mu) * rsigma[i];
141-
compute_t g = compute_gamma(gamma[j], zero_centered_gamma, use_cudnn);
142-
const compute_t dz = static_cast<compute_t>(output_grad[i * H + j]);
143-
const compute_t dy = g * dz;
144-
dgamma[j] += y * dz;
145-
if (norm_type == LayerNorm) {
146-
dbeta[j] += dz;
147-
mdy += dy;
148-
}
149-
mdyy += dy * y;
150-
}
151-
mdy /= H;
152-
mdyy /= H;
153-
154-
// Input grads
155-
for (size_t j = 0; j < H; ++j) {
156-
const compute_t x = static_cast<compute_t>(data[i * H + j]);
157-
const compute_t y = (x - local_mu) * rsigma[i];
158-
compute_t g = compute_gamma(gamma[j], zero_centered_gamma, use_cudnn);
159-
const compute_t dz = static_cast<compute_t>(output_grad[i * H + j]);
160-
const compute_t dy = g * dz;
161-
const compute_t dx = rsigma[i] * (dy - mdyy * y - mdy);
162-
data_grad[i * H + j] = static_cast<InputType>(dx);
163-
}
164-
}
165-
166-
// Weight grads
167-
for (size_t j = 0; j < H; ++j) gamma_grad[j] = static_cast<InputType>(dgamma[j]);
168-
if (norm_type == LayerNorm) for (size_t j = 0; j < H; ++j) beta_grad[j] = static_cast<InputType>(dbeta[j]);
169-
}
170-
17128
template <typename InputType, typename OutputType>
17229
void performTest(const size_t N, const size_t H, const bool zero_centered_gamma,
173-
NormType norm_type, bool use_cudnn) {
30+
NormType norm_type, bool use_cudnn, const bool cudnn_zero_centered_gamma_in_weight_dtype) {
17431
if (sizeof(InputType) < sizeof(OutputType)) {
17532
GTEST_SKIP() << "LN kernel does not support OutputType > InputType";
17633
return;
@@ -224,6 +81,12 @@ void performTest(const size_t N, const size_t H, const bool zero_centered_gamma,
22481
nvte_enable_cudnn_norm_bwd(true);
22582
}
22683

84+
if (cudnn_zero_centered_gamma_in_weight_dtype) {
85+
nvte_enable_cudnn_norm_zero_centered_gamma_in_weight_dtype(true);
86+
} else {
87+
nvte_enable_cudnn_norm_zero_centered_gamma_in_weight_dtype(false);
88+
}
89+
22790
// Forward kernel
22891
float epsilon = 1e-5;
22992
if (norm_type == LayerNorm){
@@ -271,6 +134,10 @@ void performTest(const size_t N, const size_t H, const bool zero_centered_gamma,
271134
nvte_enable_cudnn_norm_bwd(false);
272135
}
273136

137+
if (cudnn_zero_centered_gamma_in_weight_dtype) {
138+
nvte_enable_cudnn_norm_zero_centered_gamma_in_weight_dtype(false);
139+
}
140+
274141
// Reference implementations
275142
// use the GPU stats to tighten the tolerances
276143
mu.to_cpu();
@@ -289,14 +156,16 @@ void performTest(const size_t N, const size_t H, const bool zero_centered_gamma,
289156
&ref_amax,
290157
ref_scale,
291158
zero_centered_gamma,
292-
use_cudnn);
159+
use_cudnn,
160+
cudnn_zero_centered_gamma_in_weight_dtype);
293161
compute_ref_backward(norm_type, dz.rowwise_cpu_dptr<WeightType>(),
294162
input.rowwise_cpu_dptr<InputType>(),
295163
mu.rowwise_cpu_dptr<float>(), rsigma.rowwise_cpu_dptr<float>(),
296164
gamma.rowwise_cpu_dptr<WeightType>(),
297165
ref_dx.get(), ref_dgamma.get(), ref_dbeta.get(),
298166
N, H, zero_centered_gamma,
299-
use_cudnn);
167+
use_cudnn,
168+
cudnn_zero_centered_gamma_in_weight_dtype);
300169

301170
cudaDeviceSynchronize();
302171
auto err = cudaGetLastError();
@@ -341,6 +210,7 @@ NormType,
341210
transformer_engine::DType,
342211
transformer_engine::DType,
343212
std::pair<size_t, size_t>,
213+
bool,
344214
bool>> {};
345215

346216
TEST_P(NormTestSuite, TestNorm) {
@@ -353,10 +223,11 @@ TEST_P(NormTestSuite, TestNorm) {
353223
const DType output_type = std::get<3>(GetParam());
354224
const auto size = std::get<4>(GetParam());
355225
const bool zero_centered_gamma = std::get<5>(GetParam());
226+
const bool cudnn_zero_centered_gamm_in_weight_dtype = std::get<6>(GetParam());
356227

357228
TRANSFORMER_ENGINE_TYPE_SWITCH_ALL(input_type, InputType,
358229
TRANSFORMER_ENGINE_TYPE_SWITCH_ALL(output_type, OutputType,
359-
performTest<InputType, OutputType>(size.first, size.second, zero_centered_gamma, norm_type, use_cudnn);
230+
performTest<InputType, OutputType>(size.first, size.second, zero_centered_gamma, norm_type, use_cudnn, cudnn_zero_centered_gamm_in_weight_dtype);
360231
);
361232
);
362233
}
@@ -370,6 +241,7 @@ INSTANTIATE_TEST_SUITE_P(
370241
::testing::Values(DType::kFloat32, DType::kBFloat16, DType::kFloat16),
371242
::testing::Values(DType::kFloat32, DType::kBFloat16, DType::kFloat16, DType::kFloat8E4M3),
372243
::testing::ValuesIn(test_cases),
244+
::testing::Values(false, true),
373245
::testing::Values(false, true)),
374246
[](const testing::TestParamInfo<NormTestSuite::ParamType>& info) {
375247
auto backend = std::get<0>(info.param) == false ? "Te" : "Cudnn";
@@ -380,6 +252,7 @@ INSTANTIATE_TEST_SUITE_P(
380252
test::typeName(std::get<3>(info.param)) + "X" +
381253
std::to_string(std::get<4>(info.param).first) + "X" +
382254
std::to_string(std::get<4>(info.param).second) + "X" +
383-
std::to_string(std::get<5>(info.param));
255+
std::to_string(std::get<5>(info.param)) + "X" +
256+
std::to_string(std::get<6>(info.param));
384257
return name;
385258
});

0 commit comments

Comments
 (0)