Skip to content

Commit db155df

Browse files
committed
fix: honor Granite loss masks
Remove the invalid auto lazy import and preserve loss mask semantics in causal loss.
1 parent c024093 commit db155df

2 files changed

Lines changed: 37 additions & 2 deletions

File tree

paddleformers/transformers/granite/modeling.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -551,12 +551,15 @@ def forward(
551551
shift_logits = logits[:, :-1].reshape([-1, logits.shape[-1]])
552552
shift_labels = labels[:, 1:].reshape([-1])
553553
valid = shift_labels != -100
554+
if loss_mask is not None:
555+
valid = valid & paddle.cast(loss_mask[:, 1:].reshape([-1]), paddle.bool)
554556
safe_labels = paddle.where(valid, shift_labels, paddle.zeros_like(shift_labels))
555557
selected_log_probs = paddle.take_along_axis(
556558
F.log_softmax(shift_logits, axis=-1), safe_labels.unsqueeze(-1), axis=-1
557559
).squeeze(-1)
558-
valid_count = paddle.cast(valid, selected_log_probs.dtype).sum()
559-
loss = -(selected_log_probs * paddle.cast(valid, selected_log_probs.dtype)).sum() / valid_count
560+
valid_float = paddle.cast(valid, selected_log_probs.dtype)
561+
valid_count = valid_float.sum()
562+
loss = -(selected_log_probs * valid_float).sum() / paddle.clip(valid_count, min=1.0)
560563

561564
if not return_dict:
562565
output = (logits,) + outputs[1:]

tests/transformers/granite/test_modeling.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,34 @@ def create_and_check_loss(self, config, input_ids, input_mask, sequence_labels,
197197
).sum()
198198
self.parent.assertTrue(paddle.allclose(result.loss, expected_loss, rtol=1e-5, atol=1e-5))
199199

200+
def create_and_check_loss_mask(self, config, input_ids):
201+
model = GraniteForCausalLM(config)
202+
model.eval()
203+
labels = input_ids.clone()
204+
loss_mask = paddle.ones_like(input_ids)
205+
loss_mask[:, 2:4] = 0
206+
result = model(input_ids, labels=labels, loss_mask=loss_mask, return_dict=True)
207+
208+
shift_logits = result.logits[:, :-1].reshape([-1, config.vocab_size])
209+
shift_labels = labels[:, 1:].reshape([-1])
210+
valid = (shift_labels != -100) & paddle.cast(loss_mask[:, 1:].reshape([-1]), paddle.bool)
211+
safe_labels = paddle.where(valid, shift_labels, paddle.zeros_like(shift_labels))
212+
selected_log_probs = paddle.take_along_axis(
213+
paddle.nn.functional.log_softmax(shift_logits, axis=-1), safe_labels.unsqueeze(-1), axis=-1
214+
).squeeze(-1)
215+
valid_float = paddle.cast(valid, selected_log_probs.dtype)
216+
expected_loss = -(selected_log_probs * valid_float).sum() / paddle.clip(valid_float.sum(), min=1.0)
217+
self.parent.assertTrue(paddle.allclose(result.loss, expected_loss, rtol=1e-5, atol=1e-5))
218+
219+
empty_loss = model(
220+
input_ids,
221+
labels=labels,
222+
loss_mask=paddle.zeros_like(input_ids),
223+
return_dict=True,
224+
).loss
225+
self.parent.assertTrue(paddle.isfinite(empty_loss).item())
226+
self.parent.assertEqual(empty_loss.item(), 0.0)
227+
200228
def create_and_check_generate(self, config, input_ids, input_mask):
201229
model = GraniteForCausalLM(config)
202230
model.eval()
@@ -268,6 +296,10 @@ def test_loss(self):
268296
config_and_inputs = self.model_tester.prepare_config_and_inputs()
269297
self.model_tester.create_and_check_loss(*config_and_inputs)
270298

299+
def test_loss_mask(self):
300+
config_and_inputs = self.model_tester.prepare_config_and_inputs()
301+
self.model_tester.create_and_check_loss_mask(*config_and_inputs[:2])
302+
271303
def test_generate(self):
272304
config_and_inputs = self.model_tester.prepare_config_and_inputs()
273305
self.model_tester.create_and_check_generate(*config_and_inputs[:3])

0 commit comments

Comments
 (0)