Upload folder using huggingface_hub
Browse files- .gitattributes +1 -0
- LICENSE +73 -0
- README.md +300 -0
- chat_template.jinja +204 -0
- chat_utils.py +448 -0
- config.json +131 -0
- configuration_ministral_dlm.py +264 -0
- configuration_nemotron_labs_diffusion_image.py +33 -0
- demo_inference_release.py +249 -0
- emu3_vqvae/.gitattributes +35 -0
- emu3_vqvae/README.md +266 -0
- emu3_vqvae/__pycache__/configuration_emu3p5visionvq.cpython-313.pyc +0 -0
- emu3_vqvae/__pycache__/modeling_emu3p5visionvq.cpython-313.pyc +0 -0
- emu3_vqvae/config.json +32 -0
- emu3_vqvae/config.yaml +14 -0
- emu3_vqvae/configuration_emu3p5visionvq.py +101 -0
- emu3_vqvae/kmeans_16384_centroids.pt +3 -0
- emu3_vqvae/kmeans_4096_centroids.pt +3 -0
- emu3_vqvae/kmeans_8192_centroids.pt +3 -0
- emu3_vqvae/model.ckpt +3 -0
- emu3_vqvae/model.safetensors +3 -0
- emu3_vqvae/modeling_emu3p5visionvq.py +497 -0
- generation_config.json +10 -0
- model-00001-of-00006.safetensors +3 -0
- model-00002-of-00006.safetensors +3 -0
- model-00003-of-00006.safetensors +3 -0
- model-00004-of-00006.safetensors +3 -0
- model-00005-of-00006.safetensors +3 -0
- model-00006-of-00006.safetensors +3 -0
- model.safetensors.index.json +0 -0
- modeling_ministral.py +658 -0
- modeling_ministral_dlm.py +1495 -0
- modeling_nemotron_labs_diffusion_image.py +840 -0
- nemotron_diffusion_image_utils.py +16 -0
- special_tokens_map.json +0 -0
- tokenizer.json +3 -0
- tokenizer_config.json +0 -0
.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
|
|
|