Skip to content

Commit b5e1cb8

Browse files
remi-orCyrilvallez
andauthored
Add Mistral Large 4 (#50121)
* Mappings * Modular converter tmp fix * Modular first draft * Fix Rope modular * Indexer * Fix pretrained and modular * Fix dims * Conversion mappings * Nits * Thread shared_kv_... * Fix softmaxscaling * Missing layer type * Nope in indexer fix * Missing cache * Config update * Conversion, start * Inversed mapping * Fix config * Next step in converter * Fix kv sgaring * softcapping * missing converter * Add quantization conversion * processor * Conversion script * Fix conversions for permuted rope * Nits * Conversion otkenizer ihappens before config * Fixes * Fix routing not in fp32 * Resolve some TODOs * Re-wire indexer * Reorganization * Modular nits * Style * Fix * Fix repo * Doc * Review 1/n * Disable test of text model only * Fix modular converter broken in rebase and run it * Update to fit new cfg setup * Remove norm_topk_prob and add the gate weights to the keep_in_fp32 list of modules * Refactor conversion script * Fix RoPE conversion bug * Fix different name scales bug * Review * Fix for a problem that will never happen * Tests, lacking integration tests * Fix missing router logits * Move logits softcapping o the text config * Style * Fix repo * Init alpha to zeros * revert cache -> crop should not be called of uninitialized * use consolidated.safetensors natively, no new index * add dtype to config for auto dtype * fix * do not shard the attn for now * remove the hack, I fixed it upstream * MAke alpha a buffer * fix exporter tests * Nits * ignore * style * this was upstreamed --------- Co-authored-by: Cyril Vallez <cyril.vallez@gmail.com>
1 parent caa0e6c commit b5e1cb8

22 files changed

Lines changed: 3063 additions & 5 deletions

‎docs/source/en/_toctree.yml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,8 @@
14631463
title: MiniCPM-V
14641464
- local: model_doc/minicpmv4_7
14651465
title: MiniCPM-V 4.7
1466+
- local: model_doc/mistral_large4
1467+
title: Mistral Large 4
14661468
- local: model_doc/mistral3
14671469
title: Mistral3
14681470
- local: model_doc/mistral4
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<!--Copyright 2026 the HuggingFace Team. All rights reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
15+
⚠️ Note that this file is in Markdown but contains specific syntax for our doc-builder (similar to MDX) that may not be rendered properly in your Markdown viewer.
16+
17+
-->
18+
*This model was contributed to Hugging Face Transformers on 2026-10-29.*
19+
20+
<div style="float: right;">
21+
<div class="flex flex-wrap space-x-1">
22+
<img alt="SDPA" src="https://img.shields.io/badge/SDPA-DE3412?style=flat&logo=pytorch&logoColor=white">
23+
</div>
24+
</div>
25+
26+
# Mistral Large 4
27+
28+
## Overview
29+
30+
Mistral Large 4 is a natively multimodal mixture-of-experts model with 1 trillion parameters and 49 billion active
31+
parameters per token (52 billion including the embeddings and the output layer). It takes text and images as input,
32+
produces text, and can answer directly or reason first, with the reasoning effort set per request.
33+
34+
The text decoder builds on the DeepSeek-V3.2 recipe (Multi-head Latent Attention made sparse by a DSA indexer) and adds
35+
a few changes of its own:
36+
37+
- **Attention**: 72 layers of Deepseek Sparse Attention (DSA) with a 512-dimensional KV latent, made sparse by an
38+
indexer selecting the top 2048 key positions for each query. Queries use a direct projection, there is no Q-LoRA.
39+
Some layers compute their own selection, the others reuse the one of a previous layer (`"shared"`) like in
40+
[GLM-5](./glm_moe_dsa).
41+
- **NoPE layers**: every 4th layer uses no rotary embedding, in the attention and in the indexer.
42+
- **KV sharing**: from layer 39 and on, every 4th layer does not compute a KV latent, instead attending to the one of
43+
layer 35. They keep their own query, KV up-projection and output weights.
44+
- **Scaled softmax**: queries are scaled per head by `s * log(position + 1) + b`, with learned `s` and `b`, in the
45+
attention and in the indexer.
46+
- **LeRoPE**: YaRN extends the 512-token base RoPE by a factor of 2048 (1,048,576 positions), and LeRoPE adds a
47+
learned multiplier per rotary frequency.
48+
- **MoE**: the first layer is dense, every other layer routes each token to 4 of 128 experts, plus one shared expert.
49+
- **Logits**: final logits are soft-capped with `30 * tanh(logits / 30)`.
50+
51+
The vision encoder and the multimodal projector are the same as in [Mistral 3](./mistral3) (Pixtral encoder with a
52+
patch-merge projector).
53+
54+
## Usage examples
55+
56+
The checkpoint is stored in FP8 (128x128 block-scaled weights with dynamic activation scales) and is loaded as is.
57+
The full model needs about 1 TB of GPU memory, so `device_map="auto"` is used to spread it across several GPUs.
58+
59+
The chat template accepts a `reasoning_effort` argument, set to `"none"` (default) or `"high"`. With `"high"`, the model
60+
writes its reasoning between `[THINK]` and `[/THINK]` before answering.
61+
62+
<hfoptions id="usage">
63+
<hfoption id="Image and text">
64+
65+
```python
66+
from transformers import AutoProcessor, MistralLarge4ForConditionalGeneration
67+
68+
model_id = "mistralai/Mistral-Large-4-1T-A52B"
69+
70+
processor = AutoProcessor.from_pretrained(model_id)
71+
model = MistralLarge4ForConditionalGeneration.from_pretrained(model_id, device_map="auto")
72+
73+
messages = [
74+
{
75+
"role": "user",
76+
"content": [
77+
{"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"},
78+
{"type": "text", "text": "Describe this image."},
79+
],
80+
},
81+
]
82+
83+
inputs = processor.apply_chat_template(
84+
messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt"
85+
).to(model.device)
86+
87+
output = model.generate(**inputs, max_new_tokens=256)
88+
print(processor.decode(output[0, inputs["input_ids"].shape[1] :], skip_special_tokens=True))
89+
```
90+
91+
</hfoption>
92+
<hfoption id="Reasoning">
93+
94+
```python
95+
from transformers import AutoProcessor, MistralLarge4ForConditionalGeneration
96+
97+
model_id = "mistralai/Mistral-Large-4-1T-A52B"
98+
99+
processor = AutoProcessor.from_pretrained(model_id)
100+
model = MistralLarge4ForConditionalGeneration.from_pretrained(model_id, device_map="auto")
101+
102+
messages = [{"role": "user", "content": "How many prime numbers are there between 100 and 150?"}]
103+
104+
inputs = processor.apply_chat_template(
105+
messages,
106+
add_generation_prompt=True,
107+
tokenize=True,
108+
return_dict=True,
109+
return_tensors="pt",
110+
reasoning_effort="high",
111+
).to(model.device)
112+
113+
output = model.generate(**inputs, max_new_tokens=4096)
114+
# Keep the special tokens to see the reasoning between [THINK] and [/THINK]
115+
print(processor.decode(output[0, inputs["input_ids"].shape[1] :], skip_special_tokens=False))
116+
```
117+
118+
</hfoption>
119+
</hfoptions>
120+
121+
## Notes
122+
123+
- The checkpoint also contains a draft head for speculative decoding (the `mtp_dspark.*` weights) using the DSpark
124+
speculative decoding method. <!-- TODO: implement DSpark or specify this is not supported -->
125+
- The DSA indexer is applied as an attention mask on top of dense attention, with the `eager` and `sdpa` backends.
126+
It gives the same outputs as sparse attention but not its speed-up on long sequences.
127+
<!--
128+
TODO: ask tokenizer people about this
129+
- The tokenizer reads a literal `[INST]` typed in a user message as the control token, while the reference
130+
[mistral-common](https://github.com/mistralai/mistral-common) tokenizer keeps it as plain text. -->
131+
132+
## MistralLarge4Config
133+
134+
[[autodoc]] MistralLarge4Config
135+
136+
## MistralLarge4TextConfig
137+
138+
[[autodoc]] MistralLarge4TextConfig
139+
140+
## MistralLarge4PreTrainedModel
141+
142+
[[autodoc]] MistralLarge4PreTrainedModel
143+
144+
## MistralLarge4TextModel
145+
146+
[[autodoc]] MistralLarge4TextModel
147+
- forward
148+
149+
## MistralLarge4Model
150+
151+
[[autodoc]] MistralLarge4Model
152+
- forward
153+
154+
## MistralLarge4ForConditionalGeneration
155+
156+
[[autodoc]] MistralLarge4ForConditionalGeneration
157+
- forward

‎src/transformers/conversion_mapping.py‎

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2318,6 +2318,71 @@ def _build_checkpoint_conversion_mapping():
23182318
),
23192319
]
23202320

