Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add MiniCPM3#41116

Merged
vasqu merged 11 commits into
huggingface:mainfrom
bzantium:feature/#41115
Jun 23, 2026
Merged

Add MiniCPM3#41116
vasqu merged 11 commits into
huggingface:mainfrom
bzantium:feature/#41115

Conversation

@bzantium

@bzantium bzantium commented Sep 24, 2025

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds native support for the MiniCPM3 architecture from OpenBMB
(openbmb/MiniCPM3-4B).

MiniCPM3 combines:

  • Multi-head Latent Attention (MLA) from DeepSeek-V2, with the original cos/sin rotary embedding convention preserved on the rotary part of the query/key heads.
  • A standard SwiGLU MLP (no MoE).
  • Three scalar scaling factors:
    • scale_emb — multiplier on input embeddings.
    • scale_depth / sqrt(num_hidden_layers) — multiplier on residual connections.
    • hidden_size / dim_model_base — divisor on hidden states before the LM head.

When scale_depth / dim_model_base are not provided, they default to no-op values (sqrt(num_hidden_layers) and hidden_size respectively).

Implemented as a single modular_minicpm3.py deriving from LlamaConfig / LlamaModel, with a custom MiniCPM3Attention for MLA. The model reuses the upstream LlamaTokenizer (no new tokenizer files); minicpm3 is added to MODELS_WITH_INCORRECT_HUB_TOKENIZER_CLASS so the auto loader falls back to TokenizersBackend. AutoConfig / AutoModel / AutoModelForCausalLM / AutoModelForSequenceClassification mappings, docs, and tests are wired up.

Fixes #41115.

