Tokenize a single batch of trajectories for SFT. Args: trajectory_batch: List of trajectories in this batch learning_rate: Learning rate for this batch tokenizer: Tokenizer to use for encoding instruction_part: Instruction template part (e.g., "<|im_start|>user")
(
trajectory_batch: list[Trajectory],
learning_rate: float,
tokenizer: PreTrainedTokenizerBase,
instruction_part: str,
response_part: str,
)
| 364 | |
| 365 | |
| 366 | def tokenize_sft_batch( |
| 367 | trajectory_batch: list[Trajectory], |
| 368 | learning_rate: float, |
| 369 | tokenizer: PreTrainedTokenizerBase, |
| 370 | instruction_part: str, |
| 371 | response_part: str, |
| 372 | ) -> SFTBatch: |
| 373 | """Tokenize a single batch of trajectories for SFT. |
| 374 | |
| 375 | Args: |
| 376 | trajectory_batch: List of trajectories in this batch |
| 377 | learning_rate: Learning rate for this batch |
| 378 | tokenizer: Tokenizer to use for encoding |
| 379 | instruction_part: Instruction template part (e.g., "<|im_start|>user") |
| 380 | response_part: Response template part (e.g., "<|im_start|>assistant") |
| 381 | |
| 382 | Returns: |
| 383 | SFTBatch object for this batch |
| 384 | """ |
| 385 | import unsloth # noqa: F401 - Must be imported first to set UNSLOTH_IS_PRESENT env var |
| 386 | from unsloth_zoo.dataset_utils import train_on_responses_only |
| 387 | |
| 388 | train_on_responses_only_fn = train_on_responses_only( |
| 389 | trainer=None, |
| 390 | instruction_part=instruction_part, |
| 391 | response_part=response_part, |
| 392 | force_match=False, |
| 393 | tokenizer=tokenizer, |
| 394 | return_function=True, |
| 395 | ) |
| 396 | # Tokenize all trajectories (no padding — each keeps its natural length) |
| 397 | trajectory_tensors = [] |
| 398 | num_trainable_tokens = 0 |
| 399 | for trajectory in trajectory_batch: |
| 400 | messages = trajectory.messages_and_choices |
| 401 | tools = trajectory.tools |
| 402 | |
| 403 | # Single-step tokenization: apply_chat_template with tokenize=True |
| 404 | input_ids = cast( |
| 405 | list[int], |
| 406 | tokenizer.apply_chat_template( |
| 407 | cast(Any, messages), |
| 408 | tools=cast(Any, tools), |
| 409 | tokenize=True, |
| 410 | add_generation_prompt=False, |
| 411 | ), |
| 412 | ) |
| 413 | |
| 414 | attention_mask = [1] * len(input_ids) |
| 415 | |
| 416 | labels = train_on_responses_only_fn({"input_ids": [input_ids]})["labels"][0] |
| 417 | |
| 418 | trajectory_tensors.append( |
| 419 | { |
| 420 | "input_ids": torch.tensor([input_ids], dtype=torch.long), |
| 421 | "attention_mask": torch.tensor([attention_mask], dtype=torch.long), |
| 422 | "labels": torch.tensor([labels], dtype=torch.long), |
| 423 | } |