Skip to content

feat: MultiturnSFTDataset - #2315

Open
ysjprojects wants to merge 1 commit into
sj/multiturn-prompt-chatmlfrom
sj/multiturnsftdataset
Open

feat: MultiturnSFTDataset#2315
ysjprojects wants to merge 1 commit into
sj/multiturn-prompt-chatmlfrom
sj/multiturnsftdataset

Conversation

@ysjprojects

Copy link
Copy Markdown
Collaborator

Summary

Adds MultiturnSFTDataset, a training-data counterpart to SFTDataset for
supervised finetuning on multi-turn conversations. Builds on the multi-turn
apply() support landed in #<PR number of 62ffd7b> (ChatML/Llama3/R1Base +
add_generation_prompt).

Motivation

litgpt's SFT pipeline (SFTDataset) only supports single-turn
instruction/output pairs — one prompt string in, one response string out,
with a single masked prefix span. There's no way to train on a full
conversation (multiple user/assistant turns) with per-turn loss masking:
every assistant turn should contribute to the loss while prior turns stay as
context, not get flattened into independent single-turn examples the way
deita.py/lima.py currently do.

What's included

  • MultiturnSFTDataset (litgpt/data/base.py): takes a list of
    conversations (list[list[{"role", "content"}]]), and produces
    input_ids/labels with masking applied per-turn instead of a single
    prefix boundary.
    • Fast path when mask_prompt=False: one apply() + encode() call over
      the whole conversation.
    • When mask_prompt=True: since PromptStyle.apply() only returns a flat
      string with no turn-boundary info, turn boundaries are recovered by
      re-rendering growing prefixes of the conversation
      (apply(messages[:k], add_generation_prompt=False)) and diffing
      tokenized lengths — bos is applied consistently across every prefix so
      the diff stays aligned.
    • Requires prompt_style.supports_multiturn; raises a clear ValueError
      at construction otherwise.
    • Requires each conversation to end on an assistant turn (the training
      target); raises otherwise.
    • token_counts reports both raw (plain per-turn content, no template
      overhead) and raw_plus_prompt_template (actual sequence length),
      matching SFTDataset's existing convention used by the finetuning
      performance report.
  • Exported from litgpt.data alongside SFTDataset.
  • Tests in tests/data/test_base.py: parametrized coverage mirroring
    test_sft_dataset (mask_prompt / ignore_index / max_seq_length), a
    dedicated regression test for a longer alternating-turn conversation
    (catches a real bug found during development where inconsistent bos
    handling across prefixes corrupted turn boundaries), and both ValueError
    guard paths.

Out of scope (follow-up)

This PR is infrastructure only — no DataModule wires up
MultiturnSFTDataset yet. A follow-up PR will add a JSONConversations
(or similarly named) DataModule so litgpt finetune can actually consume
multi-turn JSON data end-to-end. Also out of scope: inference-side
multi-turn support (litgpt chat history, LLM.generate(messages=...)).

Test plan

  • pytest tests/data/test_base.py tests/test_prompts.py — all passing.
  • ruff check / ruff format --check clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant