How JEV encodes multiple choices in parallel using shared position IDs and an isolated attention mask so choices cannot see each other.
To score every choice fairly, each one must be conditioned on the question but not on any sibling choice. If choice B could attend to choice A, the model could exploit their relative order or wording rather than their individual merit. The solution is a carefully crafted sequence layout combined with a custom attention mask.
This is the same motivation as in parallel decoding or encoder cross-attention over multiple spans: the representations must be independently conditioned on the shared context, not on each other.
The full input sequence is assembled from four parts in order:
max_state_tokens).<option> + choice text (truncated to max_choice_tokens) + </option>. All choices are concatenated one after another."The answer is:", which closes the sequence.The code reads the hidden state at the last content token of each choice, not at the closing > of </option>. This is intentional: the last content token carries the richest contextual representation for that choice, already conditioned on the full choice text.
# choice_read_idx is choice_end_idx minus the length of the "</option>" token sequence
choice_end_token_len = len(tokenizer.encode("</option>"))
choice_read_idx = [end - choice_end_token_len for end in span["choices_end_idx"]]Standard position IDs increment monotonically from 0. In JEV, the question tokens still get sequential positions 0, 1, 2, … but every choice block restarts from the same position as the first choice. The answer tokens then start right after the longest choice, so every choice token is already in the past from the answer’s perspective.
Concretely, if the question ends at position 50, then choice A tokens get positions 51, 52, 53 … and choice B tokens also get positions 51, 52, 53 …. The answer tokens start at max(position_ids) + 1.
Why does this matter? Rotary positional embeddings (RoPE, used in Qwen) encode the relative distance between tokens. If both choices start at position 51, their internal distance structure is identical and neither has a positional advantage over the other. A shorter choice’s last token lands at a lower absolute position, but the answer token is placed after the longest choice, so all choices are equally in the answer’s past.
The attention mask is an L×L matrix (L = total sequence length) where a 1 means the row token can attend to the column token. Four regions get special treatment:
| Region | Rule | Why |
|---|---|---|
| Question → question | Causal (lower triangle) | Standard left-to-right attention within the question. |
| Choice A → question | All ones | Each choice can see the full question. |
| Choice A → choice A | Causal (lower triangle) | Within-choice left-to-right attention. |
| Choice A → choice B | All zeros | Choices are isolated from each other. |
| Answer → everything | All ones for past, causal for self | Answer tokens can see all question + all choices (but not future answer tokens). |
In code, the mask is built as a single L×L dense boolean tensor, then passed into the backbone as the attention_mask argument. Qwen’s flash attention path interprets it correctly.
The output of encode_example is a dictionary of tensors that goes straight to the DataLoader and then to the network:
{
"input_ids": [Q... <opt>C1</opt> <opt>C2</opt> ans...],
"position_ids": [0 1 2 ... | 51 52 53 | 51 52 53 | 54 55],
"attention_mask": <L x L bool tensor>,
"choice_read_idx":[idx_of_last_content_token_per_choice],
"answer_end_idx": idx_of_last_answer_token
}The choice_mask (which choices are real vs padding, used to batch variable-length examples) is computed later during collation. No labels are stored here; the dataset returns them separately and they are moved to the device in the training loop.
Say the answer out loud before revealing it — retrieving is what makes it stick.
Why must choices be isolated from each other in the attention mask?
What are parallel position IDs and why are they used?
Where exactly is the hidden state read for each choice?
What rule governs the answer tokens in the attention mask?