2321+
mapping["mistral_large4"] = [
2322+
# Dispatch the root vision_encoder to the vision model
2323+
WeightRenaming(r"^vision_encoder\.", "model.vision_tower."),
2324+
# Dispatch the root language modules to the language model
2325+
WeightRenaming(r"^tok_embeddings\.", "model.language_model.embed_tokens."),
2326+
WeightRenaming(r"^lerope\.alpha", "model.language_model.rotary_emb.alpha"),
2327+
WeightRenaming(r"^layers\.", "model.language_model.layers."),
2328+
WeightRenaming(r"^norm\.", "model.language_model.norm."),
2329+
# And the rest to the multi-modal projector
2330+
WeightRenaming(r"^output\.", "lm_head."),
2331+
WeightRenaming(r"^pre_mm_projector_norm\.", "model.multi_modal_projector.norm."),
2332+
WeightRenaming(r"^patch_merger\.", "model.multi_modal_projector.patch_merger."),
2333+
WeightRenaming(r"^vision_language_adapter\.w_in\.", "model.multi_modal_projector.linear_1."),
2334+
WeightRenaming(r"^vision_language_adapter\.w_out\.", "model.multi_modal_projector.linear_2."),
2335+
# Rename the attention projections shared by both towers: value and output
2336+
WeightRenaming(r"\.wv\.", ".v_proj."),
2337+
WeightRenaming(r"\.wo\.", ".o_proj."),
2338+
# Same for up, down and gate projection weights (except for routed experts' which will be handled by converters)
2339+
WeightRenaming(r"\.(feed_forward|shared_experts)\.w1\.", r".\1.gate_proj."),
2340+
WeightRenaming(r"\.(feed_forward|shared_experts)\.w2\.", r".\1.down_proj."),
2341+
WeightRenaming(r"\.(feed_forward|shared_experts)\.w3\.", r".\1.up_proj."),
2342+
# Vision model Q and K projectors: saved for interleaved RoPE, Pixtral expects rotate-half
2343+
WeightConverter(
2344+
source_patterns=r"attention\.wq\.",
2345+
target_patterns="attention.q_proj.",
2346+
operations=[PermuteForRope(subconfig_key="vision_config")],
2347+
),
2348+
WeightConverter(
2349+
source_patterns=r"attention\.wk\.",
2350+
target_patterns="attention.k_proj.",
2351+
operations=[PermuteForRope(subconfig_key="vision_config")],
2352+
),
2353+
]
2354+
mapping["mistral_large4_text"] = [
2355+
# Rename attention modules (the indexer keeps wk, wq_b, and weights_proj)
2356+
WeightRenaming(r"\.attention\.", r"\.self_attn\."),
2357+
WeightRenaming(r"\.wq\.", ".q_proj."),
2358+
WeightRenaming(r"\.wkv_a_with_mqa\.", r"\.kv_a_proj_with_mqa\."),
2359+
WeightRenaming(r"\.wkv_b\.", ".kv_b_proj."),
2360+
# Rename the norms
2361+
WeightRenaming(r"\.attention_norm\.", r"\.input_layernorm\."),
2362+
WeightRenaming(r"\.ffn_norm\.", r"\.post_attention_layernorm\."),
2363+
WeightRenaming(r"\.kv_a_norm\.", r"\.kv_a_layernorm\."),
2364+
# Rename MLPs and MoEs to the "mlp" prefix
2365+
WeightRenaming(r"\.feed_forward\.", r"\.mlp\."),
2366+
WeightRenaming(r"\.gate\.", r"\.mlp.gate\."),
2367+
WeightRenaming(r"\.experts\.", r"\.mlp.experts\."),
2368+
WeightRenaming(r"\.shared_experts\.", r"\.mlp.shared_experts\."),
2369+
# Rename softmax scaling module
2370+
WeightRenaming(r"\.ssmax_scaling.s", r"\.softmax_scaling.scale"),
2371+
WeightRenaming(r"\.ssmax_scaling.b", r"\.softmax_scaling.bias"),
2372+
# Concatenate w1 (gate) and w3 (up) weights into a single weight and merge across experts
2373+
WeightConverter(
2374+
source_patterns=[r"\.experts.*.w1.weight", r"\.experts.*.w3.weight"],
2375+
target_patterns=r"\.experts.gate_up_proj",
2376+
operations=[MergeModulelist(dim=0), Concatenate(dim=1)],
2377+
),
2378+
# Merge w2 (down) weights across experts
2379+
WeightConverter(
2380+
source_patterns=r"\.experts.*.w2.weight",
2381+
target_patterns=r"\.experts.down_proj",
2382+
operations=[MergeModulelist(dim=0)],
2383+
),
2384+
]
2385+
23212386
for model_type, base_pattern in _MODEL_TO_CONVERSION_PATTERN.items():
23222387
if model_type in mapping:
23232388
continue

