How a sample’s arrays line up
ASample holds its input tokens in model_input and its per-token arrays in a loss_fn_inputs mapping. The arrays line up so that each position is scored on predicting the next token:
- Input tokens:
model_inputholds the prompt and response, minus the final token. - Target tokens:
target_tokensholds the same sequence minus the first token, so positioniis scored on predictingtarget_tokens[i], the token that followsmodel_input[i]. - Weights:
weightsis the loss mask. A position with1.0trains on its target token, and a position with0.0doesn’t. To train on the response only, use0.0where the target token is part of the prompt and1.0where it’s part of the response.
t0 through t5, with a three-token prompt gives five positions:
Position 2 reads the last prompt token, but its target is the first response token, so its weight is
1.0. The last position’s target is t5, so t5 trains like any other response token, even though it isn’t in model_input.
Group relative policy optimization (GRPO) samples add two more arrays to loss_fn_inputs:
- Advantages:
advantagesholds the completion’s advantage at every trained position and0.0elsewhere. - Log-probabilities:
logprobsholds the log-probability the generator assigned to each completion token when it sampled the completion, and0.0on the prompt.
Build samples by hand
Every array inloss_fn_inputs needs one value per position. To build each array, start with one value per token in the sequence, then drop the first value, as target_tokens drops the first token. Use 0.0 for positions you don’t train on rather than leaving them out.
The build_sample function builds a cross-entropy sample from a token sequence and a loss mask with one value per token:
data and declares its dtype, either int64 or float32.
To build a GRPO sample from a sampled completion, also add the advantages and logprobs arrays. Build each one the same way as weights, from a per-token list with its first value dropped.
Build a loss mask from a chat template
To train on only the final reply in a chat conversation, build the loss mask from the model’s chat template. Render the conversation twice with the model’s tokenizer: once without the final reply, ready for the model to respond, and once in full. When the full rendering starts with the prompt rendering, every token after the prompt belongs to the reply. This example passes the resulting mask tobuild_sample:
- Thinking: Templates differ in whether they think by default and whether you can turn thinking off. For data without reasoning, set
enable_thinkingto fit the model’s thinking behavior. Theenable_thinking=Falseinrenderturns thinking off for Qwen3.8 27B. - Stop tokens: Some templates don’t close the final reply with a stop token. For those, append the model’s stop token to
tokensand1.0toloss_mask, or the model never learns to stop. - Multi-turn conversations: To train on every assistant turn, build one sample per turn from the conversation up to and including that turn. Some templates strip reasoning from earlier turns, so a later turn’s prompt doesn’t always start with the earlier turns as the model produced them. A sample per turn avoids the mismatch, because each turn trains against the prompt the template renders for it.