System info
transformers on main (c49429ed). Both are static—neither needs a run to see.
Who can help?
@Cyrilvallez—@zucchini-nlp asked in
#47912 that
MTP-model-specific things go in their own issue tagged to you.
Two things noticed while working on #47912, the EOS-past-stop bug in the shared assisted-decoding path.
Neither is that bug; both are MTP-side.
1. test_generate_with_mtp skips for every checkpoint except Inkling
tests/generation/test_utils.py:2483 gates on the model's _keys_to_ignore_on_load_unexpected:
keys_to_ignore_unexpected = model_class._keys_to_ignore_on_load_unexpected or []
# If we don't have any mtp patterns, skip
if not hasattr(config.get_text_config(), "num_mtp_layers") or not any(
"mtp" in x or re.search(r"layers\.\d+", x) is not None for x in keys_to_ignore_unexpected
):
self.skipTest("No MTP keys registered")
Those entries are regexes, so their dots are escaped in the source, and re.search(r"layers\.\d+", x) wants
a literal . where the string has \.:
| model |
_keys_to_ignore_on_load_unexpected |
gate |
deepseek_v3 |
[r"model\.layers\.61.*"] |
skips |
glm4_moe |
[r"model\.layers\.92.*", r"model\.layers\.46.*"] |
skips |
solar_open |
None |
skips |
inkling |
[r"model\.mtp\..*"] |
runs, on "mtp" in x |
So the model.layers.{num_hidden_layers+1} half of what the docstring says it covers is never exercised—the
only model reaching the test is the one registering an mtp. pattern. re.search(r"layers\\?\.\d+", x)
matches both spellings.
Worth saying it would not have caught #47912 either way: it asserts only that generation raises nothing.
2. MtpModel.forward raises UnboundLocalError when logits_processor is None
src/transformers/modeling_layers.py:540:
if logits_processor is not None and full_input_ids is not None:
next_token_scores = logits_processor(full_input_ids, next_token_logits.to(torch.float32))
if do_sample:
probs = nn.functional.softmax(next_token_scores, dim=-1, dtype=torch.float32)
next_mtp_token = torch.multinomial(probs, num_samples=1)
else:
next_mtp_token = torch.argmax(next_token_scores, dim=-1, keepdim=True)
next_token_scores is bound only inside the guard and read unconditionally two lines below, so the call
raises UnboundLocalError whenever either argument is None. MTPCandidateGenerator.__init__ declares
logits_processor: Optional["LogitsProcessorList"] = None, so constructing one directly and drafting hits
it.
Not reachable through generate, which always passes a LogitsProcessorList and supplies full_input_ids
at candidate_generator.py:1529—so it is a trap for direct construction only. The tests in #48002 pass an
explicit LogitsProcessorList() for this reason. Falling back to next_token_logits, or making the
argument required, would both do.
AI-assisted: found and written up with Claude Code; both claims re-checked against main before filing.
System info
transformersonmain(c49429ed). Both are static—neither needs a run to see.Who can help?
@Cyrilvallez—@zucchini-nlp asked in
#47912 that
MTP-model-specific things go in their own issue tagged to you.
Two things noticed while working on #47912, the EOS-past-stop bug in the shared assisted-decoding path.
Neither is that bug; both are MTP-side.
1.
test_generate_with_mtpskips for every checkpoint except Inklingtests/generation/test_utils.py:2483gates on the model's_keys_to_ignore_on_load_unexpected:Those entries are regexes, so their dots are escaped in the source, and
re.search(r"layers\.\d+", x)wantsa literal
.where the string has\.:_keys_to_ignore_on_load_unexpecteddeepseek_v3[r"model\.layers\.61.*"]glm4_moe[r"model\.layers\.92.*", r"model\.layers\.46.*"]solar_openNoneinkling[r"model\.mtp\..*"]"mtp" in xSo the
model.layers.{num_hidden_layers+1}half of what the docstring says it covers is never exercised—theonly model reaching the test is the one registering an
mtp.pattern.re.search(r"layers\\?\.\d+", x)matches both spellings.
Worth saying it would not have caught #47912 either way: it asserts only that generation raises nothing.
2.
MtpModel.forwardraisesUnboundLocalErrorwhenlogits_processoris Nonesrc/transformers/modeling_layers.py:540:next_token_scoresis bound only inside the guard and read unconditionally two lines below, so the callraises
UnboundLocalErrorwhenever either argument is None.MTPCandidateGenerator.__init__declareslogits_processor: Optional["LogitsProcessorList"] = None, so constructing one directly and drafting hitsit.
Not reachable through
generate, which always passes aLogitsProcessorListand suppliesfull_input_idsat
candidate_generator.py:1529—so it is a trap for direct construction only. The tests in #48002 pass anexplicit
LogitsProcessorList()for this reason. Falling back tonext_token_logits, or making theargument required, would both do.
AI-assisted: found and written up with Claude Code; both claims re-checked against
mainbefore filing.