Skip to content

Commit fab2fd4

Browse files
Fix Falcon-H1 gated RMSNorm shape during batched decoding (#50507)
* Fix Falcon-H1 gated RMSNorm shape during batched decoding * Add a regression test for batched cached decoding with the gated RMSNorm --------- Co-authored-by: Matt <rocketknight1@gmail.com>
1 parent 863d262 commit fab2fd4

3 files changed

Lines changed: 35 additions & 2 deletions

File tree

‎src/transformers/models/falcon_h1/modeling_falcon_h1.py‎

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/transformers/models/falcon_h1/modular_falcon_h1.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ def __init__(self, hidden_size, eps=1e-6, n_groups=1, norm_before_gate=True):
121121

122122
def forward(self, hidden_states, gate=None):
123123
input_dtype = hidden_states.dtype
124+
input_ndim = hidden_states.ndim
124125

125126
if not self.norm_before_gate and gate is not None:
126127
hidden_states = hidden_states * F.silu(gate.to(torch.float32))
@@ -140,7 +141,7 @@ def forward(self, hidden_states, gate=None):
140141
hidden_states = self.weight.view(self.n_groups, int(dim // self.n_groups)) * hidden_states
141142
hidden_states = hidden_states.view(batch_size, seq_len, dim)
142143

143-
if seq_len == 1:
144+
if input_ndim == 2:
144145
hidden_states = hidden_states.squeeze(1)
145146

146147
if self.norm_before_gate and gate is not None:

‎tests/models/falcon_h1/test_modeling_falcon_h1.py‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,33 @@ def create_and_check_mamba_chunked_prefill(self, config, input_ids, *args, devic
276276
msg=f"Max diff: {(ref_first - under_test_first).abs().max().item():.6f}",
277277
)
278278

279+
def create_and_check_gated_rms_norm_batched_cached_decoding(self, config, input_ids, *args):
280+
"""
281+
With `mamba_rms_norm=True`, a batched single-token cached step must give the same hidden states
282+
as the uncached forward pass, and must keep its `[batch_size, 1, hidden_size]` shape.
283+
"""
284+
input_ids = input_ids.to(torch_device)
285+
# The gate is applied in a different place depending on `mamba_norm_before_gate`, so we check both
286+
for norm_before_gate in (True, False):
287+
config.mamba_rms_norm = True
288+
config.mamba_norm_before_gate = norm_before_gate
289+
model = FalconH1Model(config=config)
290+
model.to(torch_device)
291+
model.eval()
292+
293+
with torch.no_grad():
294+
full_out = model(input_ids, use_cache=False).last_hidden_state
295+
prefill = model(input_ids[:, :-1], use_cache=True)
296+
step_out = model(
297+
input_ids[:, -1:], past_key_values=prefill.past_key_values, use_cache=True
298+
).last_hidden_state
299+
300+
self.parent.assertEqual(step_out.shape, (input_ids.shape[0], 1, config.hidden_size))
301+
self.parent.assertTrue(
302+
torch.allclose(full_out[:, -1:], step_out, atol=1e-4, rtol=1e-4),
303+
msg=f"Max diff: {(full_out[:, -1:] - step_out).abs().max().item():.6f}",
304+
)
305+
279306
def create_and_check_kwargs_reach_mamba2_mixer(self, config, input_ids, *args):
280307
"""
281308
Kernel kwargs given to the model must reach the Mamba2 mixer, which splats them into
@@ -357,6 +384,10 @@ def test_mamba2_chunked_prefill_cpu(self):
357384
config_and_inputs = self.model_tester.prepare_config_and_inputs()
358385
self.model_tester.create_and_check_mamba_chunked_prefill(*config_and_inputs, device="cpu")
359386

387+
def test_gated_rms_norm_batched_cached_decoding(self):
388+
config_and_inputs = self.model_tester.prepare_config_and_inputs()
389+
self.model_tester.create_and_check_gated_rms_norm_batched_cached_decoding(*config_and_inputs)
390+
360391
def test_kwargs_reach_mamba2_mixer(self):
361392
config_and_inputs = self.model_tester.prepare_config_and_inputs()
362393
self.model_tester.create_and_check_kwargs_reach_mamba2_mixer(*config_and_inputs)

0 commit comments

Comments
 (0)