‎src/transformers/models/__init__.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@
308308
from .mistral import *
309309
from .mistral3 import *
310310
from .mistral4 import *
311+
from .mistral_large4 import *
311312
from .mixtral import *
312313
from .mlcd import *
313314
from .mllama import *

‎src/transformers/models/auto/auto_mappings.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,8 @@
423423
("mistral", "MistralConfig"),
424424
("mistral3", "Mistral3Config"),
425425
("mistral4", "Mistral4Config"),
426+
("mistral_large4", "MistralLarge4Config"),
427+
("mistral_large4_text", "MistralLarge4TextConfig"),
426428
("mixtral", "MixtralConfig"),
427429
("mlcd_vision_model", "MLCDVisionConfig"),
428430
("mllama", "MllamaConfig"),
@@ -948,6 +950,7 @@
948950
("minicpmv4_7_vision", "minicpmv4_7"),
949951
("minimax_m3_vl_text", "minimax_m3_vl"),
950952
("minimax_m3_vl_vision", "minimax_m3_vl"),
953+
("mistral_large4_text", "mistral_large4"),
951954
("mlcd_vision_model", "mlcd"),
952955
("mllama_text_model", "mllama"),
953956
("mllama_vision_model", "mllama"),

‎src/transformers/models/auto/image_processing_auto.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
("mgp-str", {"torchvision": "ViTImageProcessor", "pil": "ViTImageProcessorPil"}),
119119
("minicpmv4_7", {"pil": "MiniCPMV4_6ImageProcessorPil", "torchvision": "MiniCPMV4_6ImageProcessor"}),
120120
("mistral3", {"torchvision": "PixtralImageProcessor", "pil": "PixtralImageProcessorPil"}),
121+
("mistral_large4", {"torchvision": "PixtralImageProcessor", "pil": "PixtralImageProcessorPil"}),
121122
("mlcd", {"torchvision": "CLIPImageProcessor", "pil": "CLIPImageProcessorPil"}),
122123
(
123124
"mm-grounding-dino",

‎src/transformers/models/auto/modeling_auto.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ class _BaseModelWithGenerate(PreTrainedModel, GenerationMixin):
356356
("mistral", "MistralModel"),
357357
("mistral3", "Mistral3Model"),
358358
("mistral4", "Mistral4Model"),
359+
("mistral_large4", "MistralLarge4Model"),
360+
("mistral_large4_text", "MistralLarge4TextModel"),
359361
("mixtral", "MixtralModel"),
360362
("mlcd", "MLCDVisionModel"), # Keep this to make some original hub repositories (from `DeepGlint-AI`) works
361363
("mlcd_vision_model", "MLCDVisionModel"),
@@ -693,6 +695,7 @@ class _BaseModelWithGenerate(PreTrainedModel, GenerationMixin):
693695
("megatron-bert", "MegatronBertForPreTraining"),
694696
("mistral3", "Mistral3ForConditionalGeneration"),
695697
("mistral4", "Mistral4ForCausalLM"),
698+
("mistral_large4", "MistralLarge4ForConditionalGeneration"),
696699
("mllama", "MllamaForConditionalGeneration"),
697700
("mobilebert", "MobileBertForPreTraining"),
698701
("moss_transcribe_diarize", "MossTranscribeDiarizeForConditionalGeneration"),
@@ -1196,6 +1199,7 @@ class _BaseModelWithGenerate(PreTrainedModel, GenerationMixin):
11961199
("minimax_m3_vl", "MiniMaxM3SparseForConditionalGeneration"),
11971200
("mistral3", "Mistral3ForConditionalGeneration"),
11981201
("mistral4", "Mistral4ForCausalLM"),
1202+
("mistral_large4", "MistralLarge4ForConditionalGeneration"),
11991203
("mllama", "MllamaForConditionalGeneration"),
12001204
("molmo2", "Molmo2ForConditionalGeneration"),
12011205
("muse_glimmer", "MuseGlimmerForConditionalGeneration"),

‎src/transformers/models/auto/processing_auto.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
("lasr_encoder", "LasrProcessor"),
7171
("metaclip_2", "CLIPProcessor"),
7272
("mistral3", "PixtralProcessor"),
73+
("mistral_large4", "PixtralProcessor"),
7374
("mm-grounding-dino", "GroundingDinoProcessor"),
7475
("modernvbert", "Idefics3Processor"),
7576
("moonshine", "Wav2Vec2Processor"),

‎src/transformers/models/auto/tokenization_auto.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,12 @@
229229
if is_mistral_common_available()
230230
else ("TokenizersBackend" if is_tokenizers_available() else None),
231231
),
232+
(
233+
"mistral_large4",
234+
"MistralCommonBackend"
235+
if is_mistral_common_available()
236+
else ("TokenizersBackend" if is_tokenizers_available() else None),
237+
), # TODO: needed?
232238
(
233239
"mixtral",
234240
"MistralCommonBackend"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
2+
# This file was automatically generated from the modules in `src/transformers/models/mistral_large4`.
3+
# Do NOT edit this file manually as any edits will be overwritten by auto-generation of the file.
4+
# A module is picked up once it exports a name through `__all__`.
5+
# Regenerate the file with: `python utils/check_inits.py --fix_and_overwrite`
6+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
7+
# Copyright 2026 the HuggingFace Team. All rights reserved.
8+
#
9+
# Licensed under the Apache License, Version 2.0 (the "License");
10+
# you may not use this file except in compliance with the License.
11+
# You may obtain a copy of the License at
12+
#
13+
# http://www.apache.org/licenses/LICENSE-2.0
14+
#
15+
# Unless required by applicable law or agreed to in writing, software
16+
# distributed under the License is distributed on an "AS IS" BASIS,
17+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
# See the License for the specific language governing permissions and
19+
# limitations under the License.
20+
from typing import TYPE_CHECKING
21+
22+
from ...utils import _LazyModule
23+
from ...utils.import_utils import define_import_structure
24+
25+
26+
if TYPE_CHECKING:
27+
from .configuration_mistral_large4 import *
28+
from .modeling_mistral_large4 import *
29+
else:
30+
import sys
31+
32+
_file = globals()["__file__"]
33+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)

0 commit comments

Comments
 (0)