Register the seven H3 control tokens the vocabulary omits - #56
Open
Tatlatat wants to merge 1 commit into
Open
Conversation
MiniMax declares <d>, </d>, <|cutoff|>, <|lyrics_start|>, <|lyrics_end|>,
<|caption_start|> and <|caption_end|> in tokenizer_config.json under
"additional_special_tokens". They appear in neither the BPE vocabulary nor
tokenizer.json's "added_tokens" array, which stops at 151668, so the loader
never learned them and the BPE merges swallowed the markup instead.
The damage reaches past the tag itself. Against the released FL2VA tokenizer,
"<d>[English] Hello there." + "</d>" encoded as nine pieces
90707 30768 22574 60 21927 1052 3918 67 29
where 90707 fuses "<d>[" into a single token and 3918 fuses ".</", so both the
dialogue marker and the language tag beside it reach the DiT as ordinary text.
The reference tokenizer appends the seven tokens after the last declared added
token and produces eight pieces instead:
151669 58 22574 60 21927 1052 13 151670
Assign the same identifiers by continuing from the highest declared id, which
yields 151669-151675 for the released vocabulary and stays clear of the 151936
text-encoder embedding bound. Tokens already present in tokenizer.json are left
alone, so a future release that declares them properly keeps its own ids.
Verified against transformers 5.16.1 loading FL2VA/tokenizer: identifiers and
piece boundaries now match for the dialogue, cutoff and caption cases, while
"<|im_start|>" and the existing prose cases are unchanged. tests/test_tokenizer.c
covers the three new cases and passes against both the FL2VA and Ref2VA
tokenizers.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015CbhnKLxBiCL4nUCUrbiKh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
MiniMax declares seven H3-specific control tokens in
tokenizer_config.jsonunderadditional_special_tokens:They are in neither the BPE vocabulary nor
tokenizer.json'sadded_tokensarray, which stops at 151668.h3_tokenizer_load()only reads the latter, so it never learns them and the BPE merges swallow the markup.The damage reaches past the tag itself. Against the released
FL2VA/tokenizer,<d>[English] Hello there.</d>currently encodes as nine pieces:90707fuses<d>[into one token and3918fuses.</, so the dialogue marker and the[English]language tag beside it both reach the DiT as ordinary prose.<|cutoff|>becomes six pieces,<|caption_start|>six.This matters because the official prompting guides (base, ref) build every dialogue line, cross-cut continuation and truncation on exactly these markers.
Fix
Continue the identifiers from the highest declared added token, which is what the reference tokenizer does. For the released vocabulary that yields 151669-151675, comfortably inside the 151936
TEXT_VOCABembedding bound. Tokens already present intokenizer.jsonare skipped, so a future release that declares them properly keeps its own ids rather than getting duplicates.Verification
transformers5.16.1 loading the sameFL2VA/tokenizerdirectory:h3.cafter this patch, same input, same file:tests/test_tokenizer.cgains the three cases above, including the decode round-trip thatcheck_casealready performs.make h3_tokenizer_testspasses against both the FL2VA and the Ref2VA tokenizer (83 checks, was 60), and./h3_testsstill reports its 1768 checks. Builds clean under the existing-Wall -Wextra -Wpedantic -Wshadow -Wconversion.One thing I did not do is an A/B of actual generations. I checked the embedding rows at 151669-151675 and they are statistically indistinguishable from the unused padding rows above them (norm 0.505 +/- 0.006 against 0.503 +/- 0.005 for rows 151676-151935, while the 26 genuinely declared special tokens average 0.662 with a 1.34 maximum), so these embeddings look frozen at initialization rather than trained as language-model tokens. That does not make the mapping wrong, since the text encoder is frozen and the DiT trained on top of whatever fixed vectors it produced, and it is what the reference pipeline feeds. It does mean the argument here is "match the reference tokenizer", not "measured better video".