Safetensors
nemotron_labs_diffusion_image
custom_code
shufanlNvidia commited on
Commit
609fa8e
·
verified ·
1 Parent(s): 4cd6ecd

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
LICENSE ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ NVIDIA License
2
+
3
+ 1. Definitions
4
+
5
+ “Licensor” means any person or entity that distributes its Work.
6
+
7
+ “Work” means (a) the original work of authorship made available under this license,
8
+ which may include software, documentation, or other files, and (b) any additions to or
9
+ derivative works thereof that are made available under this license.
10
+
11
+ The terms “reproduce,” “reproduction,” “derivative works,” and “distribution” have the
12
+ meaning as provided under U.S. copyright law; provided, however, that for the purposes
13
+ of this license, derivative works shall not include works that remain separable from, or
14
+ merely link (or bind by name) to the interfaces of, the Work.
15
+
16
+ Works are “made available” under this license by including in or with the Work either
17
+ (a) a copyright notice referencing the applicability of this license to the Work, or
18
+ (b) a copy of this license.
19
+
20
+ 2. License Grant
21
+
22
+ 2.1 Copyright Grant. Subject to the terms and conditions of this license, each Licensor
23
+ grants to you a perpetual, worldwide, non-exclusive, royalty-free, copyright license to
24
+ use, reproduce, prepare derivative works of, publicly display, publicly perform,
25
+ sublicense and distribute its Work and any resulting derivative works in any form.
26
+
27
+ 3. Limitations
28
+
29
+ 3.1 Redistribution. You may reproduce or distribute the Work only if (a) you do so under
30
+ this license, (b) you include a complete copy of this license with your distribution,
31
+ and (c) you retain without modification any copyright, patent, trademark, or attribution
32
+ notices that are present in the Work.
33
+
34
+ 3.2 Derivative Works. You may specify that additional or different terms apply to the
35
+ use, reproduction, and distribution of your derivative works of the Work (“Your Terms”)
36
+ only if (a) Your Terms provide that the use limitation in Section 3.3 applies to your
37
+ derivative works, and (b) you identify the specific derivative works that are subject
38
+ to Your Terms. Notwithstanding Your Terms, this license (including the redistribution
39
+ requirements in Section 3.1) will continue to apply to the Work itself.
40
+
41
+ 3.3 Use Limitation. The Work and any derivative works thereof only may be used or
42
+ intended for use non-commercially. Notwithstanding the foregoing, NVIDIA Corporation
43
+ and its affiliates may use the Work and any derivative works commercially. As used
44
+ herein, “non-commercially” means for research or evaluation purposes only.
45
+
46
+ 3.4 Patent Claims. If you bring or threaten to bring a patent claim against any
47
+ Licensor (including any claim, cross-claim or counterclaim in a lawsuit) to enforce any
48
+ patents that you allege are infringed by any Work, then your rights under this license
49
+ from such Licensor (including the grant in Section 2.1) will terminate immediately.
50
+
51
+ 3.5 Trademarks. This license does not grant any rights to use any Licensor’s or its
52
+ affiliates’ names, logos, or trademarks, except as necessary to reproduce the notices
53
+ described in this license.
54
+
55
+ 3.6 Termination. If you violate any term of this license, then your rights under this
56
+ license (including the grant in Section 2.1) will terminate immediately.
57
+
58
+ 4. Disclaimer of Warranty.
59
+
60
+ THE WORK IS PROVIDED “AS IS” WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
61
+ EXPRESS OR IMPLIED, INCLUDING WARRANTIES OR CONDITIONS OF MERCHANTABILITY, FITNESS FOR
62
+ A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT. YOU BEAR THE RISK OF UNDERTAKING ANY
63
+ ACTIVITIES UNDER THIS LICENSE.
64
+
65
+ 5. Limitation of Liability.
66
+
67
+ EXCEPT AS PROHIBITED BY APPLICABLE LAW, IN NO EVENT AND UNDER NO LEGAL THEORY, WHETHER
68
+ IN TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE SHALL ANY LICENSOR BE LIABLE TO
69
+ YOU FOR DAMAGES, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
70
+ DAMAGES ARISING OUT OF OR RELATED TO THIS LICENSE, THE USE OR INABILITY TO USE THE WORK
71
+ (INCLUDING BUT NOT LIMITED TO LOSS OF GOODWILL, BUSINESS INTERRUPTION, LOST PROFITS OR
72
+ DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY OTHER DAMAGES OR LOSSES), EVEN IF THE
73
+ LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
README.md ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: other
3
+ license_name: nvidia-license
4
+ license_link: LICENSE
5
+ ---
6
+
7
+ # Model Overview
8
+
9
+ ## Description
10
+
11
+ NL-Diffusion-Image introduces a new paradigm for high-resolution text-to-image generation via LLM based on masked discrete diffusion over tokenized image patches.
12
+ Each image is encoded into a sequence of discrete tokens (using a 128K codebook/vocabulary), and generation proceeds through iterative parallel unmasking - similar to Diffusion LLMs.
13
+ We finetune from [Nemotron-Labs-Diffusion](https://huggingface.co/nvidia/Nemotron-Labs-Diffusion-8B) and introduce 2 key components:
14
+
15
+ * A token-editing mechanism that allows the model to revise already-unmasked tokens during inference.
16
+ * Grouped Cross-Entropy (GCE) objective to handle large-vocabulary training efficiently.
17
+
18
+ This model is ready for research or non-commercial evaluation.
19
+
20
+ ### License/Terms of Use
21
+
22
+ GOVERNING TERMS: Use of this model is governed by the [NVIDIA Open Source License Agreement](https://huggingface.co/nvidia/NL-Diffusion-Image/raw/main/LICENSE).
23
+
24
+ ## Deployment Geography
25
+
26
+ Global
27
+
28
+ ## Use Case
29
+
30
+ This model is intended for text-to-image generation.
31
+
32
+ ## Release Date
33
+
34
+ Hugging Face: 07/01/2026 via [HuggingFace](https://huggingface.co/nvidia/NL-Diffusion-Image).
35
+
36
+ ## References
37
+
38
+ * NL-Diffusion-Image Paper: Shufan Li et al., "Nemotron-Labs-Diffusion-Image: Advancing Masked Discrete Diffusion for High-Resolution Image Synthesis,".
39
+ * Nemotron-Labs-Diffusion Paper: Yonggan Fu et al., "Nemotron-Labs-Diffusion: A Tri-Mode Language Model Unifying Autoregressive, Diffusion, and Self-Speculation Decoding".
40
+ * Emu3.5 Paper: Emu3.5 team, "Emu3.5: Native Multimodal Models are World Learners".
41
+
42
+ ## Model Architecture
43
+
44
+ **Architecture Type:** Neural Network <br>
45
+ **Network Architecture:** Masked Diffusion Transformer, IBQ tokenizer for visual encoding/decoding <br>
46
+ **Number of model parameters:** ~8B parameters <br>
47
+
48
+ We encode 16x16 image patches using a pretrained discrete tokenizer from Emu3.5, with a codebook size of 128k token IDs.
49
+ We expand the Nemotron-Labs-Diffusion vocabulary with a corresponding number of randomly-initialized embeddings, and fine-tune the model on a dataset of image/caption pairs.
50
+
51
+ ## Input
52
+
53
+ **Input Type(s):** Text <br>
54
+ **Input Format(s):** Characters <br>
55
+ **Other Properties Related to Input:** Maximum prompt length is 900 tokens. <br>
56
+
57
+ ## Output
58
+
59
+ **Output Type(s):** Images <br>
60
+ **Output Format:** Tensor (3xHxW) <br>
61
+ **Other Properties Related to Output:** The output represents an RGB image. <br>
62
+
63
+ ## Software Integration
64
+
65
+ **Runtime Engine(s):**
66
+ * PyTorch <br>
67
+
68
+
69
+ **Supported Hardware Microarchitecture Compatibility:** <br>
70
+ * NVIDIA Ampere <br>
71
+ * NVIDIA Blackwell <br>
72
+ * NVIDIA Jetson <br>
73
+ * NVIDIA Hopper <br>
74
+ * NVIDIA Lovelace <br>
75
+ * NVIDIA Pascal <br>
76
+ * NVIDIA Turing <br>
77
+ * NVIDIA Volta <br>
78
+
79
+ **[Preferred/Supported] Operating System(s):** <br>
80
+ * Linux
81
+ * Linux 4 Tegra
82
+ * QNX
83
+ * Windows
84
+
85
+ The integration of foundation and fine-tuned models into AI systems requires additional testing using use-case-specific data to ensure safe and effective deployment.
86
+ Following the V-model methodology, iterative testing and validation at both unit and system levels are essential to mitigate risks, meet technical and functional requirements, and ensure compliance with safety and ethical standards before deployment.
87
+
88
+ This AI model can be embedded as an Application Programming Interface (API) call into the software environment described above.
89
+
90
+ ## Model Version(s)
91
+
92
+ * NL-Diffusion-Image (8B).
93
+
94
+ **Links:**
95
+
96
+ * https://huggingface.co/nvidia/NL-Diffusion-Image
97
+
98
+ # Training and Evaluation Datasets
99
+
100
+ ## Training Dataset
101
+
102
+ **LAION-115M-Clean Recaptioned**
103
+
104
+ **Data Modality:**
105
+ * Multimodal (image, caption)
106
+
107
+ **Image Training Data Size:**
108
+ * 115M samples
109
+
110
+ **Data Collection Method by dataset:**
111
+ * Web scraping
112
+
113
+ **Labeling Method by dataset:**
114
+ * Subset of 8M images recaptioned using Qwen3-VL
115
+
116
+ **MidJourney v6 520k Recaptioned**
117
+
118
+ **Data Modality:**
119
+ * Multimodal (image, caption)
120
+
121
+ **Image Training Data Size:**
122
+ * 520k samples
123
+
124
+ **Data Collection Method by dataset:**
125
+ * Automated
126
+
127
+ **Labeling Method by dataset:**
128
+ * Images recaptioned using Qwen3-VL
129
+
130
+ **COYO700M Recaptioned**
131
+
132
+ **Data Modality:**
133
+ * Multimodal (image, caption)
134
+
135
+ **Image Training Data Size:**
136
+ * 700M samples
137
+
138
+ **Data Collection Method by dataset:**
139
+ * Automated
140
+
141
+ **Labeling Method by dataset:**
142
+ * Subset of 24M images recaptioned using Qwen3-VL
143
+
144
+ **BLIP3o-60k Recaptioned**
145
+
146
+ **Data Modality:**
147
+ * Multimodal (image, caption)
148
+
149
+ **Image Training Data Size:**
150
+ * 520k samples
151
+
152
+ **Data Collection Method by dataset:**
153
+ * Automated
154
+
155
+ **Labeling Method by dataset:**
156
+ * Images recaptioned using Qwen3-VL
157
+
158
+ ## Evaluation Datasets
159
+
160
+ **ImageNet**
161
+
162
+ **Link:**
163
+ * [ImageNet](https://www.image-net.org/)
164
+
165
+ **Data Collection:**
166
+ * Automated
167
+
168
+ **Labeling Method:**
169
+ * Manually-Collected
170
+
171
+ **Training Images:**
172
+ * 1,281,167
173
+
174
+ **Validation Images:**
175
+ * 50,000
176
+
177
+ **GenEval**
178
+
179
+ **Link:**
180
+ * [GenEval](https://github.com/djghosh13/geneval)
181
+
182
+ **Data Collection:**
183
+ * Manually-Collected
184
+
185
+ **Labeling Method:**
186
+ * Manually-Collected
187
+
188
+ **Captions/annotations:**
189
+ * 553 samples
190
+
191
+ **DPGBench**
192
+
193
+ **Link:**
194
+ * [DPGBench](https://github.com/TencentQQGYLab/ELLA)
195
+
196
+ **Data Collection:**
197
+ * Manually-Collected
198
+
199
+ **Labeling Method:**
200
+ * Manually-Collected
201
+
202
+ **Captions/annotations:**
203
+ * 1065 samples
204
+
205
+ **MJHQ-30K**
206
+
207
+ **Link:**
208
+ * [MJHQ-30K](https://huggingface.co/datasets/playgroundai/MJHQ-30K/blob/main/README.md)
209
+
210
+ **Data Collection:**
211
+ * Manually-Collected
212
+
213
+ **Labeling Method:**
214
+ * Automated
215
+
216
+ **CaptionsImages:**
217
+ * 30k samples
218
+
219
+ ## GenEval Benchmark
220
+
221
+
222
+ | Model | Params | Single Object | Two Objects | Counting | Colors | Position | Color Attri. | Overall |
223
+ |------------|---------|-------------|-----------|-------------|--------|----------|--------------|---------|
224
+ | Qwen-Image-2507 | 20B | 0.99 | 0.92 | 0.89 | 0.88 | 0.76 | 0.77 | 0.87 |
225
+ | Nemotron-Labs-Diffusion-Image | 8B | 0.98 | 0.93 | 0.83 | 0.94 | 0.88 | 0.82 | 0.90 |
226
+
227
+ ## Text-to-Image Generation Performance on DPG Benchmark and MJHQ-30k Dataset
228
+
229
+ | Model | Params | Codebook | DPG | MJHQ FID | MJHQ HPSv3 |
230
+ |------------|--------|-----------|----|----------|-------------|
231
+ | MMaDa | 8B | 8,192 | 53.4 | 32.85 | 5.43 |
232
+ | LaViDa-O | 10B | 8,192 | 81.8 | 6.68 | 8.81 |
233
+ | Nemotron-Labs-Diffusion-Image | 8B | 131,072 | 85.2 | 6.46 | 9.61|
234
+ | Nemotron-Labs-Diffusion-Image*</sup> | 8B | 131,072 | 86.9 | 12.23 | 10.76 |
235
+
236
+ <sup>*</sup> Finetuned on 6M synthetic data for better image quality
237
+
238
+
239
+ ## Inference
240
+
241
+ **Acceleration Engine:** TensorRT, TensorRT-LLM <br>
242
+ **Engine:** PyTorch <br>
243
+ **Test Hardware:** NVIDIA Hopper (H100) <br>
244
+
245
+ ## Ethical Considerations
246
+
247
+ NVIDIA believes Trustworthy AI is a shared responsibility and we have established policies and practices to enable development for a wide array of AI applications. Developers should work with their internal model team to ensure this model meets requirements for the relevant industry and use case and addresses unforeseen product misuse.
248
+
249
+ Please make sure you have proper rights and permissions for all input image and video content; if image or video includes people, personal health information, or intellectual property, the image or video generated will not blur or maintain proportions of image subjects included.
250
+
251
+ For more detailed information on ethical considerations for this model, please see the Model Card++ Explainability, Bias, Safety & Security, and Privacy Subcards below.
252
+
253
+ Please report model quality, risk, security vulnerabilities or NVIDIA AI Concerns [here](https://www.nvidia.com/en-us/support/submit-security-vulnerability/).
254
+
255
+ ### Bias
256
+
257
+ Field | Response
258
+ :---------------------------------------------------------------------------------------------------|:---------------
259
+ Participation considerations from adversely impacted groups [protected classes](https://www.senate.ca.gov/content/protected-classes) in model design and testing: | None
260
+ Measures taken to mitigate against unwanted bias: | None
261
+ Bias Metric (If Measured): | None
262
+
263
+ ### Explainability
264
+
265
+ Field | Response
266
+ :------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------
267
+ Intended Task/Domain: | Text-to-image generation
268
+ Model Type: | Masked Diffusion Model
269
+ Intended Users: | Research
270
+ Output: | Images
271
+ Describe how the model works: | The model takes a caption as input and generated an image.
272
+ Name the adversely impacted groups this has been tested to deliver comparable outcomes regardless of: | Not Applicable
273
+ Technical Limitations: | The model generates images in a single resolution of 1024x1024 pixels.
274
+ Verified to have met prescribed NVIDIA quality standards: | Yes
275
+ Performance Metrics: | GenEVal, DPG, MJHQ.
276
+ Potential Known Risks: | This model may not perform well on visual domains that are not represented in the training data. The generated images might fail to disambiguate differences in prompts that appear evident to humans. Domain-specific evaluation is required for the target application.
277
+ Licensing: | [NVIDIA Open Source License](https://huggingface.co/nvidia/NL-Diffusion-Image/raw/main/LICENSE)
278
+
279
+
280
+ ### Privacy
281
+
282
+ Field | Response
283
+ :----------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------
284
+ Generatable or reverse engineerable personal data? | No
285
+ Personal data used to create this model? | No
286
+ How often is dataset reviewed? | Before Every Release
287
+ Is there provenance for all datasets used in training? | Yes
288
+ Does data labeling (annotation, metadata) comply with privacy laws? | Yes
289
+ Is data compliant with data subject requests for data correction or removal, if such a request was made? | Yes
290
+ Was data from user interactions with the AI model (e.g. user input and prompts) used to train the model? | No
291
+ Applicable Privacy Policy | https://www.nvidia.com/en-us/about-nvidia/privacy-policy/
292
+
293
+ ### Safety
294
+
295
+ Field | Response
296
+ :---------------------------------------------------|:----------------------------------
297
+ Model Application Field(s): | Generation of images
298
+ Describe the life critical impact (if present). | Not Applicable
299
+ Use Case Restrictions: | Research/evaluation only, non-commercial applications.
300
+ Model and dataset restrictions: | The Principle of least privilege (PoLP) is applied limiting access for dataset generation and model development. Restrictions enforce dataset access during training, and dataset license constraints adhered to.
chat_template.jinja ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% macro render_extra_keys(json_dict, handled_keys) %}
2
+ {%- if json_dict is mapping %}
3
+ {%- for json_key in json_dict if json_key not in handled_keys %}
4
+ {%- if json_dict[json_key] is mapping or (json_dict[json_key] is sequence and json_dict[json_key] is not string) %}
5
+ {{- '\n<' ~ json_key ~ '>' ~ (json_dict[json_key] | tojson | safe) ~ '</' ~ json_key ~ '>' }}
6
+ {%- else %}
7
+ {{-'\n<' ~ json_key ~ '>' ~ (json_dict[json_key] | string) ~ '</' ~ json_key ~ '>' }}
8
+ {%- endif %}
9
+ {%- endfor %}
10
+ {%- endif %}
11
+ {% endmacro %}
12
+ {%- set enable_thinking = enable_thinking if enable_thinking is defined else True %}
13
+ {%- set truncate_history_thinking = truncate_history_thinking if truncate_history_thinking is defined else True %}
14
+
15
+ {%- set ns = namespace(last_user_idx = -1) %}
16
+ {%- set loop_messages = messages %}
17
+ {%- for m in loop_messages %}
18
+ {%- if m["role"] == "user" %}
19
+ {%- set ns.last_user_idx = loop.index0 %}
20
+ {%- endif %}
21
+ {%- endfor %}
22
+
23
+ {%- if messages[0]["role"] == "system" %}
24
+ {%- set system_message = messages[0]["content"] %}
25
+ {%- set loop_messages = messages[1:] %}
26
+ {%- else %}
27
+ {%- set system_message = "" %}
28
+ {%- set loop_messages = messages %}
29
+ {%- endif %}
30
+ {%- if not tools is defined %}
31
+ {%- set tools = [] %}
32
+ {%- endif %}
33
+ {# Recompute last_user_idx relative to loop_messages after handling system #}
34
+ {%- set ns = namespace(last_user_idx = -1) %}
35
+ {%- for m in loop_messages %}
36
+ {%- if m["role"] == "user" %}
37
+ {%- set ns.last_user_idx = loop.index0 %}
38
+ {%- endif %}
39
+ {%- endfor %}
40
+ {%- if system_message is defined %}
41
+ {{- "<|im_start|>system\n" + system_message }}
42
+ {%- else %}
43
+ {%- if tools is iterable and tools | length > 0 %}
44
+ {{- "<|im_start|>system\n" }}
45
+ {%- endif %}
46
+ {%- endif %}
47
+ {%- if tools is iterable and tools | length > 0 %}
48
+ {%- if system_message is defined and system_message | length > 0 %}
49
+ {{- "\n\n" }}
50
+ {%- endif %}
51
+ {{- "# Tools\n\nYou have access to the following functions:\n\n" }}
52
+ {{- "<tools>" }}
53
+ {%- for tool in tools %}
54
+ {%- if tool.function is defined %}
55
+ {%- set tool = tool.function %}
56
+ {%- endif %}
57
+ {{- "\n<function>\n<name>" ~ tool.name ~ "</name>" }}
58
+ {%- if tool.description is defined %}
59
+ {{- '\n<description>' ~ (tool.description | trim) ~ '</description>' }}
60
+ {%- endif %}
61
+ {{- '\n<parameters>' }}
62
+ {%- if tool.parameters is defined and tool.parameters is mapping and tool.parameters.properties is defined and tool.parameters.properties is mapping %}
63
+ {%- for param_name, param_fields in tool.parameters.properties|items %}
64
+ {{- '\n<parameter>' }}
65
+ {{- '\n<name>' ~ param_name ~ '</name>' }}
66
+ {%- if param_fields.type is defined %}
67
+ {{- '\n<type>' ~ (param_fields.type | string) ~ '</type>' }}
68
+ {%- endif %}
69
+ {%- if param_fields.description is defined %}
70
+ {{- '\n<description>' ~ (param_fields.description | trim) ~ '</description>' }}
71
+ {%- endif %}
72
+ {%- if param_fields.enum is defined %}
73
+ {{- '\n<enum>' ~ (param_fields.enum | tojson | safe) ~ '</enum>' }}
74
+ {%- endif %}
75
+ {%- set handled_keys = ['name', 'type', 'description', 'enum'] %}
76
+ {{- render_extra_keys(param_fields, handled_keys) }}
77
+ {{- '\n</parameter>' }}
78
+ {%- endfor %}
79
+ {%- endif %}
80
+ {% set handled_keys = ['type', 'properties', 'required'] %}
81
+ {{- render_extra_keys(tool.parameters, handled_keys) }}
82
+ {%- if tool.parameters is defined and tool.parameters.required is defined %}
83
+ {{- '\n<required>' ~ (tool.parameters.required | tojson | safe) ~ '</required>' }}
84
+ {%- endif %}
85
+ {{- '\n</parameters>' }}
86
+ {%- set handled_keys = ['type', 'name', 'description', 'parameters'] %}
87
+ {{- render_extra_keys(tool, handled_keys) }}
88
+ {{- '\n</function>' }}
89
+ {%- endfor %}
90
+ {{- "\n</tools>" }}
91
+
92
+ {{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<tool_call>\n<function=example_function_name>\n<parameter=example_parameter_1>\nvalue_1\n</parameter>\n<parameter=example_parameter_2>\nThis is the value for the second parameter\nthat can span\nmultiple lines\n</parameter>\n</function>\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags\n- Required parameters MUST be specified\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\n</IMPORTANT>' }}
93
+ {%- endif %}
94
+
95
+
96
+ {%- if system_message is defined %}
97
+ {{- '<|im_end|>\n' }}
98
+ {%- else %}
99
+ {%- if tools is iterable and tools | length > 0 %}
100
+ {{- '<|im_end|>\n' }}
101
+ {%- endif %}
102
+ {%- endif %}
103
+
104
+ {%- for message in loop_messages %}
105
+ {%- if message.role == "assistant" %}
106
+ {# Add reasoning content in to content field for unified processing below. #}
107
+ {%- if message.reasoning_content is defined and message.reasoning_content is string and message.reasoning_content | trim | length > 0 %}
108
+ {%- set content = "<think>\n" ~ message.reasoning_content ~ "\n</think>\n" ~ (message.content | default('', true)) %}
109
+ {%- else %}
110
+ {%- set content = message.content | default('', true) %}
111
+ {%- if content is string -%}
112
+ {# Allow downstream logic to to take care of broken thought, only handle coherent reasoning here. #}
113
+ {%- if '<think>' not in content and '</think>' not in content -%}
114
+ {%- set content = "<think></think>" ~ content -%}
115
+ {%- endif -%}
116
+ {%- else -%}
117
+ {%- set content = content -%}
118
+ {%- endif -%}
119
+ {%- endif %}
120
+ {%- if message.tool_calls is defined and message.tool_calls is iterable and message.tool_calls | length > 0 %}
121
+ {# Assistant message has tool calls. #}
122
+ {{- '<|im_start|>assistant\n' }}
123
+ {%- set include_content = not (truncate_history_thinking and loop.index0 < ns.last_user_idx) %}
124
+ {%- if content is string and content | trim | length > 0 %}
125
+ {%- if include_content %}
126
+ {{- (content | trim) ~ '\n' -}}
127
+ {%- else %}
128
+ {%- set c = (content | string) %}
129
+ {%- if '</think>' in c %}
130
+ {# Keep only content after the last closing think. Also generation prompt causes this. #}
131
+ {%- set c = c.split('</think>')[-1] %}
132
+ {%- elif '<think>' in c %}
133
+ {# If <think> was opened but never closed, drop the trailing think segment #}
134
+ {%- set c = c.split('<think>')[0] %}
135
+ {%- endif %}
136
+ {%- set c = "<think></think>" ~ c | trim %}
137
+ {%- if c | length > 0 %}
138
+ {{- c ~ '\n' -}}
139
+ {%- endif %}
140
+ {%- endif %}
141
+ {%- else %}
142
+ {{- "<think></think>" -}}
143
+ {%- endif %}
144
+ {%- for tool_call in message.tool_calls %}
145
+ {%- if tool_call.function is defined %}
146
+ {%- set tool_call = tool_call.function %}
147
+ {%- endif %}
148
+ {{- '<tool_call>\n<function=' ~ tool_call.name ~ '>\n' -}}
149
+ {%- if tool_call.arguments is defined %}
150
+ {%- for args_name, args_value in tool_call.arguments|items %}
151
+ {{- '<parameter=' ~ args_name ~ '>\n' -}}
152
+ {%- set args_value = args_value | tojson | safe if args_value is mapping or (args_value is sequence and args_value is not string) else args_value | string %}
153
+ {{- args_value ~ '\n</parameter>\n' -}}
154
+ {%- endfor %}
155
+ {%- endif %}
156
+ {{- '</function>\n</tool_call>\n' -}}
157
+ {%- endfor %}
158
+ {{- '<|im_end|>\n' }}
159
+ {%- else %}
160
+ {# Assistant message doesn't have tool calls. #}
161
+ {%- if not (truncate_history_thinking and loop.index0 < ns.last_user_idx) %}
162
+ {{- '<|im_start|>assistant\n' ~ (content | default('', true) | string | trim) ~ '<|im_end|>\n' }}
163
+ {%- else %}
164
+ {%- set c = (content | default('', true) | string) %}
165
+ {%- if '<think>' in c and '</think>' in c %}
166
+ {%- set c = "<think></think>" ~ c.split('</think>')[-1] %}
167
+ {%- endif %}
168
+ {%- set c = c | trim %}
169
+ {%- if c | length > 0 %}
170
+ {{- '<|im_start|>assistant\n' ~ c ~ '<|im_end|>\n' }}
171
+ {%- else %}
172
+ {{- '<|im_start|>assistant\n<|im_end|>\n' }}
173
+ {%- endif %}
174
+ {%- endif %}
175
+ {%- endif %}
176
+ {%- elif message.role == "user" or message.role == "system" %}
177
+ {{- '<|im_start|>' + message.role + '\n' }}
178
+ {%- set content = message.content | string %}
179
+ {{- content }}
180
+ {{- '<|im_end|>\n' }}
181
+ {%- elif message.role == "tool" %}
182
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
183
+ {{- '<|im_start|>user\n' }}
184
+ {%- endif %}
185
+ {{- '<tool_response>\n' }}
186
+ {{- message.content }}
187
+ {{- '\n</tool_response>\n' }}
188
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
189
+ {{- '<|im_end|>\n' }}
190
+ {%- elif loop.last %}
191
+ {{- '<|im_end|>\n' }}
192
+ {%- endif %}
193
+ {%- else %}
194
+ {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>\n' }}
195
+ {%- endif %}
196
+ {%- endfor %}
197
+
198
+ {%- if add_generation_prompt %}
199
+ {%- if enable_thinking %}
200
+ {{- '<|im_start|>assistant\n<think>\n' }}
201
+ {%- else %}
202
+ {{- '<|im_start|>assistant\n<think></think>' }}
203
+ {%- endif %}
204
+ {%- endif %}
chat_utils.py ADDED
@@ -0,0 +1,448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import torch
3
+ import torch.nn.functional as F
4
+
5
+ from transformers.utils import ModelOutput
6
+ from dataclasses import dataclass
7
+ from transformers.cache_utils import Cache, DynamicCache
8
+ @dataclass
9
+ class SimpleOutputWithPast(ModelOutput):
10
+ loss: torch.FloatTensor | None = None
11
+ logits: torch.FloatTensor | None = None
12
+ causal_logits: torch.FloatTensor | None = None
13
+ past_key_values: Cache | None = None
14
+ hidden_states: tuple[torch.FloatTensor, ...] | None = None
15
+ attentions: tuple[torch.FloatTensor, ...] | None = None
16
+
17
+ from .nemotron_diffusion_image_utils import maybe_truncate_last_dim, pad_along_last_dim
18
+
19
+
20
+ def wte(model,x,t2i_inference=False,gen_shape=None,x_gen=None,inputs_embeds_curr=None,new_token_mask=None):
21
+
22
+ if t2i_inference:
23
+ assert x_gen is not None
24
+ if new_token_mask is None:
25
+ new_token_mask = x >= INT_MAX
26
+ # if x_gen is None:
27
+ # x_gen = x[new_token_mask] - OFFSET
28
+ # else:
29
+ # x_gen = x_gen - OFFSET
30
+
31
+ gen_latents_comp_embeds = model.call_gen_embedding(x_gen,gen_shape)
32
+ if inputs_embeds_curr is None:
33
+ x_txt_only = x.clone()
34
+
35
+ # replace consequtent [1] * 4096 to [1] * 1024
36
+
37
+ x_txt_only[new_token_mask] = 0
38
+ inputs_embeds_curr = model.embed_tokens(x_txt_only)
39
+ inputs_embeds_curr[new_token_mask] = pad_along_last_dim(gen_latents_comp_embeds,inputs_embeds_curr.shape[-1]).view(-1,inputs_embeds_curr.shape[-1])
40
+ else:
41
+ inputs_embeds_curr = model.embed_tokens(x)
42
+ new_token_mask = None
43
+ return inputs_embeds_curr,new_token_mask
44
+
45
+
46
+ INT_MAX = 1_000_000
47
+ def get_logits(model,input_emnbeddings,modality_indices=None,t2i_inference=False,past_key_values=None,gen_shape=None,timesteps=None,input_modality_indices=None):
48
+ if t2i_inference:
49
+ if input_modality_indices is None:
50
+ input_modality_indices =modality_indices
51
+ output = model(None,input_embeddings=input_emnbeddings,modality_indices=input_modality_indices,output_hidden_states=True,past_key_values=past_key_values,
52
+ is_training=False,
53
+ overwrite_attn_impl='flash_attn'
54
+ )
55
+ hidden_states = output.hidden_states[-1]
56
+ gen_hidden_states = hidden_states[modality_indices]
57
+ gen_hidden_states = maybe_truncate_last_dim(gen_hidden_states,model.config.d_model_gen)
58
+ gen_logits = model.call_gen_predictor(gen_hidden_states,gen_shape,timesteps=timesteps) # * 8 D
59
+ seq_len_per_img = np.prod(gen_shape)
60
+ if len(gen_logits.shape) == 2:
61
+ gen_logits = gen_logits.view(-1,seq_len_per_img,gen_logits.shape[-1])
62
+ else:
63
+ gen_logits = gen_logits.view(-1,seq_len_per_img,*gen_logits.shape[-2:])
64
+ # N L 8 D
65
+ return gen_logits
66
+
67
+
68
+ final_logits = torch.zeros(*gen_logits.shape[:-1],OFFSET+gen_logits.shape[-1],dtype=output.logits.dtype,device=output.logits.device)
69
+ final_logits[:] = float('-inf')
70
+ final_logits[...,OFFSET:] = gen_logits
71
+ # breakpoint()
72
+ # inal_logits = torch.zeros(*hidden_states.shape[:-1],OFFSET+gen_logits.shape[-1],dtype=output.logits.dtype,device=output.logits.device)
73
+
74
+ # final_logits = final_logits + float('-inf')
75
+ # final_logits[...,:output.logits.shape[-1]] = output.logits
76
+ # final_logits[modality_indices] = float('-inf')
77
+ # local = final_logits[modality_indices]
78
+
79
+ # local[...,OFFSET:] = gen_logits
80
+ # final_logits[modality_indices] = local
81
+
82
+ logits = final_logits
83
+ return logits
84
+ else:
85
+ modality_indices = torch.zeros(input_emnbeddings.shape[:-1],device=input_emnbeddings.device,dtype=torch.bool)
86
+ logits = model(None,input_embeddings=input_emnbeddings,modality_indices=modality_indices,past_key_values=past_key_values).logits
87
+ return logits
88
+
89
+ def add_gumbel_noise(logits, temperature):
90
+ '''
91
+ The Gumbel max is a method for sampling categorical distributions.
92
+ According to arXiv:2409.02908, for MDM, low-precision Gumbel Max improves perplexity score but reduces generation quality.
93
+ Thus, we use float64.
94
+ '''
95
+ if temperature == 0:
96
+ return logits
97
+ logits = logits.to(torch.float64)
98
+ noise = torch.rand_like(logits, dtype=torch.float64)
99
+ gumbel_noise = (- torch.log(noise)) ** temperature
100
+ return logits.exp() / gumbel_noise
101
+
102
+
103
+ def get_transfer_index(logits, temperature, remasking, mask_index, x, num_transfer_tokens, threshold=None, neg_entropy=False):
104
+ logits_with_noise = add_gumbel_noise(logits, temperature=temperature)
105
+ x0 = torch.argmax(logits_with_noise, dim=-1)
106
+
107
+ if remasking == 'low_confidence':
108
+ # p = F.softmax(logits.to(torch.float64), dim=-1)
109
+ p = F.softmax(logits, dim=-1)
110
+ x0_p = torch.squeeze(
111
+ torch.gather(p, dim=-1, index=torch.unsqueeze(x0, -1)), -1) # b, l
112
+ elif remasking == 'top_p_margin':
113
+ # Compute probabilities
114
+ p = F.softmax(logits, dim=-1) # (B, L, V)
115
+ # Top-2 per position
116
+ top2 = torch.topk(p, k=2, dim=-1).values # (B, L, 2)
117
+ margin = top2[..., 0] - top2[..., 1] # (B, L)
118
+
119
+ # Normalize margin to [0,1] over MASKED positions per row
120
+ plus_inf = torch.full_like(margin, float('inf'))
121
+ minus_inf = torch.full_like(margin, float('-inf'))
122
+ masked_for_min = torch.where(mask_index, margin, plus_inf)
123
+ masked_for_max = torch.where(mask_index, margin, minus_inf)
124
+ row_min = masked_for_min.amin(dim=1, keepdim=True) # (B, 1)
125
+ row_max = masked_for_max.amax(dim=1, keepdim=True) # (B, 1)
126
+ denom = (row_max - row_min)
127
+
128
+ # If denom==0 (all equal), set normalized=1 on masked; 0 elsewhere by default
129
+ normalized = torch.zeros_like(margin)
130
+ nonzero = denom > 0
131
+ normalized = torch.where(
132
+ mask_index & nonzero,
133
+ (margin - row_min) / (denom + 1e-12),
134
+ normalized
135
+ )
136
+ normalized = torch.where(
137
+ mask_index & (~nonzero),
138
+ torch.ones_like(normalized),
139
+ normalized
140
+ )
141
+ x0_p = normalized # ∈ [0,1] on masked positions
142
+ elif remasking == 'random':
143
+ x0_p = torch.rand((x0.shape[0], x0.shape[1]), device=x0.device)
144
+ else:
145
+ raise NotImplementedError(remasking)
146
+
147
+ # Calculate negative entropy if requested
148
+ if neg_entropy:
149
+ # p = F.softmax(logits.to(torch.float64), dim=-1)
150
+ p = F.softmax(logits, dim=-1)
151
+ epsilon = 1e-10
152
+ log_probs = torch.log(p + epsilon)
153
+ confidence_scores = torch.sum(p * log_probs, dim=-1) # negative entropy per position
154
+ else:
155
+ confidence_scores = x0_p
156
+
157
+ x0 = torch.where(mask_index, x0, x)
158
+ confidence = torch.where(mask_index, confidence_scores, -np.inf)
159
+
160
+ transfer_index = torch.zeros_like(x0, dtype=torch.bool, device=x0.device)
161
+ if threshold is not None:
162
+ num_transfer_tokens = mask_index.sum(dim=1, keepdim=True)
163
+ # print(f'confidence: {confidence}')
164
+ for j in range(confidence.shape[0]):
165
+ _, select_index = torch.topk(confidence[j], k=num_transfer_tokens[j])
166
+ transfer_index[j, select_index] = True
167
+ if threshold is not None:
168
+ for k in range(1, num_transfer_tokens[j]):
169
+ if confidence[j, select_index[k]] < threshold:
170
+ transfer_index[j, select_index[k]] = False
171
+ return x0, transfer_index
172
+
173
+
174
+ def get_num_transfer_tokens(mask_index, steps: int):
175
+ mask_num = mask_index.sum(dim=1, keepdim=True)
176
+ base = mask_num // steps
177
+ remainder = mask_num % steps
178
+ num_transfer_tokens = torch.zeros(mask_num.size(0), steps, device=mask_index.device, dtype=torch.int64) + base
179
+ for i in range(mask_num.size(0)):
180
+ num_transfer_tokens[i, : int(remainder[i])] += 1
181
+ return num_transfer_tokens
182
+
183
+ def simple_fwd(model,input_ids=None,inputs_embeds=None,attention_mask=None,position_ids=None,past_key_values=None,**kwargs):
184
+ enc_out = model.encoder(
185
+ past_key_values=past_key_values,
186
+ input_ids=input_ids,
187
+ inputs_embeds=inputs_embeds,
188
+ attention_mask=attention_mask,
189
+ position_ids=position_ids,
190
+ is_training=False,
191
+ overwrite_attn_impl='flash_attn',
192
+ # overwrite_attn_impl='flash_attn',
193
+ # overwrite_block_mask='full',
194
+ **kwargs,
195
+ )
196
+ logits = model.diffusion_head(enc_out.last_hidden_state)
197
+
198
+ return SimpleOutputWithPast(
199
+ loss=logits,
200
+ logits=logits,
201
+ causal_logits=None,
202
+ past_key_values=enc_out.past_key_values,
203
+ hidden_states=None,
204
+ attentions=None,
205
+ )
206
+
207
+
208
+ @torch.no_grad()
209
+ def generate_with_prefix_cache_block_diff(
210
+ model,
211
+ prompt=None,
212
+ prompt_embeds=None,
213
+ steps=128,
214
+ gen_length=128,
215
+ block_length=128,
216
+ temperature=0.,
217
+ remasking='low_confidence',
218
+ mask_id=126336,
219
+ threshold=None,
220
+ factor=None,
221
+ shift_logits=False,
222
+ neg_entropy=False,
223
+ causal_context=False,
224
+ eos_token_id=None,
225
+ max_thinking_tokens=None,
226
+ end_think_token_id=None,
227
+ ):
228
+ dream_style=shift_logits
229
+ if (prompt is None) == (prompt_embeds is None):
230
+ raise ValueError("Exactly one of `prompt` or `prompt_embeds` must be provided.")
231
+
232
+ if prompt is not None:
233
+ prompt_ids = prompt
234
+ prompt_len = prompt_ids.shape[1]
235
+ x_accum = prompt_ids.clone()
236
+ B = prompt_ids.shape[0]
237
+ token_device = prompt_ids.device
238
+ token_dtype = prompt_ids.dtype
239
+ else:
240
+ prompt_ids = None
241
+ prompt_len = prompt_embeds.shape[1]
242
+ B = prompt_embeds.shape[0]
243
+ token_device = prompt_embeds.device
244
+ token_dtype = torch.long
245
+ # Keep prefix slots so block slicing by prompt_len stays identical.
246
+ x_accum = torch.full((B, prompt_len), mask_id, dtype=token_dtype, device=token_device)
247
+
248
+ assert gen_length % block_length == 0
249
+ num_blocks = gen_length // block_length
250
+
251
+ assert steps % num_blocks == 0
252
+ steps_per_block = steps // num_blocks
253
+
254
+ nfe = 0
255
+ model_module = model.module if hasattr(model, "module") else model
256
+ for layer in model_module.encoder.layers:
257
+ layer.self_attn.mode = 'bidirectional'
258
+
259
+ if causal_context:
260
+ for layer in model_module.encoder.layers:
261
+ if hasattr(layer.self_attn, 'diffusion_lm'):
262
+ layer.self_attn.diffusion_lm=False
263
+
264
+ # Compute KV cache for the prompt initially
265
+ output = simple_fwd(model,
266
+ input_ids=prompt_ids,
267
+ inputs_embeds=prompt_embeds,
268
+ use_cache=True,
269
+ use_causal_mask=causal_context,
270
+ )
271
+ past_key_values = output.past_key_values
272
+
273
+ if causal_context:
274
+ for layer in model_module.encoder.layers:
275
+ if hasattr(layer.self_attn, 'diffusion_lm'):
276
+ layer.self_attn.diffusion_lm=True
277
+
278
+ # Causal prefill: next token from last position (same as linear_spec_generate).
279
+ next_token = None
280
+ if causal_context:
281
+ last_logit = output.logits[:, -1, :]
282
+ if temperature > 0:
283
+ probs = torch.softmax(last_logit / temperature, dim=-1)
284
+ next_token = torch.multinomial(probs, num_samples=1)
285
+ else:
286
+ next_token = torch.argmax(last_logit, dim=-1, keepdim=True)
287
+
288
+ # For dream_style: store the "next token logit" of the context
289
+ next_logits_context = None
290
+ if dream_style:
291
+ next_logits_context = output.logits[:, -1:, :] # (B, 1, V)
292
+
293
+ for num_block in range(num_blocks):
294
+ # Create a new block with mask tokens; under causal context, seed position 0
295
+ # with the next-token prediction from the previous causal forward (prefill or
296
+ # post-block encode), matching linear_spec_generate.
297
+ mask_block = torch.ones(
298
+ (B, block_length),
299
+ dtype=token_dtype,
300
+ device=token_device,
301
+ ) * mask_id
302
+ if causal_context:
303
+ mask_block[:, 0] = next_token[:, 0]
304
+
305
+ # Append the block of masks
306
+ x_accum = torch.cat([x_accum, mask_block], dim=1)
307
+ current_block_start = prompt_len + num_block * block_length
308
+ block_slice = slice(current_block_start, current_block_start + block_length)
309
+
310
+ # ---- thinking budget enforcement ----
311
+ # If we've generated >= max_thinking_tokens without a </think>, inject one.
312
+ if end_think_token_id is not None and max_thinking_tokens is not None:
313
+ tokens_before_block = num_block * block_length
314
+ tokens_after_block = tokens_before_block + block_length
315
+ if tokens_after_block > max_thinking_tokens:
316
+ gen_so_far = x_accum[:, prompt_len:current_block_start]
317
+ has_end_think = (
318
+ (gen_so_far == end_think_token_id).any(dim=1)
319
+ if gen_so_far.size(1) > 0
320
+ else torch.zeros(B, dtype=torch.bool, device=token_device)
321
+ )
322
+ if not has_end_think.all():
323
+ if tokens_before_block < max_thinking_tokens:
324
+ offset = max_thinking_tokens - tokens_before_block
325
+ else:
326
+ offset = 0
327
+ inject_pos = current_block_start + offset
328
+ for b in range(B):
329
+ if not has_end_think[b]:
330
+ x_accum[b, inject_pos] = end_think_token_id
331
+
332
+ # Build the initial mask for this block
333
+ mask_block_idx0 = (x_accum[:, block_slice] == mask_id) # (B, Lb)
334
+
335
+ # Precompute the transfer schedule for this block
336
+ if dream_style:
337
+ # masked positions only (position 0 may be causal-seeded, not mask_id)
338
+ schedule_mask = mask_block_idx0
339
+ else:
340
+ schedule_mask = mask_block_idx0
341
+
342
+ num_transfer_tokens = get_num_transfer_tokens(schedule_mask, steps_per_block) # (B, steps)
343
+
344
+ # Denoise the current block
345
+ for i in range(steps_per_block):
346
+ mask_block_idx = (x_accum[:, block_slice] == mask_id) # (B, Lb)
347
+ if mask_block_idx.sum() == 0:
348
+ break
349
+
350
+ nfe += 1
351
+
352
+ # Forward only the current noisy block using cached context
353
+ logits_block = simple_fwd(model,
354
+ x_accum[:, block_slice],
355
+ past_key_values=past_key_values,
356
+ use_cache=False
357
+ ).logits
358
+
359
+ if dream_style:
360
+ # Align logits so that each masked position has a predictor:
361
+ # prepend context-next logit, then use logits_block[:-1]
362
+ if block_length == 1:
363
+ logits_use = next_logits_context # (B, 1, V)
364
+ else:
365
+ logits_use = torch.cat(
366
+ [next_logits_context, logits_block[:, :-1, :]],
367
+ dim=1
368
+ ) # (B, Lb, V)
369
+
370
+ mask_use = mask_block_idx # (B, Lb)
371
+ x_use = x_accum[:, block_slice] # (B, Lb)
372
+
373
+ x0, transfer_idx = get_transfer_index(
374
+ logits_use, temperature, remasking, mask_use, x_use,
375
+ num_transfer_tokens=num_transfer_tokens[:, i],
376
+ threshold=threshold, neg_entropy=neg_entropy
377
+ )
378
+ cur = x_accum[:, block_slice].clone()
379
+ cur[transfer_idx] = x0[transfer_idx]
380
+ x_accum[:, block_slice] = cur
381
+
382
+ else:
383
+ # non-AR (same-position) case
384
+ x0, transfer_idx = get_transfer_index(
385
+ logits_block, temperature, remasking, mask_block_idx,
386
+ x_accum[:, block_slice],
387
+ num_transfer_tokens=num_transfer_tokens[:, i],
388
+ threshold=threshold, neg_entropy=neg_entropy
389
+ )
390
+ cur = x_accum[:, block_slice].clone()
391
+ cur[transfer_idx] = x0[transfer_idx]
392
+ x_accum[:, block_slice] = cur
393
+
394
+ if eos_token_id is not None:
395
+ block_tokens = x_accum[:, block_slice] # (B, Lb)
396
+ eos_mask = (block_tokens == eos_token_id) # (B, Lb)
397
+ any_eos = eos_mask.any(dim=1) # (B,)
398
+ if any_eos.any():
399
+ after_eos = eos_mask.cumsum(dim=1).bool() # (B, Lb)
400
+ mask_before = (block_tokens == mask_id) & ~after_eos
401
+ if (any_eos & ~mask_before.any(dim=1)).any():
402
+ break
403
+
404
+ if causal_context:
405
+ for layer in model_module.encoder.layers:
406
+ if hasattr(layer.self_attn, 'diffusion_lm'):
407
+ layer.self_attn.diffusion_lm=False
408
+
409
+ # after block is fully denoised, update KV cache
410
+ output = simple_fwd(model,
411
+ x_accum[:, block_slice],
412
+ past_key_values=past_key_values,
413
+ use_cache=True,
414
+ use_causal_mask=causal_context
415
+ )
416
+ past_key_values = output.past_key_values
417
+ nfe += 1
418
+
419
+ if causal_context:
420
+ for layer in model_module.encoder.layers:
421
+ if hasattr(layer.self_attn, 'diffusion_lm'):
422
+ layer.self_attn.diffusion_lm=True
423
+ # Next block's first position = greedy/sampled next token from this causal encode
424
+ last_logit = output.logits[:, -1, :]
425
+ if temperature > 0:
426
+ probs = torch.softmax(last_logit / temperature, dim=-1)
427
+ next_token = torch.multinomial(probs, num_samples=1)
428
+ else:
429
+ next_token = torch.argmax(last_logit, dim=-1, keepdim=True)
430
+
431
+ if dream_style and num_block < num_blocks - 1:
432
+ # refresh context-next logit for the next block
433
+ next_logits_context = output.logits[:, -1:, :] # (B, 1, V)
434
+
435
+ if eos_token_id is not None:
436
+ gen_so_far = x_accum[:, prompt_len:] # (B, gen_len_so_far)
437
+ is_eos = (gen_so_far == eos_token_id) # (B, gen_len_so_far)
438
+ has_eos = is_eos.any(dim=1) # (B,)
439
+ if has_eos.all():
440
+ first_eos_pos = is_eos.to(torch.int64).argmax(dim=1) # (B,)
441
+ max_eos = first_eos_pos.max().item()
442
+ if prompt_ids is None:
443
+ return x_accum[:, prompt_len : prompt_len + max_eos + 1], nfe
444
+ return x_accum[:, : prompt_len + max_eos + 1], nfe
445
+
446
+ if prompt_ids is None:
447
+ return x_accum[:, prompt_len:], nfe
448
+ return x_accum, nfe
config.json ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "ada_dlm_loss_ratio": null,
3
+ "ada_perm_ratio_global": null,
4
+ "ada_perm_ratio_per_block": null,
5
+ "adaptive_mask_rate": false,
6
+ "add_faster_video": false,
7
+ "add_time_instruction": false,
8
+ "ar_loss_weight": 1.0,
9
+ "architectures": [
10
+ "NemotronLabsDiffusionImageForMaskedDiffusion"
11
+ ],
12
+ "attention_bias": false,
13
+ "attention_dropout": 0.0,
14
+ "attn_implementation": null,
15
+ "auto_map": {
16
+ "AutoConfig": "configuration_nemotron_labs_diffusion_image.NemotronLabsDiffusionImageConfig",
17
+ "AutoModel": "modeling_nemotron_labs_diffusion_image.NemotronLabsDiffusionImageForMaskedDiffusion",
18
+ "AutoModelForCausalLM": "modeling_nemotron_labs_diffusion_image.NemotronLabsDiffusionImageForMaskedDiffusion"
19
+ },
20
+ "block_size": 32,
21
+ "bos_token_id": 1,
22
+ "d_model": 4096,
23
+ "d_model_gen": 4096,
24
+ "diff_loss_weight": 1,
25
+ "dlm_arch": "encoder",
26
+ "dlm_loss_weight": null,
27
+ "dlm_paradigm": "bidirectional",
28
+ "dlm_type": "llada",
29
+ "downsample": true,
30
+ "dp_varying_mask_ratio": false,
31
+ "dtype": "bfloat16",
32
+ "dual_tower": true,
33
+ "dual_tower_layers": 16,
34
+ "enable_self_spec": false,
35
+ "enforce_mask": false,
36
+ "eos_token_id": 11,
37
+ "faster_token_stride": 10,
38
+ "flip_ratio": 0.2,
39
+ "force_sample": false,
40
+ "gen_edit_loss_weight": 0.2,
41
+ "global_loss_avg": false,
42
+ "group_ce_weight": "{16384:0.2}",
43
+ "head_dim": 128,
44
+ "hidden_act": "silu",
45
+ "hidden_size": 4096,
46
+ "image_aspect_ratio": "t2i_only",
47
+ "image_crop_resolution": null,
48
+ "image_grid_pinpoints": [
49
+ [384, 768],
50
+ [768, 384],
51
+ [768, 768],
52
+ [1152, 384],
53
+ [384, 1152]
54
+ ],
55
+ "image_split_resolution": null,
56
+ "include_bias": false,
57
+ "initializer_range": 0.02,
58
+ "intermediate_size": 14336,
59
+ "mask_token_id": 100,
60
+ "max_position_embeddings": 262144,
61
+ "mlp_bias": false,
62
+ "mlp_hidden_size_gen": 14336,
63
+ "mm_hidden_size": 3584,
64
+ "mm_newline_position": "grid",
65
+ "mm_patch_merge_type": "spatial_unpad",
66
+ "mm_pooler_ratio": 2,
67
+ "mm_projector_lr": null,
68
+ "mm_projector_type": "mlp2x_gelu",
69
+ "mm_resampler_type": "none",
70
+ "mm_spatial_pool_mode": "conv",
71
+ "mm_spatial_pool_out_channels": 3584,
72
+ "mm_spatial_pool_stride": 1,
73
+ "mm_tunable_parts": "mm_language_model",
74
+ "mm_use_im_patch_token": false,
75
+ "mm_use_im_start_end": false,
76
+ "mm_vision_select_feature": "patch",
77
+ "mm_vision_select_layer": -2,
78
+ "mm_vision_tower": null,
79
+ "mm_vision_tower_lr": null,
80
+ "mm_vqvae": "emu3_vqvae",
81
+ "model_type": "nemotron_labs_diffusion_image",
82
+ "multi_sampling": null,
83
+ "num_ar_layers": 0,
84
+ "num_attention_heads": 32,
85
+ "num_diffusion_layers": 0,
86
+ "num_hidden_layers": 34,
87
+ "num_key_value_heads": 8,
88
+ "num_skip_loss_tokens": 0,
89
+ "pad_token_id": 11,
90
+ "pos_skipping_range": 4096,
91
+ "prefix_ratio": 0.8,
92
+ "prompt_drop_rate": 0.1,
93
+ "random_length_prob": 0,
94
+ "rms_norm_eps": 1e-05,
95
+ "rope_parameters": {
96
+ "beta_fast": 32.0,
97
+ "beta_slow": 1.0,
98
+ "factor": 16.0,
99
+ "llama_4_scaling_beta": 0.1,
100
+ "mscale": 1.0,
101
+ "mscale_all_dim": 1.0,
102
+ "original_max_position_embeddings": 16384,
103
+ "rope_theta": 1000000.0,
104
+ "rope_type": "yarn",
105
+ "type": "yarn"
106
+ },
107
+ "rope_scaling": {
108
+ "beta_fast": 32.0,
109
+ "beta_slow": 1.0,
110
+ "factor": 16.0,
111
+ "llama_4_scaling_beta": 0.1,
112
+ "mscale": 1.0,
113
+ "mscale_all_dim": 1.0,
114
+ "original_max_position_embeddings": 16384,
115
+ "rope_theta": 1000000.0,
116
+ "rope_type": "yarn",
117
+ "type": "yarn"
118
+ },
119
+ "rope_theta": 1000000.0,
120
+ "sliding_window": null,
121
+ "tie_word_embeddings": false,
122
+ "tok_mask_half_life_ratio": null,
123
+ "tokenizer_model_max_length": 4096,
124
+ "tokenizer_padding_side": "right",
125
+ "transformers_version": "4.57.6",
126
+ "use_cache": false,
127
+ "use_mm_proj": false,
128
+ "use_pos_skipping": false,
129
+ "vision_tower_pretrained": null,
130
+ "vocab_size": 132101
131
+ }
configuration_ministral_dlm.py ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2022 EleutherAI and the HuggingFace Inc. team. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Ministral DLM model configuration"""
16
+
17
+ from transformers.configuration_utils import PretrainedConfig
18
+ try:
19
+ from transformers.modeling_rope_utils import rope_config_validation
20
+ except ImportError:
21
+ rope_config_validation = None
22
+ from transformers.utils import logging
23
+
24
+
25
+ logger = logging.get_logger(__name__)
26
+
27
+
28
+ class MinistralDLMConfig(PretrainedConfig):
29
+ r"""
30
+ This is the configuration class to store the configuration of a [`Ministral3Model`] for diffusion language models.
31
+ It is used to instantiate a Ministral model according to the specified arguments, defining the model architecture.
32
+
33
+ Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
34
+ documentation from [`PretrainedConfig`] for more information.
35
+
36
+ Args:
37
+ vocab_size (`int`, *optional*, defaults to 131072):
38
+ Vocabulary size of the Ministral model.
39
+ hidden_size (`int`, *optional*, defaults to 4096):
40
+ Dimension of the hidden representations.
41
+ intermediate_size (`int`, *optional*, defaults to 14336):
42
+ Dimension of the MLP representations.
43
+ num_hidden_layers (`int`, *optional*, defaults to 34):
44
+ Number of hidden layers in the Transformer decoder.
45
+ num_attention_heads (`int`, *optional*, defaults to 32):
46
+ Number of attention heads for each attention layer.
47
+ num_key_value_heads (`int`, *optional*, defaults to 8):
48
+ Number of key_value heads for Grouped Query Attention.
49
+ head_dim (`int`, *optional*, defaults to 128):
50
+ The attention head dimension.
51
+ hidden_act (`str` or `function`, *optional*, defaults to `"silu"`):
52
+ The non-linear activation function.
53
+ max_position_embeddings (`int`, *optional*, defaults to 262144):
54
+ The maximum sequence length.
55
+ initializer_range (`float`, *optional*, defaults to 0.02):
56
+ The standard deviation of the truncated_normal_initializer.
57
+ rms_norm_eps (`float`, *optional*, defaults to 1e-05):
58
+ The epsilon used by the rms normalization layers.
59
+ use_cache (`bool`, *optional*, defaults to `True`):
60
+ Whether or not the model should return the last key/values attentions.
61
+ tie_word_embeddings (`bool`, *optional*, defaults to `False`):
62
+ Whether the model's input and output word embeddings should be tied.
63
+ rope_theta (`float`, *optional*, defaults to 1000000.0):
64
+ The base period of the RoPE embeddings.
65
+ rope_parameters (`Dict`, *optional*):
66
+ Dictionary containing the scaling configuration for the RoPE embeddings.
67
+ Default uses YaRN scaling with factor=16, original_max_position_embeddings=16384.
68
+ attention_bias (`bool`, defaults to `False`):
69
+ Whether to use a bias in the query, key, value and output projection layers.
70
+ attention_dropout (`float`, *optional*, defaults to 0.0):
71
+ The dropout ratio for the attention probabilities.
72
+ mlp_bias (`bool`, *optional*, defaults to `False`):
73
+ Whether to use a bias in up_proj, down_proj and gate_proj layers.
74
+ sliding_window (`int`, *optional*, defaults to None):
75
+ Sliding window attention size.
76
+ mask_token_id (`int`, *optional*, defaults to -1):
77
+ Token ID for masking in diffusion.
78
+ dlm_type (`str`, *optional*, defaults to 'llada'):
79
+ Type of diffusion language model ('llada', 'dream').
80
+ random_length_prob (`float`, *optional*):
81
+ Probability of using random lengths during training.
82
+ num_ar_layers (`int`, *optional*, defaults to 0):
83
+ Number of autoregressive layers.
84
+ num_diffusion_layers (`int`, *optional*, defaults to 0):
85
+ Number of diffusion layers.
86
+ diff_loss_weight (`float`, *optional*, defaults to 1):
87
+ Weight for diffusion loss.
88
+ enforce_mask (`bool`, *optional*, defaults to False):
89
+ Whether to enforce masking.
90
+ prefix_ratio (`float`, *optional*, defaults to 0.8):
91
+ Ratio for prefix in prefix_bidirectional mode.
92
+ dlm_paradigm (`str`, *optional*, defaults to 'bidirectional'):
93
+ Paradigm for diffusion ('bidirectional', 'autoregressive', 'prefix_bidirectional', 'efficient_block_diff', 'block_diff', 'sbd_block_diff').
94
+ dlm_arch (`str`, *optional*, defaults to 'encoder'):
95
+ Architecture type ('encoder', 'encoder_decoder').
96
+ block_size (`int`, *optional*, defaults to 32):
97
+ Block size for block diffusion paradigms.
98
+ tok_mask_half_life_ratio (`float`, *optional*):
99
+ Half-life ratio for token masking.
100
+ adaptive_mask_rate (`bool`, *optional*, defaults to False):
101
+ Whether to use adaptive mask rate.
102
+ multi_sampling (`int`, *optional*):
103
+ Number of samples for multi-sampling.
104
+ num_skip_loss_tokens (`int`, *optional*, defaults to 0):
105
+ Number of tokens to skip in loss calculation.
106
+ dlm_loss_weight (`float`, *optional*):
107
+ Weight for diffusion LM loss.
108
+ ar_loss_weight (`float`, *optional*, defaults to 1.0):
109
+ Weight for autoregressive loss in sbd_block_diff paradigm. Use 10000 to only use AR loss.
110
+ global_loss_avg (`bool`, *optional*, defaults to False):
111
+ Whether to use global loss average.
112
+ dp_varying_mask_ratio (`bool`, *optional*, defaults to False):
113
+ Whether to use varying mask ratio for each DP rank during sampling.
114
+ ada_perm_ratio_per_block (`float`, *optional*):
115
+ Adaptive permutation ratio for each block.
116
+ ada_perm_ratio_global (`float`, *optional*):
117
+ Adaptive permutation ratio for global.
118
+ enable_self_spec (`bool`, *optional*, defaults to `False`):
119
+ Force MinistralFlexAttention for all paradigms (including bidirectional/autoregressive).
120
+ Required for self speculative generation; leave False for standard eval to use faster SDPA kernels.
121
+ """
122
+
123
+ model_type = "ministral_dlm"
124
+ keys_to_ignore_at_inference = ["past_key_values"]
125
+
126
+ # Default tensor parallel plan for base model `Ministral`
127
+ base_model_tp_plan = {
128
+ "layers.*.self_attn.q_proj": "colwise",
129
+ "layers.*.self_attn.k_proj": "colwise",
130
+ "layers.*.self_attn.v_proj": "colwise",
131
+ "layers.*.self_attn.o_proj": "rowwise",
132
+ "layers.*.mlp.gate_proj": "colwise",
133
+ "layers.*.mlp.up_proj": "colwise",
134
+ "layers.*.mlp.down_proj": "rowwise",
135
+ }
136
+ base_model_pp_plan = {
137
+ "embed_tokens": (["input_ids"], ["inputs_embeds"]),
138
+ "layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
139
+ "norm": (["hidden_states"], ["hidden_states"]),
140
+ }
141
+
142
+ def __init__(
143
+ self,
144
+ vocab_size=131072,
145
+ hidden_size=4096,
146
+ intermediate_size=14336,
147
+ num_hidden_layers=34,
148
+ num_attention_heads=32,
149
+ num_key_value_heads=8,
150
+ head_dim=128,
151
+ hidden_act="silu",
152
+ max_position_embeddings=262144,
153
+ initializer_range=0.02,
154
+ rms_norm_eps=1e-05,
155
+ use_cache=True,
156
+ pad_token_id=None,
157
+ bos_token_id=1,
158
+ eos_token_id=2,
159
+ tie_word_embeddings=False,
160
+ rope_theta=1000000.0,
161
+ rope_parameters=None,
162
+ rope_scaling=None,
163
+ attention_bias=False,
164
+ attention_dropout=0.0,
165
+ mlp_bias=False,
166
+ sliding_window=None,
167
+ attn_implementation="sdpa",
168
+ mask_token_id=None,
169
+ dlm_type='llada',
170
+ random_length_prob=None,
171
+ num_ar_layers=0,
172
+ num_diffusion_layers=0,
173
+ diff_loss_weight=1,
174
+ enforce_mask=False,
175
+ prefix_ratio=0.8,
176
+ dlm_paradigm='bidirectional',
177
+ dlm_arch='encoder',
178
+ block_size=32,
179
+ tok_mask_half_life_ratio=None,
180
+ adaptive_mask_rate=False,
181
+ multi_sampling=None,
182
+ num_skip_loss_tokens=0,
183
+ dlm_loss_weight=None,
184
+ ar_loss_weight=1.0,
185
+ global_loss_avg=False,
186
+ dp_varying_mask_ratio=False,
187
+ ada_perm_ratio_per_block=None,
188
+ ada_perm_ratio_global=None,
189
+ ada_dlm_loss_ratio=None,
190
+ enable_self_spec=False,
191
+ **kwargs,
192
+ ):
193
+ self.vocab_size = vocab_size
194
+ self.max_position_embeddings = max_position_embeddings
195
+ self.hidden_size = hidden_size
196
+ self.intermediate_size = intermediate_size
197
+ self.num_hidden_layers = num_hidden_layers
198
+ self.num_attention_heads = num_attention_heads
199
+
200
+ # for backward compatibility
201
+ if num_key_value_heads is None:
202
+ num_key_value_heads = num_attention_heads
203
+
204
+ self.num_key_value_heads = num_key_value_heads
205
+ self.head_dim = head_dim
206
+ self.hidden_act = hidden_act
207
+ self.initializer_range = initializer_range
208
+ self.rms_norm_eps = rms_norm_eps
209
+ self.use_cache = use_cache
210
+ self.rope_theta = rope_theta
211
+ if rope_parameters is None and rope_scaling is not None:
212
+ rope_parameters = dict(rope_scaling)
213
+ # llama_4_scaling_beta is used directly by the attention layer; do not strip it.
214
+ self.rope_parameters = rope_parameters
215
+ self.rope_scaling = rope_scaling
216
+ self.attention_bias = attention_bias
217
+ self.attention_dropout = attention_dropout
218
+ self.mlp_bias = mlp_bias
219
+ self.sliding_window = sliding_window
220
+
221
+ self.attn_implementation = attn_implementation
222
+
223
+ self.mask_token_id = mask_token_id
224
+ self.dlm_type = dlm_type
225
+ self.random_length_prob = random_length_prob
226
+ self.num_ar_layers = num_ar_layers
227
+ self.num_diffusion_layers = num_diffusion_layers
228
+ self.diff_loss_weight = diff_loss_weight
229
+ self.enforce_mask = enforce_mask
230
+ self.prefix_ratio = prefix_ratio
231
+ self.dlm_paradigm = dlm_paradigm
232
+ self.dlm_arch = dlm_arch
233
+ self.block_size = block_size
234
+ self.tok_mask_half_life_ratio = tok_mask_half_life_ratio
235
+ self.adaptive_mask_rate = adaptive_mask_rate
236
+ self.multi_sampling = multi_sampling
237
+ self.num_skip_loss_tokens = num_skip_loss_tokens
238
+ self.dlm_loss_weight = dlm_loss_weight
239
+ self.ar_loss_weight = ar_loss_weight
240
+ self.global_loss_avg = global_loss_avg
241
+ self.dp_varying_mask_ratio = dp_varying_mask_ratio
242
+ self.ada_perm_ratio_per_block = ada_perm_ratio_per_block
243
+ self.ada_perm_ratio_global = ada_perm_ratio_global
244
+ self.ada_dlm_loss_ratio = ada_dlm_loss_ratio
245
+ self.enable_self_spec = enable_self_spec
246
+ super().__init__(
247
+ pad_token_id=pad_token_id,
248
+ bos_token_id=bos_token_id,
249
+ eos_token_id=eos_token_id,
250
+ tie_word_embeddings=tie_word_embeddings,
251
+ **kwargs,
252
+ )
253
+
254
+ # Transformers>=4.57 expects standardized/validated rope_parameters.
255
+ if hasattr(self, "standardize_rope_params"):
256
+ self.standardize_rope_params()
257
+ if hasattr(self, "validate_rope"):
258
+ self.validate_rope()
259
+ elif rope_config_validation is not None:
260
+ rope_config_validation(self)
261
+
262
+
263
+ __all__ = ["MinistralDLMConfig"]
264
+
configuration_nemotron_labs_diffusion_image.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .configuration_ministral_dlm import MinistralDLMConfig
2
+
3
+
4
+ class NemotronLabsDiffusionImageConfig(MinistralDLMConfig):
5
+ model_type = "nemotron_labs_diffusion_image"
6
+
7
+ def __init__(
8
+ self,
9
+ max_position_embeddings=262144,
10
+ rope_parameters=None,
11
+ rope_scaling=None,
12
+ **kwargs,
13
+ ):
14
+ # Newer transformers standardize RoPE params during PretrainedConfig init.
15
+ # Make these attributes available early and normalize legacy rope_scaling.
16
+ if rope_parameters is None and rope_scaling is not None:
17
+ rope_parameters = dict(rope_scaling)
18
+
19
+ self.max_position_embeddings = max_position_embeddings
20
+ if rope_parameters is not None:
21
+ self.rope_parameters = rope_parameters
22
+ if rope_scaling is not None:
23
+ self.rope_scaling = rope_scaling
24
+
25
+ super().__init__(
26
+ max_position_embeddings=max_position_embeddings,
27
+ rope_parameters=rope_parameters,
28
+ rope_scaling=rope_scaling,
29
+ **kwargs,
30
+ )
31
+
32
+ if getattr(self, "rope_parameters", None) is None and getattr(self, "rope_scaling", None) is not None:
33
+ self.rope_parameters = dict(self.rope_scaling)
demo_inference_release.py ADDED
@@ -0,0 +1,249 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import os
3
+ from pathlib import Path
4
+
5
+ import torch
6
+ from transformers import AutoModelForCausalLM, PreTrainedTokenizerFast
7
+
8
+ # Keep behavior aligned with the existing demo entrypoints.
9
+ os.environ.setdefault("DEBUG_FIX_PADDING", "1")
10
+ os.environ.setdefault("NOT_ALWASY_DO_2DPOOL", "1")
11
+
12
+ DEFAULT_CKPT = "/lustre/fsw/portfolios/nvr/users/shufanl/projects/ministral-output/nemotron-labs-diffuion-image-8B-release"
13
+ DEFAULT_PROMPT = (
14
+ "A full-body shot of hyper-realistic female cyborg, human facial skin seamlessly integrated with a glossy white mechanical head shell. "
15
+ "Features a realistic human ear, blue eyes. bright, outdoor, background with blue sky, illuminated by striking bright white studio lighting, "
16
+ "casting soft shadows. Cyberpunk aesthetic, high-tech minimalism, shot on 85mm lens, photorealistic, Unreal Engine 5 render, intricately detailed, "
17
+ "8k resolution, high dynamic range, chest with whit armor plate, cute, beautiful, sexy, glossy surface, reflective, Artstation, pixiv, no hair, "
18
+ "3D render, stylized eyesz"
19
+ )
20
+ DEFAULT_OUTPUT = "/lustre/fsw/portfolios/nvr/users/shufanl/code/LaVida-O/outputs/demo_inference_release.webp"
21
+
22
+ SCHEDULE_CHOICES = ["shift"]
23
+ CONFIDENCE_POLICY_CHOICES = ["mask_git", "mmada", "stratified"]
24
+ SCHEDULE_TEMP_CHOICES = ["linear", "cosine2", "shift", "exp"]
25
+ RESOLUTION_CHOICES = [256, 512, 1024]
26
+
27
+ # Match the default generation setup in gradio_t2i_demo.py.
28
+ DEFAULT_GENERATION_CONFIG = {
29
+ "guidance_scale": 5.0,
30
+ "n_steps": 64,
31
+ "shift": 5,
32
+ "schedule": "shift",
33
+ "alg_temp": 1.0,
34
+ "dynamic_temperature": False,
35
+ "min_temperature": 0.01,
36
+ "schedule_temp": "linear",
37
+ "temperature": 0.86,
38
+ "confidence_policy": "mmada",
39
+ "micro_cond": "ORIGINAL WIDTH : 1024; ORIGINAL HEIGHT : 1024; TOP : 0; LEFT : 0; SCORE : 6.520; HPS: 3.220",
40
+ "template": "Generate an image with the caption:\n <prompt>",
41
+ "edit_threshold": 0.6,
42
+ }
43
+
44
+
45
+ def load_release_model_and_tokenizer(model_path: str, device: str):
46
+ tokenizer = PreTrainedTokenizerFast.from_pretrained(model_path)
47
+ if tokenizer.pad_token_id is None:
48
+ tokenizer.pad_token_id = tokenizer.eos_token_id
49
+ tokenizer.pad_token = tokenizer.eos_token
50
+
51
+ model = AutoModelForCausalLM.from_pretrained(
52
+ model_path,
53
+ trust_remote_code=True,
54
+ torch_dtype=torch.bfloat16,
55
+ low_cpu_mem_usage=False,
56
+ )
57
+ model.to(device)
58
+ model.eval()
59
+ model.requires_grad_(False)
60
+
61
+ return tokenizer, model
62
+
63
+
64
+ def n_tokens_from_resolution(image_resolution: int) -> int:
65
+ return (image_resolution // 16) * (image_resolution // 16)
66
+
67
+
68
+ def parse_args() -> argparse.Namespace:
69
+ parser = argparse.ArgumentParser(
70
+ description="Single-image LaVida-O text-to-image inference using the release package defaults.",
71
+ formatter_class=argparse.RawTextHelpFormatter,
72
+ )
73
+ parser.add_argument(
74
+ "--pretrained",
75
+ type=str,
76
+ default=DEFAULT_CKPT,
77
+ help="Path to the model directory.\nChoices: any local HF-style checkpoint or release directory.",
78
+ )
79
+ parser.add_argument(
80
+ "--prompt",
81
+ type=str,
82
+ default=DEFAULT_PROMPT,
83
+ help="Prompt text for generation.\nChoices: any text string.",
84
+ )
85
+ parser.add_argument(
86
+ "--output",
87
+ type=str,
88
+ default=DEFAULT_OUTPUT,
89
+ help="Output image path.\nChoices: any writable file path; extension should match a Pillow-supported format such as .webp, .png, or .jpg.",
90
+ )
91
+ parser.add_argument(
92
+ "--image-resolution",
93
+ type=int,
94
+ choices=RESOLUTION_CHOICES,
95
+ default=1024,
96
+ help="Output resolution in pixels.\nChoices: 256, 512, 1024.",
97
+ )
98
+ parser.add_argument(
99
+ "--guidance-scale",
100
+ type=float,
101
+ default=DEFAULT_GENERATION_CONFIG["guidance_scale"],
102
+ help="Classifier-free guidance strength.\nChoices: any positive float; default is the inline release demo setting.",
103
+ )
104
+ parser.add_argument(
105
+ "--temperature",
106
+ type=float,
107
+ default=DEFAULT_GENERATION_CONFIG["temperature"],
108
+ help="Sampling temperature for token draws.\nChoices: any positive float; lower is more conservative.",
109
+ )
110
+ parser.add_argument(
111
+ "--n-steps",
112
+ type=int,
113
+ default=DEFAULT_GENERATION_CONFIG["n_steps"],
114
+ help="Number of denoising steps.\nChoices: any positive integer; default is the inline release demo setting.",
115
+ )
116
+ parser.add_argument(
117
+ "--schedule",
118
+ type=str,
119
+ choices=SCHEDULE_CHOICES,
120
+ default=DEFAULT_GENERATION_CONFIG["schedule"],
121
+ help="Token transfer schedule.\nChoices: shift.",
122
+ )
123
+ parser.add_argument(
124
+ "--shift",
125
+ type=int,
126
+ default=DEFAULT_GENERATION_CONFIG["shift"],
127
+ help="Shift parameter used by the shift schedule.\nChoices: any non-negative integer; default is the inline release demo setting.",
128
+ )
129
+ parser.add_argument(
130
+ "--confidence-policy",
131
+ type=str,
132
+ choices=CONFIDENCE_POLICY_CHOICES,
133
+ default=DEFAULT_GENERATION_CONFIG["confidence_policy"],
134
+ help="Policy for selecting which masked tokens to reveal next.\nChoices: mask_git, mmada, stratified.",
135
+ )
136
+ parser.add_argument(
137
+ "--schedule-temp",
138
+ type=str,
139
+ choices=SCHEDULE_TEMP_CHOICES,
140
+ default=DEFAULT_GENERATION_CONFIG["schedule_temp"],
141
+ help="Temperature schedule shape across denoising steps.\nChoices: linear, cosine2, shift, exp.",
142
+ )
143
+ parser.add_argument(
144
+ "--alg-temp",
145
+ type=float,
146
+ default=DEFAULT_GENERATION_CONFIG["alg_temp"],
147
+ help="Confidence-ranking temperature used by the reveal policy.\nChoices: any positive float; default is the inline release demo setting.",
148
+ )
149
+ parser.add_argument(
150
+ "--dynamic-temperature",
151
+ action="store_true",
152
+ default=DEFAULT_GENERATION_CONFIG["dynamic_temperature"],
153
+ help="Enable dynamic temperature scaling over time.\nChoices: enabled with --dynamic-temperature, disabled with --no-dynamic-temperature.",
154
+ )
155
+ parser.add_argument(
156
+ "--no-dynamic-temperature",
157
+ dest="dynamic_temperature",
158
+ action="store_false",
159
+ help="Disable dynamic temperature scaling.",
160
+ )
161
+ parser.add_argument(
162
+ "--edit-threshold",
163
+ type=float,
164
+ default=DEFAULT_GENERATION_CONFIG["edit_threshold"],
165
+ help="Post-sampling token editing threshold.\nChoices: any float in practice; use -1 to disable edit-based replacement as in the Gradio demo semantics.",
166
+ )
167
+ parser.add_argument(
168
+ "--seed",
169
+ type=int,
170
+ default=42,
171
+ help="Random seed.\nChoices: any integer; use -1 to sample a fresh random seed.",
172
+ )
173
+ parser.add_argument(
174
+ "--micro-cond",
175
+ type=str,
176
+ default=DEFAULT_GENERATION_CONFIG["micro_cond"],
177
+ help="Micro-conditioning string injected into the prompt template.\nChoices: any string matching the model's expected metadata style.",
178
+ )
179
+ parser.add_argument(
180
+ "--device",
181
+ type=str,
182
+ default="cuda",
183
+ help="Torch device for model execution.\nChoices: typically cuda or cpu; cuda is expected for practical inference speed.",
184
+ )
185
+ parser.add_argument(
186
+ "--use-cache",
187
+ action="store_true",
188
+ help="Enable KV-cache prefill path during denoising.\nChoices: set flag to enable, omit to disable.",
189
+ )
190
+ parser.add_argument(
191
+ "--is-legacy",
192
+ action="store_true",
193
+ help="Use legacy generation behavior expected by older checkpoints.\nChoices: set flag to enable, omit to disable.",
194
+ )
195
+ return parser.parse_args()
196
+
197
+
198
+ def main() -> None:
199
+ args = parse_args()
200
+
201
+ gen_cfg = dict(DEFAULT_GENERATION_CONFIG)
202
+ gen_cfg.update(
203
+ micro_cond=args.micro_cond,
204
+ guidance_scale=args.guidance_scale,
205
+ temperature=args.temperature,
206
+ edit_threshold=args.edit_threshold,
207
+ n_steps=args.n_steps,
208
+ schedule=args.schedule,
209
+ shift=args.shift,
210
+ confidence_policy=args.confidence_policy,
211
+ schedule_temp=args.schedule_temp,
212
+ alg_temp=args.alg_temp,
213
+ dynamic_temperature=args.dynamic_temperature,
214
+ block_policy=2,
215
+ )
216
+
217
+ if args.seed < 0:
218
+ args.seed = int(torch.seed() % (2**31 - 1))
219
+ torch.manual_seed(args.seed)
220
+
221
+ tokenizer, model = load_release_model_and_tokenizer(args.pretrained, args.device)
222
+ model.config.dlm_paradigm = "bidirectional"
223
+
224
+ with torch.no_grad():
225
+ with torch.inference_mode():
226
+ image = model.text_to_image(
227
+ args.prompt,
228
+ tokenizer=tokenizer,
229
+ **gen_cfg,
230
+ image_resolution=args.image_resolution,
231
+ n_tokens=n_tokens_from_resolution(args.image_resolution),
232
+ is_legacy=args.is_legacy,
233
+ use_cache=args.use_cache,
234
+ disable_tqdm=False,
235
+ return_intermediate_steps=False,
236
+ )
237
+
238
+ output_path = Path(args.output)
239
+ output_path.parent.mkdir(parents=True, exist_ok=True)
240
+ image.save(output_path)
241
+
242
+ print(f"Saved image to {output_path}")
243
+ print(f"Seed: {args.seed}")
244
+ print(f"Resolution: {args.image_resolution}")
245
+ print(f"Checkpoint: {args.pretrained}")
246
+
247
+
248
+ if __name__ == "__main__":
249
+ main()
emu3_vqvae/.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
emu3_vqvae/README.md ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ ---
4
+ <div align='center'>
5
+ <h1>Emu3.5: Native Multimodal Models are World Learners</h1>
6
+
7
+ Emu3.5 Team, BAAI
8
+
9
+ [Project Page](https://emu.world/pages/web/landingPage) | [🤗HF Models](https://huggingface.co/collections/BAAI/emu35) | [Paper](https://arxiv.org/pdf/2510.26583) | [App](https://emu.world/pages/web/home?route=index)
10
+ </div>
11
+
12
+
13
+ > 🔔 **Latest**: Emu3.5 Web & Mobile Apps and vLLM offline inference are live — see [🔥 News](#news) for details.
14
+
15
+
16
+ <div align='center'>
17
+ <img src="https://github.com/baaivision/Emu3.5/blob/main/assets/arch.png?raw=True" class="interpolation-image" alt="arch." height="100%" width="100%" />
18
+ </div>
19
+
20
+
21
+ <div align='center'>
22
+ <img src="https://github.com/baaivision/Emu3.5/blob/main/assets/co.png?raw=True" class="interpolation-image" alt="arch." height="90%" width="90%" />
23
+ </div>
24
+
25
+
26
+ | 🔹 | **Core Concept** | **Description** |
27
+ | :-: | :--------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------- |
28
+ | 🧠 | **Unified World Modeling** | Predicts the **next state jointly across vision and language**, enabling coherent **world modeling** and **generation**. |
29
+ | 🧩 | **End-to-End Pretraining** | Trained with a **unified next-token prediction** objective over **interleaved vision–language sequences**. |
30
+ | 📚 | **Over 10T+ Multimodal Tokens** | Pre-trained on **over 10 trillion interleaved tokens** from **video frames** and **transcripts**, capturing **spatiotemporal structure**. |
31
+ | 🔄 | **Native Multimodal I/O** | Processes and generates **interleaved visual–text sequences** without **modality adapters** or **task-specific heads**. |
32
+ | 🎯 | **RL Post-Training** | Large-scale **reinforcement learning** enhances **reasoning**, **compositionality**, and **generation quality**. |
33
+ | ⚡ | **Discrete Diffusion Adaptation (DiDA)** | Converts **sequential decoding → bidirectional parallel prediction**, achieving **≈20× faster inference without performance loss**. |
34
+ | 🖼️ | **Versatile Generation** | Excels in **long-horizon vision–language generation**, **any-to-image (X2I)** synthesis, and **text-rich image creation**. |
35
+ | 🌐 | **Generalizable World Modeling** | Enables **spatiotemporally consistent world exploration**, and **open-world embodied manipulation** across diverse scenarios. |
36
+ | 🏆 | **Performance Benchmark** | Matches **Gemini 2.5 Flash Image (Nano Banana)** on **image generation/editing**, and **outperforms** on **interleaved generation tasks**. |
37
+
38
+
39
+ <a id="news"></a>
40
+
41
+ ## 🔥 News
42
+
43
+ - **2025-11-28 · 🌐 Emu3.5 Web & Mobile Apps Live** — Official product experience is **now available** on the web at [zh.emu.world](https://zh.emu.world) (Mainland China) and [emu.world](https://emu.world) (global) 🎉 The new homepage highlights featured cases and a “Get Started” entry, while the workspace and mobile apps bring together creation, inspiration feed, history, profile, and language switch across web, Android APK, and H5. *([See more details](#official-web--mobile-apps) below.)*
44
+ - **2025-11-19 · 🚀 vLLM Offline Inference Released** — Meet `inference_vllm.py` with a new cond/uncond batch scheduler, delivering **4–5× faster end-to-end generation** on vLLM 0.11.0 across Emu3.5 tasks. Jump to [#Run Inference with vLLM](#run-inference-with-vllm) for setup guidance and see PR [#47](https://github.com/baaivision/Emu3.5/pull/47) for full details.
45
+ - **2025-11-17 · 🎛️ Gradio Demo (Transformers Backend)** — Introduced `gradio_demo_image.py` and `gradio_demo_interleave.py` presets for the standard Transformers runtime, providing turnkey T2I/X2I and interleaved generation experiences with streaming output. Try the commands in [#Gradio Demo](#3-gradio-demo) to launch both UIs locally.
46
+
47
+ ## Table of Contents
48
+
49
+ 1. [Model & Weights](#1-model--weights)
50
+ 2. [Quick Start](#2-quick-start)
51
+ 3. [Gradio Demo](#3-gradio-demo)
52
+ 4. [Schedule](#4-schedule)
53
+ 5. [Citation](#5-citation)
54
+
55
+ ## 1. Model & Weights
56
+
57
+ | Model name | HF Weight |
58
+ | ------------------------ | --------- |
59
+ | Emu3.5 | [🤗 HF link](https://huggingface.co/BAAI/Emu3.5/tree/main) |
60
+ | Emu3.5-Image | [🤗 HF link](https://huggingface.co/BAAI/Emu3.5-Image/tree/main) |
61
+ | Emu3.5-VisionTokenizer | [🤗 HF link](https://huggingface.co/BAAI/Emu3.5-VisionTokenizer/tree/main) |
62
+
63
+
64
+ *Note:*
65
+ - **Emu3.5** supports general-purpose multimodal predictions, including interleaved image-text generation and single-image generation (T2I/X2I) tasks.
66
+ - **Emu3.5-Image** is a model focused on T2I/X2I tasks for best performance on these scenarios.
67
+ - Both models are pure next-token predictors without DiDA acceleration (each image may take several minutes to generate).
68
+ - ⚡ **Stay tuned for DiDA-accelerated weights.**
69
+
70
+ > 💡 **Usage tip:**
71
+ > For **interleaved image-text generation**, use **Emu3.5**.
72
+ > For **single-image generation** (T2I and X2I), use **Emu3.5-Image** for the best quality.
73
+
74
+
75
+
76
+ ## 2. Quick Start
77
+
78
+ ### Environment Setup
79
+
80
+ ```bash
81
+ # Requires Python 3.12 or higher.
82
+ git clone https://github.com/baaivision/Emu3.5
83
+ cd Emu3.5
84
+ pip install -r requirements/transformers.txt
85
+ pip install flash_attn==2.8.3 --no-build-isolation
86
+ ```
87
+ ### Configuration
88
+
89
+ Edit `configs/config.py` to set:
90
+
91
+ - Paths: `model_path`, `vq_path`
92
+ - Task template: `task_type in {t2i, x2i, howto, story, explore, vla}`
93
+ - Input image: `use_image` (True to provide reference images, controls <|IMAGE|> token); set `reference_image` in each prompt to specify the image path. For x2i task, we recommand using `reference_image` as a list containing single/multiple image paths to be compatible with multi-image input.
94
+ - Sampling: `sampling_params` (classifier_free_guidance, temperature, top_k/top_p, etc.)
95
+ - Aspect Ratio (for t2i task): `aspect_ratio` ("4:3", "21:9", "1:1", "auto" etc..)
96
+
97
+ ### Run Inference
98
+
99
+ ```bash
100
+ python inference.py --cfg configs/config.py
101
+ ```
102
+
103
+
104
+ #### Example Configurations by Task
105
+ Below are example commands for different tasks.
106
+ Make sure to set CUDA_VISIBLE_DEVICES according to your available GPUs.
107
+
108
+
109
+ ```bash
110
+ # 🖼️ Text-to-Image (T2I) task
111
+ CUDA_VISIBLE_DEVICES=0 python inference.py --cfg configs/example_config_t2i.py
112
+
113
+ # 🔄 Any-to-Image (X2I) task
114
+ CUDA_VISIBLE_DEVICES=0,1 python inference.py --cfg configs/example_config_x2i.py
115
+
116
+ # 🎯 Visual Guidance task
117
+ CUDA_VISIBLE_DEVICES=0,1 python inference.py --cfg configs/example_config_visual_guidance.py
118
+
119
+ # 📖 Visual Narrative task
120
+ CUDA_VISIBLE_DEVICES=0,1 python inference.py --cfg configs/example_config_visual_narrative.py
121
+
122
+
123
+ # After running inference, the model will generate results in protobuf format (.pb files) for each input prompt.
124
+ ```
125
+
126
+
127
+ Protobuf outputs are written to `outputs/<exp_name>/proto/`. For better throughput, we recommend ≥2 GPUs.
128
+
129
+
130
+ ### Run Inference with vLLM
131
+
132
+ #### vLLM Enviroment Setup
133
+
134
+ 1. [Optional Recommendation] Use a new virtual environment for vLLM backend.
135
+ ```bash
136
+ conda create -n Emu3p5 python=3.12
137
+ ```
138
+
139
+ 2. Install vLLM and apply the patch files.
140
+ ```bash
141
+ # Requires Python 3.12 or higher.
142
+ # Recommended: CUDA 12.8.
143
+ pip install -r requirements/vllm.txt
144
+ pip install flash_attn==2.8.3 --no-build-isolation
145
+
146
+ cd Emu3.5
147
+ python src/patch/apply.py
148
+ ```
149
+
150
+ #### Example Configurations by Task
151
+
152
+ ```bash
153
+ # 🖼️ Text-to-Image (T2I) task
154
+ CUDA_VISIBLE_DEVICES=0,1 python inference_vllm.py --cfg configs/example_config_t2i.py
155
+
156
+ # 🔄 Any-to-Image (X2I) task
157
+ CUDA_VISIBLE_DEVICES=0,1 python inference_vllm.py --cfg configs/example_config_x2i.py
158
+
159
+ # 🎯 Visual Guidance task
160
+ CUDA_VISIBLE_DEVICES=0,1 python inference_vllm.py --cfg configs/example_config_visual_guidance.py
161
+
162
+ # 📖 Visual Narrative task
163
+ CUDA_VISIBLE_DEVICES=0,1 python inference_vllm.py --cfg configs/example_config_visual_narrative.py
164
+ ```
165
+
166
+
167
+ ### Visualize Protobuf Outputs
168
+
169
+ To visualize generated protobuf files (--video: Generate video visualizations for interleaved output):
170
+
171
+ ```bash
172
+ python src/utils/vis_proto.py --input <input_proto_path> [--output <output_dir>] [--video]
173
+ ```
174
+
175
+ - `--input`: supports a single `.pb` file or a directory; directories are scanned recursively.
176
+ - `--output`: optional; defaults to `<input_dir>/results/<file_stem>` for files, or `<parent_dir_of_input>/results` for directories.
177
+
178
+ Expected output directory layout (example):
179
+
180
+ ```text
181
+ results/<pb_name>/
182
+ ├── 000_question.txt
183
+ ├── 000_global_cot.txt
184
+ ├── 001_text.txt
185
+ ├── 001_00_image.png
186
+ ├── 001_00_image_cot.txt
187
+ ├── 002_text.txt
188
+ ├── 002_00_image.png
189
+ ├── ...
190
+ └── video.mp4 # only when --video is enabled
191
+ ```
192
+
193
+ Each `*_text.txt` stores decoded segments, `*_image.png` stores generated frames, and matching `*_image_cot.txt` keeps image-level chain-of-thought notes when available.
194
+
195
+ ## 3. Gradio Demo
196
+
197
+ We provide two Gradio Demos for different application scenarios:
198
+
199
+ Emu3.5-Image Demo —— Interactive interface optimized for Text-to-Image (T2I) and Any-to-Image (X2I) tasks:
200
+
201
+ ```bash
202
+ CUDA_VISIBLE_DEVICES=0,1 python gradio_demo_image.py --host 0.0.0.0 --port 7860
203
+ ```
204
+
205
+ Emu3.5-Interleave Demo —— Launch Emu3.5 Interleave Tasks (Visual Guidance and Visual Narrate) Gradio Demo
206
+ ```bash
207
+ CUDA_VISIBLE_DEVICES=0,1 python gradio_demo_interleave.py --host 0.0.0.0 --port 7860
208
+ ```
209
+
210
+ ### Features
211
+
212
+ - Image Generation: Support Text-to-Image Generation and Multimodal Image Generation
213
+ - Interleaved Generation: Support long-sequence creation with alternating image and text generation
214
+ - Multiple Aspect Ratios for T2I: 9 preset aspect ratios (4:3, 16:9, 1:1, etc.) plus auto mode
215
+ - Chain-of-Thought Display: Automatically parse and format model's internal thinking process
216
+ - Real-time Streaming: Stream text and image generation with live updates
217
+
218
+ ### Official Web & Mobile Apps
219
+
220
+ - **Web**: Production-ready Emu3.5 experience is available at [zh.emu.world](https://zh.emu.world) (Mainland China) and [emu.world](https://emu.world) (global), featuring a curated homepage, “Create” workspace, inspiration feed, history, personal profile, and language switching.
221
+ - **Mobile (Android APK & H5)**: Mobile clients provide the same core flows — prompt-based creation, “inspiration” gallery, personal center, and feedback & privacy entrypoints — with automatic UI language selection based on system settings.
222
+ - **Docs**: For product usage details, see the **Emu3.5 AI 使用指南 (Chinese)** and **Emu3.5 AI User Guide (English)**:
223
+ - CN: [Emu3.5 AI 使用指南](https://jwolpxeehx.feishu.cn/wiki/BKuKwkzZOi4pdRkVV13csI0FnIg?from=from_copylink)
224
+ - EN: [Emu3.5 AI User Guide](https://jwolpxeehx.feishu.cn/wiki/Gcxtw9XHhisUu8kBEaac6s6xnhc?from=from_copylink)
225
+
226
+ #### Mobile App Download (QR Codes)
227
+
228
+ <div align='center'>
229
+ <table>
230
+ <tr>
231
+ <td align="center">
232
+ <img src="https://github.com/baaivision/Emu3.5/blob/main/assets/qr_zh.png?raw=True" alt="Emu3.5 Mobile App (Mainland China)" width="220" />
233
+ <br />
234
+ <sub><b>Emu3.5 Mobile · Mainland China</b></sub>
235
+ </td>
236
+ <td align="center">
237
+ <img src="https://github.com/baaivision/Emu3.5/blob/main/assets/qr.png?raw=True" alt="Emu3.5 Mobile App (Global)" width="220" />
238
+ <br />
239
+ <sub><b>Emu3.5 Mobile · Global</b></sub>
240
+ </td>
241
+ </tr>
242
+ </table>
243
+ </div>
244
+
245
+
246
+
247
+ ## 4. Schedule
248
+
249
+ - [x] Inference Code (NTP Version)
250
+ - [ ] Advanced Image Decoder
251
+ - [ ] Discrete Diffusion Adaptation (DiDA) Inference & Weights
252
+
253
+
254
+ ## 5. Citation
255
+
256
+ ```bibtex
257
+ @misc{cui2025emu35nativemultimodalmodels,
258
+ title={Emu3.5: Native Multimodal Models are World Learners},
259
+ author={Yufeng Cui and Honghao Chen and Haoge Deng and Xu Huang and Xinghang Li and Jirong Liu and Yang Liu and Zhuoyan Luo and Jinsheng Wang and Wenxuan Wang and Yueze Wang and Chengyuan Wang and Fan Zhang and Yingli Zhao and Ting Pan and Xianduo Li and Zecheng Hao and Wenxuan Ma and Zhuo Chen and Yulong Ao and Tiejun Huang and Zhongyuan Wang and Xinlong Wang},
260
+ year={2025},
261
+ eprint={2510.26583},
262
+ archivePrefix={arXiv},
263
+ primaryClass={cs.CV},
264
+ url={https://arxiv.org/abs/2510.26583},
265
+ }
266
+ ```
emu3_vqvae/__pycache__/configuration_emu3p5visionvq.cpython-313.pyc ADDED
Binary file (4.12 kB). View file
 
emu3_vqvae/__pycache__/modeling_emu3p5visionvq.cpython-313.pyc ADDED
Binary file (22 kB). View file
 
emu3_vqvae/config.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "Emu3p5VisionVQModel"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_emu3p5visionvq.Emu3p5VisionVQConfig",
7
+ "AutoModel": "modeling_emu3p5visionvq.Emu3p5VisionVQModel"
8
+ },
9
+ "attn_resolutions": [
10
+ 16
11
+ ],
12
+ "ch": 256,
13
+ "ch_mult": [
14
+ 1,
15
+ 1,
16
+ 2,
17
+ 2,
18
+ 4
19
+ ],
20
+ "codebook_size": 131072,
21
+ "double_z": false,
22
+ "dropout": 0.0,
23
+ "embed_dim": 256,
24
+ "in_channels": 3,
25
+ "model_type": "Emu3p5VisionVQ",
26
+ "num_res_blocks": 4,
27
+ "out_ch": 3,
28
+ "resolution": 256,
29
+ "torch_dtype": "float32",
30
+ "transformers_version": "4.51.0",
31
+ "z_channels": 256
32
+ }
emu3_vqvae/config.yaml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ddconfig:
2
+ double_z: False
3
+ z_channels: 256
4
+ resolution: 256
5
+ in_channels: 3
6
+ out_ch: 3
7
+ ch: 256
8
+ ch_mult: [1, 1, 2, 2, 4]
9
+ num_res_blocks: 4
10
+ attn_resolutions: [16]
11
+ dropout: 0.0
12
+
13
+ n_embed: 131072
14
+ embed_dim: 256
emu3_vqvae/configuration_emu3p5visionvq.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2025 The Emu team, BAAI and The HuggingFace Inc. team. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """ Emu3p5VisionVQ model configuration """
16
+
17
+ from typing import List
18
+
19
+ from transformers.configuration_utils import PretrainedConfig
20
+ from transformers.utils import logging
21
+
22
+
23
+ logger = logging.get_logger(__name__)
24
+
25
+
26
+ class Emu3p5VisionVQConfig(PretrainedConfig):
27
+ r"""
28
+ This is the configuration class to store the configuration of a [`Emu3p5VisionVQ`]. It is used to instantiate an video movq
29
+ model according to the specified arguments, defining the model architecture. Instantiating a configuration with the
30
+ defaults will yield a configuration to the VQ model presented in Emu3p5 paper.
31
+ Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
32
+ documentation from [`PretrainedConfig`] for more information.
33
+ Args:
34
+ codebook_size (`int`, *optional*, defaults to 32768):
35
+ Codebook size of the VQ model.
36
+ embed_dim (`int`, *optional*, defaults to 4):
37
+ Dimension of the quantized vector in codebook.
38
+ z_channels (`int`, *optional*, defaults to 4):
39
+ Dimension of the output channel of encoder and the input channel of decoder
40
+ double_z (`bool`, *optional*, defaults to False):
41
+ Whether double the output dim of the encoder.
42
+ in_channels (`int`, *optional*, defaults to 3):
43
+ Input channel of encoder.
44
+ out_channels (`int`, *optional*, defaults to 3):
45
+ Output channel of decoder.
46
+ temporal_downsample_factor (`int`, *optional*, defaults to 4):
47
+ Temporal downsample factor.
48
+ ch (`int`, *optional*, defaults to 256):
49
+ Basic channel number of the intermediate blocks.
50
+ ch_mult (`List[int]`, *optional*, defaults to `[1, 2, 2, 4]`):
51
+ Channel scaling factor of the intermediate blocks.
52
+ num_res_blocks (`int`, *optional*, defaults to 2):
53
+ Residual block number in each stage.
54
+ attn_resolutions (`List[int]`, *optional*, defaults to 3):
55
+ Stage indices to apply attention.
56
+ dropout (`float`, *optional*, defaults to 0.0):
57
+ Dropout probability.
58
+ ```python
59
+ >>> from configuration_emu3p5visionvq import Emu3VisionVQConfig
60
+ >>> from modeling_emu3p5visionvq import Emu3VisionVQ
61
+ >>> # Initializing a video VQ model of Emu3 configuration
62
+ >>> configuration = Emu3VisionVQConfig()
63
+ >>> # Initializing a model from the Emu3 VQ model style configuration
64
+ >>> model = Emu3VisionVQModel(configuration)
65
+ >>> # Accessing the model configuration
66
+ >>> configuration = model.config
67
+ ```"""
68
+
69
+ model_type = "Emu3p5VisionVQ"
70
+
71
+ def __init__(
72
+ self,
73
+ double_z: bool = False,
74
+ z_channels: int = 256,
75
+ resolution: int = 256,
76
+ in_channels: int = 3,
77
+ out_ch: int = 3,
78
+ ch: int = 256,
79
+ ch_mult: List[int] = [1, 1, 2, 2, 4],
80
+ num_res_blocks: int = 4,
81
+ attn_resolutions: List[int] = [16],
82
+ dropout: float = 0.0,
83
+ codebook_size: int = 131072,
84
+ embed_dim: int = 256,
85
+ **kwargs,
86
+ ):
87
+ super().__init__(**kwargs)
88
+
89
+ self.double_z = double_z
90
+ self.z_channels = z_channels
91
+ self.resolution = resolution
92
+ self.in_channels = in_channels
93
+ self.out_ch = out_ch
94
+ self.ch = ch
95
+ self.ch_mult = ch_mult
96
+ self.num_res_blocks = num_res_blocks
97
+ self.attn_resolutions = attn_resolutions
98
+ self.dropout = dropout
99
+
100
+ self.codebook_size = codebook_size
101
+ self.embed_dim = embed_dim
emu3_vqvae/kmeans_16384_centroids.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:067f23d13ab9a2395937b08c12fc58a421f76ac274e3e0190a62bd508a251d7e
3
+ size 17827709
emu3_vqvae/kmeans_4096_centroids.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b1c23d1383f62aa820c90ae1bd63824e3527ca8652aef149b03bf7ab269f92ec
3
+ size 5244726
emu3_vqvae/kmeans_8192_centroids.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ac5a012f68e85291f838697645351f8cc22f8b874b6406cabbaf760e3d701bc5
3
+ size 9439030
emu3_vqvae/model.ckpt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fe8bdb9e6546861b493d1f10f125e60394459656674510104ee47c61ff849d08
3
+ size 1821481006
emu3_vqvae/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a808dc617e489c37be7f51a63a0e7cb77a97a54ceb59f674255d2e7bc7b2c080
3
+ size 1821405084
emu3_vqvae/modeling_emu3p5visionvq.py ADDED
@@ -0,0 +1,497 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2025 The Emu team, BAAI and The HuggingFace Inc. team. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """ Emu3p5VisionVQ model """
16
+
17
+
18
+ import math
19
+ from typing import Optional, Tuple, Union
20
+
21
+ import torch
22
+ from torch import nn, einsum
23
+ from torch.nn import functional as F
24
+ from transformers.modeling_utils import PreTrainedModel
25
+
26
+ from .configuration_emu3p5visionvq import Emu3p5VisionVQConfig
27
+
28
+
29
+ def nonlinearity(x):
30
+ # swish
31
+ return x * torch.sigmoid(x)
32
+
33
+
34
+ def Emu3p5VisionVQNormalize(in_channels):
35
+ return nn.GroupNorm(num_groups=32, num_channels=in_channels, eps=1e-6, affine=True)
36
+
37
+
38
+ class Emu3p5VisionVQUpsample(nn.Module):
39
+
40
+ def __init__(self, in_channels):
41
+ super().__init__()
42
+ self.conv = nn.Conv2d(
43
+ in_channels,
44
+ in_channels,
45
+ kernel_size=3,
46
+ stride=1,
47
+ padding=1,
48
+ )
49
+
50
+ def forward(self, x):
51
+ x = F.interpolate(x, scale_factor=2.0, mode="nearest")
52
+ x = self.conv(x)
53
+ return x
54
+
55
+
56
+ class Emu3p5VisionVQDownsample(nn.Module):
57
+
58
+ def __init__(self, in_channels):
59
+ super().__init__()
60
+ self.conv = nn.Conv2d(
61
+ in_channels,
62
+ in_channels,
63
+ kernel_size=3,
64
+ stride=2,
65
+ padding=0,
66
+ )
67
+
68
+ def forward(self, x):
69
+ pad = (0, 1, 0, 1)
70
+ x = F.pad(x, pad, mode="constant", value=0)
71
+ x = self.conv(x)
72
+ return x
73
+
74
+
75
+ class Emu3p5VisionVQResnetBlock(nn.Module):
76
+
77
+ def __init__(
78
+ self,
79
+ *,
80
+ in_channels: int,
81
+ out_channels: Optional[int] = None,
82
+ conv_shortcut: bool = False,
83
+ dropout: float = 0.0
84
+ ):
85
+ super().__init__()
86
+ self.in_channels = in_channels
87
+ out_channels = in_channels if out_channels is None else out_channels
88
+ self.out_channels = out_channels
89
+ self.use_conv_shortcut = conv_shortcut
90
+
91
+ self.norm1 = Emu3p5VisionVQNormalize(in_channels)
92
+ self.conv1 = nn.Conv2d(
93
+ in_channels,
94
+ out_channels,
95
+ kernel_size=3,
96
+ stride=1,
97
+ padding=1,
98
+ )
99
+ self.norm2 = Emu3p5VisionVQNormalize(out_channels)
100
+ self.dropout = nn.Dropout(dropout)
101
+ self.conv2 = nn.Conv2d(
102
+ out_channels,
103
+ out_channels,
104
+ kernel_size=3,
105
+ stride=1,
106
+ padding=1,
107
+ )
108
+
109
+ if self.in_channels != self.out_channels:
110
+ if self.use_conv_shortcut:
111
+ self.conv_shortcut = nn.Conv2d(
112
+ in_channels,
113
+ out_channels,
114
+ kernel_size=3,
115
+ stride=1,
116
+ padding=1,
117
+ )
118
+ else:
119
+ self.nin_shortcut = nn.Conv2d(
120
+ in_channels,
121
+ out_channels,
122
+ kernel_size=1,
123
+ stride=1,
124
+ padding=0,
125
+ )
126
+
127
+ def forward(self, x):
128
+ h = x
129
+ h = self.norm1(h)
130
+ h = nonlinearity(h)
131
+ h = self.conv1(h)
132
+
133
+ h = self.norm2(h)
134
+ h = nonlinearity(h)
135
+ h = self.dropout(h)
136
+ h = self.conv2(h)
137
+
138
+ if self.in_channels != self.out_channels:
139
+ if self.use_conv_shortcut:
140
+ x = self.conv_shortcut(x)
141
+ else:
142
+ x = self.nin_shortcut(x)
143
+
144
+ return x + h
145
+
146
+
147
+ class Emu3p5VisionVQAttnBlock(nn.Module):
148
+
149
+ def __init__(self, in_channels):
150
+ super().__init__()
151
+ self.in_channels = in_channels
152
+
153
+ self.norm = Emu3p5VisionVQNormalize(in_channels)
154
+ self.q = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0)
155
+ self.k = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0)
156
+ self.v = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0)
157
+ self.proj_out = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0)
158
+
159
+
160
+ def forward(self, x):
161
+ h_ = x
162
+ h_ = self.norm(h_)
163
+ q = self.q(h_)
164
+ k = self.k(h_)
165
+ v = self.v(h_)
166
+
167
+ # compute attention
168
+ b,c,h,w = q.shape
169
+ q = q.reshape(b, c, h * w)
170
+ q = q.permute(0, 2, 1) # b,hw,c
171
+ k = k.reshape(b, c, h * w) # b,c,hw
172
+ w_ = torch.bmm(q, k) # b,hw,hw w[b,i,j]=sum_c q[b,i,c]k[b,c,j]
173
+ w_ = w_ * (int(c) ** (-0.5))
174
+ w_ = F.softmax(w_, dim=2)
175
+
176
+ # attend to values
177
+ v = v.reshape(b, c, h * w)
178
+ w_ = w_.permute(0, 2, 1) # b,hw,hw (first hw of k, second of q)
179
+ h_ = torch.bmm(v, w_) # b, c,hw (hw of q) h_[b,c,j] = sum_i v[b,c,i] w_[b,i,j]
180
+ h_ = h_.reshape(b, c, h, w)
181
+
182
+ h_ = self.proj_out(h_)
183
+
184
+ return x + h_
185
+
186
+
187
+ class Emu3p5VisionVQEncoder(nn.Module):
188
+
189
+ def __init__(self, config: Emu3p5VisionVQConfig):
190
+ super().__init__()
191
+ self.ch = config.ch
192
+ self.num_resolutions = len(config.ch_mult)
193
+ self.num_res_blocks = config.num_res_blocks
194
+ self.in_channels = config.in_channels
195
+ self.resolution = config.resolution
196
+
197
+ # downsampling
198
+ self.conv_in = nn.Conv2d(
199
+ self.in_channels,
200
+ self.ch,
201
+ kernel_size=3,
202
+ stride=1,
203
+ padding=1,
204
+ )
205
+
206
+ curr_res = self.resolution
207
+
208
+ in_ch_mult = (1, ) + tuple(config.ch_mult)
209
+ self.down = nn.ModuleList()
210
+ for i_level in range(self.num_resolutions):
211
+ block = nn.ModuleList()
212
+ attn = nn.ModuleList()
213
+ block_in = config.ch * in_ch_mult[i_level]
214
+ block_out = config.ch * config.ch_mult[i_level]
215
+ for i_block in range(self.num_res_blocks):
216
+ block.append(
217
+ Emu3p5VisionVQResnetBlock(
218
+ in_channels=block_in,
219
+ out_channels=block_out,
220
+ dropout=config.dropout,
221
+ ),
222
+ )
223
+ block_in = block_out
224
+ if curr_res in config.attn_resolutions:
225
+ attn.append(Emu3p5VisionVQAttnBlock(block_in))
226
+
227
+ down = nn.Module()
228
+ down.block = block
229
+ down.attn = attn
230
+ if i_level != self.num_resolutions - 1:
231
+ down.downsample = Emu3p5VisionVQDownsample(block_in)
232
+ curr_res = curr_res // 2
233
+
234
+ self.down.append(down)
235
+
236
+ # middle
237
+ self.mid = nn.Module()
238
+ self.mid.block_1 = Emu3p5VisionVQResnetBlock(
239
+ in_channels=block_in,
240
+ out_channels=block_in,
241
+ dropout=config.dropout,
242
+ )
243
+ self.mid.attn_1 = Emu3p5VisionVQAttnBlock(block_in)
244
+ self.mid.block_2 = Emu3p5VisionVQResnetBlock(
245
+ in_channels=block_in,
246
+ out_channels=block_in,
247
+ dropout=config.dropout,
248
+ )
249
+
250
+ # end
251
+ self.norm_out = Emu3p5VisionVQNormalize(block_in)
252
+ self.conv_out = nn.Conv2d(
253
+ block_in,
254
+ 2 * config.z_channels if config.double_z else config.z_channels,
255
+ kernel_size=3,
256
+ stride=1,
257
+ padding=1,
258
+ )
259
+
260
+
261
+ def forward(self, x):
262
+ # downsampling
263
+ hs = [self.conv_in(x)]
264
+ for i_level in range(self.num_resolutions):
265
+ for i_block in range(self.num_res_blocks):
266
+ h = self.down[i_level].block[i_block](hs[-1])
267
+ if len(self.down[i_level].attn) > 0:
268
+ h = self.down[i_level].attn[i_block](h)
269
+ hs.append(h)
270
+
271
+ if i_level != self.num_resolutions - 1:
272
+ hs.append(self.down[i_level].downsample(hs[-1]))
273
+
274
+ # middle
275
+ h = hs[-1]
276
+ h = self.mid.block_1(h)
277
+ h = self.mid.attn_1(h)
278
+ h = self.mid.block_2(h)
279
+
280
+ # end
281
+ h = self.norm_out(h)
282
+ h = nonlinearity(h)
283
+ h = self.conv_out(h)
284
+ return h
285
+
286
+
287
+ class Emu3p5VisionVQDecoder(nn.Module):
288
+
289
+ def __init__(self, config: Emu3p5VisionVQConfig):
290
+ super().__init__()
291
+ self.ch = config.ch
292
+ self.num_resolutions = len(config.ch_mult)
293
+ self.num_res_blocks = config.num_res_blocks
294
+
295
+ self.resolution = config.resolution
296
+
297
+ # compute in_ch_mult, block_in and curr_res at lowest res
298
+ in_ch_mult = (1, ) + tuple(config.ch_mult)
299
+ block_in = config.ch * config.ch_mult[self.num_resolutions-1]
300
+
301
+ curr_res = config.resolution // 2 ** (self.num_resolutions - 1)
302
+ self.z_shape = (1, config.z_channels, curr_res, curr_res)
303
+
304
+ # z to block_in
305
+ self.conv_in = nn.Conv2d(
306
+ config.z_channels,
307
+ block_in,
308
+ kernel_size=3,
309
+ stride=1,
310
+ padding=1,
311
+ )
312
+
313
+ # middle
314
+ self.mid = nn.Module()
315
+ self.mid.block_1 = Emu3p5VisionVQResnetBlock(
316
+ in_channels=block_in,
317
+ out_channels=block_in,
318
+ dropout=config.dropout,
319
+ )
320
+ self.mid.attn_1 = Emu3p5VisionVQAttnBlock(block_in)
321
+ self.mid.block_2 = Emu3p5VisionVQResnetBlock(
322
+ in_channels=block_in,
323
+ out_channels=block_in,
324
+ dropout=config.dropout,
325
+ )
326
+
327
+ # upsampling
328
+ self.up = nn.ModuleList()
329
+ for i_level in reversed(range(self.num_resolutions)):
330
+ block = nn.ModuleList()
331
+ attn = nn.ModuleList()
332
+ block_out = config.ch * config.ch_mult[i_level]
333
+ for i_block in range(self.num_res_blocks + 1):
334
+ block.append(
335
+ Emu3p5VisionVQResnetBlock(
336
+ in_channels=block_in,
337
+ out_channels=block_out,
338
+ dropout=config.dropout,
339
+ ),
340
+ )
341
+ block_in = block_out
342
+ if curr_res in config.attn_resolutions:
343
+ attn.append(Emu3p5VisionVQAttnBlock(block_in))
344
+
345
+ up = nn.Module()
346
+ up.block = block
347
+ up.attn = attn
348
+ if i_level != 0:
349
+ up.upsample = Emu3p5VisionVQUpsample(block_in)
350
+ curr_res = curr_res * 2
351
+ self.up.insert(0, up) # prepend to get consistent order
352
+
353
+ # end
354
+ self.norm_out = Emu3p5VisionVQNormalize(block_in)
355
+ self.conv_out = nn.Conv2d(
356
+ block_in,
357
+ config.out_ch,
358
+ kernel_size=3,
359
+ stride=1,
360
+ padding=1,
361
+ )
362
+
363
+ def forward(self, z):
364
+ # z to block_in
365
+ h = self.conv_in(z)
366
+
367
+ # middle
368
+ h = self.mid.block_1(h)
369
+ h = self.mid.attn_1(h)
370
+ h = self.mid.block_2(h)
371
+
372
+ # upsampling
373
+ for i_level in reversed(range(self.num_resolutions)):
374
+ for i_block in range(self.num_res_blocks + 1):
375
+ h = self.up[i_level].block[i_block](h)
376
+ if len(self.up[i_level].attn) > 0:
377
+ h = self.up[i_level].attn[i_block](h)
378
+
379
+ if i_level != 0:
380
+ h = self.up[i_level].upsample(h)
381
+
382
+ h = self.norm_out(h)
383
+ h = nonlinearity(h)
384
+ h = self.conv_out(h)
385
+
386
+ return h
387
+
388
+
389
+ class Emu3p5VisionVQVectorQuantizer(nn.Module):
390
+
391
+ def __init__(self, config):
392
+ super().__init__()
393
+
394
+ self.n_e = config.codebook_size
395
+ self.e_dim = config.embed_dim
396
+
397
+ self.embedding = nn.Embedding(self.n_e, self.e_dim)
398
+
399
+ def forward(self, z):
400
+ # z: [b, d, h, w]
401
+ embedding = self.embedding.weight # [n, d]
402
+
403
+ # cal similarity
404
+ logits = torch.einsum("b d h w, n d -> b n h w", z, embedding)
405
+
406
+ # get max indices
407
+ ind = logits.argmax(dim=1) # [b, h, w]
408
+
409
+ # lookup embedding
410
+ z_q = embedding[ind] # [b, h, w, d]
411
+ z_q = z_q.permute(0, 3, 1, 2).contiguous() # -> [b, d, h, w]
412
+
413
+ return z_q, ind.flatten()
414
+
415
+ def get_codebook_entry(self, indices, shape=None):
416
+ # get quantized latent vectors
417
+ z_q = self.embedding(indices)
418
+
419
+ # shape should in B H W
420
+ if shape is not None:
421
+ if len(shape) == 3:
422
+ shape = shape + (self.e_dim, )
423
+
424
+ z_q = z_q.view(shape)
425
+
426
+ # reshape back to match original input shape
427
+ # b h w c -> b c h w
428
+ z_q = z_q.permute(0, 3, 1, 2).contiguous()
429
+
430
+ return z_q
431
+
432
+
433
+ class Emu3p5VisionVQPretrainedModel(PreTrainedModel):
434
+ """
435
+ An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained
436
+ models.
437
+ """
438
+
439
+ config_class = Emu3p5VisionVQConfig
440
+ base_model_prefix = "emu3p5visionvq"
441
+ main_input_name = "pixel_values"
442
+ _no_split_modules = ["Emu3p5VisionVQResnetBlock", "Emu3p5VisionVQAttnBlock"]
443
+
444
+ def _init_weights(self, module):
445
+ if isinstance(module, nn.Conv2d):
446
+ nn.init.kaiming_normal_(module.weight, mode="fan_out", nonlinearity="relu")
447
+ # copied from the `reset_parameters` method of `class Linear(Module)` in `torch`.
448
+ elif isinstance(module, nn.Linear):
449
+ nn.init.kaiming_uniform_(module.weight, a=math.sqrt(5))
450
+ if module.bias is not None:
451
+ fan_in, _ = nn.init._calculate_fan_in_and_fan_out(module.weight)
452
+ bound = 1 / math.sqrt(fan_in) if fan_in > 0 else 0
453
+ nn.init.uniform_(module.bias, -bound, bound)
454
+ elif isinstance(module, (nn.BatchNorm2d, nn.GroupNorm)):
455
+ nn.init.constant_(module.weight, 1)
456
+ nn.init.constant_(module.bias, 0)
457
+
458
+
459
+ class Emu3p5VisionVQModel(Emu3p5VisionVQPretrainedModel):
460
+
461
+ def __init__(self, config):
462
+ super().__init__(config)
463
+ self.config = config
464
+
465
+ self.encoder = Emu3p5VisionVQEncoder(config)
466
+ self.decoder = Emu3p5VisionVQDecoder(config)
467
+ self.quantize = Emu3p5VisionVQVectorQuantizer(config)
468
+
469
+ self.quant_conv = nn.Conv2d(config.z_channels, config.embed_dim, 1)
470
+ self.post_quant_conv = nn.Conv2d(config.embed_dim, config.z_channels, 1)
471
+
472
+ self.post_init()
473
+
474
+ def encode(self, x: torch.Tensor):
475
+ h = self.encoder(x)
476
+ h = self.quant_conv(h)
477
+ quant_embed, token_ids = self.quantize(h)
478
+ return quant_embed, None, (None, None, token_ids)
479
+
480
+ def decode(self, x: torch.Tensor):
481
+ quant = self.post_quant_conv(x)
482
+ dec = self.decoder(quant)
483
+ return dec
484
+
485
+ def decode_code(self, code_b, shape=None):
486
+ # shape specifying (batch, height, width, channel)
487
+ quant_b = self.quantize.get_codebook_entry(code_b, shape=shape)
488
+ dec = self.decode(quant_b)
489
+ return dec
490
+
491
+ @property
492
+ def device(self):
493
+ return next(self.parameters()).device
494
+
495
+ @property
496
+ def dtype(self):
497
+ return next(self.parameters()).dtype
generation_config.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 1,
4
+ "eos_token_id": [
5
+ 11
6
+ ],
7
+ "pad_token_id": 11,
8
+ "transformers_version": "4.57.6",
9
+ "use_cache": false
10
+ }
model-00001-of-00006.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fca85a57b1599179932dc1a86e59e8e62bc8274546352b3652306b6416f1e4d7
3
+ size 4890748112
model-00002-of-00006.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5d71d0e8ee75eee705a5dbf1a1dc222c14573313e2b50e003d0d820987914bc8
3
+ size 4999819544
model-00003-of-00006.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7684d01a16c378fc244612b03af29abd8b7256e95f3efe8c90198c220fa457df
3
+ size 4915916384
model-00004-of-00006.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9706f2fd60f19d4a7e0ff6f3ba82f186c5aec3ef79bb344ecc554bff7b1fbdbd
3
+ size 4809726808
model-00005-of-00006.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fa98aa61fa6080ed55366254228da6abbf15dac3e2b2404e891be615336b706d
3
+ size 3929908038
model-00006-of-00006.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0d50ce0c9d8d64e6557f1ad4a65299dce801fc3b9591868b5c5880873723a644
3
+ size 2155913464
model.safetensors.index.json ADDED
The diff for this file is too large to render. See raw diff
 
modeling_ministral.py ADDED
@@ -0,0 +1,658 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections.abc import Callable
2
+ from typing import Optional, Union
3
+
4
+ import torch
5
+ from torch import nn
6
+ from torch.utils.checkpoint import checkpoint as torch_checkpoint
7
+
8
+ from transformers.utils.generic import check_model_inputs
9
+
10
+ from transformers.activations import ACT2FN
11
+ from transformers.cache_utils import Cache, DynamicCache
12
+ from transformers.generation import GenerationMixin
13
+ # from transformers.integrations import use_kernel_forward_from_hub, use_kernel_func_from_hub, use_kernelized_func
14
+ from transformers.integrations import use_kernel_forward_from_hub
15
+ from transformers.masking_utils import create_causal_mask, create_sliding_window_causal_mask, ALL_MASK_ATTENTION_FUNCTIONS
16
+ try:
17
+ from transformers.masking_utils import sdpa_mask_older_torch
18
+ except ImportError:
19
+ sdpa_mask_older_torch = None
20
+ from transformers.modeling_flash_attention_utils import FlashAttentionKwargs
21
+ from transformers.modeling_layers import (
22
+ GenericForQuestionAnswering,
23
+ GenericForSequenceClassification,
24
+ GenericForTokenClassification,
25
+ GradientCheckpointingLayer,
26
+ )
27
+ from transformers.modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast
28
+ from transformers.modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update
29
+ from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
30
+ from transformers.processing_utils import Unpack
31
+ from transformers.utils import TransformersKwargs, auto_docstring, can_return_tuple
32
+ # from transformers.utils.generic import maybe_autocast
33
+ from .configuration_ministral_dlm import MinistralDLMConfig
34
+ from functools import partial
35
+ #ALL_MASK_ATTENTION_FUNCTIONS._global_mapping['sdpa'] = sdpa_mask_older_torch
36
+
37
+ def rotate_half(x):
38
+ """Rotates half the hidden dims of the input."""
39
+ x1 = x[..., : x.shape[-1] // 2]
40
+ x2 = x[..., x.shape[-1] // 2 :]
41
+ return torch.cat((-x2, x1), dim=-1)
42
+
43
+ # @use_kernel_func_from_hub("rotary_pos_emb")
44
+ def apply_rotary_pos_emb(q, k, cos, sin, position_ids=None, unsqueeze_dim=1):
45
+ """Applies Rotary Position Embedding to the query and key tensors.
46
+
47
+ Args:
48
+ q (`torch.Tensor`): The query tensor.
49
+ k (`torch.Tensor`): The key tensor.
50
+ cos (`torch.Tensor`): The cosine part of the rotary embedding.
51
+ sin (`torch.Tensor`): The sine part of the rotary embedding.
52
+ position_ids (`torch.Tensor`, *optional*):
53
+ Deprecated and unused.
54
+ unsqueeze_dim (`int`, *optional*, defaults to 1):
55
+ The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
56
+ sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
57
+ that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
58
+ k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
59
+ cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
60
+ the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
61
+ Returns:
62
+ `tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
63
+ """
64
+ cos = cos.unsqueeze(unsqueeze_dim)
65
+ sin = sin.unsqueeze(unsqueeze_dim)
66
+ q_embed = (q * cos) + (rotate_half(q) * sin)
67
+ k_embed = (k * cos) + (rotate_half(k) * sin)
68
+ return q_embed, k_embed
69
+
70
+
71
+ def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
72
+ """
73
+ This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
74
+ num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
75
+ """
76
+ batch, num_key_value_heads, slen, head_dim = hidden_states.shape
77
+ if n_rep == 1:
78
+ return hidden_states
79
+ hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
80
+ return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
81
+
82
+
83
+ def eager_attention_forward(
84
+ module: nn.Module,
85
+ query: torch.Tensor,
86
+ key: torch.Tensor,
87
+ value: torch.Tensor,
88
+ attention_mask: Optional[torch.Tensor],
89
+ scaling: float,
90
+ dropout: float = 0.0,
91
+ **kwargs: Unpack[TransformersKwargs],
92
+ ):
93
+ key_states = repeat_kv(key, module.num_key_value_groups)
94
+ value_states = repeat_kv(value, module.num_key_value_groups)
95
+
96
+ attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
97
+ if attention_mask is not None:
98
+ causal_mask = attention_mask[:, :, :, : key_states.shape[-2]]
99
+ attn_weights = attn_weights + causal_mask
100
+
101
+ attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
102
+ attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
103
+ attn_output = torch.matmul(attn_weights, value_states)
104
+ attn_output = attn_output.transpose(1, 2).contiguous()
105
+
106
+ return attn_output, attn_weights
107
+
108
+
109
+ def _get_llama_4_attn_scale(positions_ids: torch.Tensor, beta, max_position_embeddings) -> torch.Tensor:
110
+ if not beta or not max_position_embeddings:
111
+ return torch.ones(1, device=positions_ids.device, dtype=torch.float32)
112
+ scaling = 1 + beta * torch.log(1 + torch.floor(positions_ids / max_position_embeddings))
113
+ return scaling.unsqueeze(-1)
114
+
115
+
116
+ # @use_kernelized_func(apply_rotary_pos_emb)
117
+ class Ministral3Attention(nn.Module):
118
+ """Multi-headed attention from 'Attention Is All You Need' paper"""
119
+
120
+ def __init__(self, config: MinistralDLMConfig, layer_idx: int):
121
+ super().__init__()
122
+ self.config = config
123
+ self.layer_idx = layer_idx
124
+ self.head_dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads
125
+ self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
126
+ self.scaling = self.head_dim**-0.5
127
+ self.attention_dropout = config.attention_dropout
128
+ self.is_causal = True
129
+ self.q_proj = nn.Linear(config.hidden_size, config.num_attention_heads * self.head_dim, bias=False)
130
+ self.k_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=False)
131
+ self.v_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=False)
132
+ self.o_proj = nn.Linear(config.num_attention_heads * self.head_dim, config.hidden_size, bias=False)
133
+
134
+ self.diffusion_lm = getattr(config, 'diffusion_lm', False)
135
+
136
+ def forward(
137
+ self,
138
+ hidden_states: torch.Tensor,
139
+ position_embeddings: tuple[torch.Tensor, torch.Tensor],
140
+ attention_mask: Optional[torch.Tensor],
141
+ past_key_values: Optional[Cache] = None,
142
+ cache_position: Optional[torch.LongTensor] = None,
143
+ use_cache: Optional[bool] = False,
144
+ **kwargs: Unpack[FlashAttentionKwargs],
145
+ ) -> tuple[torch.Tensor, Optional[torch.Tensor]]:
146
+ input_shape = hidden_states.shape[:-1]
147
+ hidden_shape = (*input_shape, -1, self.head_dim)
148
+
149
+ query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
150
+ key_states = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
151
+ value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
152
+
153
+ cos, sin = position_embeddings
154
+ query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
155
+ query_states = query_states * _get_llama_4_attn_scale(
156
+ cache_position,
157
+ self.config.rope_parameters.get("llama_4_scaling_beta"),
158
+ self.config.rope_parameters.get("original_max_position_embeddings"),
159
+ ).to(query_states.dtype)
160
+
161
+ if past_key_values is not None:
162
+ if use_cache:
163
+ # sin and cos are specific to RoPE models; cache_position needed for the static cache
164
+ cache_kwargs = {"sin": sin, "cos": cos, "cache_position": cache_position}
165
+ key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx, cache_kwargs)
166
+ else: ## if use_cache == False, do not update cache
167
+ old_k, old_v = past_key_values.layers[self.layer_idx].keys, past_key_values.layers[self.layer_idx].values
168
+ key_states = torch.cat([old_k, key_states], dim=-2)
169
+ value_states = torch.cat([old_v, value_states], dim=-2)
170
+
171
+ attention_interface: Callable = eager_attention_forward
172
+ if self.config._attn_implementation != "eager":
173
+ attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation]
174
+
175
+ if self.diffusion_lm:
176
+ attn_output, attn_weights = attention_interface(
177
+ self,
178
+ query_states,
179
+ key_states,
180
+ value_states,
181
+ None,
182
+ dropout=0.0 if not self.training else self.attention_dropout,
183
+ scaling=self.scaling,
184
+ is_causal=False,
185
+ **kwargs,
186
+ )
187
+
188
+ else:
189
+ attn_output, attn_weights = attention_interface(
190
+ self,
191
+ query_states,
192
+ key_states,
193
+ value_states,
194
+ attention_mask,
195
+ dropout=0.0 if not self.training else self.attention_dropout,
196
+ scaling=self.scaling,
197
+ sliding_window=getattr(self.config, "sliding_window", None), # main diff with Llama
198
+ **kwargs,
199
+ )
200
+
201
+ attn_output = attn_output.reshape(*input_shape, -1).contiguous()
202
+ attn_output = self.o_proj(attn_output)
203
+ return attn_output, attn_weights
204
+
205
+
206
+ class Ministral3MLP(nn.Module):
207
+ def __init__(self, config):
208
+ super().__init__()
209
+ self.config = config
210
+ self.hidden_size = config.hidden_size
211
+ self.intermediate_size = config.intermediate_size
212
+ self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
213
+ self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
214
+ self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
215
+ self.act_fn = ACT2FN[config.hidden_act]
216
+
217
+ def forward(self, x):
218
+ down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
219
+ return down_proj
220
+
221
+
222
+ @use_kernel_forward_from_hub("RMSNorm")
223
+ class Ministral3RMSNorm(nn.Module):
224
+ def __init__(self, hidden_size, eps=1e-6):
225
+ """
226
+ Ministral3RMSNorm is equivalent to T5LayerNorm
227
+ """
228
+ super().__init__()
229
+ self.weight = nn.Parameter(torch.ones(hidden_size))
230
+ self.variance_epsilon = eps
231
+
232
+ def forward(self, hidden_states):
233
+ input_dtype = hidden_states.dtype
234
+ hidden_states = hidden_states.to(torch.float32)
235
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
236
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
237
+ return self.weight * hidden_states.to(input_dtype)
238
+
239
+ def extra_repr(self):
240
+ return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"
241
+
242
+ # hack
243
+ try:
244
+ import deepspeed
245
+ except ImportError:
246
+ deepspeed = None
247
+
248
+
249
+ class DeepSpeedGradientCheckpointingLayer(GradientCheckpointingLayer):
250
+ """Base class for layers with gradient checkpointing.
251
+
252
+ This class enables gradient checkpointing functionality for a layer. By default, gradient checkpointing is disabled
253
+ (`gradient_checkpointing = False`). When `model.set_gradient_checkpointing()` is called, gradient checkpointing is
254
+ enabled by setting `gradient_checkpointing = True` and assigning a checkpointing function to `_gradient_checkpointing_func`.
255
+
256
+ Important:
257
+
258
+ When using gradient checkpointing with `use_reentrant=True`, inputs that require gradients (e.g. hidden states)
259
+ must be passed as positional arguments (`*args`) rather than keyword arguments to properly propagate gradients.
260
+
261
+ Example:
262
+
263
+ ```python
264
+ >>> # Correct - hidden_states passed as positional arg
265
+ >>> out = self.layer(hidden_states, attention_mask=attention_mask)
266
+
267
+ >>> # Incorrect - hidden_states passed as keyword arg
268
+ >>> out = self.layer(hidden_states=hidden_states, attention_mask=attention_mask)
269
+ ```
270
+ """
271
+
272
+ gradient_checkpointing = False
273
+
274
+ def __call__(self,
275
+ hidden_states: torch.Tensor,
276
+ attention_mask: Optional[torch.Tensor] = None,
277
+ position_ids: Optional[torch.LongTensor] = None,
278
+ past_key_values: Optional[Cache] = None,
279
+ use_cache: Optional[bool] = False,
280
+ cache_position: Optional[torch.LongTensor] = None,
281
+ position_embeddings: Optional[tuple[torch.Tensor, torch.Tensor]] = None,
282
+ **kwargs: Unpack[TransformersKwargs]
283
+ ):
284
+ if self.gradient_checkpointing and self.training:
285
+ do_warn = False
286
+ layer_name = self.__class__.__name__
287
+ message = f"Caching is incompatible with gradient checkpointing in {layer_name}. Setting"
288
+
289
+ if "use_cache" in kwargs and kwargs["use_cache"]:
290
+ kwargs["use_cache"] = False
291
+ message += " `use_cache=False`,"
292
+ do_warn = True
293
+
294
+ if "past_key_value" in kwargs and kwargs["past_key_value"] is not None:
295
+ kwargs["past_key_value"] = None
296
+ message += " `past_key_value=None`,"
297
+ do_warn = True
298
+
299
+ if "past_key_values" in kwargs and kwargs["past_key_values"] is not None:
300
+ kwargs["past_key_values"] = None
301
+ message += " `past_key_values=None`,"
302
+ do_warn = True
303
+
304
+ if "layer_past" in kwargs and kwargs["layer_past"] is not None:
305
+ kwargs["layer_past"] = None
306
+ message += " `layer_past=None`,"
307
+ do_warn = True
308
+
309
+ # warn if anything was changed
310
+ if do_warn:
311
+ message = message.rstrip(",") + "."
312
+ print(message)
313
+ # breakpoint()
314
+ assert not any([isinstance(x,torch.Tensor) for x in kwargs.values()])
315
+ checkpoint_fn = deepspeed.checkpointing.checkpoint if deepspeed is not None else torch_checkpoint
316
+ return checkpoint_fn(
317
+ partial(super().__call__, **kwargs),
318
+ hidden_states,
319
+ attention_mask,
320
+ position_ids,
321
+ past_key_values,
322
+ use_cache,
323
+ cache_position,
324
+ position_embeddings,
325
+ )
326
+ return super().__call__(
327
+ hidden_states,attention_mask,position_ids,past_key_values,use_cache,cache_position,
328
+ position_embeddings, **kwargs
329
+ )
330
+
331
+
332
+ class Ministral3DecoderLayer(DeepSpeedGradientCheckpointingLayer):
333
+ def __init__(self, config: MinistralDLMConfig, layer_idx: int):
334
+ super().__init__()
335
+ self.hidden_size = config.hidden_size
336
+
337
+ if hasattr(config, 'attn_class'):
338
+ attn_class = config.attn_class
339
+ else:
340
+ attn_class = Ministral3Attention
341
+
342
+ self.self_attn = attn_class(config=config, layer_idx=layer_idx)
343
+ self.mlp = Ministral3MLP(config)
344
+ self.input_layernorm = Ministral3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
345
+ self.post_attention_layernorm = Ministral3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
346
+
347
+ def forward(
348
+ self,
349
+ hidden_states: torch.Tensor,
350
+ attention_mask: Optional[torch.Tensor] = None,
351
+ position_ids: Optional[torch.LongTensor] = None,
352
+ past_key_values: Optional[Cache] = None,
353
+ use_cache: Optional[bool] = False,
354
+ cache_position: Optional[torch.LongTensor] = None,
355
+ position_embeddings: Optional[tuple[torch.Tensor, torch.Tensor]] = None,
356
+ **kwargs: Unpack[TransformersKwargs],
357
+ ) -> torch.Tensor:
358
+ residual = hidden_states
359
+ hidden_states = self.input_layernorm(hidden_states)
360
+ # Self Attention
361
+ hidden_states, _ = self.self_attn(
362
+ hidden_states=hidden_states,
363
+ attention_mask=attention_mask,
364
+ position_ids=position_ids,
365
+ past_key_values=past_key_values,
366
+ use_cache=use_cache,
367
+ cache_position=cache_position,
368
+ position_embeddings=position_embeddings,
369
+ **kwargs,
370
+ )
371
+ hidden_states = residual + hidden_states
372
+
373
+ # Fully Connected
374
+ residual = hidden_states
375
+ hidden_states = self.post_attention_layernorm(hidden_states)
376
+ hidden_states = self.mlp(hidden_states)
377
+ hidden_states = residual + hidden_states
378
+ return hidden_states
379
+
380
+
381
+ @auto_docstring
382
+ class Ministral3PreTrainedModel(PreTrainedModel):
383
+ config: MinistralDLMConfig
384
+ base_model_prefix = "model"
385
+ supports_gradient_checkpointing = True
386
+ _no_split_modules = ["Ministral3DecoderLayer"]
387
+ _skip_keys_device_placement = ["past_key_values"]
388
+ _supports_flash_attn = True
389
+ _supports_sdpa = True
390
+ _supports_flex_attn = True
391
+
392
+ _can_compile_fullgraph = True
393
+ _supports_attention_backend = True
394
+ _can_record_outputs = {
395
+ "hidden_states": Ministral3DecoderLayer,
396
+ "attentions": Ministral3Attention,
397
+ }
398
+
399
+
400
+ class Ministral3RotaryEmbedding(nn.Module):
401
+ inv_freq: torch.Tensor # fix linting for `register_buffer`
402
+
403
+ def __init__(self, config: MinistralDLMConfig, device=None):
404
+ super().__init__()
405
+ self.max_seq_len_cached = config.max_position_embeddings
406
+ self.original_max_seq_len = config.max_position_embeddings
407
+
408
+ self.config = config
409
+
410
+ self.rope_type = self.config.rope_parameters["rope_type"]
411
+ rope_init_fn: Callable = self.compute_default_rope_parameters
412
+ if self.rope_type != "default":
413
+ rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
414
+ inv_freq, self.attention_scaling = rope_init_fn(self.config, device)
415
+
416
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
417
+ self.original_inv_freq = inv_freq
418
+
419
+
420
+ @staticmethod
421
+ def compute_default_rope_parameters(
422
+ config: Optional[MinistralDLMConfig] = None,
423
+ device: Optional["torch.device"] = None,
424
+ seq_len: Optional[int] = None,
425
+ ) -> tuple["torch.Tensor", float]:
426
+ """
427
+ Computes the inverse frequencies according to the original RoPE implementation
428
+ Args:
429
+ config ([`~transformers.PreTrainedConfig`]):
430
+ The model configuration.
431
+ device (`torch.device`):
432
+ The device to use for initialization of the inverse frequencies.
433
+ seq_len (`int`, *optional*):
434
+ The current sequence length. Unused for this type of RoPE.
435
+ Returns:
436
+ Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the
437
+ post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE).
438
+ """
439
+ base = config.rope_parameters["rope_theta"]
440
+ dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads
441
+
442
+ attention_factor = 1.0 # Unused in this type of RoPE
443
+
444
+ # Compute the inverse frequencies
445
+ inv_freq = 1.0 / (
446
+ base ** (torch.arange(0, dim, 2, dtype=torch.int64).to(device=device, dtype=torch.float) / dim)
447
+ )
448
+ return inv_freq, attention_factor
449
+
450
+ @torch.no_grad()
451
+ @dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope)
452
+ def forward(self, x, position_ids):
453
+ inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1).to(x.device)
454
+ position_ids_expanded = position_ids[:, None, :].float()
455
+
456
+ # device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
457
+ # with maybe_autocast(device_type=device_type, enabled=False): # Force float32
458
+
459
+ freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
460
+ emb = torch.cat((freqs, freqs), dim=-1)
461
+ cos = emb.cos() * self.attention_scaling
462
+ sin = emb.sin() * self.attention_scaling
463
+
464
+ return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
465
+
466
+
467
+ @auto_docstring
468
+ class Ministral3Model(Ministral3PreTrainedModel):
469
+ def __init__(self, config: MinistralDLMConfig):
470
+ super().__init__(config)
471
+ self.padding_idx = config.pad_token_id
472
+ self.vocab_size = config.vocab_size
473
+
474
+ self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
475
+ self.layers = nn.ModuleList(
476
+ [Ministral3DecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
477
+ )
478
+ self.norm = Ministral3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
479
+ self.rotary_emb = Ministral3RotaryEmbedding(config=config)
480
+ self.gradient_checkpointing = False
481
+
482
+ # Initialize weights and apply final processing
483
+ self.post_init()
484
+
485
+ @check_model_inputs
486
+ @auto_docstring
487
+ def forward(
488
+ self,
489
+ input_ids: Optional[torch.LongTensor] = None,
490
+ attention_mask: Optional[torch.Tensor] = None,
491
+ position_ids: Optional[torch.LongTensor] = None,
492
+ past_key_values: Optional[Cache] = None,
493
+ inputs_embeds: Optional[torch.FloatTensor] = None,
494
+ use_cache: Optional[bool] = None,
495
+ cache_position: Optional[torch.LongTensor] = None,
496
+ input_embeddings: Optional[torch.FloatTensor] = None, # for compatibility with LLaVA-1.5 input
497
+ **kwargs: Unpack[TransformersKwargs],
498
+ ) -> BaseModelOutputWithPast:
499
+ """
500
+ Args:
501
+ input_embeddings (`torch.FloatTensor`, *optional*):
502
+ Alias for `inputs_embeds` kept for backward compatibility with older LLaVA-style callers.
503
+ If provided, it overrides `inputs_embeds`.
504
+ """
505
+ if input_embeddings is not None:
506
+ inputs_embeds = input_embeddings
507
+ input_embeddings = None
508
+ # breakpoint()
509
+ if (input_ids is None) ^ (inputs_embeds is not None):
510
+ raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
511
+
512
+ if inputs_embeds is None:
513
+ inputs_embeds = self.embed_tokens(input_ids)
514
+
515
+ if use_cache and past_key_values is None:
516
+ # past_key_values = DynamicCache(config=self.config)
517
+ past_key_values = DynamicCache()
518
+
519
+ if cache_position is None:
520
+ past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
521
+ cache_position = torch.arange(
522
+ past_seen_tokens, past_seen_tokens + inputs_embeds.shape[1], device=inputs_embeds.device
523
+ )
524
+
525
+ if position_ids is None:
526
+ position_ids = cache_position.unsqueeze(0)
527
+
528
+ if kwargs.get("use_causal_mask", False):
529
+ mask_function = create_causal_mask if self.config.sliding_window is None else create_sliding_window_causal_mask
530
+ causal_mask = mask_function(
531
+ config=self.config,
532
+ input_embeds=inputs_embeds,
533
+ attention_mask=attention_mask,
534
+ cache_position=cache_position,
535
+ past_key_values=past_key_values,
536
+ position_ids=position_ids,
537
+ )
538
+
539
+ else:
540
+ causal_mask = None
541
+
542
+ hidden_states = inputs_embeds
543
+ position_embeddings = self.rotary_emb(hidden_states, position_ids=position_ids)
544
+
545
+ for decoder_layer in self.layers[: self.config.num_hidden_layers]:
546
+ hidden_states = decoder_layer(
547
+ hidden_states,
548
+ attention_mask=causal_mask,
549
+ position_ids=position_ids,
550
+ past_key_values=past_key_values,
551
+ use_cache=use_cache,
552
+ cache_position=cache_position,
553
+ position_embeddings=position_embeddings,
554
+ **kwargs,
555
+ )
556
+ hidden_states = self.norm(hidden_states)
557
+ return BaseModelOutputWithPast(
558
+ last_hidden_state=hidden_states,
559
+ past_key_values=past_key_values if use_cache else None,
560
+ )
561
+
562
+
563
+ @auto_docstring
564
+ class Ministral3ForCausalLM(Ministral3PreTrainedModel, GenerationMixin):
565
+ _tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
566
+ _tp_plan = {"lm_head": "colwise_rep"}
567
+ _pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
568
+
569
+ def __init__(self, config):
570
+ super().__init__(config)
571
+ self.model = Ministral3Model(config)
572
+ self.vocab_size = config.vocab_size
573
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
574
+
575
+ # Initialize weights and apply final processing
576
+ self.post_init()
577
+
578
+ @can_return_tuple
579
+ @auto_docstring
580
+ def forward(
581
+ self,
582
+ input_ids: Optional[torch.LongTensor] = None,
583
+ attention_mask: Optional[torch.Tensor] = None,
584
+ position_ids: Optional[torch.LongTensor] = None,
585
+ past_key_values: Optional[Cache] = None,
586
+ inputs_embeds: Optional[torch.FloatTensor] = None,
587
+ labels: Optional[torch.LongTensor] = None,
588
+ use_cache: Optional[bool] = None,
589
+ cache_position: Optional[torch.LongTensor] = None,
590
+ logits_to_keep: Union[int, torch.Tensor] = 0,
591
+ **kwargs: Unpack[TransformersKwargs],
592
+ ) -> CausalLMOutputWithPast:
593
+ r"""
594
+ Example:
595
+
596
+ ```python
597
+ >>> from transformers import AutoTokenizer, Ministral3ForCausalLM
598
+
599
+ >>> model = Ministral3ForCausalLM.from_pretrained("meta-ministral3/Ministral3-2-7b-hf")
600
+ >>> tokenizer = AutoTokenizer.from_pretrained("meta-ministral3/Ministral3-2-7b-hf")
601
+
602
+ >>> prompt = "Hey, are you conscious? Can you talk to me?"
603
+ >>> inputs = tokenizer(prompt, return_tensors="pt")
604
+
605
+ >>> # Generate
606
+ >>> generate_ids = model.generate(inputs.input_ids, max_length=30)
607
+ >>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
608
+ "Hey, are you conscious? Can you talk to me?\nI'm not conscious, but I can talk to you."
609
+ ```"""
610
+ outputs: BaseModelOutputWithPast = self.model(
611
+ input_ids=input_ids,
612
+ attention_mask=attention_mask,
613
+ position_ids=position_ids,
614
+ past_key_values=past_key_values,
615
+ inputs_embeds=inputs_embeds,
616
+ use_cache=use_cache,
617
+ cache_position=cache_position,
618
+ **kwargs,
619
+ )
620
+
621
+ hidden_states = outputs.last_hidden_state
622
+ # Only compute necessary logits, and do not upcast them to float if we are not computing the loss
623
+ slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
624
+ logits = self.lm_head(hidden_states[:, slice_indices, :])
625
+
626
+ loss = None
627
+ if labels is not None:
628
+ loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size, **kwargs)
629
+
630
+ return CausalLMOutputWithPast(
631
+ loss=loss,
632
+ logits=logits,
633
+ past_key_values=outputs.past_key_values,
634
+ hidden_states=outputs.hidden_states,
635
+ attentions=outputs.attentions,
636
+ )
637
+
638
+
639
+ class Ministral3ForTokenClassification(GenericForTokenClassification, Ministral3PreTrainedModel):
640
+ pass
641
+
642
+
643
+ class Ministral3ForSequenceClassification(GenericForSequenceClassification, Ministral3PreTrainedModel):
644
+ pass
645
+
646
+
647
+ class Ministral3ForQuestionAnswering(GenericForQuestionAnswering, Ministral3PreTrainedModel):
648
+ pass
649
+
650
+
651
+ __all__ = [
652
+ "Ministral3ForCausalLM",
653
+ "Ministral3ForQuestionAnswering",
654
+ "Ministral3Model",
655
+ "Ministral3PreTrainedModel",
656
+ "Ministral3ForSequenceClassification",
657
+ "Ministral3ForTokenClassification",
658
+ ]
modeling_ministral_dlm.py ADDED
@@ -0,0 +1,1495 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ from dataclasses import dataclass
3
+ from typing import Callable, Optional, Tuple, Union
4
+ import random
5
+ import os
6
+ import sys
7
+ import json
8
+ import numpy as np
9
+
10
+ import torch
11
+ import torch.nn.functional as F
12
+ from torch import nn
13
+ from transformers.modeling_outputs import CausalLMOutputWithPast, BaseModelOutput
14
+ from transformers.utils import ModelOutput
15
+
16
+ from torch.nn.attention.flex_attention import BlockMask, flex_attention, create_block_mask, or_masks
17
+
18
+ from transformers.modeling_flash_attention_utils import FlashAttentionKwargs
19
+
20
+ from transformers.processing_utils import Unpack
21
+
22
+ from transformers.cache_utils import Cache, DynamicCache
23
+
24
+ from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss
25
+
26
+ from transformers.generation import GenerationMixin
27
+
28
+ import math
29
+
30
+ from .chat_utils import generate_with_prefix_cache_block_diff
31
+ from .modeling_ministral import Ministral3Model, Ministral3PreTrainedModel, Ministral3Attention, apply_rotary_pos_emb, repeat_kv, _get_llama_4_attn_scale
32
+ from .configuration_ministral_dlm import MinistralDLMConfig
33
+
34
+ try:
35
+ from flash_attn import flash_attn_func
36
+ except:
37
+ print("flash attention not found, please install flash attention for better performance.")
38
+ __all__ = ["MinistralDiffEncoderModel", "MinistralFlexAttention"]
39
+
40
+ @dataclass
41
+ class MinistralDiffOutputWithPast(ModelOutput):
42
+ loss: torch.FloatTensor | None = None
43
+ logits: torch.FloatTensor | None = None
44
+ causal_logits: torch.FloatTensor | None = None
45
+ past_key_values: Cache | None = None
46
+ hidden_states: tuple[torch.FloatTensor, ...] | None = None
47
+ attentions: tuple[torch.FloatTensor, ...] | None = None
48
+
49
+
50
+ # @torch.compile(dynamic=True, mode="reduce-overhead")
51
+ # @torch.compile(mode="default")
52
+ # @torch.compile(fullgraph=True, mode="reduce-overhead", dynamic=False)
53
+ @torch.compile(fullgraph=True, mode="max-autotune-no-cudagraphs", dynamic=False)
54
+ def fused_flex_attention(q, k, v, block_mask=None):
55
+ return flex_attention(q, k, v, block_mask=block_mask)
56
+
57
+
58
+ def _crop_dynamic_cache(past_key_values: DynamicCache, max_length: int):
59
+ """Crop a DynamicCache to max_length, compatible with both old and new transformers."""
60
+ if hasattr(past_key_values, 'crop'):
61
+ past_key_values.crop(max_length)
62
+ else:
63
+ for layer_idx in range(len(past_key_values)):
64
+ past_key_values.key_cache[layer_idx] = past_key_values.key_cache[layer_idx][:, :, :max_length]
65
+ past_key_values.value_cache[layer_idx] = past_key_values.value_cache[layer_idx][:, :, :max_length]
66
+ past_key_values._seen_tokens = max_length
67
+
68
+
69
+ def _extract_draft_kv_cache(past_key_values: DynamicCache, clean_len: int, block_length: int):
70
+ """After quadratic decoding, extract only draft tokens (first of each block) from cache."""
71
+ for layer_idx in range(len(past_key_values)):
72
+ if hasattr(past_key_values, 'layers'):
73
+ layer_cache = past_key_values.layers[layer_idx]
74
+ k, v = layer_cache.keys, layer_cache.values
75
+ else:
76
+ k = past_key_values.key_cache[layer_idx]
77
+ v = past_key_values.value_cache[layer_idx]
78
+
79
+ clean_k, draft_k = k[:, :, :clean_len], k[:, :, clean_len::block_length + 1]
80
+ clean_v, draft_v = v[:, :, :clean_len], v[:, :, clean_len::block_length + 1]
81
+ new_k = torch.cat([clean_k, draft_k], dim=2)
82
+ new_v = torch.cat([clean_v, draft_v], dim=2)
83
+
84
+ if hasattr(past_key_values, 'layers'):
85
+ layer_cache.keys = new_k
86
+ layer_cache.values = new_v
87
+ else:
88
+ past_key_values.key_cache[layer_idx] = new_k
89
+ past_key_values.value_cache[layer_idx] = new_v
90
+
91
+ past_key_values._seen_tokens = clean_len + block_length
92
+
93
+ # with reference to https://github.com/pytorch-labs/attention-gym/blob/main/examples/flex_attn.ipynb
94
+ class MinistralFlexAttention(Ministral3Attention):
95
+ def __init__(self, *args, **kwargs):
96
+ super().__init__(*args, **kwargs)
97
+
98
+ self.max_seq_length = getattr(self.config, 'max_seq_length', 4096)
99
+ self.block_size_orig = self.config.block_size
100
+ self.bidirectional_mask = None
101
+ if self.config.dlm_paradigm == 'bidirectional':
102
+ self.bidirectional_mask = self.compute_block_mask(mode='bidirectional')
103
+ elif self.config.dlm_paradigm == 'autoregressive':
104
+ self.autoregressive_mask = self.compute_block_mask(mode='autoregressive')
105
+ elif self.config.dlm_paradigm == 'block_diff':
106
+ self.block_diff_mask = None
107
+ elif self.config.dlm_paradigm == 'sbd_block_diff':
108
+ self.sbd_block_diff_mask = None
109
+ else:
110
+ raise ValueError(f"Unknown attention mode: {self.config.dlm_paradigm}")
111
+
112
+ self.block_size = self.block_size_orig
113
+ self.mode = self.config.dlm_paradigm
114
+ self._quadratic_block_mask = {}
115
+
116
+ import torch._dynamo.config as dcfg
117
+ dcfg.cache_size_limit = 512
118
+
119
+
120
+ def _get_sbd_inference_quadratic_decoding_block_mask(self, block_length: int):
121
+ if block_length not in self._quadratic_block_mask:
122
+ draft_len = block_length * (block_length + 1)
123
+
124
+ def quadratic(b, h, q_idx, kv_idx):
125
+ first_clean = torch.logical_and(
126
+ kv_idx % (block_length + 1) == 0,
127
+ kv_idx < draft_len,
128
+ )
129
+ first_clean = torch.logical_and(first_clean, q_idx >= kv_idx)
130
+ block_q = q_idx // (block_length + 1)
131
+ block_kv = kv_idx // (block_length + 1)
132
+ same_block = torch.logical_and(block_q == block_kv, q_idx < draft_len)
133
+ same_block_except_first = torch.logical_and(
134
+ same_block,
135
+ q_idx % (block_length + 1) != 0,
136
+ )
137
+ draft_part = torch.logical_or(first_clean, same_block_except_first)
138
+ clean_part = kv_idx >= draft_len
139
+ return torch.logical_or(draft_part, clean_part)
140
+
141
+ block_mask = create_block_mask(
142
+ quadratic,
143
+ B=None,
144
+ H=None,
145
+ Q_LEN=draft_len,
146
+ KV_LEN=draft_len + self.config.max_position_embeddings,
147
+ device="cuda",
148
+ )
149
+
150
+ self._quadratic_block_mask[block_length] = block_mask
151
+
152
+ return self._quadratic_block_mask[block_length]
153
+
154
+
155
+ def set_attention_mode(self, mode, block_size=None):
156
+ self.mode = mode
157
+ self.block_size = block_size
158
+
159
+ def compute_block_mask(self, mode, q_len=None, block_size=None):
160
+
161
+ def bidirectional_mask(b, h, q, kv):
162
+ return (q >= kv) | (q < kv)
163
+
164
+ def autoregressive_mask(b, h, q, kv):
165
+ return (q >= kv)
166
+
167
+ def block_diff_mask(block_size, b, h, q_idx, kv_idx, n):
168
+ x0_flag_q = (q_idx >= n)
169
+ x0_flag_kv = (kv_idx >= n)
170
+
171
+ # Compute block indices
172
+ block_q = torch.where(x0_flag_q == 1,
173
+ (q_idx - n) // block_size,
174
+ q_idx // block_size)
175
+ block_kv = torch.where(x0_flag_kv == 1,
176
+ (kv_idx - n) // block_size,
177
+ kv_idx // block_size)
178
+
179
+ # **1. Block Diagonal Mask (M_BD) **
180
+ block_diagonal = (block_q == block_kv) & (x0_flag_q == x0_flag_kv)
181
+
182
+ # **2. Offset Block-Causal Mask (M_OBC) **
183
+ offset_block_causal = (
184
+ (block_q > block_kv)
185
+ & (x0_flag_kv == 1)
186
+ & (x0_flag_q == 0)
187
+ )
188
+
189
+ # **3. Block-Causal Mask (M_BC) **
190
+ block_causal = (block_q >= block_kv) & (x0_flag_kv == 1) & (x0_flag_q == 1)
191
+
192
+ # **4. Combine Masks **
193
+ return block_diagonal | offset_block_causal | block_causal
194
+
195
+
196
+ def sbd_block_diff_mask(block_size, b, h, q_idx, kv_idx, n):
197
+ x0_flag_q = (q_idx >= n)
198
+ x0_flag_kv = (kv_idx >= n)
199
+
200
+ # Compute block indices
201
+ block_q = torch.where(x0_flag_q == 1,
202
+ (q_idx - n) // block_size,
203
+ q_idx // block_size)
204
+ block_kv = torch.where(x0_flag_kv == 1,
205
+ (kv_idx - n) // block_size,
206
+ kv_idx // block_size)
207
+
208
+ # **1. Block Diagonal Mask (M_BD) **
209
+ block_diagonal = (block_q == block_kv) & (x0_flag_kv == 0) & (x0_flag_q == 0)
210
+
211
+ # **2. Offset Block-Causal Mask (M_OBC) **
212
+ offset_block_causal = (
213
+ (block_q > block_kv)
214
+ & (x0_flag_kv == 1)
215
+ & (x0_flag_q == 0)
216
+ )
217
+
218
+ # **3. Fully Causal Mask (M_BC) **
219
+ fully_causal = (q_idx >= kv_idx) & (x0_flag_kv == 1) & (x0_flag_q == 1)
220
+
221
+ # **4. Combine Masks **
222
+ return block_diagonal | offset_block_causal | fully_causal
223
+
224
+ def modality_indices_based_mask(block_size, b, h, q_idx, kv_idx, image_doc_id):
225
+ return (image_doc_id[b, q_idx] > 0) & (image_doc_id[b, q_idx] == image_doc_id[b, kv_idx])
226
+
227
+ if mode == 'bidirectional':
228
+ attn_mask = bidirectional_mask
229
+ elif mode == 'autoregressive':
230
+ attn_mask = autoregressive_mask
231
+ elif mode == 'block_diff':
232
+ assert block_size is not None
233
+ attn_mask = lambda b, h, q, kv: block_diff_mask(block_size, b, h, q, kv, self.max_seq_length)
234
+ elif mode == 'sbd_block_diff':
235
+ assert block_size is not None
236
+ attn_mask = lambda b, h, q, kv: sbd_block_diff_mask(block_size, b, h, q, kv, self.max_seq_length)
237
+ else:
238
+ raise ValueError(f"Unknown attention mode: {mode}")
239
+
240
+ if q_len is not None:
241
+ Q_LEN = q_len
242
+ else:
243
+ if mode in ['block_diff', 'sbd_block_diff']:
244
+ Q_LEN = self.max_seq_length * 2
245
+ else:
246
+ Q_LEN = self.max_seq_length
247
+
248
+ block_mask = create_block_mask(
249
+ attn_mask, B=None, H=None, Q_LEN=Q_LEN, KV_LEN=Q_LEN
250
+ )
251
+
252
+ return block_mask
253
+
254
+
255
+ def forward(
256
+ self,
257
+ hidden_states: torch.Tensor,
258
+ position_embeddings: Tuple[torch.Tensor, torch.Tensor],
259
+ attention_mask: Optional[torch.Tensor],
260
+ past_key_values: Optional[Cache] = None,
261
+ cache_position: Optional[torch.LongTensor] = None,
262
+ is_training: bool = True,
263
+ overwrite_block_mask = None,
264
+ overwrite_attn_impl = None,
265
+ use_cache: Optional[bool] = False,
266
+ **kwargs: Unpack[FlashAttentionKwargs],
267
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
268
+ if overwrite_attn_impl == 'base':
269
+ return super().forward(
270
+ hidden_states=hidden_states,
271
+ position_embeddings=position_embeddings,
272
+ attention_mask=attention_mask,
273
+ past_key_values=past_key_values,
274
+ cache_position=cache_position,
275
+ is_training=is_training,
276
+ use_cache=use_cache,
277
+ **kwargs,
278
+ )
279
+ bsz, q_len, _ = hidden_states.size()
280
+ input_shape = hidden_states.shape[:-1]
281
+ hidden_shape = (*input_shape, -1, self.head_dim)
282
+
283
+ query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
284
+ key_states = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
285
+ value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
286
+
287
+ cos, sin = position_embeddings
288
+
289
+ if self.mode in ['block_diff', 'sbd_block_diff'] and is_training:
290
+ # Split query and key states in half along sequence length dimension
291
+ q1, q2 = query_states.chunk(2, dim=2)
292
+ k1, k2 = key_states.chunk(2, dim=2)
293
+
294
+ # Apply RoPE independently to each half
295
+ q1, k1 = apply_rotary_pos_emb(q1, k1, cos, sin)
296
+ q2, k2 = apply_rotary_pos_emb(q2, k2, cos, sin)
297
+
298
+ # Recombine the halves
299
+ query_states = torch.cat([q1, q2], dim=2)
300
+ key_states = torch.cat([k1, k2], dim=2)
301
+ else:
302
+ query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
303
+
304
+ query_states = query_states * _get_llama_4_attn_scale(
305
+ cache_position,
306
+ self.config.rope_parameters.get("llama_4_scaling_beta"),
307
+ self.config.rope_parameters.get("original_max_position_embeddings"),
308
+ ).to(query_states.dtype)
309
+
310
+ if past_key_values is not None:
311
+ # sin and cos are specific to RoPE models; cache_position needed for the static cache
312
+ if use_cache:
313
+ cache_kwargs = {"sin": sin, "cos": cos, "cache_position": cache_position}
314
+ key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx, cache_kwargs)
315
+ else: ## if use_cache == False, do not update cache
316
+ old_k, old_v = past_key_values.layers[self.layer_idx].keys, past_key_values.layers[self.layer_idx].values
317
+ key_states = torch.cat([old_k, key_states], dim=-2)
318
+ value_states = torch.cat([old_v, value_states], dim=-2)
319
+
320
+
321
+ self_spec_inference_mode = getattr(self.config, "self_spec_inference_mode", None)
322
+ if self_spec_inference_mode is not None:
323
+ if self_spec_inference_mode == "quadratic":
324
+ block_length = getattr(self.config, "block_length", None) or getattr(self.config, "block_size", None)
325
+ if block_length is None:
326
+ raise ValueError("SBD quadratic decoding requires block_length in config.")
327
+ if past_key_values is not None:
328
+ seq_len = key_states.shape[2]
329
+ draft_len = block_length * (block_length + 1)
330
+
331
+ clean_keys = key_states[:, :, :-draft_len]
332
+ draft_keys = key_states[:, :, -draft_len:]
333
+ clean_values = value_states[:, :, :-draft_len]
334
+ draft_values = value_states[:, :, -draft_len:]
335
+ key_states = torch.cat([draft_keys, clean_keys], dim=2)
336
+ value_states = torch.cat([draft_values, clean_values], dim=2)
337
+
338
+ block_mask: BlockMask = self._get_sbd_inference_quadratic_decoding_block_mask(
339
+ block_length=block_length
340
+ )
341
+ block_mask.seq_lengths = (draft_len, seq_len)
342
+ else:
343
+ seq_len = query_states.shape[2]
344
+ draft_len = block_length * (block_length + 1)
345
+ clean_len = seq_len - draft_len
346
+
347
+ def _causal_mask(b, h, q_idx, kv_idx):
348
+ return torch.logical_and(q_idx >= kv_idx, q_idx < clean_len)
349
+
350
+ def _draft2clean_mask(b, h, q_idx, kv_idx):
351
+ full_clean = torch.logical_and(q_idx >= clean_len, kv_idx <= clean_len)
352
+ first_clean = torch.logical_and(
353
+ q_idx >= clean_len, (kv_idx - clean_len) % (block_length + 1) == 0
354
+ )
355
+ first_clean = torch.logical_and(first_clean, q_idx >= kv_idx)
356
+ return torch.logical_or(full_clean, first_clean)
357
+
358
+ def _draft_mask(b, h, q_idx, kv_idx):
359
+ block_q = (q_idx - clean_len) // (block_length + 1)
360
+ block_kv = (kv_idx - clean_len) // (block_length + 1)
361
+ quadrant = torch.logical_and(q_idx >= clean_len, kv_idx >= clean_len)
362
+ same_block = torch.logical_and(block_q == block_kv, quadrant)
363
+ same_block_except_first = torch.logical_and(
364
+ same_block,
365
+ (q_idx - clean_len) % (block_length + 1) != 0,
366
+ )
367
+ return torch.logical_and(block_q == block_kv, same_block_except_first)
368
+
369
+ mask = or_masks(_causal_mask, _draft2clean_mask)
370
+ mask = or_masks(mask, _draft_mask)
371
+
372
+ block_mask = create_block_mask(
373
+ mask, B=None, H=None, Q_LEN=seq_len, KV_LEN=seq_len,
374
+ )
375
+
376
+ key_states = repeat_kv(key_states, self.num_key_value_groups)
377
+ value_states = repeat_kv(value_states, self.num_key_value_groups)
378
+ attn_output = flex_attention(query_states, key_states, value_states, block_mask=block_mask)
379
+ attn_output = attn_output.transpose(1, 2).reshape(*input_shape, -1).contiguous()
380
+ attn_output = self.o_proj(attn_output)
381
+ return attn_output, None
382
+
383
+ elif self_spec_inference_mode == "default":
384
+ block_length = getattr(self.config, "block_length", None) or getattr(self.config, "block_size", None)
385
+ if block_length is None:
386
+ raise ValueError("SBD default decoding requires block_length in config.")
387
+ seq_len = query_states.shape[2]
388
+ prefix_len = seq_len - block_length
389
+
390
+ def _clean_q_mask(b, h, q_idx, kv_idx):
391
+ return torch.logical_and(q_idx >= kv_idx, q_idx < prefix_len)
392
+
393
+ def _noisy_q_mask(b, h, q_idx, kv_idx):
394
+ return q_idx >= prefix_len
395
+
396
+ block_mask = create_block_mask(
397
+ or_masks(_clean_q_mask, _noisy_q_mask),
398
+ B=None,
399
+ H=None,
400
+ Q_LEN=seq_len,
401
+ KV_LEN=seq_len,
402
+ )
403
+
404
+ key_states = repeat_kv(key_states, self.num_key_value_groups)
405
+ value_states = repeat_kv(value_states, self.num_key_value_groups)
406
+ attn_output = flex_attention(query_states, key_states, value_states, block_mask=block_mask)
407
+ attn_output = attn_output.transpose(1, 2).reshape(*input_shape, -1).contiguous()
408
+ attn_output = self.o_proj(attn_output)
409
+ return attn_output, None
410
+
411
+ else:
412
+ key_states = repeat_kv(key_states, self.num_key_value_groups)
413
+ value_states = repeat_kv(value_states, self.num_key_value_groups)
414
+
415
+ if overwrite_block_mask is not None:
416
+ block_mask = overwrite_block_mask
417
+ if block_mask == 'full':
418
+ block_mask = None
419
+ else:
420
+ if self.mode == 'bidirectional':
421
+ block_mask = None
422
+ overwrite_attn_impl = 'flash_attn'
423
+ # if self.bidirectional_mask is None or q_len != self.bidirectional_mask.shape[-2]:
424
+ # block_mask = self.compute_block_mask(mode='bidirectional', q_len=q_len)
425
+ # else:
426
+ # block_mask = self.bidirectional_mask
427
+
428
+ elif self.mode == 'autoregressive':
429
+ if self.autoregressive_mask is None or q_len != self.autoregressive_mask.shape[-2]:
430
+ block_mask = self.compute_block_mask(mode='autoregressive', q_len=q_len)
431
+ else:
432
+ block_mask = self.autoregressive_mask
433
+
434
+ elif self.mode == 'block_diff':
435
+ if self.block_diff_mask is None or self.block_size != self.block_size_orig or q_len != self.block_diff_mask.shape[-2]:
436
+ block_mask = self.compute_block_mask(mode='block_diff', block_size=self.block_size, q_len=q_len)
437
+ else:
438
+ block_mask = self.block_diff_mask
439
+ elif self.mode == 'sbd_block_diff':
440
+ if self.sbd_block_diff_mask is None or self.block_size != self.block_size_orig or q_len != self.sbd_block_diff_mask.shape[-2]:
441
+ block_mask = self.compute_block_mask(mode='sbd_block_diff', block_size=self.block_size, q_len=q_len)
442
+ else:
443
+ block_mask = self.sbd_block_diff_mask
444
+ else:
445
+ raise ValueError(f"Unknown attention mode: {self.mode}")
446
+ if overwrite_attn_impl == 'flash_attn':
447
+
448
+
449
+ # FlashAttention expects (batch, seqlen, nheads, headdim)
450
+ # Ensure your tensors are in this layout or permute them here
451
+ #print(query_states.shape,key_states.shape,value_states.shape)
452
+ if self.diffusion_lm:
453
+ causal = False
454
+ else:
455
+ causal = True
456
+ attn_output = flash_attn_func(
457
+ query_states.transpose(1,2),
458
+ key_states.transpose(1,2),
459
+ value_states.transpose(1,2),
460
+ dropout_p=0.0, # Set your dropout probability
461
+ softmax_scale=None, # Defaults to 1/sqrt(head_dim)
462
+ causal=causal # Set to True if using a causal block_mask logic
463
+ ).transpose(1,2)
464
+
465
+ else:
466
+ attn_output = fused_flex_attention(query_states, key_states, value_states, block_mask=block_mask)
467
+ attn_output = attn_output.transpose(1, 2).reshape(*input_shape, -1).contiguous()
468
+
469
+ attn_output = self.o_proj(attn_output)
470
+
471
+ return attn_output, None
472
+
473
+
474
+ def gumbel_topk(log_w: torch.Tensor, k: int) -> torch.Tensor:
475
+ """Return a Bool mask of length len(log_w) with exactly k True."""
476
+ g = -torch.log(-torch.log(torch.rand_like(log_w) + 1e-9) + 1e-9)
477
+ topk = torch.topk(log_w + g, k).indices
478
+ mask = torch.zeros_like(log_w, dtype=torch.bool)
479
+ mask[topk] = True
480
+ return mask
481
+
482
+
483
+ class MinistralDiffEncoderModel(Ministral3PreTrainedModel, GenerationMixin):
484
+ """
485
+ A single model with:
486
+ - a bidirectional encoder + diffusion‐LM head over A
487
+ - a causal decoder + LM head over B, conditioned on F_A
488
+ """
489
+
490
+ # Shared/tied tensors that can appear dynamically based on config.
491
+ # Registering these patterns lets save_pretrained() deduplicate safely.
492
+ # _dynamic_tied_weights_keys = [
493
+ # r"encoder\.embed_tokens\.weight",
494
+ # r"diffusion_head\.weight",
495
+ # r"encoder\.vision_tower(?:\.vision_tower)?\.visual_bridge_model\.quantizer\.quantize\.codebooks\.\d+\.(?:embed|embed_ema|cluster_size_ema)",
496
+ # ]
497
+
498
+ def __init__(self, config: MinistralDLMConfig):
499
+ super().__init__(config)
500
+
501
+ self.mask_token_id = config.mask_token_id
502
+
503
+ diffusion_config = copy.deepcopy(config)
504
+ diffusion_config.diffusion_lm = True
505
+
506
+ use_flex = getattr(config, 'enable_self_spec', False)
507
+
508
+ if config.dlm_paradigm in ['block_diff', 'sbd_block_diff']:
509
+ diffusion_config.attn_class = MinistralFlexAttention
510
+ elif config.dlm_paradigm in ['bidirectional', 'autoregressive']:
511
+ diffusion_config.attn_class = MinistralFlexAttention if use_flex else Ministral3Attention
512
+ if config.dlm_paradigm == 'autoregressive':
513
+ diffusion_config.diffusion_lm = False
514
+ else:
515
+ raise ValueError(f"Unsupported DLM paradigm: {config.dlm_paradigm}")
516
+
517
+ self.encoder = Ministral3Model(diffusion_config)
518
+ self.diffusion_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
519
+ self.vocab_size = config.vocab_size
520
+
521
+ self.current_iter_ratio = None
522
+
523
+ self.post_init()
524
+
525
+
526
+ def get_input_embeddings(self):
527
+ return self.encoder.embed_tokens
528
+
529
+ def set_input_embeddings(self, value):
530
+ self.encoder.embed_tokens = value
531
+
532
+ def get_output_embeddings(self):
533
+ return self.diffusion_head
534
+
535
+ def set_output_embeddings(self, new_embeddings):
536
+ self.diffusion_head = new_embeddings
537
+
538
+
539
+ def forward_process(self, input_ids, eps=1e-3, block_size=None, loss_mask=None):
540
+ b, l = input_ids.shape
541
+ device = input_ids.device
542
+
543
+ if self.config.dp_varying_mask_ratio:
544
+ # Enable different random seeds for each DP rank during sampling
545
+ import torch.distributed as dist
546
+ dp_rank = 0
547
+ if dist.is_initialized():
548
+ try:
549
+ dp_rank = dist.get_rank()
550
+ except Exception:
551
+ dp_rank = 0
552
+ # Use a local generator to avoid affecting global RNG state
553
+ generator = torch.Generator(device=device)
554
+ generator.manual_seed(torch.seed() + dp_rank)
555
+ else:
556
+ generator = None
557
+
558
+ if self.config.adaptive_mask_rate:
559
+ assert block_size is not None
560
+
561
+ # --- simple linear window mapping ---
562
+ bs_min = getattr(self.config, "t_bs_min", 16)
563
+ bs_max = getattr(self.config, "t_bs_max", 128)
564
+ w = getattr(self.config, "t_window_width", 0.6) # fixed width
565
+
566
+ # fraction in [0,1] (unclamped first)
567
+ frac = (float(block_size) - float(bs_min)) / max(1.0, float(bs_max - bs_min))
568
+ # upper bound decreases linearly from 1.0 -> 0.5
569
+ u_max = 1.0 - w * frac
570
+ # clamp to [0.6, 1.0] to handle bs outside [bs_min, bs_max]
571
+ u_max = max(0.6, min(1.0, u_max))
572
+ u_min = u_max - w # ensures width = w
573
+
574
+ # sample t ~ Uniform(u_min, u_max)
575
+ t = u_min + (u_max - u_min) * torch.rand(b, device=device, generator=generator)
576
+ else:
577
+ t = torch.rand(b, device=device, generator=generator)
578
+
579
+ p_mask = (1 - eps) * t + eps # shape: (b,)
580
+ p_mask = p_mask[:, None].expand(-1, l) # shape: (b, l)
581
+
582
+ masked_indices = torch.rand((b, l), device=device) < p_mask
583
+
584
+ if loss_mask is not None:
585
+ masked_indices[loss_mask == 0] = 0
586
+
587
+ noisy_batch = torch.where(masked_indices, self.mask_token_id, input_ids)
588
+
589
+ return noisy_batch, masked_indices, p_mask
590
+
591
+
592
+ def forward_process_exp(
593
+ self,
594
+ input_ids: torch.Tensor,
595
+ eps: float = 1e-3,
596
+ block_size: int | None = None,
597
+ half_life_ratio: float = 0.25, # λ = ln 2 / (half_life_ratio·L)
598
+ loss_mask: Optional[torch.Tensor] = None,
599
+ ):
600
+ """
601
+ Two-stage corruption with optional per-block sampling.
602
+ • Stage 1: m ~ U(eps, 1) → k = round(m · len) (exact budget).
603
+ • Stage 2: sample exactly k positions with weights
604
+ w_i(m) = exp[ λ · (1−m) · i ] (late-heavy when m→0,
605
+ uniform when m→1).
606
+ If `block_size` is given, the procedure is run *independently*
607
+ inside each contiguous block of that length (last block may be shorter).
608
+ When block_size is provided, m is sampled per-block and p_mask is per-block.
609
+ Args
610
+ ----
611
+ input_ids : (B, L) LongTensor
612
+ eps : minimum corruption ratio
613
+ block_size: if not None, operate block-wise with per-block m sampling
614
+ half_life_ratio : controls steepness when m→0
615
+ """
616
+ B, L = input_ids.shape
617
+ device = input_ids.device
618
+ dtype = torch.float32
619
+
620
+ masked_indices = torch.zeros((B, L), dtype=torch.bool, device=device)
621
+ p_mask = torch.zeros((B, L), dtype=dtype, device=device)
622
+
623
+ # ---------- Stage 1 & 2: whole-sentence or block-wise -------------------
624
+ for b in range(B):
625
+ if block_size is None:
626
+ # ---------- Per-batch sampling (original behavior) ----------
627
+ m = eps + (1.0 - eps) * torch.rand(1, device=device).item() # scalar
628
+ k_tot = int(round(m * L))
629
+ k_tot = max(1, min(k_tot, L)) # clamp to [1, L]
630
+
631
+ # Fill p_mask for this batch
632
+ p_mask[b, :] = m
633
+
634
+ slope = 1.0 - m # ∈ [0,1]; 0 ⇒ uniform, 1 ⇒ late-heavy
635
+
636
+ # ------- single pool over the whole sentence -------------
637
+ lam_base = math.log(2.0) / (half_life_ratio * L) # base decay rate (λ when slope=1)
638
+
639
+ pos = torch.arange(L, device=device, dtype=dtype)
640
+ log_w = (lam_base * slope * pos).clone()
641
+
642
+ masked_indices[b] = gumbel_topk(log_w, k_tot)
643
+
644
+ else:
645
+ # ---------- Per-block sampling ----------
646
+ num_blocks = math.ceil(L / block_size)
647
+ lam_base = math.log(2.0) / (half_life_ratio * block_size) # base decay rate (λ when slope=1)
648
+
649
+ for blk in range(num_blocks):
650
+ start = blk * block_size
651
+ end = min((blk + 1) * block_size, L)
652
+ blk_len = end - start
653
+
654
+ # Sample m per block
655
+ m_blk = eps + (1.0 - eps) * torch.rand(1, device=device).item()
656
+
657
+ # Fill p_mask for this block
658
+ p_mask[b, start:end] = m_blk
659
+
660
+ # per-block budget
661
+ k_blk = int(round(m_blk * blk_len))
662
+ k_blk = max(0, min(k_blk, blk_len))
663
+ if k_blk == 0:
664
+ continue
665
+
666
+ slope = 1.0 - m_blk # ∈ [0,1]; 0 ⇒ uniform, 1 ⇒ late-heavy
667
+
668
+ pos = torch.arange(blk_len, device=device, dtype=dtype)
669
+ log_w = lam_base * slope * pos
670
+
671
+ blk_mask = gumbel_topk(log_w, k_blk)
672
+ masked_indices[b, start:end] = blk_mask
673
+
674
+ if loss_mask is not None:
675
+ masked_indices[loss_mask == 0] = 0
676
+
677
+ noisy_batch = torch.where(masked_indices, self.mask_token_id, input_ids)
678
+ return noisy_batch, masked_indices, p_mask
679
+
680
+
681
+ def forward(
682
+ self,
683
+ input_ids: torch.LongTensor = None,
684
+ attention_mask: Optional[torch.Tensor] = None,
685
+ position_ids: Optional[torch.LongTensor] = None,
686
+ labels: Optional[torch.LongTensor] = None,
687
+ split_len: Optional[int] = None,
688
+ past_key_values: Optional[Cache] = None,
689
+ block_size: Optional[int] = None,
690
+ block_diff_ppl: bool = False,
691
+ eps: float = 1e-3,
692
+ is_teacher: bool = False,
693
+ masked_indices: Optional[torch.Tensor] = None,
694
+ p_mask: Optional[torch.Tensor] = None,
695
+ teacher_logits: Optional[torch.Tensor] = None,
696
+ masked_indices_teacher: Optional[torch.Tensor] = None,
697
+ loss_mask: Optional[torch.Tensor] = None,
698
+ ce_loss_weight: float = 1.0,
699
+ output_last_hidden_states_only: bool = False,
700
+ skip_loss: bool = False,
701
+ inputs_embeds: torch.Tensor = None,
702
+ **kwargs,
703
+ ) -> CausalLMOutputWithPast:
704
+
705
+ if input_ids is None:
706
+ if inputs_embeds is None:
707
+ raise ValueError("Either `input_ids` or `inputs_embeds` must be provided.")
708
+ batch_size, seq_len = inputs_embeds.shape[:2]
709
+ if labels is not None:
710
+ raise ValueError("`labels` training path requires `input_ids`.")
711
+ else:
712
+ batch_size, seq_len = input_ids.shape
713
+
714
+
715
+ if self.config.dlm_paradigm == 'bidirectional' or self.config.dlm_paradigm == 'autoregressive':
716
+ if labels is not None and torch.rand(1) < self.config.random_length_prob:
717
+ raise NotImplementedError("Random length training not yet implemented for bidirectional/autoregressive paradigms.")
718
+ random_length = torch.randint(2, input_ids.shape[1] + 1, (1,))
719
+ input_ids = input_ids[:, :random_length]
720
+ labels = labels[:, :random_length]
721
+
722
+ if attention_mask is not None:
723
+ attention_mask = attention_mask[:, :random_length]
724
+ if position_ids is not None:
725
+ position_ids = position_ids[:, :random_length]
726
+ if loss_mask is not None:
727
+ loss_mask = loss_mask[:, :random_length]
728
+
729
+ elif self.config.dlm_paradigm in ['block_diff', 'sbd_block_diff']:
730
+ if labels is not None and block_size is None:
731
+ if torch.rand(1) < self.config.random_length_prob:
732
+ block_size = torch.randint(1, 8, (1,)).item() * 4 ## [4, 32] divisible by 4
733
+ else:
734
+ block_size = self.config.block_size
735
+
736
+ else:
737
+ raise ValueError(f"Unknown dLM paradigm: {self.config.dlm_paradigm}")
738
+
739
+ if labels is not None and self.config.dlm_paradigm != 'autoregressive':
740
+ if masked_indices is not None:
741
+ # assert p_mask is not None
742
+
743
+ if loss_mask is not None:
744
+ masked_indices[loss_mask == 0] = 0
745
+
746
+ noisy_inputs = torch.where(masked_indices, self.mask_token_id, input_ids)
747
+
748
+ else:
749
+ if self.config.tok_mask_half_life_ratio is not None:
750
+ noisy_inputs, masked_indices, p_mask = self.forward_process_exp(input_ids, eps=eps, block_size=block_size, half_life_ratio=self.config.tok_mask_half_life_ratio, loss_mask=loss_mask)
751
+ else:
752
+ noisy_inputs, masked_indices, p_mask = self.forward_process(input_ids, eps=eps, block_size=block_size, loss_mask=loss_mask)
753
+
754
+ else:
755
+ noisy_inputs = input_ids
756
+ masked_indices = None
757
+ p_mask = None
758
+
759
+ if self.config.dlm_paradigm in ['block_diff', 'sbd_block_diff']:
760
+ for layer in self.encoder.layers:
761
+ if hasattr(layer.self_attn, 'set_attention_mode'):
762
+ layer.self_attn.set_attention_mode(self.config.dlm_paradigm, block_size=block_size)
763
+
764
+ input_ids_len = noisy_inputs.shape[1] if noisy_inputs is not None else seq_len
765
+ if labels is not None and self.config.dlm_paradigm in ['block_diff', 'sbd_block_diff']:
766
+ if position_ids is None:
767
+ position_ids = torch.arange(input_ids_len, device=noisy_inputs.device).unsqueeze(0)
768
+ noisy_inputs = torch.cat([noisy_inputs, input_ids], dim=1)
769
+
770
+ if block_diff_ppl:
771
+ if position_ids is None:
772
+ position_ids = torch.arange(input_ids_len // 2, device=noisy_inputs.device).unsqueeze(0)
773
+
774
+ enc_out = self.encoder(
775
+ past_key_values=past_key_values,
776
+ input_ids=noisy_inputs,
777
+ inputs_embeds=inputs_embeds if noisy_inputs is None else None,
778
+ attention_mask=attention_mask,
779
+ position_ids=position_ids,
780
+ is_training=(labels is not None) or (block_diff_ppl),
781
+ **kwargs,
782
+ )
783
+
784
+ if output_last_hidden_states_only:
785
+ return BaseModelOutput(last_hidden_state=enc_out.last_hidden_state)
786
+
787
+ logits = self.diffusion_head(enc_out.last_hidden_state) # (batch, len_B, vocab)
788
+ causal_logits = None
789
+
790
+ if labels is not None and self.config.dlm_paradigm in ['block_diff', 'sbd_block_diff']:
791
+ if self.config.dlm_paradigm == 'sbd_block_diff':
792
+ causal_logits = logits[:, input_ids_len:]
793
+ else:
794
+ causal_logits = None
795
+
796
+ logits = logits[:, :input_ids_len]
797
+
798
+ loss = None
799
+ if labels is not None and not skip_loss:
800
+ if self.config.dlm_paradigm == 'autoregressive':
801
+ shift_logits = logits[..., :-1, :].contiguous()
802
+ shift_labels = labels[..., 1:].contiguous()
803
+
804
+ if loss_mask is None:
805
+ loss_fct = CrossEntropyLoss()
806
+ shift_logits = shift_logits.view(-1, shift_logits.size(-1))
807
+ shift_labels = shift_labels.view(-1)
808
+ loss = loss_fct(shift_logits, shift_labels)
809
+
810
+ else:
811
+ loss_mask = loss_mask[..., 1:].contiguous()
812
+
813
+ loss_fct = CrossEntropyLoss(reduction='none')
814
+ shift_logits = shift_logits.view(-1, shift_logits.size(-1))
815
+ shift_labels = shift_labels.view(-1)
816
+ shift_labels = shift_labels.to(shift_logits.device)
817
+
818
+ token_losses = loss_fct(shift_logits, shift_labels)
819
+
820
+ flat_loss_mask = loss_mask.reshape(-1)
821
+ loss = token_losses[flat_loss_mask == 1].sum() / flat_loss_mask.sum()
822
+
823
+ else:
824
+ # Handle DREAM vs LLADA style losses
825
+ if hasattr(self.config, 'dlm_type') and self.config.dlm_type == 'dream':
826
+ logits = logits[..., :-1, :].contiguous()
827
+ labels = labels[..., 1:].contiguous()
828
+ masked_indices = masked_indices[:, 1:]
829
+ p_mask = p_mask[:, 1:]
830
+
831
+ if self.config.ada_perm_ratio_per_block is not None:
832
+ # Only compute loss for the top ada_perm_ratio_per_block tokens by confidence within each block
833
+ block_size = self.config.block_size
834
+ batch_size, seq_len = masked_indices.shape
835
+ num_blocks = seq_len // block_size
836
+
837
+ # Get the max logit (confidence) for each position
838
+ confidence = logits.max(dim=-1).values.detach() # (batch_size, seq_len)
839
+
840
+ # Create a mask for tokens to include in loss
841
+ selected_mask = torch.zeros_like(masked_indices, dtype=torch.bool)
842
+
843
+ for blk in range(num_blocks):
844
+ start = blk * block_size
845
+ end = min((blk + 1) * block_size, seq_len)
846
+
847
+ # Get masked indices within this block
848
+ block_masked = masked_indices[:, start:end] # (batch_size, block_len)
849
+ block_confidence = confidence[:, start:end] # (batch_size, block_len)
850
+
851
+ for b in range(batch_size):
852
+ # Get positions that are masked in this block for this batch
853
+ masked_positions = torch.where(block_masked[b])[0]
854
+ num_masked = len(masked_positions)
855
+
856
+ if num_masked > 0:
857
+ # Number of tokens to keep (top by confidence)
858
+ k = min(max(1, int(block_size * self.config.ada_perm_ratio_per_block)), num_masked)
859
+
860
+ # Get confidence values for masked positions
861
+ masked_confidence = block_confidence[b, masked_positions]
862
+
863
+ # Get indices of top-k confident tokens
864
+ _, topk_indices = torch.topk(masked_confidence, k)
865
+ selected_positions = masked_positions[topk_indices]
866
+
867
+ # Mark these positions in the selected mask
868
+ selected_mask[b, start + selected_positions] = True
869
+
870
+ # Calculate loss only for selected positions
871
+ token_loss = torch.nn.functional.cross_entropy(
872
+ logits[selected_mask],
873
+ labels[selected_mask],
874
+ reduction='none'
875
+ ) / p_mask[selected_mask]
876
+
877
+ num_mask_tokens = selected_mask.sum()
878
+
879
+ else:
880
+ # Calculate token-wise cross entropy loss for masked positions in B
881
+ token_loss = torch.nn.functional.cross_entropy(
882
+ logits[masked_indices],
883
+ labels[masked_indices],
884
+ reduction='none'
885
+ ) / p_mask[masked_indices]
886
+
887
+ num_mask_tokens = masked_indices.sum()
888
+
889
+ if self.config.global_loss_avg:
890
+ loss = token_loss.sum()
891
+ else:
892
+ loss = token_loss.sum() / num_mask_tokens
893
+
894
+ if self.config.ada_dlm_loss_ratio is not None:
895
+ assert self.current_iter_ratio is not None
896
+ assert self.config.dlm_loss_weight is not None
897
+
898
+ dlm_loss_weight = min(self.config.dlm_loss_weight, self.current_iter_ratio / self.config.ada_dlm_loss_ratio * self.config.dlm_loss_weight)
899
+ loss = dlm_loss_weight * loss
900
+
901
+ elif self.config.dlm_loss_weight is not None:
902
+ loss = self.config.dlm_loss_weight * loss
903
+
904
+ if self.config.dlm_paradigm == 'sbd_block_diff':
905
+ causal_logits = causal_logits[..., :-1, :].contiguous()
906
+ causal_logits = causal_logits.view(-1, causal_logits.size(-1))
907
+
908
+ if hasattr(self.config, 'dlm_type') and self.config.dlm_type == 'dream':
909
+ causal_labels = labels.view(-1)
910
+ else:
911
+ causal_labels = labels[..., 1:].contiguous().view(-1)
912
+
913
+ if self.config.global_loss_avg:
914
+ loss_fct = CrossEntropyLoss(reduction='sum')
915
+ ar_loss = loss_fct(causal_logits, causal_labels)
916
+
917
+ self.loss_diffusion = loss.detach().item() / num_mask_tokens
918
+ self.loss_ar = ar_loss.detach().item() / seq_len
919
+
920
+ loss = loss + self.config.ar_loss_weight * ar_loss
921
+ else:
922
+ loss_fct = CrossEntropyLoss()
923
+ ar_loss = loss_fct(causal_logits, causal_labels)
924
+
925
+ self.loss_diffusion = loss.detach().item()
926
+ self.loss_ar = ar_loss.detach().item()
927
+
928
+ loss = loss + self.config.ar_loss_weight * ar_loss
929
+
930
+ if self.config.global_loss_avg:
931
+ if self.config.dlm_paradigm == 'sbd_block_diff':
932
+ loss = (loss, num_mask_tokens + int(self.config.ar_loss_weight * seq_len))
933
+ else:
934
+ loss = (loss, num_mask_tokens)
935
+
936
+ return MinistralDiffOutputWithPast(
937
+ loss=loss if not is_teacher else logits,
938
+ logits=logits,
939
+ causal_logits=causal_logits,
940
+ past_key_values=enc_out.past_key_values,
941
+ hidden_states=None,
942
+ attentions=None,
943
+ )
944
+
945
+
946
+ def generate_diffusion(self, prompt_ids, max_new_tokens=512, steps=512, block_length=32, shift_logits=False, threshold=0.9, causal_context=True, temperature=0, eos_token_id=None, max_thinking_tokens=None, end_think_token_id=None, step_ratio=None,prompt_embeds=None,**kwargs):
947
+ if prompt_embeds is None and prompt_ids is not None and torch.is_floating_point(prompt_ids):
948
+ prompt_embeds = prompt_ids
949
+ prompt_ids = None
950
+
951
+ if (prompt_ids is None) == (prompt_embeds is None):
952
+ raise ValueError("Exactly one of `prompt_ids` or `prompt_embeds` must be provided.")
953
+
954
+ if eos_token_id is None:
955
+ eos_token_id = getattr(self.config, 'eos_token_id', None)
956
+ if step_ratio is not None:
957
+ steps_per_block = int(block_length * step_ratio)
958
+ num_blocks = max_new_tokens // block_length
959
+ steps = steps_per_block * num_blocks
960
+ out_ids, nfe = generate_with_prefix_cache_block_diff(
961
+ model=self,
962
+ prompt=prompt_ids,
963
+ prompt_embeds=prompt_embeds,
964
+ gen_length=max_new_tokens,
965
+ steps=steps,
966
+ block_length=block_length,
967
+ remasking="low_confidence",
968
+ temperature=temperature,
969
+ mask_id=self.mask_token_id,
970
+ threshold=threshold,
971
+ shift_logits=shift_logits,
972
+ neg_entropy=False,
973
+ causal_context=causal_context,
974
+ eos_token_id=eos_token_id,
975
+ max_thinking_tokens=max_thinking_tokens,
976
+ end_think_token_id=end_think_token_id,
977
+ )
978
+
979
+ return out_ids, nfe
980
+
981
+
982
+ @torch.no_grad()
983
+ def sbd_inference_diffusion_quadratic(
984
+ self,
985
+ clean_input_ids: Optional[torch.Tensor],
986
+ draft_input_ids: torch.Tensor,
987
+ block_length: int,
988
+ draft_only: bool = False,
989
+ past_key_values: Optional[Cache] = None,
990
+ use_cache: bool = False,
991
+ ):
992
+ enc_config = self.encoder.config
993
+ enc_config.use_sbd_objective = True
994
+ enc_config.block_length = block_length
995
+
996
+ if draft_only:
997
+ assert clean_input_ids is not None
998
+
999
+ if use_cache and past_key_values is None:
1000
+ past_key_values = DynamicCache()
1001
+
1002
+ enc_config.self_spec_inference_mode = "default"
1003
+ input_ids = torch.cat([clean_input_ids, draft_input_ids], dim=-1)
1004
+ outputs = self.encoder(
1005
+ input_ids=input_ids,
1006
+ position_ids=None,
1007
+ past_key_values=past_key_values,
1008
+ use_cache=use_cache,
1009
+ is_training=False,
1010
+ )
1011
+
1012
+ hidden_states = outputs.last_hidden_state
1013
+ logits = self.diffusion_head(hidden_states)
1014
+
1015
+ past_key_values = getattr(outputs, "past_key_values", None)
1016
+ if use_cache and past_key_values is not None:
1017
+ _crop_dynamic_cache(past_key_values, clean_input_ids.shape[1])
1018
+
1019
+ return logits, past_key_values
1020
+ else:
1021
+ enc_config.self_spec_inference_mode = "quadratic"
1022
+
1023
+ draft_len = block_length * (block_length + 1)
1024
+ draft_input_ids = torch.cat(
1025
+ [
1026
+ draft_input_ids.view(-1, block_length, 1),
1027
+ torch.full(
1028
+ (draft_input_ids.shape[0], block_length, block_length),
1029
+ fill_value=self.config.mask_token_id,
1030
+ device=draft_input_ids.device,
1031
+ ),
1032
+ ],
1033
+ dim=-1,
1034
+ ).view(-1, draft_len)
1035
+
1036
+ if use_cache:
1037
+ assert past_key_values is not None, (
1038
+ "Past key values should be provided when using cache, e.g. run draft_only=True first."
1039
+ )
1040
+ assert clean_input_ids is None, (
1041
+ "Clean input ids should already be in cache, thus none should be provided."
1042
+ )
1043
+ clean_len = past_key_values.get_seq_length()
1044
+ input_ids = draft_input_ids
1045
+ else:
1046
+ clean_len = clean_input_ids.shape[1]
1047
+ input_ids = torch.cat([clean_input_ids, draft_input_ids], dim=-1)
1048
+
1049
+ per_block_position_ids = torch.arange(
1050
+ clean_len, clean_len + block_length + 1, device=draft_input_ids.device
1051
+ )[None,].repeat(block_length, 1)
1052
+ per_block_position_ids += torch.arange(block_length, device=draft_input_ids.device).view(-1, 1)
1053
+
1054
+ if use_cache:
1055
+ position_ids = per_block_position_ids.view(-1)[None,]
1056
+ else:
1057
+ clean_position_ids = torch.arange(clean_len, device=draft_input_ids.device)
1058
+ position_ids = torch.cat([clean_position_ids, per_block_position_ids.view(-1)], dim=-1)[None,]
1059
+
1060
+ outputs = self.encoder(
1061
+ input_ids=input_ids,
1062
+ position_ids=position_ids,
1063
+ past_key_values=past_key_values,
1064
+ use_cache=use_cache,
1065
+ is_training=False,
1066
+ )
1067
+
1068
+ hidden_states = outputs.last_hidden_state
1069
+ logits = self.diffusion_head(hidden_states)
1070
+ past_key_values = getattr(outputs, "past_key_values", None)
1071
+
1072
+ if use_cache and past_key_values is not None:
1073
+ _extract_draft_kv_cache(past_key_values, clean_len, block_length)
1074
+
1075
+ return logits, past_key_values
1076
+
1077
+
1078
+ @torch.no_grad()
1079
+ def ar_generate(
1080
+ self,
1081
+ prompt_ids: torch.Tensor,
1082
+ max_new_tokens: int = 128,
1083
+ temperature: float = 0.0,
1084
+ eos_token_id: Optional[int] = None,
1085
+ max_thinking_tokens: Optional[int] = None,
1086
+ end_think_token_id: Optional[int] = None,
1087
+ ) -> tuple:
1088
+ """Autoregressive generation calling the encoder directly (injected by build_hf_tidar_repo).
1089
+
1090
+ Bypasses MinistralDiffEncoderModel.forward() to avoid diffusion-specific
1091
+ code paths. Calls self.encoder (Ministral3Model) with explicit cache_position,
1092
+ position_ids, and use_cache so the KV cache and causal masking behave
1093
+ identically to MistralForCausalLM / vLLM.
1094
+
1095
+ Returns:
1096
+ (output_ids, nfe) where output_ids includes the prompt.
1097
+ """
1098
+ for layer in self.encoder.layers:
1099
+ if hasattr(layer.self_attn, 'diffusion_lm'):
1100
+ layer.self_attn.diffusion_lm = False
1101
+
1102
+ if eos_token_id is None:
1103
+ eos_token_id = getattr(self.config, 'eos_token_id', None)
1104
+
1105
+ device = prompt_ids.device
1106
+ batch_size, prompt_len = prompt_ids.shape
1107
+
1108
+ past_key_values = DynamicCache()
1109
+ cache_position = torch.arange(prompt_len, device=device)
1110
+ position_ids = cache_position.unsqueeze(0).expand(batch_size, -1)
1111
+
1112
+ enc_out = self.encoder(
1113
+ input_ids=prompt_ids,
1114
+ position_ids=position_ids,
1115
+ past_key_values=past_key_values,
1116
+ use_cache=True,
1117
+ cache_position=cache_position,
1118
+ )
1119
+ past_key_values = enc_out.past_key_values
1120
+ next_logit = self.diffusion_head(enc_out.last_hidden_state[:, -1:, :]).squeeze(1)
1121
+
1122
+ generated_tokens = []
1123
+ nfe = 0
1124
+
1125
+ for step in range(max_new_tokens):
1126
+ nfe += 1
1127
+
1128
+ if temperature > 0:
1129
+ probs = torch.softmax(next_logit / temperature, dim=-1)
1130
+ next_token = torch.multinomial(probs, num_samples=1)
1131
+ else:
1132
+ next_token = torch.argmax(next_logit, dim=-1, keepdim=True)
1133
+
1134
+ # ---- thinking budget enforcement ----
1135
+ if end_think_token_id is not None and max_thinking_tokens is not None:
1136
+ if step >= max_thinking_tokens:
1137
+ if generated_tokens:
1138
+ gen_tensor = torch.cat(generated_tokens, dim=1)
1139
+ has_end_think = (gen_tensor == end_think_token_id).any(dim=1)
1140
+ else:
1141
+ has_end_think = torch.zeros(batch_size, dtype=torch.bool, device=device)
1142
+ for b in range(batch_size):
1143
+ if not has_end_think[b]:
1144
+ next_token[b] = end_think_token_id
1145
+
1146
+ generated_tokens.append(next_token)
1147
+
1148
+ if eos_token_id is not None and (next_token == eos_token_id).all():
1149
+ break
1150
+
1151
+ if step < max_new_tokens - 1:
1152
+ cur_pos = prompt_len + step
1153
+ step_cache_pos = torch.tensor([cur_pos], device=device)
1154
+ step_pos_ids = step_cache_pos.unsqueeze(0).expand(batch_size, -1)
1155
+
1156
+ enc_out = self.encoder(
1157
+ input_ids=next_token,
1158
+ position_ids=step_pos_ids,
1159
+ past_key_values=past_key_values,
1160
+ use_cache=True,
1161
+ cache_position=step_cache_pos,
1162
+ )
1163
+ past_key_values = enc_out.past_key_values
1164
+ next_logit = self.diffusion_head(enc_out.last_hidden_state[:, -1:, :]).squeeze(1)
1165
+
1166
+ all_generated = torch.cat(generated_tokens, dim=1)
1167
+ output_ids = torch.cat([prompt_ids, all_generated], dim=1)
1168
+ return output_ids, nfe
1169
+
1170
+
1171
+ @torch.no_grad()
1172
+ def self_spec_generate(
1173
+ self,
1174
+ prompt_ids: torch.Tensor,
1175
+ max_new_tokens: int = 128,
1176
+ steps: int = 128,
1177
+ block_length: int = 16,
1178
+ ar_mix_weight: Optional[float] = None,
1179
+ temperature: float = 0.0,
1180
+ mask_token_id: Optional[int] = None,
1181
+ eos_token_id: Optional[int] = None,
1182
+ max_thinking_tokens: Optional[int] = None,
1183
+ end_think_token_id: Optional[int] = None,
1184
+ ):
1185
+ self.config.use_sbd_objective = True
1186
+ self.config.dlm_paradigm = "sbd"
1187
+
1188
+ if prompt_ids.shape[0] != 1:
1189
+ raise ValueError("Self speculation quadratic decoding currently requires batch_size == 1")
1190
+
1191
+ token_mask_id = mask_token_id if mask_token_id is not None else self.config.mask_token_id
1192
+ if eos_token_id is None:
1193
+ eos_token_id = getattr(self.config, "eos_token_id", None)
1194
+
1195
+ x = torch.full(
1196
+ (1, prompt_ids.shape[1] + max_new_tokens + block_length * 2),
1197
+ token_mask_id,
1198
+ dtype=torch.long,
1199
+ device=prompt_ids.device,
1200
+ )
1201
+ x[:, : prompt_ids.shape[1]] = prompt_ids.clone()
1202
+
1203
+ if max_new_tokens % block_length != 0:
1204
+ raise ValueError("max_new_tokens must be divisible by block_length")
1205
+ num_blocks = max_new_tokens // block_length
1206
+ if steps % num_blocks != 0:
1207
+ raise ValueError("steps must be divisible by (max_new_tokens // block_length)")
1208
+
1209
+ prompt_len = prompt_ids.shape[1]
1210
+ nfe = 0
1211
+ nfe += 1
1212
+ logits, past_key_values = self.sbd_inference_diffusion_quadratic(
1213
+ clean_input_ids=x[:, :prompt_len],
1214
+ draft_input_ids=x[:, prompt_len : prompt_len + block_length],
1215
+ block_length=block_length,
1216
+ draft_only=True,
1217
+ use_cache=True,
1218
+ )
1219
+
1220
+ logits_proposal = logits[:, prompt_len - 1 : prompt_len + block_length]
1221
+ logits_proposal[:, 1] = logits_proposal[:, 0]
1222
+ logits_proposal = logits_proposal[:, 1:]
1223
+ x0_proposal = torch.argmax(logits_proposal, dim=-1)
1224
+ x[:, prompt_len : prompt_len + block_length] = x0_proposal
1225
+
1226
+ total_accept_token = 0
1227
+ while True:
1228
+ nfe += 1
1229
+ block_start = prompt_len + total_accept_token
1230
+ block_end = block_start + block_length
1231
+ draft_input_ids = x[:, block_start:block_end]
1232
+
1233
+ logits, past_key_values = self.sbd_inference_diffusion_quadratic(
1234
+ clean_input_ids=None,
1235
+ draft_input_ids=draft_input_ids,
1236
+ block_length=block_length,
1237
+ draft_only=False,
1238
+ past_key_values=past_key_values,
1239
+ use_cache=True,
1240
+ )
1241
+
1242
+ useful_token_logits = logits.view(1, block_length, block_length + 1, -1)
1243
+ if ar_mix_weight is None:
1244
+ useful_token_logits[:, :, 1] = useful_token_logits[:, :, 0]
1245
+ else:
1246
+ if not (0.0 <= ar_mix_weight <= 1.0):
1247
+ raise ValueError("ar_mix_weight must be between 0 and 1")
1248
+ mix_logits = useful_token_logits[:, :, 0] * ar_mix_weight + useful_token_logits[:, :, 1] * (1 - ar_mix_weight)
1249
+ useful_token_logits[:, :, 0] = mix_logits
1250
+ useful_token_logits[:, :, 1] = mix_logits
1251
+
1252
+ if temperature > 0:
1253
+ useful_token_logits = useful_token_logits / temperature
1254
+
1255
+ useful_token_pred = torch.argmax(useful_token_logits, dim=-1)
1256
+ new_draft_input_ids = useful_token_pred[:, 0, 1:]
1257
+ accept_cnt = 1
1258
+
1259
+ while accept_cnt < block_length:
1260
+ if useful_token_pred[:, accept_cnt - 1, 0].item() != draft_input_ids[:, accept_cnt].item():
1261
+ break
1262
+ new_draft_input_ids = useful_token_pred[:, accept_cnt, 1:]
1263
+ accept_cnt += 1
1264
+
1265
+ x[:, block_start : block_start + accept_cnt] = draft_input_ids[:, :accept_cnt]
1266
+
1267
+ # EoS early stopping: all accepted tokens are finalized left-to-right,
1268
+ # so if any is EoS we can truncate and return immediately.
1269
+ if eos_token_id is not None:
1270
+ accepted = x[0, block_start : block_start + accept_cnt]
1271
+ eos_positions = (accepted == eos_token_id).nonzero(as_tuple=True)[0]
1272
+ if len(eos_positions) > 0:
1273
+ first_eos_rel = eos_positions[0].item()
1274
+ total_accept_token += first_eos_rel + 1
1275
+ output_end = prompt_len + total_accept_token
1276
+ return x[:, :output_end], nfe
1277
+
1278
+ x[:, block_start + accept_cnt : block_start + accept_cnt + block_length] = new_draft_input_ids
1279
+ past_key_values.crop(block_start + accept_cnt)
1280
+
1281
+ # ---- thinking budget enforcement ----
1282
+ # Insert end_think as the first token of the next draft block,
1283
+ # shifting all subsequent tokens right by 1 (discarding the last).
1284
+ # The first draft token is always accepted unconditionally, so
1285
+ # end_think is guaranteed to be finalized in the next iteration
1286
+ # without needing to re-encode or touch the KV cache.
1287
+ if end_think_token_id is not None and max_thinking_tokens is not None:
1288
+ tokens_so_far = total_accept_token + accept_cnt
1289
+ if tokens_so_far > max_thinking_tokens:
1290
+ gen_so_far = x[0, prompt_len : prompt_len + tokens_so_far]
1291
+ has_end_think = (gen_so_far == end_think_token_id).any()
1292
+ if not has_end_think:
1293
+ insert_pos = block_start + accept_cnt
1294
+ x[0, insert_pos + 1:] = x[0, insert_pos:-1].clone()
1295
+ x[0, insert_pos] = end_think_token_id
1296
+
1297
+ total_accept_token += accept_cnt
1298
+
1299
+ if total_accept_token >= max_new_tokens:
1300
+ break
1301
+
1302
+ return x[:, : -(block_length * 2)], nfe
1303
+
1304
+
1305
+ @torch.no_grad()
1306
+ def linear_spec_generate(
1307
+ self,
1308
+ prompt_ids: torch.Tensor,
1309
+ max_new_tokens: int = 128,
1310
+ block_length: int = 32,
1311
+ temperature: float = 0.0,
1312
+ mask_token_id: Optional[int] = None,
1313
+ eos_token_id: Optional[int] = None,
1314
+ max_thinking_tokens: Optional[int] = None,
1315
+ end_think_token_id: Optional[int] = None,
1316
+ threshold: float = 0.0,
1317
+ ):
1318
+ """Linear speculative decoding: diffusion draft + AR verification.
1319
+
1320
+ Each step:
1321
+ 1. Draft: forward [last_accepted, mask, ...] with bidirectional attention
1322
+ (diffusion_lm=True, use_cache=False). Shift AR logits to get
1323
+ per-position predictions; apply confidence filtering.
1324
+ 2. Verify: forward the drafted block with causal attention
1325
+ (diffusion_lm=False, use_cache=True, use_causal_mask=True).
1326
+ Accept consecutive AR-matching tokens plus one bonus token.
1327
+
1328
+ Args:
1329
+ prompt_ids: Input token IDs of shape (1, prompt_len).
1330
+ max_new_tokens: Maximum number of tokens to generate.
1331
+ block_length: Number of tokens per draft/verify block.
1332
+ temperature: Sampling temperature (0 = greedy).
1333
+ mask_token_id: Override for config.mask_token_id.
1334
+ eos_token_id: Override for config.eos_token_id.
1335
+ max_thinking_tokens: Budget for thinking tokens before forcing end_think.
1336
+ end_think_token_id: Token ID inserted when thinking budget is exceeded.
1337
+ threshold: Confidence threshold for accepting draft predictions.
1338
+
1339
+ Returns:
1340
+ (output_ids, nfe): output_ids includes the prompt; nfe is the number
1341
+ of forward evaluations (matching self_spec_generate interface).
1342
+ """
1343
+ if prompt_ids.shape[0] != 1:
1344
+ raise ValueError("Linear speculative decoding requires batch_size == 1")
1345
+
1346
+ token_mask_id = mask_token_id if mask_token_id is not None else self.config.mask_token_id
1347
+ if eos_token_id is None:
1348
+ eos_token_id = getattr(self.config, "eos_token_id", None)
1349
+
1350
+ device = prompt_ids.device
1351
+ prompt_len = prompt_ids.shape[1]
1352
+ dream_style = getattr(self.config, 'dlm_type', 'llada') == 'dream'
1353
+
1354
+ def _set_diffusion_lm(val: bool):
1355
+ for layer in self.encoder.layers:
1356
+ if hasattr(layer.self_attn, 'diffusion_lm'):
1357
+ layer.self_attn.diffusion_lm = val
1358
+
1359
+ # ===== Prefill (causal) =====
1360
+ _set_diffusion_lm(False)
1361
+
1362
+ enc_out = self.encoder(
1363
+ input_ids=prompt_ids,
1364
+ past_key_values=DynamicCache(),
1365
+ use_cache=True,
1366
+ use_causal_mask=True,
1367
+ )
1368
+ past_key_values = enc_out.past_key_values
1369
+ last_logit = self.diffusion_head(enc_out.last_hidden_state[:, -1:, :]).squeeze(1)
1370
+ nfe = 1
1371
+
1372
+ if temperature > 0:
1373
+ probs = torch.softmax(last_logit / temperature, dim=-1)
1374
+ next_token = torch.multinomial(probs, num_samples=1)
1375
+ else:
1376
+ next_token = torch.argmax(last_logit, dim=-1, keepdim=True)
1377
+
1378
+ if eos_token_id is not None and next_token.item() == eos_token_id:
1379
+ output_ids = torch.cat([prompt_ids, next_token], dim=1)
1380
+ return output_ids, nfe
1381
+
1382
+ generated = [next_token]
1383
+ total_gen = 1
1384
+
1385
+ # ===== Main loop =====
1386
+ while total_gen < max_new_tokens:
1387
+ cache_len = past_key_values.get_seq_length()
1388
+
1389
+ block = torch.full(
1390
+ (1, block_length), token_mask_id, dtype=torch.long, device=device
1391
+ )
1392
+ block[0, 0] = next_token.item()
1393
+
1394
+ # -------- Draft (bidirectional, don't update cache) --------
1395
+ _set_diffusion_lm(True)
1396
+ enc_out = self.encoder(
1397
+ input_ids=block,
1398
+ past_key_values=past_key_values,
1399
+ use_cache=False,
1400
+ )
1401
+ nfe += 1
1402
+
1403
+ draft_logits = self.diffusion_head(enc_out.last_hidden_state)
1404
+ if dream_style:
1405
+ # DREAM: logit[i] predicts position i+1 → shift to self-prediction
1406
+ draft_logits = torch.cat(
1407
+ [draft_logits[:, :1, :], draft_logits[:, :-1, :]], dim=1
1408
+ )
1409
+ # LLaDA: logit[i] already predicts position i → no shift needed
1410
+
1411
+ if temperature > 0:
1412
+ draft_probs = torch.softmax(draft_logits / temperature, dim=-1)
1413
+ draft_tokens = torch.multinomial(
1414
+ draft_probs.view(-1, draft_probs.shape[-1]), num_samples=1
1415
+ ).view(1, block_length)
1416
+ else:
1417
+ draft_tokens = draft_logits.argmax(dim=-1)
1418
+ draft_probs = torch.softmax(draft_logits, dim=-1)
1419
+
1420
+ draft_conf = torch.gather(
1421
+ draft_probs, -1, draft_tokens.unsqueeze(-1)
1422
+ ).squeeze(-1)
1423
+
1424
+ is_mask = block == token_mask_id
1425
+ draft_conf = torch.where(is_mask, draft_conf, -torch.inf)
1426
+ unmask = draft_conf > threshold
1427
+
1428
+ if unmask.sum() > 0:
1429
+ block[unmask] = draft_tokens[unmask]
1430
+ else:
1431
+ raise AssertionError(
1432
+ "No mask token above threshold for prediction"
1433
+ )
1434
+
1435
+ # -------- Verify (causal, update cache) --------
1436
+ _set_diffusion_lm(False)
1437
+ enc_out = self.encoder(
1438
+ input_ids=block,
1439
+ past_key_values=past_key_values,
1440
+ use_cache=True,
1441
+ use_causal_mask=True,
1442
+ )
1443
+ past_key_values = enc_out.past_key_values
1444
+ nfe += 1
1445
+
1446
+ verify_logits = self.diffusion_head(enc_out.last_hidden_state)
1447
+ if temperature > 0:
1448
+ verify_probs = torch.softmax(verify_logits / temperature, dim=-1)
1449
+ ar_tokens = torch.multinomial(
1450
+ verify_probs.view(-1, verify_probs.shape[-1]), num_samples=1
1451
+ ).view(1, block_length)
1452
+ else:
1453
+ ar_tokens = verify_logits.argmax(dim=-1)
1454
+
1455
+ accepted = 0
1456
+ for i in range(block_length - 1):
1457
+ if ar_tokens[0, i].item() == block[0, i + 1].item():
1458
+ accepted += 1
1459
+ else:
1460
+ break
1461
+ accepted += 1 # bonus token from AR verification
1462
+
1463
+ accepted_toks = ar_tokens[:, :accepted]
1464
+ generated.append(accepted_toks)
1465
+ total_gen += accepted
1466
+
1467
+ _crop_dynamic_cache(past_key_values, cache_len + accepted)
1468
+
1469
+ next_token = ar_tokens[:, accepted - 1 : accepted]
1470
+
1471
+ # -------- EOS check --------
1472
+ if eos_token_id is not None:
1473
+ eos_pos = (accepted_toks[0] == eos_token_id).nonzero(as_tuple=True)[0]
1474
+ if len(eos_pos) > 0:
1475
+ first_eos = eos_pos[0].item()
1476
+ generated[-1] = accepted_toks[:, : first_eos + 1]
1477
+ total_gen = total_gen - accepted + first_eos + 1
1478
+ break
1479
+
1480
+ # -------- Thinking budget enforcement --------
1481
+ if end_think_token_id is not None and max_thinking_tokens is not None:
1482
+ if total_gen > max_thinking_tokens:
1483
+ all_gen = torch.cat(generated, dim=1)
1484
+ if not (all_gen == end_think_token_id).any():
1485
+ next_token = torch.tensor(
1486
+ [[end_think_token_id]], device=device
1487
+ )
1488
+
1489
+ if total_gen >= max_new_tokens:
1490
+ break
1491
+
1492
+ all_generated = torch.cat(generated, dim=1)
1493
+ output_ids = torch.cat([prompt_ids, all_generated], dim=1)
1494
+
1495
+ return output_ids, nfe
modeling_nemotron_labs_diffusion_image.py ADDED
@@ -0,0 +1,840 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ import math
3
+ import random
4
+ import time
5
+ from pathlib import Path
6
+ from typing import List, Optional, Tuple, Union
7
+
8
+ import numpy as np
9
+ import torch
10
+ import torch.distributions as dists
11
+ import torch.nn as nn
12
+ import torch.nn.functional as F
13
+ from diffusers.models.resnet import Downsample2D, Upsample2D
14
+ from einops import rearrange
15
+ from PIL import Image
16
+ from tqdm.auto import tqdm
17
+ from transformers import AutoConfig, AutoModel, AutoModelForCausalLM
18
+ from transformers.generation.utils import GenerateOutput
19
+
20
+ from .configuration_nemotron_labs_diffusion_image import NemotronLabsDiffusionImageConfig
21
+ from .modeling_ministral import Ministral3Model
22
+ from .modeling_ministral_dlm import MinistralDiffEncoderModel
23
+ # The imports below are not used directly but MUST stay here so that HF's
24
+ # dynamic-module cache scanner (regex: r"from\.X import") copies every
25
+ # transitive dependency into the hash directory.
26
+ from .chat_utils import generate_with_prefix_cache_block_diff as _gcbd # noqa: F401
27
+ from .nemotron_diffusion_image_utils import maybe_truncate_last_dim as _mtld # noqa: F401
28
+ from .configuration_ministral_dlm import MinistralDLMConfig as _MinistralDLMConfig # noqa: F401
29
+
30
+
31
+ def _resolve_local_path(path_value: str) -> Path:
32
+ base_dir = Path(__file__).resolve().parent
33
+ candidate = Path(path_value)
34
+ if candidate.is_absolute():
35
+ return candidate
36
+ return (base_dir / candidate).resolve()
37
+
38
+
39
+ def _load_vqvae_from_local(vqvae_path: Path):
40
+ """Load Emu3p5VisionVQModel directly from local files.
41
+
42
+ Bypasses AutoModel.from_pretrained because newer huggingface_hub versions
43
+ validate the path argument as a HF repo ID, rejecting absolute local paths.
44
+ """
45
+ import importlib.util
46
+ import json
47
+ import sys
48
+ import types
49
+
50
+ from safetensors.torch import load_file
51
+
52
+ pkg = f"_emu3_vqvae_{vqvae_path.name}"
53
+
54
+ # Create a package namespace so relative imports inside the vqvae files work
55
+ pkg_mod = types.ModuleType(pkg)
56
+ pkg_mod.__path__ = [str(vqvae_path)]
57
+ pkg_mod.__package__ = pkg
58
+ sys.modules[pkg] = pkg_mod
59
+
60
+ def _load_mod(mod_name, filename):
61
+ spec = importlib.util.spec_from_file_location(
62
+ f"{pkg}.{mod_name}",
63
+ vqvae_path / filename,
64
+ submodule_search_locations=[str(vqvae_path)],
65
+ )
66
+ mod = importlib.util.module_from_spec(spec)
67
+ mod.__package__ = pkg
68
+ sys.modules[f"{pkg}.{mod_name}"] = mod
69
+ spec.loader.exec_module(mod)
70
+ return mod
71
+
72
+ cfg_mod = _load_mod("configuration_emu3p5visionvq", "configuration_emu3p5visionvq.py")
73
+ mdl_mod = _load_mod("modeling_emu3p5visionvq", "modeling_emu3p5visionvq.py")
74
+
75
+ with open(vqvae_path / "config.json") as f:
76
+ cfg_data = json.load(f)
77
+
78
+ # PretrainedConfig accepts and stores arbitrary kwargs, so pass everything
79
+ vqvae_config = cfg_mod.Emu3p5VisionVQConfig(**cfg_data)
80
+ model = mdl_mod.Emu3p5VisionVQModel(vqvae_config)
81
+
82
+ sf_path = vqvae_path / "model.safetensors"
83
+ state_dict = load_file(str(sf_path))
84
+ model.load_state_dict(state_dict)
85
+
86
+ return model
87
+
88
+
89
+ def _preprocess_emu3_image(image):
90
+ if image.mode != "RGB":
91
+ image = image.convert("RGB")
92
+ image = np.asarray(image, dtype=np.float32)
93
+ image = image / 127.5 - 1.0
94
+ return torch.from_numpy(image).permute(2, 0, 1).float()
95
+
96
+
97
+ class Emu3ImageProcessor:
98
+ def preprocess(self, image):
99
+ return _preprocess_emu3_image(image).unsqueeze(0)
100
+
101
+
102
+ # ---------------------------------------------------------------------------
103
+ # T2I helpers (inlined — no llava imports required)
104
+ # ---------------------------------------------------------------------------
105
+
106
+ class _NC:
107
+ """Token constants for the Ministral diffusion model."""
108
+ reserve_id = 18
109
+ reserve_id_token = '<SPECIAL_18>'
110
+ reserve_id_enc = 19
111
+ reserve_id_token_enc = '<SPECIAL_19>'
112
+ mask_id = 100
113
+ eos_id = 11
114
+ gen_im_start_token = '<SPECIAL_21>'
115
+ gen_im_end_token = '<SPECIAL_22>'
116
+
117
+
118
+ def _pad_along_last_dim(tensor: torch.Tensor, size: int) -> torch.Tensor:
119
+ pad_size = size - tensor.shape[-1]
120
+ if pad_size <= 0:
121
+ return tensor
122
+ padding = torch.zeros(*tensor.shape[:-1], pad_size,
123
+ dtype=tensor.dtype, device=tensor.device)
124
+ return torch.cat([tensor, padding], dim=-1)
125
+
126
+
127
+ def _maybe_truncate_last_dim(tensor: torch.Tensor, size: int) -> torch.Tensor:
128
+ if size >= tensor.shape[-1]:
129
+ return tensor
130
+ return tensor[..., :size]
131
+
132
+
133
+ _INT_MAX = 1_000_000
134
+
135
+
136
+ def _t2i_wte(model, x, gen_shape=None, x_gen=None,
137
+ inputs_embeds_curr=None, new_token_mask=None):
138
+ """Embed text tokens and splice in gen-token embeddings."""
139
+ assert x_gen is not None
140
+ if new_token_mask is None or not torch.any(new_token_mask):
141
+ if inputs_embeds_curr is None:
142
+ return model.embed_tokens(x), new_token_mask
143
+ return inputs_embeds_curr, new_token_mask
144
+ gen_latents_comp_embeds = model.call_gen_embedding(x_gen, gen_shape)
145
+ if inputs_embeds_curr is None:
146
+ x_txt_only = x.clone()
147
+ x_txt_only[new_token_mask] = 0
148
+ inputs_embeds_curr = model.embed_tokens(x_txt_only)
149
+ inputs_embeds_curr[new_token_mask] = (
150
+ _pad_along_last_dim(gen_latents_comp_embeds, inputs_embeds_curr.shape[-1])
151
+ .view(-1, inputs_embeds_curr.shape[-1])
152
+ )
153
+ return inputs_embeds_curr, new_token_mask
154
+
155
+
156
+ def _t2i_get_logits(model, input_embeddings, modality_indices,
157
+ past_key_values=None, gen_shape=None, timesteps=None,
158
+ input_modality_indices=None):
159
+ """Forward pass returning generation logits only."""
160
+ if input_modality_indices is None:
161
+ input_modality_indices = modality_indices
162
+ output = model(
163
+ None,
164
+ input_embeddings=input_embeddings,
165
+ modality_indices=input_modality_indices,
166
+ past_key_values=past_key_values,
167
+ is_training=False,
168
+ overwrite_attn_impl='flash_attn',
169
+ )
170
+ hidden_states = output.last_hidden_state
171
+ gen_hidden_states = hidden_states[modality_indices]
172
+ gen_hidden_states = _maybe_truncate_last_dim(gen_hidden_states, model.config.d_model_gen)
173
+ gen_logits = model.call_gen_predictor(gen_hidden_states, gen_shape, timesteps=timesteps)
174
+ seq_len_per_img = int(np.prod(gen_shape))
175
+ if len(gen_logits.shape) == 2:
176
+ gen_logits = gen_logits.view(-1, seq_len_per_img, gen_logits.shape[-1])
177
+ else:
178
+ gen_logits = gen_logits.view(-1, seq_len_per_img, *gen_logits.shape[-2:])
179
+ return gen_logits
180
+
181
+
182
+ def _cosine_schedule_2(x):
183
+ x = 1.0 - np.clip(x, 0.0, 1.0)
184
+ return np.cos(np.pi * x / 2.0)
185
+
186
+
187
+ def _exp_schedule(x):
188
+ z = (1.0 - np.exp(-5.0 * x)) / (1.0 - np.exp(-5.0))
189
+ return np.clip(z, 0.0001, 1.0)
190
+
191
+
192
+ def _logit_normal_schedule(shift, sigmas):
193
+ return shift * sigmas / (1.0 + (shift - 1.0) * sigmas)
194
+
195
+
196
+ def _get_num_transfer_tokens(mask_index: torch.Tensor, steps: int,
197
+ schedule: str = 'shift',
198
+ shift: int = 3) -> torch.Tensor:
199
+ mask_num = mask_index.sum(dim=1, keepdim=True)
200
+ steps = int(min(steps, mask_num[0]))
201
+ t = torch.linspace(0, 1, steps + 1)
202
+ sigmas = _logit_normal_schedule(shift, t)
203
+ sigmas = sigmas.to(mask_num.device)
204
+ num_transfer_tokens = torch.zeros(mask_num.size(0), steps,
205
+ device=mask_index.device, dtype=torch.int64)
206
+ for i in range(mask_num.size(0)):
207
+ sigmas_sample = (sigmas * mask_num[i]).to(torch.int64)
208
+ sigmas_sample = sigmas_sample[1:] - sigmas_sample[:-1]
209
+ sigmas_sample = torch.clamp(sigmas_sample, 1, None)
210
+ delta = sigmas_sample.sum() - mask_num[i]
211
+ assert delta >= 0
212
+ j = 0
213
+ while delta > 0:
214
+ j = j % len(sigmas_sample)
215
+ if sigmas_sample[j] == 1:
216
+ j += 1
217
+ continue
218
+ delta -= 1
219
+ sigmas_sample[j] -= 1
220
+ j += 1
221
+ assert sigmas_sample.sum() == mask_num[i]
222
+ num_transfer_tokens[i] = sigmas_sample
223
+ return num_transfer_tokens.flip(-1)
224
+
225
+
226
+ class _MinistralConv:
227
+ """Minimal CHATML conversation template for the Ministral model."""
228
+ _SYSTEM = (
229
+ "<|im_start|>system\n"
230
+ "You are a helpful language and vision assistant. "
231
+ "You are able to understand the visual content that the user provides, "
232
+ "and assist the user with a variety of tasks using natural language."
233
+ )
234
+ _SEP = "<|im_end|>"
235
+ _ROLES = ("<|im_start|>user", "<|im_start|>assistant")
236
+
237
+ def __init__(self):
238
+ self.messages: List[Tuple[str, Optional[str]]] = []
239
+
240
+ def append_message(self, role: str, message: Optional[str]) -> None:
241
+ self.messages.append((role, message))
242
+
243
+ def get_prompt(self) -> str:
244
+ ret = self._SYSTEM + self._SEP + "\n"
245
+ for role, message in self.messages:
246
+ if message is not None:
247
+ ret += role + "\n" + message + self._SEP + "\n"
248
+ else:
249
+ ret += role + "\n"
250
+ return ret
251
+
252
+ @property
253
+ def roles(self):
254
+ return self._ROLES
255
+
256
+
257
+ _IMAGE_TOKEN_INDEX = -200
258
+
259
+
260
+ def _tokenizer_image_token(prompt: str, tokenizer,
261
+ return_tensors: str = "pt") -> torch.Tensor:
262
+ """Tokenise a prompt that may contain <image> placeholder tokens."""
263
+ prompt_chunks = [tokenizer(chunk).input_ids for chunk in prompt.split("<image>")]
264
+
265
+ def _insert_sep(X, sep):
266
+ return [e for pair in zip(X, [sep] * len(X)) for e in pair][:-1]
267
+
268
+ input_ids: List[int] = []
269
+ offset = 0
270
+ if (prompt_chunks and prompt_chunks[0]
271
+ and prompt_chunks[0][0] == tokenizer.bos_token_id):
272
+ offset = 1
273
+ input_ids.append(prompt_chunks[0][0])
274
+ for x in _insert_sep(prompt_chunks, [_IMAGE_TOKEN_INDEX] * (offset + 1)):
275
+ input_ids.extend(x[offset:])
276
+ ids = torch.tensor(input_ids, dtype=torch.long)
277
+ if return_tensors == "pt":
278
+ return ids
279
+ return ids.tolist()
280
+
281
+
282
+ def _stratified_random(n: int = 64, seed: Optional[int] = None,
283
+ shuffle_blocks: bool = True) -> List[int]:
284
+ """Progressive Multi-Jittered ordering over an n×n integer grid."""
285
+ if n <= 0 or (n & (n - 1)) != 0:
286
+ raise ValueError("n must be a positive power of two")
287
+ rng = random.Random(seed)
288
+ occupied = [[False] * n for _ in range(n)]
289
+ seq: List[int] = []
290
+ blocks: List[Tuple[int, int, int]] = [(0, 0, n)]
291
+
292
+ def _has(x0, y0, size):
293
+ for yy in range(y0, y0 + size):
294
+ for xx in range(x0, x0 + size):
295
+ if occupied[yy][xx]:
296
+ return True
297
+ return False
298
+
299
+ def _place(x0, y0, size):
300
+ x, y, attempts = rng.randrange(x0, x0 + size), rng.randrange(y0, y0 + size), 0
301
+ while occupied[y][x]:
302
+ x, y = rng.randrange(x0, x0 + size), rng.randrange(y0, y0 + size)
303
+ attempts += 1
304
+ if attempts > 10000:
305
+ raise RuntimeError("placement failed")
306
+ occupied[y][x] = True
307
+ seq.append(y * n + x)
308
+
309
+ size = n
310
+ while size > 1:
311
+ half = size // 2
312
+ children = [(x0 + dx, y0 + dy, half)
313
+ for (x0, y0, _) in blocks
314
+ for dx, dy in [(0, 0), (half, 0), (0, half), (half, half)]]
315
+ if shuffle_blocks:
316
+ rng.shuffle(children)
317
+ for (x0, y0, s) in children:
318
+ if not _has(x0, y0, s):
319
+ _place(x0, y0, s)
320
+ blocks = children
321
+ size = half
322
+
323
+ remaining = [y * n + x for y in range(n) for x in range(n) if not occupied[y][x]]
324
+ rng.shuffle(remaining)
325
+ seq.extend(remaining)
326
+ return seq
327
+
328
+
329
+ def _gumbel_noise(t: torch.Tensor) -> torch.Tensor:
330
+ noise = torch.zeros_like(t).uniform_(0, 1)
331
+ return -torch.log(-torch.log(noise))
332
+
333
+
334
+ class SimpleUVitBlock(nn.Module):
335
+ def __init__(self, channels, downsample: bool, upsample: bool):
336
+ super().__init__()
337
+ self.downsample = None
338
+ self.upsample = None
339
+ if downsample:
340
+ self.downsample = Downsample2D(
341
+ channels,
342
+ use_conv=True,
343
+ padding=0,
344
+ name="Conv2d_0",
345
+ kernel_size=2,
346
+ norm_type="rms_norm",
347
+ eps=1e-6,
348
+ elementwise_affine=True,
349
+ bias=False,
350
+ out_channels=channels,
351
+ )
352
+ if upsample:
353
+ self.upsample = Upsample2D(
354
+ channels,
355
+ use_conv_transpose=True,
356
+ kernel_size=2,
357
+ padding=0,
358
+ name="conv",
359
+ norm_type="rms_norm",
360
+ eps=1e-6,
361
+ elementwise_affine=True,
362
+ bias=False,
363
+ interpolate=False,
364
+ out_channels=channels,
365
+ )
366
+
367
+ def forward(self, hidden_states, size):
368
+ hidden_states = rearrange(hidden_states, "b (h w) d -> b d h w", h=size[0], w=size[1])
369
+ if self.downsample is not None:
370
+ hidden_states = self.downsample(hidden_states)
371
+ if self.upsample is not None:
372
+ hidden_states = self.upsample(hidden_states)
373
+ return rearrange(hidden_states, "b d h w -> b (h w) d")
374
+
375
+
376
+ class NemotronLabsDiffusionImageModel(Ministral3Model):
377
+ config_class = NemotronLabsDiffusionImageConfig
378
+
379
+ def __init__(self, config):
380
+ super().__init__(config)
381
+ self.build_vqvae(config)
382
+ self.build_gen_embedding(config)
383
+ self.image_newline = nn.Parameter(torch.empty(config.hidden_size))
384
+
385
+ def build_vqvae(self, config):
386
+ mm_vqvae = getattr(config, "mm_vqvae", "emu3_vqvae")
387
+ # Prefer model_dir/_name_or_path so this works both from the release dir
388
+ # and when loaded via trust_remote_code (where __file__ is the HF cache).
389
+ model_dir = Path(getattr(config, "_name_or_path", ""))
390
+ if model_dir.is_dir():
391
+ vqvae_path = (model_dir / mm_vqvae).resolve()
392
+ else:
393
+ vqvae_path = _resolve_local_path(mm_vqvae)
394
+ self.vqvae = _load_vqvae_from_local(vqvae_path)
395
+ self.vqvae.eval()
396
+ self.vqvae.requires_grad_(False)
397
+ self.image_processor_gen = Emu3ImageProcessor()
398
+
399
+ def build_gen_embedding(self, config):
400
+ self.downsample_gen = SimpleUVitBlock(config.d_model_gen, downsample=True, upsample=False) if config.downsample else None
401
+ self.upsample_gen = SimpleUVitBlock(config.d_model_gen, downsample=False, upsample=True) if config.downsample else None
402
+ self.gen_embedding = nn.Embedding(self.vqvae.config.codebook_size + 256, config.d_model_gen)
403
+ self.gen_predictor = nn.Linear(config.d_model_gen, self.vqvae.config.codebook_size, bias=config.include_bias)
404
+ self.gen_embedding_2 = None
405
+ self.gen_predictor_2 = None
406
+
407
+ def call_gen_embedding(self, token_ids, gen_shape=None, enc=False):
408
+ del enc
409
+ hidden_states = self.gen_embedding(token_ids)
410
+ if self.downsample_gen is not None:
411
+ hidden_states = self.downsample_gen(hidden_states, gen_shape)
412
+ return hidden_states
413
+
414
+ def call_gen_predictor(self, gen_hidden_states, gen_shape=None, timesteps=None, labels=None):
415
+ del timesteps, labels
416
+ if self.upsample_gen is not None:
417
+ seq_len_per_image = (gen_shape[0] // 2) * (gen_shape[1] // 2)
418
+ gen_hidden_states = self.upsample_gen(
419
+ gen_hidden_states.view(-1, seq_len_per_image, gen_hidden_states.shape[-1]),
420
+ (gen_shape[0] // 2, gen_shape[1] // 2),
421
+ )
422
+ gen_hidden_states = gen_hidden_states.flatten(0, 1)
423
+ return self.gen_predictor(gen_hidden_states)
424
+
425
+ def encode_image_gen(self, images, enc=False):
426
+ batch_size = images.shape[0]
427
+ # Emu3p5VisionVQModel.encode does not accept mini_batch_size;
428
+ # implement manual chunking for large images.
429
+ if images.shape[2] > 256 and batch_size > 2:
430
+ mini_bs = 2
431
+ qs, idxs = [], []
432
+ for i in range(0, batch_size, mini_bs):
433
+ q, _, (_, _, idx) = self.vqvae.encode(images[i:i + mini_bs])
434
+ qs.append(q)
435
+ idxs.append(idx)
436
+ quantized = torch.cat(qs, dim=0)
437
+ indices = torch.cat(idxs, dim=0)
438
+ else:
439
+ quantized, _, (_, _, indices) = self.vqvae.encode(images)
440
+ latent_height, latent_width = quantized.shape[-2], quantized.shape[-1]
441
+ return indices.reshape(batch_size, -1), (latent_height, latent_width)
442
+
443
+ @torch.no_grad()
444
+ def decode_image_gen(self, images_to_decode, height, width):
445
+ vae_scale_factor = 16
446
+ indices = self.vqvae.quantize.get_codebook_entry(images_to_decode)
447
+ indices = rearrange(
448
+ indices,
449
+ "b (h w) d -> b d h w",
450
+ h=height // vae_scale_factor,
451
+ w=width // vae_scale_factor,
452
+ )
453
+ # Emu3p5VisionVQModel.decode does not accept mini_batch_size;
454
+ # implement manual chunking for large images.
455
+ if height > 256 and len(indices) > 2:
456
+ mini_bs = 2
457
+ chunks = [self.vqvae.decode(indices[i:i + mini_bs])
458
+ for i in range(0, len(indices), mini_bs)]
459
+ images = torch.cat(chunks, dim=0).float()
460
+ else:
461
+ images = self.vqvae.decode(indices).float()
462
+ images = images.clamp(-1, 1)
463
+ images = (images + 1) / 2
464
+ images = (images * 255).permute(0, 2, 3, 1).cpu().numpy().astype(np.uint8)
465
+ return images
466
+
467
+
468
+ class NemotronLabsDiffusionImageForMaskedDiffusion(MinistralDiffEncoderModel):
469
+ config_class = NemotronLabsDiffusionImageConfig
470
+ supports_gradient_checkpointing = True
471
+ base_model_prefix = ""
472
+
473
+ def __init__(self, config: NemotronLabsDiffusionImageConfig, **kwargs):
474
+ del kwargs
475
+ config.d_model = config.hidden_size
476
+ config.include_bias = config.mlp_bias
477
+ if not hasattr(config, "d_model_gen") or config.d_model_gen < 0:
478
+ config.d_model_gen = config.d_model
479
+ if not hasattr(config, "mlp_hidden_size_gen") or config.mlp_hidden_size_gen < 0:
480
+ config.mlp_hidden_size_gen = config.intermediate_size
481
+ if not hasattr(config, "downsample"):
482
+ config.downsample = False
483
+ super().__init__(config)
484
+ self.encoder = NemotronLabsDiffusionImageModel(self.config)
485
+ self.post_init()
486
+
487
+ @property
488
+ def model(self):
489
+ return self.encoder
490
+
491
+ def get_model(self):
492
+ return self.encoder
493
+
494
+ @torch.no_grad()
495
+ def generate(
496
+ self,
497
+ inputs: Optional[torch.Tensor] = None,
498
+ images: Optional[torch.Tensor] = None,
499
+ image_sizes: Optional[torch.Tensor] = None,
500
+ modalities: Optional[List[str]] = None,
501
+ return_nfe: bool = False,
502
+ **kwargs,
503
+ ) -> Union[GenerateOutput, torch.LongTensor]:
504
+ del image_sizes, modalities
505
+ if images is not None:
506
+ raise NotImplementedError("This public release only supports text-to-image generation without multimodal image inputs.")
507
+ if "inputs_embeds" in kwargs:
508
+ raise NotImplementedError("inputs_embeds is not supported")
509
+ if self.config.dlm_paradigm == "bidirectional":
510
+ kwargs.setdefault("causal_context", False)
511
+ inputs_embeds = self.get_model().embed_tokens(inputs)
512
+ output, nfe = MinistralDiffEncoderModel.generate_diffusion(
513
+ self,
514
+ prompt_ids=None,
515
+ prompt_embeds=inputs_embeds,
516
+ **kwargs,
517
+ )
518
+ if return_nfe:
519
+ return output, nfe
520
+ return output
521
+
522
+ def encode_image_gen(self, images, enc=False):
523
+ return self.encoder.encode_image_gen(images, enc=enc)
524
+
525
+ def decode_image_gen(self, images_to_decode, height, width):
526
+ return self.encoder.decode_image_gen(images_to_decode, height, width)
527
+
528
+ def prepare_inputs_for_generation(self, input_ids, past_key_values=None, inputs_embeds=None, **kwargs):
529
+ return super().prepare_inputs_for_generation(
530
+ input_ids,
531
+ past_key_values=past_key_values,
532
+ inputs_embeds=inputs_embeds,
533
+ **kwargs,
534
+ )
535
+
536
+ @torch.no_grad()
537
+ def text_to_image(
538
+ self,
539
+ prompt: str,
540
+ tokenizer,
541
+ sample_policy: str = 'multinomial',
542
+ confidence_policy: str = 'mmada',
543
+ guidance_scale: float = 5.0,
544
+ n_steps: int = 20,
545
+ batch_size: int = 1,
546
+ image_resolution: int = 512,
547
+ n_tokens: int = 1024,
548
+ shift: int = 3,
549
+ alg_temp: float = 1.0,
550
+ min_temperature: float = 0.01,
551
+ dynamic_temperature: bool = False,
552
+ micro_cond: str = 'ORIGINAL WIDTH : 1024; ORIGINAL HEIGHT : 1024; TOP : 0; LEFT : 0; SCORE : 6.5',
553
+ temperature: float = 1.0,
554
+ schedule_temp: str = 'linear',
555
+ shift_alg=None,
556
+ top_p=None,
557
+ top_k=None,
558
+ unmask_order=None,
559
+ cfg_interval=(0, 1),
560
+ order_cutoff: float = 100,
561
+ template: str = 'Generate an image with the caption:\n <prompt>',
562
+ use_cache=None,
563
+ cache_prompt=None,
564
+ causal_context: bool = True,
565
+ is_legacy: bool = False,
566
+ edit_threshold: float = -1,
567
+ disable_tqdm: bool = False,
568
+ return_intermediate_steps: bool = False,
569
+ **kwargs,
570
+ ):
571
+ """Generate an image from a text prompt using masked diffusion."""
572
+ if shift_alg is None:
573
+ shift_alg = shift
574
+
575
+ NC = _NC
576
+ device = self.get_model().device
577
+
578
+ reserve_token = NC.reserve_id_token
579
+ reserve_id = NC.reserve_id
580
+ img_mask_id = 131073 # Emu3 VQ mask token
581
+ txt_mask_id = NC.mask_id
582
+ eot_id = NC.eos_id
583
+ img_begin = NC.gen_im_start_token
584
+ img_end = NC.gen_im_end_token
585
+
586
+ if use_cache is None:
587
+ use_cache = True
588
+ if cache_prompt is None:
589
+ cache_prompt = True
590
+ if self.config.dlm_paradigm == 'bidirectional':
591
+ causal_context = False
592
+ cache_prompt = False
593
+ use_cache = False
594
+
595
+ if is_legacy:
596
+ img_begin = img_end = ''
597
+
598
+ model_module = self.module if hasattr(self, "module") else self
599
+ for layer in model_module.encoder.layers:
600
+ layer.self_attn.mode = 'bidirectional'
601
+ for layer in model_module.encoder.layers:
602
+ if hasattr(layer.self_attn, 'diffusion_lm'):
603
+ layer.self_attn.diffusion_lm = True
604
+
605
+ gen_shape_map = {1024: (64, 64), 512: (32, 32), 256: (16, 16)}
606
+ gen_shape = gen_shape_map[image_resolution]
607
+ n_tokens_txt = 1024 if image_resolution == 1024 else n_tokens
608
+
609
+ prompt_full = f"{prompt} {micro_cond}"
610
+ question = template.replace('<prompt>', prompt_full)
611
+
612
+ conv = _MinistralConv()
613
+ conv.append_message(conv.roles[0], question)
614
+ conv.append_message(conv.roles[1],
615
+ f"Sure {img_begin}{reserve_token * n_tokens_txt}{img_end}")
616
+ prompt_question = conv.get_prompt()
617
+ print(prompt_question.replace(reserve_token, '*'))
618
+
619
+ input_ids = _tokenizer_image_token(
620
+ prompt_question, tokenizer, return_tensors="pt"
621
+ ).unsqueeze(0).to(device)
622
+
623
+ is_gen = input_ids == reserve_id
624
+ is_gen_enc = input_ids == NC.reserve_id_enc
625
+ is_eot = torch.where(input_ids == eot_id)[1]
626
+ assert len(is_eot) == 3, f"Expected 3 EOT tokens, got {len(is_eot)}"
627
+ prompt_cutoff = is_eot[1]
628
+ is_prompt = torch.zeros_like(input_ids, dtype=torch.bool)
629
+ is_prompt[:, :prompt_cutoff + 1] = True
630
+ raw_input_ids = input_ids
631
+
632
+ # Standard text embedding (no gen tokens yet)
633
+ inputs_embeds = self.get_model().embed_tokens(raw_input_ids)
634
+
635
+ inputs_embeds_uncond = inputs_embeds.clone()
636
+ noise_embed = self.get_model().embed_tokens(
637
+ torch.tensor([txt_mask_id], device=device)
638
+ )
639
+ inputs_embeds_uncond[is_prompt] = noise_embed
640
+
641
+ xt = torch.full((batch_size, n_tokens), img_mask_id,
642
+ dtype=torch.long, device=device)
643
+
644
+ mask_idx = xt == img_mask_id
645
+ num_transfer_tokens = _get_num_transfer_tokens(
646
+ mask_idx, n_steps, schedule='shift', shift=shift
647
+ )
648
+ print(num_transfer_tokens)
649
+
650
+ sch_t = np.linspace(0, 1, n_steps)
651
+ if schedule_temp == 'linear':
652
+ sch_temperatures = (1.0 - sch_t) * (1.0 - min_temperature) + min_temperature
653
+ elif schedule_temp == 'cosine2':
654
+ sch_temperatures = _cosine_schedule_2(1.0 - sch_t) * (1.0 - min_temperature) + min_temperature
655
+ elif schedule_temp == 'shift':
656
+ sch_temperatures = _logit_normal_schedule(shift_alg, 1.0 - sch_t) * (1.0 - min_temperature) + min_temperature
657
+ elif schedule_temp == 'exp':
658
+ sch_temperatures = _exp_schedule(1.0 - sch_t) * (1.0 - min_temperature) + min_temperature
659
+ else:
660
+ raise NotImplementedError(f"Unknown schedule_temp: {schedule_temp}")
661
+ sch_temperatures = torch.tensor(sch_temperatures, device=device, dtype=torch.float32)
662
+
663
+ cfg_start = int(cfg_interval[0] * n_steps)
664
+ cfg_end = int(cfg_interval[1] * n_steps)
665
+
666
+ if confidence_policy == 'stratified' and unmask_order is None:
667
+ _dim = int(math.sqrt(n_tokens))
668
+ unmask_order = _stratified_random(n=_dim, seed=42, shuffle_blocks=True)
669
+
670
+ total_edited = 0
671
+ intermediate_x0s = []
672
+ temp_idx = 0
673
+ past_key_values = None
674
+ cache_len = 0
675
+
676
+ for decode_step_idx, num_transfer in tqdm(
677
+ enumerate(num_transfer_tokens[0]),
678
+ total=num_transfer_tokens.shape[1],
679
+ disable=disable_tqdm,
680
+ ):
681
+ local_temp = sch_temperatures[temp_idx]
682
+ temp_idx += 1
683
+ if temp_idx / n_steps > order_cutoff:
684
+ confidence_policy = 'mmada'
685
+
686
+ mask_idx = xt == img_mask_id
687
+ n_mask = mask_idx.sum()
688
+ timesteps = (n_mask / mask_idx.numel()).view(1)
689
+
690
+ do_cfg = guidance_scale > 0 and cfg_start <= temp_idx <= cfg_end
691
+ if do_cfg:
692
+ input_embeddings_input = torch.cat([inputs_embeds_uncond, inputs_embeds]).clone()
693
+ xt_input = torch.cat([xt, xt])
694
+ new_token_mask = is_gen.repeat(2, 1)
695
+ is_gen_enc_mask = is_gen_enc.repeat(2, 1)
696
+ is_gen_enc_mask[0, :] = False
697
+ timesteps_in = timesteps.repeat(2)
698
+ else:
699
+ input_embeddings_input = inputs_embeds.clone()
700
+ new_token_mask = is_gen
701
+ xt_input = xt
702
+ is_gen_enc_mask = is_gen_enc
703
+ timesteps_in = timesteps
704
+
705
+ all_input_embeddings, new_token_mask = _t2i_wte(
706
+ self.get_model(), None, gen_shape=gen_shape,
707
+ x_gen=xt_input,
708
+ inputs_embeds_curr=input_embeddings_input,
709
+ new_token_mask=new_token_mask,
710
+ )
711
+
712
+ if use_cache and cache_prompt:
713
+ if decode_step_idx == 0:
714
+ if causal_context:
715
+ for layer in model_module.encoder.layers:
716
+ if hasattr(layer.self_attn, 'diffusion_lm'):
717
+ layer.self_attn.diffusion_lm = False
718
+ output = self.get_model()(
719
+ None,
720
+ input_embeddings=all_input_embeddings[:, :prompt_cutoff],
721
+ modality_indices=new_token_mask[:, :prompt_cutoff],
722
+ output_hidden_states=True,
723
+ past_key_values=None,
724
+ is_training=False,
725
+ use_cache=True,
726
+ overwrite_attn_impl='flash_attn',
727
+ )
728
+ past_key_values = output.past_key_values
729
+ cache_len = past_key_values.get_seq_length()
730
+ if causal_context:
731
+ for layer in model_module.encoder.layers:
732
+ if hasattr(layer.self_attn, 'diffusion_lm'):
733
+ layer.self_attn.diffusion_lm = True
734
+ else:
735
+ past_key_values = None
736
+ cache_len = 0
737
+
738
+ logits = _t2i_get_logits(
739
+ self.get_model(),
740
+ all_input_embeddings[:, cache_len:],
741
+ new_token_mask[:, cache_len:],
742
+ past_key_values=past_key_values,
743
+ gen_shape=gen_shape,
744
+ input_modality_indices=new_token_mask[:, cache_len:],
745
+ timesteps=timesteps_in,
746
+ )
747
+
748
+ if do_cfg:
749
+ new_token_mask, _ = new_token_mask.chunk(2)
750
+ logits_un, logits = logits.chunk(2)
751
+ logits_is_ninf = logits == -np.inf
752
+ logits = (1.0 + guidance_scale) * logits - guidance_scale * logits_un
753
+ logits[logits_is_ninf] = -np.inf
754
+
755
+ if top_p is not None or top_k is not None:
756
+ _b, _l, _v = logits.shape
757
+ logits_flat = logits.view(_b * _l, _v)
758
+ if top_k and top_k > 0:
759
+ topk = min(top_k, logits_flat.size(-1))
760
+ idx_rm = logits_flat < torch.topk(logits_flat, topk)[0][..., -1, None]
761
+ logits_flat[idx_rm] = -np.inf
762
+ if top_p and top_p < 1.0:
763
+ sl, si = torch.sort(logits_flat, descending=True)
764
+ cp = torch.cumsum(F.softmax(sl, dim=-1), dim=-1)
765
+ si_rm = cp > top_p
766
+ si_rm[..., 1:] = si_rm[..., :-1].clone()
767
+ si_rm[..., 0] = 0
768
+ logits_flat[si_rm.scatter(1, si, si_rm)] = -np.inf
769
+ logits = logits_flat.view(_b, _l, _v)
770
+
771
+ probs = logits.softmax(dim=-1)
772
+ if sample_policy == 'multinomial':
773
+ x0 = dists.Categorical(logits=logits / temperature).sample()
774
+ x0_p = torch.gather(probs, -1, x0.long()[..., None]).squeeze(-1)
775
+ elif sample_policy == 'argmax':
776
+ x0 = logits.argmax(-1)
777
+ x0_p = torch.gather(probs, -1, x0.long()[..., None]).squeeze(-1)
778
+ else:
779
+ raise NotImplementedError(f"Unknown sample_policy: {sample_policy}")
780
+
781
+ if edit_threshold <= 0:
782
+ x0 = torch.where(mask_idx, x0, xt)
783
+
784
+ if confidence_policy == 'mask_git':
785
+ _alg_t = alg_temp * local_temp if dynamic_temperature else alg_temp
786
+ confidence = torch.where(mask_idx, x0_p / _alg_t, torch.tensor(-np.inf, device=device))
787
+ confidence = torch.softmax(confidence, dim=-1)
788
+ select_index = torch.multinomial(confidence, num_samples=num_transfer)
789
+ elif confidence_policy == 'mmada':
790
+ _alg_t = alg_temp * local_temp if dynamic_temperature else alg_temp
791
+ confidence = torch.log(x0_p.clamp(1e-20)) + _alg_t * _gumbel_noise(x0_p)
792
+ confidence = torch.where(mask_idx, confidence, torch.tensor(-np.inf, device=device))
793
+ _, select_index = torch.topk(confidence[0], k=num_transfer)
794
+ elif confidence_policy == 'stratified':
795
+ assert unmask_order is not None
796
+ start = n_tokens - n_mask
797
+ select_index = torch.tensor(
798
+ unmask_order[start: start + num_transfer],
799
+ device=x0.device, dtype=torch.long,
800
+ )
801
+ else:
802
+ raise NotImplementedError(f"Unknown confidence_policy: {confidence_policy}")
803
+
804
+ transfer_index = torch.zeros_like(x0, dtype=torch.bool)
805
+ transfer_index[0, select_index] = True
806
+ xt[transfer_index] = x0[transfer_index]
807
+
808
+ xt_is_mask = xt == img_mask_id
809
+ if edit_threshold > 0:
810
+ editable = (~xt_is_mask) & (~transfer_index)
811
+ hi_conf = torch.where(editable, x0_p, torch.tensor(-torch.inf, device=device)) > edit_threshold
812
+ changed = (x0 != xt) & hi_conf
813
+ if changed.sum() > 0:
814
+ xt[changed] = x0[changed]
815
+ total_edited += changed.sum().item()
816
+
817
+ if return_intermediate_steps:
818
+ x0_inter = xt.clone()
819
+ x0_inter[xt_is_mask] = x0[xt_is_mask]
820
+ intermediate_x0s.append(x0_inter.cpu())
821
+
822
+ xt = x0.clone()
823
+ xt[xt == img_mask_id] = x0[xt == img_mask_id]
824
+ x0_img = xt
825
+ print(f"Total edited tokens: {total_edited}")
826
+
827
+ if return_intermediate_steps:
828
+ images_npy = self.decode_image_gen(
829
+ torch.cat(intermediate_x0s).to(x0_img.device),
830
+ image_resolution, image_resolution,
831
+ )
832
+ return [Image.fromarray(x) for x in images_npy]
833
+ return Image.fromarray(
834
+ self.decode_image_gen(x0_img, image_resolution, image_resolution)[0]
835
+ )
836
+
837
+
838
+ AutoConfig.register("nemotron_labs_diffusion_image", NemotronLabsDiffusionImageConfig)
839
+ AutoModel.register(NemotronLabsDiffusionImageConfig, NemotronLabsDiffusionImageForMaskedDiffusion)
840
+ AutoModelForCausalLM.register(NemotronLabsDiffusionImageConfig, NemotronLabsDiffusionImageForMaskedDiffusion)
nemotron_diffusion_image_utils.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+
3
+
4
+ def pad_along_last_dim(tensor, size):
5
+ pad_size = size - tensor.shape[-1]
6
+ if pad_size <= 0:
7
+ return tensor
8
+ padding = torch.zeros(*tensor.shape[:-1], pad_size, dtype=tensor.dtype, device=tensor.device)
9
+ return torch.cat([tensor, padding], dim=-1)
10
+
11
+
12
+ def maybe_truncate_last_dim(tensor, size):
13
+ if size >= tensor.shape[-1]:
14
+ return tensor
15
+ return tensor[..., :size]
16
+ return tensor[..., :size]
special_tokens_map.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f9ad3482369ba91711ff939f9eeb761d618b3157fcbfc0715f18e34b918eca97
3
+ size 17268792
tokenizer_config.json ADDED
The diff for this file is too large to render. See raw diff