Skip to content

Commit a04b753

Browse files
avenkateshhaclaude
andcommitted
fix(xtoken): keep the offset layout for all-empty text batches
When every text in a batch tokenizes to no tokens, the tokenizer returns offset_mapping as a (B, 0) tensor without the start/end axis. Text batches now pad to the longest row, so such a batch is padded to one sequence-length multiple, and concatenating (B, pad, 2) offsets onto the (B, 0) tensor raised "Tensors must have same number of dimensions: got 2 and 3". Reshape the offsets to (B, T, 2) from the token ids' shape, so the batch collates to all-padding rows as it did when text batches padded to the full context length. Non-empty batches are unchanged. Add a regression test for an all-empty text batch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Adithya Hanasoge <avenkateshha@nvidia.com>
1 parent 6f98ca3 commit a04b753

2 files changed

Lines changed: 17 additions & 1 deletion

File tree

‎nemo_rl/data/cross_tokenizer/cross_tokenizer_collate.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,10 @@ def _tokenize_batch(
670670
)
671671
input_ids: torch.Tensor = encoded["input_ids"]
672672
attention_mask: torch.Tensor = encoded["attention_mask"]
673-
offset_mapping: torch.Tensor = encoded["offset_mapping"]
673+
# An all-empty batch returns (B, 0) offsets; keep the (B, T, 2) layout.
674+
offset_mapping: torch.Tensor = encoded["offset_mapping"].reshape(
675+
*input_ids.shape, 2
676+
)
674677

675678
b, t = input_ids.shape
676679
pad = CrossTokenizerCollator._padded_width(t, make_seq_div_by) - t

‎tests/unit/data/test_cross_tokenizer_collate.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,19 @@ def test_batch_matches_full_context_padding_at_real_positions(self):
797797
for key in ("alignment_0_pair_valid", "alignment_0_pair_is_correct"):
798798
assert torch.equal(new[key][row, pairs], old[key][row, pairs]), key
799799

800+
def test_all_empty_batch_pads_to_the_divisor(self):
801+
collator = _text_collator(ctx_length_student=8, ctx_length_teachers=[16, 8])
802+
out = collator([_datum("", idx=0), _datum("", idx=1)])
803+
# No row has tokens, so each side pads to one sequence-length multiple.
804+
assert out["input_ids"].shape == (2, 4)
805+
assert out["teacher_0_input_ids"].shape == (2, 3)
806+
assert out["input_lengths"].tolist() == [0, 0]
807+
assert out["teacher_0_input_lengths"].tolist() == [0, 0]
808+
assert out["token_mask"].eq(0).all()
809+
assert out["teacher_0_token_mask"].eq(0).all()
810+
assert out["alignment_0_student_chunk_id"].eq(-1).all()
811+
assert out["alignment_0_teacher_chunk_id"].eq(-1).all()
812+
800813

801814
class TestCollatorPadTokenFallback:
802815
def test_missing_pad_token_set_from_eos(self):

0 commit comments

Comments
 (0)