A second, more recent PR (#45613) covers the same model. This PR (#41116) is the original; the implementations differ on the RoPE convention (this one preserves the original cos/sin RoPE; #45613 uses DeepSeek-V2's complex RoPE) and on a few config defaults.

AI assistance was used during the rebase/refactor; the changes have been reviewed and tested locally end-to-end (see follow-up comment for the example run on openbmb/MiniCPM3-4B).

Before submitting

  • This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
  • Did you read the contributor guideline,
    Pull Request section?
  • Was this discussed/approved via a Github issue or the forum? Please add a link
    to it if that's the case. — Add Model Architecture for MiniCPM3 #41115
  • Did you make sure to update the documentation with your changes?
  • Did you write any new necessary tests?

Who can review?

@ArthurZucker @Cyrilvallez

@Rocketknight1

Copy link
Copy Markdown
Member

cc @ArthurZucker for text models

@bzantium

bzantium commented Oct 1, 2025

Copy link
Copy Markdown
Contributor Author

@ArthurZucker please check this out! I've tested with MiniCPM3-4B and it worked well.

@bzantium

bzantium commented Oct 9, 2025

Copy link
Copy Markdown
Contributor Author

@ArthurZucker I've tested MiniCPM3-4B and our in-house model for the case q_lora_rank is None. Please review this when you are available and let me know if more needed! thanks a lot :) I hope this can be merged because we are going to open-weights one of models using this modeling in the near future.

@bzantium

bzantium commented Apr 29, 2026

Copy link
Copy Markdown
Contributor Author

End-to-end check on openbmb/MiniCPM3-4B:

import torch
from transformers import AutoTokenizer, MiniCPM3ForCausalLM

tokenizer = AutoTokenizer.from_pretrained("openbmb/MiniCPM3-4B")
model = MiniCPM3ForCausalLM.from_pretrained(
    "openbmb/MiniCPM3-4B",
    dtype=torch.float16,
    device_map="auto",
    attn_implementation="eager",
).eval()

messages = [{"role": "user", "content": "Tell me a fun fact about the Eiffel Tower."}]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = tokenizer(text, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=80, do_sample=False)
print(tokenizer.decode(out[0], skip_special_tokens=True))

Output:

user
Tell me a fun fact about the Eiffel Tower.
 assistant
The Eiffel Tower was originally intended to be a temporary structure, designed for the 1889 World's Fair to celebrate the 100th anniversary of the French Revolution. It was meant to be a symbol of the Industrial Revolution and a demonstration of France's engineering prowess. However, it was so popular that it was allowed to stand after the Fair. It

@bzantium

Copy link
Copy Markdown
Contributor Author

@aliyevaladddin Sorry I missed your email earlier. I just rebased this PR, would be happy to add you as coauthor since your message got me to come back to it.

bzantium and others added 2 commits April 29, 2026 16:02
Adds support for the OpenBMB MiniCPM3 architecture (e.g.
`openbmb/MiniCPM3-4B`). MiniCPM3 combines Multi-head Latent
Attention (MLA) from DeepSeek-V2 with a standard SwiGLU MLP and
three scalar scaling factors that govern signal flow:

- `scale_emb` scales input embeddings.
- `scale_depth / sqrt(num_hidden_layers)` scales residual
  connections.
- `hidden_size / dim_model_base` scales hidden states before the
  language-model head.

The implementation follows the modular pattern, deriving the config
and model from `LlamaConfig` / `LlamaModel`. The MLA attention
keeps the cos/sin rotary convention used by the original
implementation, registered classes are wired into the auto
mappings, and `tokenizer_auto` is updated so the upstream tokenizer
falls back to the tokenizers backend.

Verified with `openbmb/MiniCPM3-4B` end-to-end: weights load
without missing/mismatched keys and greedy generation produces a
coherent reply via `attn_implementation="eager"`.

Co-authored-by: Aladdin Aliyev <[email protected]>
`scale_depth=1.0` and `dim_model_base=1` make the residual and
logit scalings collapse, which prevented the small tester model
from training and broke the `test_training_overfit` CI job.

Mirror the original MiniCPM3 defaults: when not provided,
`scale_depth` falls back to `sqrt(num_hidden_layers)` and
`dim_model_base` falls back to `hidden_size`, so both factors
become exact no-ops. Drop the explicit overrides in
`MiniCPM3ModelTester` so the small test config inherits the new
defaults.

The real `openbmb/MiniCPM3-4B` config is unaffected: it sets
all three scalars explicitly.

Co-authored-by: Aladdin Aliyev <[email protected]>
@bzantium

Copy link
Copy Markdown
Contributor Author

@ArthurZucker @Cyrilvallez when you have a moment, would appreciate a review on this. Thanks!

@aliyevaladddin

Copy link
Copy Markdown
Contributor

Thanks for the rebase, @bzantium! I'm honored to be added as a co-author. I'm really excited to see MiniCPM3 support getting closer to being merged. Let me know if there's anything else I can help with regarding testing or further updates!

@vasqu

vasqu commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Will try to take a look today 🤗

@vasqu vasqu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial comments from my side 🫡

Comment thread docs/source/en/model_doc/minicpm3.md Outdated
Comment thread docs/source/en/model_doc/minicpm3.md Outdated
Comment thread docs/source/en/model_doc/minicpm3.md Outdated
Comment thread src/transformers/models/minicpm3/__init__.py Outdated
Comment thread src/transformers/models/minicpm3/modular_minicpm3.py Outdated
Comment thread src/transformers/models/minicpm3/modular_minicpm3.py Outdated
Comment thread src/transformers/models/minicpm3/modular_minicpm3.py Outdated
Comment thread tests/models/minicpm3/test_modeling_minicpm3.py Outdated
Comment thread tests/models/minicpm3/test_modeling_minicpm3.py Outdated
Comment thread tests/models/minicpm3/test_modeling_minicpm3.py
bzantium added 2 commits June 17, 2026 11:23
- MiniCPM3Attention now inherits DeepseekV2Attention and overrides only
  forward (cos/sin RoPE instead of DeepSeek-V2's complex rotary), removing
  the duplicated MLA __init__. Forward output is numerically identical.
- Drop config fields that match LlamaConfig defaults; keep only the ones
  that differ plus the MLA/scaling extras.
- Remove the validate_architecture override so the standard Llama
  divisibility check applies, matching dsv2/dsv3.
- Precompute the residual depth scaling per layer; expose the logit
  scaling as a config property; add comments highlighting the diffs from
  Llama (embedding, residual, logit scalings).
- Bump copyright years to 2026; use AutoModelForCausalLM in the docs
  example; drop the MoE-oriented test_all_params_have_gradient flag.
- Rework integration tests to the value-based Expectations pattern
  (expected logits/text to be filled from a CI reference run).
…1115

# Conflicts:
#	docs/source/en/_toctree.yml
#	src/transformers/models/auto/modeling_auto.py
@github-actions

Copy link
Copy Markdown
Contributor

View the CircleCI Test Summary for this PR:

https://huggingface.co/spaces/transformers-community/circle-ci-viz?pr=41116&sha=42b80e

Update the date line to the current "published in HF papers on ... and
contributed to ..." format expected by utils/add_dates.py, fixing the
check_repository_consistency failure.

@vasqu vasqu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some small comments but overall lgtm. Let me update the CI tomorrow then after you fixed the last comments 🫡

Comment thread src/transformers/models/minicpm3/modular_minicpm3.py Outdated
Comment thread src/transformers/models/minicpm3/modular_minicpm3.py Outdated
Comment thread src/transformers/models/minicpm3/modular_minicpm3.py
Comment thread src/transformers/models/minicpm3/modular_minicpm3.py Outdated
Comment thread tests/models/minicpm3/test_modeling_minicpm3.py
Comment thread tests/models/minicpm3/test_modeling_minicpm3.py Outdated
@vasqu

vasqu commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

We also need to sync with main and fix CI please

…tion values

- Default config to the openbmb/MiniCPM3-4B checkpoint values (scale_emb=12,
  scale_depth=1.4, dim_model_base=256); no-op scaling only when set to None.
- Drop redundant keys_to_ignore_at_inference (inherited from LlamaConfig).
- Move embedding scaling into MiniCPM3ScaledWordEmbedding so input_ids and
  inputs_embeds paths stay consistent (fixes inputs_embeds-vs-input_ids tests).
- Remove redundant self_attn assignment in the decoder layer (modular renames it).
- Highlight the MLA RoPE diff vs DeepSeek-V2/V3 with a comment.
- Fill integration test Expectations with verified A100 (bf16) reference values.
@bzantium

bzantium commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

@vasqu

The security-gate / security-check failure comes from the "Enforce allowlist" step. The only offending file is docs/source/en/_toctree.yml, which the gate rejects because .yml is not allowed outside tests/ (only .py, .txt, .md are permitted there). That _toctree.yml entry is required to register MiniCPM3 in the docs navigation, so it cannot be dropped.

This gate only runs for fork PRs, and the failure comment notes that a maintainer can manually approve CI when a finding is a false positive. Could you approve CI when you get a chance? All 11 other changed files pass the allowlist. Thanks!

MiniCPM3 uses MLA (inherited from DeepSeek-V2), so the query/key head dim
(qk_nope + qk_rope) differs from the value head dim. PyTorch's flash kernel
requires q, k, v to share the same last dim, so SDPA cannot dispatch on flash.
Skip the test as DeepSeek-V3 already does for the same reason.
@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution 🤗!

CI Security Gate — automatic approval blocked

This PR was not automatically approved for CI because the security gate failed.

Possible reasons:

  • A changed file is outside the allowed directories (src/, tests/, docs/, utils/) or has a disallowed extension (only .py, .txt, .md are permitted outside tests/)
  • A new high-severity security issue was detected in the changed Python files (Bandit check)

See the workflow run for the exact violations.

A maintainer can review and manually approve CI if a finding is a false positive.

Comment thread src/transformers/models/minicpm3/modular_minicpm3.py Outdated

@vasqu vasqu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, the logits differ quite a bit from 8 to 8.6 so just wanna make sure if you can check that I didnt break anything

@vasqu

vasqu commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

gentle ping @bzantium

@github-actions

Copy link
Copy Markdown
Contributor

[For maintainers] Suggested jobs to run (before merge)

run-slow: auto, minicpm3

@bzantium

Copy link
Copy Markdown
Contributor Author

@vasqu Thanks for the careful check! I verified on an A100 (compute capability 8.0, same hardware the ("cuda", 8) reference came from) using the current branch, which includes your modular cleanup. Nothing is broken.

bf16 reproduction (A100, cc 8.0):

slice : [0.765625, 3.640625, -0.189453, -0.835938, -0.835938]
ref   : [0.765625, 3.640625, -0.189453125, -0.8359375, -0.8359375]
diff  : [0, 0, 0, 0, 0]   # exact match

So your refactor (inheriting Gemma3TextScaledWordEmbedding and dropping the duplicated MiniCPM3Model.forward) is numerically a no op. That matches the code too: the new embedding base is identical to the old one, and the removed forward was a verbatim copy of the inherited LlamaModel.forward.

On the 8 vs 8.6 gap: both buckets run bf16 (the config torch_dtype is bfloat16, and the test loads with dtype="auto"), so the difference is purely cross GPU bf16 variation, not a dtype or code change. These particular logits sit near zero and the model is 62 layers deep, so bf16 rounding accumulates and the low magnitude entries wobble. To put a number on it, I also ran fp32 as a ground truth on the same A100:

fp32  : [0.535951, 3.610042, -0.174161, -1.174419, -1.174420]

The bf16 vs fp32 gap reaches about 0.34, which is larger than the 8.0 vs 8.6 gap of about 0.08. Most importantly, the argmax token is 11213 in bf16 and fp32 alike, so the actual prediction is stable across precision and only the near zero logit tail moves.

Net: your (8, 6) bucket is a legitimate per hardware entry and the existing (8) reference still reproduces exactly. No regression. Good to go from my side.

@vasqu

vasqu commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

run-slow: minicpm3

@vasqu

vasqu commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Just sanity checking but should be good to go then 🫡

@github-actions

Copy link
Copy Markdown
Contributor

Workflow Run ⚙️

This comment contains run-slow, running the specified jobs:

models: ["models/minicpm3"]
quantizations: []

@github-actions

Copy link
Copy Markdown
Contributor

CI Results

Workflow Run ⚙️

Commit Info

Context Commit Description
RUN bc3a358c workflow commit (merge commit)
PR baf1d586 branch commit (from PR)
main 43639365 base commit (on main)

✅ No failing test specific to this PR 🎉 👏 !

@HuggingFaceDocBuilderDev

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@vasqu vasqu added this pull request to the merge queue Jun 23, 2026
Merged via the queue into huggingface:main with commit 8964b4b Jun 23, 2026
104 checks passed
@vasqu

vasqu commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Nice thanks for sticking through and gz on the merge 🤗

@aliyevaladddin

Copy link
Copy Markdown
Contributor

Finaly!

@bzantium bzantium deleted the feature/#41115 branch June 24, 2026 03:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Model Architecture for MiniCPM3

6 participants