Skip to content

Commit cffb4e5

Browse files
Sdccodingcopybara-github
authored andcommitted
Optimize Gemma 4 MoE router input buffering and scaling:
- Changed `router_in` storage type from `BF16` to `float` in `Activations` to avoid `BF16`->`float`->`BF16` round-tripping. - Copies pre-FFW activations directly to the `float` `router_in` without type conversion. - Performs fused inline scaling using Highway SIMD (`Decompress1AndCompressInplace`) avoiding per-token type roundtrips and temporary vector allocations. PiperOrigin-RevId: 954067115
1 parent c48a9ae commit cffb4e5

2 files changed

Lines changed: 20 additions & 25 deletions

File tree

gemma/activations.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ struct Activations {
723723
TensorStats s_ffw_out;
724724

725725
// For MoE layers. These are used outside the expert-parallel loop:
726-
MatStorageT<BF16> router_in;
726+
MatStorageT<float> router_in;
727727
MatStorageT<float> router_logits; // batch_size x num_experts
728728

729729
// DeepSeek MLA (zero-sized unless a layer uses MLA).

gemma/gemma4_moe.cc

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -112,34 +112,29 @@ struct Gemma4MoE {
112112

113113
for (size_t token_idx = 0; token_idx < num_tokens; ++token_idx) {
114114
const float* pre_ffw_row = activations.x.Row(token_idx);
115-
BF16* router_in_row = activations.router_in.Row(token_idx);
116-
117-
for (size_t col = 0; col < model_dim; ++col) {
118-
router_in_row[col] = hwy::ConvertScalarTo<BF16>(pre_ffw_row[col]);
119-
}
115+
float* router_in_row = activations.router_in.Row(token_idx);
116+
std::copy_n(pre_ffw_row, model_dim, router_in_row);
120117
}
121118

122119
RMSNormNoScaleInplaceBatched(activations.router_in, env.ctx);
123120

124-
// TODO(philculliton): Use a float buffer for router_in to avoid the
125-
// BF16->float->BF16 round-trip, and precompute scale_factor * router_scale
126-
// once rather than per-token. Per the CL comment: we are converting to
127-
// bf16, but then converting back to float below. Should we set up a
128-
// router_in_row_f32 so we can just keep it as float? (That would help if
129-
// num_tokens>>1, because we could precompute * scale_factor once.)
130-
for (size_t token_idx = 0; token_idx < num_tokens; ++token_idx) {
131-
BF16* router_in_row = activations.router_in.Row(token_idx);
132-
if (has_router_scale) {
133-
for (size_t col = 0; col < model_dim; ++col) {
134-
router_in_row[col] = hwy::ConvertScalarTo<BF16>(
135-
hwy::ConvertScalarTo<float>(router_in_row[col]) * scale_factor *
136-
hwy::ConvertScalarTo<float>(scale_ptr[col]));
137-
}
138-
} else {
139-
for (size_t col = 0; col < model_dim; ++col) {
140-
router_in_row[col] = hwy::ConvertScalarTo<BF16>(
141-
hwy::ConvertScalarTo<float>(router_in_row[col]) * scale_factor);
142-
}
121+
namespace hn = hwy::HWY_NAMESPACE;
122+
using DF = hn::ScalableTag<float>;
123+
using VF = hn::Vec<DF>;
124+
125+
if (has_router_scale) {
126+
for (size_t token_idx = 0; token_idx < num_tokens; ++token_idx) {
127+
float* router_in_row = activations.router_in.Row(token_idx);
128+
Decompress1AndCompressInplace(
129+
DF(), router_in_row, model_dim, scale_ptr, 0,
130+
[scale_factor](DF df, VF inout, VF scale) HWY_ATTR {
131+
return hn::Mul(inout, hn::Mul(scale, hn::Set(df, scale_factor)));
132+
});
133+
}
134+
} else {
135+
for (size_t token_idx = 0; token_idx < num_tokens; ++token_idx) {
136+
float* router_in_row = activations.router_in.Row(token_idx);
137+
MulByConst(scale_factor, router_in_row, model_dim);
143138
}
144139
}
145140

0 commit comments

Comments
 (0)