Commit ·
18218f7
0
Parent(s):
Initial release
Browse files- .gitattributes +18 -0
- .gitignore +4 -0
- LICENSE +153 -0
- LICENSES/Apache-2.0.txt +202 -0
- LICENSES/NVIDIA-Open-Model-License.txt +153 -0
- LICENSES/README.md +9 -0
- LICENSES/README_zh.md +16 -0
- NOTICE +23 -0
- README.md +643 -0
- THIRD_PARTY_LICENSES.md +30 -0
- __init__.py +16 -0
- assets/logos/gemini.png +0 -0
- assets/logos/gemma.png +0 -0
- assets/logos/grok.png +0 -0
- assets/logos/qwen.png +0 -0
- assets/logos/stepfun.png +0 -0
- assets/logos/taichu.png +0 -0
- assets/taichu-release-benchmark-comparison.svg +0 -0
- assets/taichu-vs-closed-models.svg +0 -0
- chat_template.jinja +154 -0
- config.json +395 -0
- configuration.py +231 -0
- cradio_config.py +54 -0
- cradio_model.py +699 -0
- generation_config.json +16 -0
- image_processing.py +268 -0
- model-1-of-5.safetensors +3 -0
- model-2-of-5.safetensors +3 -0
- model-3-of-5.safetensors +3 -0
- model-4-of-5.safetensors +3 -0
- model-5-of-5.safetensors +3 -0
- model.safetensors.index.json +827 -0
- modeling.py +1109 -0
- preprocessor_config.json +25 -0
- processing.py +530 -0
- processor_config.json +31 -0
- tokenizer.json +3 -0
- tokenizer_config.json +27 -0
- vision_utils.py +583 -0
.gitattributes
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
* text=auto eol=lf
|
| 2 |
+
*.py text diff=python
|
| 3 |
+
*.md text
|
| 4 |
+
*.json text
|
| 5 |
+
*.jinja text
|
| 6 |
+
*.txt text
|
| 7 |
+
*.png binary
|
| 8 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.gguf filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
assets/benchmark-comparison.pdf filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
assets/benchmark-comparison.png filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__pycache__/
|
| 2 |
+
*.py[cod]
|
| 3 |
+
*.orig
|
| 4 |
+
*.rej
|
LICENSE
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
NVIDIA Open Model License Agreement
|
| 2 |
+
|
| 3 |
+
This NVIDIA Open Model License Agreement (the “Agreement”) is a legal agreement
|
| 4 |
+
between the Legal Entity You represent, or if no entity is identified, You and
|
| 5 |
+
NVIDIA Corporation and its Affiliates (“NVIDIA”) and governs Your use of the
|
| 6 |
+
Models that NVIDIA provides to You under this Agreement. NVIDIA and You are
|
| 7 |
+
each a “party” and collectively the “parties.”
|
| 8 |
+
|
| 9 |
+
NVIDIA models released under this Agreement are intended to be used
|
| 10 |
+
permissively and enable the further development of AI technologies. Subject to
|
| 11 |
+
the terms of this Agreement, NVIDIA confirms that:
|
| 12 |
+
|
| 13 |
+
- Models are commercially useable.
|
| 14 |
+
- You are free to create and distribute Derivative Models.
|
| 15 |
+
- NVIDIA does not claim ownership to any outputs generated using the Models or
|
| 16 |
+
Model Derivatives.
|
| 17 |
+
|
| 18 |
+
By using, reproducing, modifying, distributing, performing or displaying any
|
| 19 |
+
portion or element of the Model or Derivative Model, or otherwise accepting
|
| 20 |
+
the terms of this Agreement, you agree to be bound by this Agreement.
|
| 21 |
+
|
| 22 |
+
1. Definitions. The following definitions apply to this Agreement:
|
| 23 |
+
|
| 24 |
+
1.1. “Derivative Model” means all (a) modifications to the Model, (b) works
|
| 25 |
+
based on the Model, and (c) any other derivative works of the Model. An output
|
| 26 |
+
is not a Derivative Model.
|
| 27 |
+
|
| 28 |
+
1.2. “Legal Entity” means the union of the acting entity and all other entities
|
| 29 |
+
that control, are controlled by, or are under common control with that entity.
|
| 30 |
+
For the purposes of this definition, “control” means (a) the power, direct or
|
| 31 |
+
indirect, to cause the direction or management of such entity, whether by
|
| 32 |
+
contract or otherwise, or (b) ownership of fifty percent (50%) or more of the
|
| 33 |
+
outstanding shares, or (c) beneficial ownership of such entity.
|
| 34 |
+
|
| 35 |
+
1.3. “Model” means the machine learning model, software, checkpoints, learnt
|
| 36 |
+
weights, algorithms, parameters, configuration files and documentation shared
|
| 37 |
+
under this Agreement.
|
| 38 |
+
|
| 39 |
+
1.4. “You” or “Your” means an individual or Legal Entity exercising
|
| 40 |
+
permissions granted by this Agreement.
|
| 41 |
+
|
| 42 |
+
2. Conditions for Use, License Grant, AI Ethics and IP Ownership.
|
| 43 |
+
|
| 44 |
+
2.1. Conditions for Use. The Model and any Derivative Model are subject to
|
| 45 |
+
additional terms as described in Section 2 and Section 3 of this Agreement and
|
| 46 |
+
govern Your use. If You institute copyright or patent litigation against any
|
| 47 |
+
entity (including a cross-claim or counterclaim in a lawsuit) alleging that the
|
| 48 |
+
Model or a Derivative Model constitutes direct or contributory copyright or
|
| 49 |
+
patent infringement, then any licenses granted to You under this Agreement for
|
| 50 |
+
that Model or Derivative Model will terminate as of the date such litigation is
|
| 51 |
+
filed. NVIDIA may update this Agreement to comply with legal and regulatory
|
| 52 |
+
requirements at any time and You agree to either comply with any updated
|
| 53 |
+
license or cease Your copying, use, and distribution of the Model and any
|
| 54 |
+
Derivative Model.
|
| 55 |
+
|
| 56 |
+
2.2. License Grant. The rights granted herein are explicitly conditioned on
|
| 57 |
+
Your full compliance with the terms of this Agreement. Subject to the terms and
|
| 58 |
+
conditions of this Agreement, NVIDIA hereby grants to You a perpetual,
|
| 59 |
+
worldwide, non-exclusive, no-charge, royalty-free, revocable (as stated in
|
| 60 |
+
Section 2.1) license to publicly perform, publicly display, reproduce, use,
|
| 61 |
+
create derivative works of, make, have made, sell, offer for sale, distribute
|
| 62 |
+
(through multiple tiers of distribution) and import the Model.
|
| 63 |
+
|
| 64 |
+
2.3. AI Ethics. NVIDIA is committed to safety, trust and transparency in AI
|
| 65 |
+
development. NVIDIA encourages You to (a) ensure that the product or service
|
| 66 |
+
You develop, use, offer as a service or distributes meets the legal and ethical
|
| 67 |
+
requirements of the relevant industry or use case, (b) take reasonable
|
| 68 |
+
measures to address unintended bias and to mitigate harm to others, including
|
| 69 |
+
underrepresented or vulnerable groups, and (c) inform users of the nature and
|
| 70 |
+
limitations of the product or service. NVIDIA expressly prohibits the use of
|
| 71 |
+
its products or services for any purpose in violation of applicable law or
|
| 72 |
+
regulation, including but not limited to (a) illegal surveillance, (b) illegal
|
| 73 |
+
collection or processing of biometric information without the consent of the
|
| 74 |
+
subject where required under applicable law, or (c) illegal harassment, abuse,
|
| 75 |
+
threatening or bullying of individuals or groups of individuals or
|
| 76 |
+
intentionally misleading or deceiving others.
|
| 77 |
+
|
| 78 |
+
2.4. NVIDIA owns the Model and any Model Derivatives created by NVIDIA. Subject
|
| 79 |
+
to NVIDIA’s underlying ownership rights in the Model or its Model Derivatives,
|
| 80 |
+
You are and will be the owner of Your Model Derivatives. NVIDIA claims no
|
| 81 |
+
ownership rights in outputs. You are responsible for outputs and their
|
| 82 |
+
subsequent uses. Except as expressly granted in this Agreement, (a) NVIDIA
|
| 83 |
+
reserves all rights, interests and remedies in connection with the Model and
|
| 84 |
+
(b) no other license or right is granted to you by implication, estoppel or
|
| 85 |
+
otherwise.
|
| 86 |
+
|
| 87 |
+
3. Redistribution. You may reproduce and distribute copies of the Model or
|
| 88 |
+
Derivative Models thereof in any medium, with or without modifications,
|
| 89 |
+
provided that You meet the following conditions:
|
| 90 |
+
|
| 91 |
+
3.1. If you distribute the Model, You must give any other recipients of the
|
| 92 |
+
Model a copy of this Agreement and include the following attribution notice
|
| 93 |
+
within a “Notice” text file with such copies: “Licensed by NVIDIA Corporation
|
| 94 |
+
under the NVIDIA Open Model License”; and
|
| 95 |
+
|
| 96 |
+
3.2. You may add Your own copyright statement to Your modifications and may
|
| 97 |
+
provide additional or different license terms and conditions for use,
|
| 98 |
+
reproduction, or distribution of Your modifications, or for any such Derivative
|
| 99 |
+
Models as a whole, provided Your use, reproduction, and distribution of the
|
| 100 |
+
Model otherwise complies with the conditions stated in this Agreement.
|
| 101 |
+
|
| 102 |
+
4. Trademarks. This Agreement does not grant permission to use the trade names,
|
| 103 |
+
trademarks, service marks, or product names of NVIDIA, except as required for
|
| 104 |
+
reasonable and customary use in describing the origin of the Model and
|
| 105 |
+
reproducing the content of the “Notice” text file.
|
| 106 |
+
|
| 107 |
+
5. Disclaimer of Warranty. Unless required by applicable law or agreed to in
|
| 108 |
+
writing, NVIDIA provides the Model on an “AS IS” BASIS, WITHOUT WARRANTIES OR
|
| 109 |
+
CONDITIONS OF ANY KIND, either express or implied, including, without
|
| 110 |
+
limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT,
|
| 111 |
+
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely
|
| 112 |
+
responsible for determining the appropriateness of using or redistributing the
|
| 113 |
+
Model, Derivative Models and outputs and assume any risks associated with Your
|
| 114 |
+
exercise of permissions under this Agreement.
|
| 115 |
+
|
| 116 |
+
6. Limitation of Liability. In no event and under no legal theory, whether in
|
| 117 |
+
tort (including negligence), contract, or otherwise, unless required by
|
| 118 |
+
applicable law (such as deliberate and grossly negligent acts) or agreed to in
|
| 119 |
+
writing, will NVIDIA be liable to You for damages, including any direct,
|
| 120 |
+
indirect, special, incidental, or consequential damages of any character
|
| 121 |
+
arising as a result of this Agreement or out of the use or inability to use the
|
| 122 |
+
Model, Derivative Models or outputs (including but not limited to damages for
|
| 123 |
+
loss of goodwill, work stoppage, computer failure or malfunction, or any and
|
| 124 |
+
all other commercial damages or losses), even if NVIDIA has been advised of the
|
| 125 |
+
possibility of such damages.
|
| 126 |
+
|
| 127 |
+
7. Indemnity. You will indemnify and hold harmless NVIDIA from and against any
|
| 128 |
+
claim by any third party arising out of or related to your use or distribution
|
| 129 |
+
of the Model, Model Derivatives or outputs.
|
| 130 |
+
|
| 131 |
+
8. Feedback. NVIDIA appreciates your feedback, and You agree that NVIDIA may
|
| 132 |
+
use it without restriction or compensation to You.
|
| 133 |
+
|
| 134 |
+
9. Governing Law. This Agreement will be governed in all respects by the laws
|
| 135 |
+
of the United States and the laws of the State of Delaware, without regard to
|
| 136 |
+
conflict of laws principles or the United Nations Convention on Contracts for
|
| 137 |
+
the International Sale of Goods. The state and federal courts residing in
|
| 138 |
+
Santa Clara County, California will have exclusive jurisdiction over any
|
| 139 |
+
dispute or claim arising out of or related to this Agreement, and the parties
|
| 140 |
+
irrevocably consent to personal jurisdiction and venue in those courts; except
|
| 141 |
+
that, either party may apply for injunctive remedies or an equivalent type of
|
| 142 |
+
urgent legal relief in any jurisdiction.
|
| 143 |
+
|
| 144 |
+
10. Trade and Compliance. You agree to comply with all applicable export,
|
| 145 |
+
import, trade and economic sanctions laws and regulations, as amended,
|
| 146 |
+
including without limitation U.S. Export Administration Regulations and Office
|
| 147 |
+
of Foreign Assets Control regulations. These laws include restrictions on
|
| 148 |
+
destinations, end-users and end-use.
|
| 149 |
+
|
| 150 |
+
Version Release Date: June 14, 2024
|
| 151 |
+
|
| 152 |
+
Authoritative PDF:
|
| 153 |
+
https://developer.download.nvidia.com/licenses/nvidia-open-model-license-agreement-june-2024.pdf
|
LICENSES/Apache-2.0.txt
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Apache License
|
| 3 |
+
Version 2.0, January 2004
|
| 4 |
+
http://www.apache.org/licenses/
|
| 5 |
+
|
| 6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
+
|
| 8 |
+
1. Definitions.
|
| 9 |
+
|
| 10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
+
|
| 13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
+
the copyright owner that is granting the License.
|
| 15 |
+
|
| 16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
+
other entities that control, are controlled by, or are under common
|
| 18 |
+
control with that entity. For the purposes of this definition,
|
| 19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
+
direction or management of such entity, whether by contract or
|
| 21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
+
|
| 24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
+
exercising permissions granted by this License.
|
| 26 |
+
|
| 27 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
+
including but not limited to software source code, documentation
|
| 29 |
+
source, and configuration files.
|
| 30 |
+
|
| 31 |
+
"Object" form shall mean any form resulting from mechanical
|
| 32 |
+
transformation or translation of a Source form, including but
|
| 33 |
+
not limited to compiled object code, generated documentation,
|
| 34 |
+
and conversions to other media types.
|
| 35 |
+
|
| 36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
+
Object form, made available under the License, as indicated by a
|
| 38 |
+
copyright notice that is included in or attached to the work
|
| 39 |
+
(an example is provided in the Appendix below).
|
| 40 |
+
|
| 41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
+
form, that is based on (or derived from) the Work and for which the
|
| 43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
+
of this License, Derivative Works shall not include works that remain
|
| 46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
+
the Work and Derivative Works thereof.
|
| 48 |
+
|
| 49 |
+
"Contribution" shall mean any work of authorship, including
|
| 50 |
+
the original version of the Work and any modifications or additions
|
| 51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
+
means any form of electronic, verbal, or written communication sent
|
| 56 |
+
to the Licensor or its representatives, including but not limited to
|
| 57 |
+
communication on electronic mailing lists, source code control systems,
|
| 58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
+
excluding communication that is conspicuously marked or otherwise
|
| 61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
+
|
| 63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
+
subsequently incorporated within the Work.
|
| 66 |
+
|
| 67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
+
Work and such Derivative Works in Source or Object form.
|
| 73 |
+
|
| 74 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
+
(except as stated in this section) patent license to make, have made,
|
| 78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
+
where such license applies only to those patent claims licensable
|
| 80 |
+
by such Contributor that are necessarily infringed by their
|
| 81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
+
institute patent litigation against any entity (including a
|
| 84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
+
or contributory patent infringement, then any patent licenses
|
| 87 |
+
granted to You under this License for that Work shall terminate
|
| 88 |
+
as of the date such litigation is filed.
|
| 89 |
+
|
| 90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
+
modifications, and in Source or Object form, provided that You
|
| 93 |
+
meet the following conditions:
|
| 94 |
+
|
| 95 |
+
(a) You must give any other recipients of the Work or
|
| 96 |
+
Derivative Works a copy of this License; and
|
| 97 |
+
|
| 98 |
+
(b) You must cause any modified files to carry prominent notices
|
| 99 |
+
stating that You changed the files; and
|
| 100 |
+
|
| 101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
+
that You distribute, all copyright, patent, trademark, and
|
| 103 |
+
attribution notices from the Source form of the Work,
|
| 104 |
+
excluding those notices that do not pertain to any part of
|
| 105 |
+
the Derivative Works; and
|
| 106 |
+
|
| 107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
+
distribution, then any Derivative Works that You distribute must
|
| 109 |
+
include a readable copy of the attribution notices contained
|
| 110 |
+
within such NOTICE file, excluding those notices that do not
|
| 111 |
+
pertain to any part of the Derivative Works, in at least one
|
| 112 |
+
of the following places: within a NOTICE text file distributed
|
| 113 |
+
as part of the Derivative Works; within the Source form or
|
| 114 |
+
documentation, if provided along with the Derivative Works; or,
|
| 115 |
+
within a display generated by the Derivative Works, if and
|
| 116 |
+
wherever such third-party notices normally appear. The contents
|
| 117 |
+
of the NOTICE file are for informational purposes only and
|
| 118 |
+
do not modify the License. You may add Your own attribution
|
| 119 |
+
notices within Derivative Works that You distribute, alongside
|
| 120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
+
that such additional attribution notices cannot be construed
|
| 122 |
+
as modifying the License.
|
| 123 |
+
|
| 124 |
+
You may add Your own copyright statement to Your modifications and
|
| 125 |
+
may provide additional or different license terms and conditions
|
| 126 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
+
the conditions stated in this License.
|
| 130 |
+
|
| 131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
+
this License, without any additional terms or conditions.
|
| 135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
+
the terms of any separate license agreement you may have executed
|
| 137 |
+
with Licensor regarding such Contributions.
|
| 138 |
+
|
| 139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
+
except as required for reasonable and customary use in describing the
|
| 142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
+
|
| 144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
+
implied, including, without limitation, any warranties or conditions
|
| 149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
+
appropriateness of using or redistributing the Work and assume any
|
| 152 |
+
risks associated with Your exercise of permissions under this License.
|
| 153 |
+
|
| 154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
+
unless required by applicable law (such as deliberate and grossly
|
| 157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
+
liable to You for damages, including any direct, indirect, special,
|
| 159 |
+
incidental, or consequential damages of any character arising as a
|
| 160 |
+
result of this License or out of the use or inability to use the
|
| 161 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
+
other commercial damages or losses), even if such Contributor
|
| 164 |
+
has been advised of the possibility of such damages.
|
| 165 |
+
|
| 166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
+
or other liability obligations and/or rights consistent with this
|
| 170 |
+
License. However, in accepting such obligations, You may act only
|
| 171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
+
defend, and hold each Contributor harmless for any liability
|
| 174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
+
of your accepting any such warranty or additional liability.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
| 178 |
+
|
| 179 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 180 |
+
|
| 181 |
+
To apply the Apache License to your work, attach the following
|
| 182 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 183 |
+
replaced with your own identifying information. (Don't include
|
| 184 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 185 |
+
comment syntax for the file format. We also recommend that a
|
| 186 |
+
file or class name and description of purpose be included on the
|
| 187 |
+
same "printed page" as the copyright notice for easier
|
| 188 |
+
identification within third-party archives.
|
| 189 |
+
|
| 190 |
+
Copyright [yyyy] [name of copyright owner]
|
| 191 |
+
|
| 192 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 193 |
+
you may not use this file except in compliance with the License.
|
| 194 |
+
You may obtain a copy of the License at
|
| 195 |
+
|
| 196 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 197 |
+
|
| 198 |
+
Unless required by applicable law or agreed to in writing, software
|
| 199 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 200 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 201 |
+
See the License for the specific language governing permissions and
|
| 202 |
+
limitations under the License.
|
LICENSES/NVIDIA-Open-Model-License.txt
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
NVIDIA Open Model License Agreement
|
| 2 |
+
|
| 3 |
+
This NVIDIA Open Model License Agreement (the “Agreement”) is a legal agreement
|
| 4 |
+
between the Legal Entity You represent, or if no entity is identified, You and
|
| 5 |
+
NVIDIA Corporation and its Affiliates (“NVIDIA”) and governs Your use of the
|
| 6 |
+
Models that NVIDIA provides to You under this Agreement. NVIDIA and You are
|
| 7 |
+
each a “party” and collectively the “parties.”
|
| 8 |
+
|
| 9 |
+
NVIDIA models released under this Agreement are intended to be used
|
| 10 |
+
permissively and enable the further development of AI technologies. Subject to
|
| 11 |
+
the terms of this Agreement, NVIDIA confirms that:
|
| 12 |
+
|
| 13 |
+
- Models are commercially useable.
|
| 14 |
+
- You are free to create and distribute Derivative Models.
|
| 15 |
+
- NVIDIA does not claim ownership to any outputs generated using the Models or
|
| 16 |
+
Model Derivatives.
|
| 17 |
+
|
| 18 |
+
By using, reproducing, modifying, distributing, performing or displaying any
|
| 19 |
+
portion or element of the Model or Derivative Model, or otherwise accepting
|
| 20 |
+
the terms of this Agreement, you agree to be bound by this Agreement.
|
| 21 |
+
|
| 22 |
+
1. Definitions. The following definitions apply to this Agreement:
|
| 23 |
+
|
| 24 |
+
1.1. “Derivative Model” means all (a) modifications to the Model, (b) works
|
| 25 |
+
based on the Model, and (c) any other derivative works of the Model. An output
|
| 26 |
+
is not a Derivative Model.
|
| 27 |
+
|
| 28 |
+
1.2. “Legal Entity” means the union of the acting entity and all other entities
|
| 29 |
+
that control, are controlled by, or are under common control with that entity.
|
| 30 |
+
For the purposes of this definition, “control” means (a) the power, direct or
|
| 31 |
+
indirect, to cause the direction or management of such entity, whether by
|
| 32 |
+
contract or otherwise, or (b) ownership of fifty percent (50%) or more of the
|
| 33 |
+
outstanding shares, or (c) beneficial ownership of such entity.
|
| 34 |
+
|
| 35 |
+
1.3. “Model” means the machine learning model, software, checkpoints, learnt
|
| 36 |
+
weights, algorithms, parameters, configuration files and documentation shared
|
| 37 |
+
under this Agreement.
|
| 38 |
+
|
| 39 |
+
1.4. “You” or “Your” means an individual or Legal Entity exercising
|
| 40 |
+
permissions granted by this Agreement.
|
| 41 |
+
|
| 42 |
+
2. Conditions for Use, License Grant, AI Ethics and IP Ownership.
|
| 43 |
+
|
| 44 |
+
2.1. Conditions for Use. The Model and any Derivative Model are subject to
|
| 45 |
+
additional terms as described in Section 2 and Section 3 of this Agreement and
|
| 46 |
+
govern Your use. If You institute copyright or patent litigation against any
|
| 47 |
+
entity (including a cross-claim or counterclaim in a lawsuit) alleging that the
|
| 48 |
+
Model or a Derivative Model constitutes direct or contributory copyright or
|
| 49 |
+
patent infringement, then any licenses granted to You under this Agreement for
|
| 50 |
+
that Model or Derivative Model will terminate as of the date such litigation is
|
| 51 |
+
filed. NVIDIA may update this Agreement to comply with legal and regulatory
|
| 52 |
+
requirements at any time and You agree to either comply with any updated
|
| 53 |
+
license or cease Your copying, use, and distribution of the Model and any
|
| 54 |
+
Derivative Model.
|
| 55 |
+
|
| 56 |
+
2.2. License Grant. The rights granted herein are explicitly conditioned on
|
| 57 |
+
Your full compliance with the terms of this Agreement. Subject to the terms and
|
| 58 |
+
conditions of this Agreement, NVIDIA hereby grants to You a perpetual,
|
| 59 |
+
worldwide, non-exclusive, no-charge, royalty-free, revocable (as stated in
|
| 60 |
+
Section 2.1) license to publicly perform, publicly display, reproduce, use,
|
| 61 |
+
create derivative works of, make, have made, sell, offer for sale, distribute
|
| 62 |
+
(through multiple tiers of distribution) and import the Model.
|
| 63 |
+
|
| 64 |
+
2.3. AI Ethics. NVIDIA is committed to safety, trust and transparency in AI
|
| 65 |
+
development. NVIDIA encourages You to (a) ensure that the product or service
|
| 66 |
+
You develop, use, offer as a service or distributes meets the legal and ethical
|
| 67 |
+
requirements of the relevant industry or use case, (b) take reasonable
|
| 68 |
+
measures to address unintended bias and to mitigate harm to others, including
|
| 69 |
+
underrepresented or vulnerable groups, and (c) inform users of the nature and
|
| 70 |
+
limitations of the product or service. NVIDIA expressly prohibits the use of
|
| 71 |
+
its products or services for any purpose in violation of applicable law or
|
| 72 |
+
regulation, including but not limited to (a) illegal surveillance, (b) illegal
|
| 73 |
+
collection or processing of biometric information without the consent of the
|
| 74 |
+
subject where required under applicable law, or (c) illegal harassment, abuse,
|
| 75 |
+
threatening or bullying of individuals or groups of individuals or
|
| 76 |
+
intentionally misleading or deceiving others.
|
| 77 |
+
|
| 78 |
+
2.4. NVIDIA owns the Model and any Model Derivatives created by NVIDIA. Subject
|
| 79 |
+
to NVIDIA’s underlying ownership rights in the Model or its Model Derivatives,
|
| 80 |
+
You are and will be the owner of Your Model Derivatives. NVIDIA claims no
|
| 81 |
+
ownership rights in outputs. You are responsible for outputs and their
|
| 82 |
+
subsequent uses. Except as expressly granted in this Agreement, (a) NVIDIA
|
| 83 |
+
reserves all rights, interests and remedies in connection with the Model and
|
| 84 |
+
(b) no other license or right is granted to you by implication, estoppel or
|
| 85 |
+
otherwise.
|
| 86 |
+
|
| 87 |
+
3. Redistribution. You may reproduce and distribute copies of the Model or
|
| 88 |
+
Derivative Models thereof in any medium, with or without modifications,
|
| 89 |
+
provided that You meet the following conditions:
|
| 90 |
+
|
| 91 |
+
3.1. If you distribute the Model, You must give any other recipients of the
|
| 92 |
+
Model a copy of this Agreement and include the following attribution notice
|
| 93 |
+
within a “Notice” text file with such copies: “Licensed by NVIDIA Corporation
|
| 94 |
+
under the NVIDIA Open Model License”; and
|
| 95 |
+
|
| 96 |
+
3.2. You may add Your own copyright statement to Your modifications and may
|
| 97 |
+
provide additional or different license terms and conditions for use,
|
| 98 |
+
reproduction, or distribution of Your modifications, or for any such Derivative
|
| 99 |
+
Models as a whole, provided Your use, reproduction, and distribution of the
|
| 100 |
+
Model otherwise complies with the conditions stated in this Agreement.
|
| 101 |
+
|
| 102 |
+
4. Trademarks. This Agreement does not grant permission to use the trade names,
|
| 103 |
+
trademarks, service marks, or product names of NVIDIA, except as required for
|
| 104 |
+
reasonable and customary use in describing the origin of the Model and
|
| 105 |
+
reproducing the content of the “Notice” text file.
|
| 106 |
+
|
| 107 |
+
5. Disclaimer of Warranty. Unless required by applicable law or agreed to in
|
| 108 |
+
writing, NVIDIA provides the Model on an “AS IS” BASIS, WITHOUT WARRANTIES OR
|
| 109 |
+
CONDITIONS OF ANY KIND, either express or implied, including, without
|
| 110 |
+
limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT,
|
| 111 |
+
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely
|
| 112 |
+
responsible for determining the appropriateness of using or redistributing the
|
| 113 |
+
Model, Derivative Models and outputs and assume any risks associated with Your
|
| 114 |
+
exercise of permissions under this Agreement.
|
| 115 |
+
|
| 116 |
+
6. Limitation of Liability. In no event and under no legal theory, whether in
|
| 117 |
+
tort (including negligence), contract, or otherwise, unless required by
|
| 118 |
+
applicable law (such as deliberate and grossly negligent acts) or agreed to in
|
| 119 |
+
writing, will NVIDIA be liable to You for damages, including any direct,
|
| 120 |
+
indirect, special, incidental, or consequential damages of any character
|
| 121 |
+
arising as a result of this Agreement or out of the use or inability to use the
|
| 122 |
+
Model, Derivative Models or outputs (including but not limited to damages for
|
| 123 |
+
loss of goodwill, work stoppage, computer failure or malfunction, or any and
|
| 124 |
+
all other commercial damages or losses), even if NVIDIA has been advised of the
|
| 125 |
+
possibility of such damages.
|
| 126 |
+
|
| 127 |
+
7. Indemnity. You will indemnify and hold harmless NVIDIA from and against any
|
| 128 |
+
claim by any third party arising out of or related to your use or distribution
|
| 129 |
+
of the Model, Model Derivatives or outputs.
|
| 130 |
+
|
| 131 |
+
8. Feedback. NVIDIA appreciates your feedback, and You agree that NVIDIA may
|
| 132 |
+
use it without restriction or compensation to You.
|
| 133 |
+
|
| 134 |
+
9. Governing Law. This Agreement will be governed in all respects by the laws
|
| 135 |
+
of the United States and the laws of the State of Delaware, without regard to
|
| 136 |
+
conflict of laws principles or the United Nations Convention on Contracts for
|
| 137 |
+
the International Sale of Goods. The state and federal courts residing in
|
| 138 |
+
Santa Clara County, California will have exclusive jurisdiction over any
|
| 139 |
+
dispute or claim arising out of or related to this Agreement, and the parties
|
| 140 |
+
irrevocably consent to personal jurisdiction and venue in those courts; except
|
| 141 |
+
that, either party may apply for injunctive remedies or an equivalent type of
|
| 142 |
+
urgent legal relief in any jurisdiction.
|
| 143 |
+
|
| 144 |
+
10. Trade and Compliance. You agree to comply with all applicable export,
|
| 145 |
+
import, trade and economic sanctions laws and regulations, as amended,
|
| 146 |
+
including without limitation U.S. Export Administration Regulations and Office
|
| 147 |
+
of Foreign Assets Control regulations. These laws include restrictions on
|
| 148 |
+
destinations, end-users and end-use.
|
| 149 |
+
|
| 150 |
+
Version Release Date: June 14, 2024
|
| 151 |
+
|
| 152 |
+
Authoritative PDF:
|
| 153 |
+
https://developer.download.nvidia.com/licenses/nvidia-open-model-license-agreement-june-2024.pdf
|
LICENSES/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# License files
|
| 2 |
+
|
| 3 |
+
- `NVIDIA-Open-Model-License.txt` governs C-RADIOv4-H and the corresponding
|
| 4 |
+
derivative-model obligations.
|
| 5 |
+
- `Apache-2.0.txt` is retained for Qwen3.5 and Apache-licensed source files.
|
| 6 |
+
|
| 7 |
+
The root `LICENSE` is the model-weight repository's primary license text.
|
| 8 |
+
File-level copyright and license headers take precedence for the corresponding
|
| 9 |
+
source files.
|
LICENSES/README_zh.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<a id="license-files"></a>
|
| 2 |
+
|
| 3 |
+
# 许可证文件
|
| 4 |
+
|
| 5 |
+
[English](README.md) | 简体中文
|
| 6 |
+
|
| 7 |
+
> 本文为英文 README 的中文版本;代码、命令、模型名称、评测数值及资源文件保持原样。
|
| 8 |
+
> 许可相关译文仅作说明,不替代适用的许可证及声明原文。
|
| 9 |
+
|
| 10 |
+
- `NVIDIA-Open-Model-License.txt` 适用于 C-RADIOv4-H 及相应的
|
| 11 |
+
衍生模型义务。
|
| 12 |
+
- 保留 `Apache-2.0.txt`,用于 Qwen3.5 及采用 Apache 许可的源文件。
|
| 13 |
+
|
| 14 |
+
根目录的 `LICENSE` 是模型权重仓库的主要许可证文本。
|
| 15 |
+
相应源文件应优先遵循
|
| 16 |
+
文件级的版权声明和许可证头。
|
NOTICE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
ZDTaichu-5.0-9B
|
| 2 |
+
Copyright 2026 ZDTaichu-5.0-9B contributors
|
| 3 |
+
|
| 4 |
+
This distribution contains ZDTaichu-5.0-9B model weights, configuration,
|
| 5 |
+
tokenizer artifacts, and Hugging Face inference code. Third-party licenses
|
| 6 |
+
remain in force; see THIRD_PARTY_LICENSES.md and LICENSES/.
|
| 7 |
+
|
| 8 |
+
This product includes C-RADIOv4-H components from NVIDIA Corporation.
|
| 9 |
+
|
| 10 |
+
Licensed by NVIDIA Corporation under the NVIDIA Open Model License
|
| 11 |
+
|
| 12 |
+
The C-RADIOv4-H upstream model was obtained from nvidia/C-RADIOv4-H at
|
| 13 |
+
Hugging Face revision 0057b339059c0b9e1b4ba996f975410ebbfdfcc8. Original
|
| 14 |
+
copyright and license notices have been retained.
|
| 15 |
+
|
| 16 |
+
This product includes software derived from OpenGVLab/InternVL. Original
|
| 17 |
+
OpenGVLab copyright notices have been retained. See
|
| 18 |
+
LICENSES/MIT-OpenGVLab.txt.
|
| 19 |
+
|
| 20 |
+
The Qwen3.5-9B language backbone and upstream artifacts are provided by the
|
| 21 |
+
Qwen team under Apache License 2.0. See LICENSES/Apache-2.0.txt.
|
| 22 |
+
|
| 23 |
+
No upstream artifact is relicensed by this Notice.
|
README.md
ADDED
|
@@ -0,0 +1,643 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
language:
|
| 3 |
+
- en
|
| 4 |
+
- zh
|
| 5 |
+
pipeline_tag: image-text-to-text
|
| 6 |
+
tags:
|
| 7 |
+
- multimodal
|
| 8 |
+
- vision-language-model
|
| 9 |
+
- spatial-reasoning
|
| 10 |
+
- agent
|
| 11 |
+
- video-understanding
|
| 12 |
+
---
|
| 13 |
+
|
| 14 |
+
# ZDTaichu5.0-9B
|
| 15 |
+
|
| 16 |
+
[Project Page](https://taichu-ai.github.io/ZDTaichu5.0-9B/) | [GitHub](https://github.com/Taichu-AI/ZDTaichu5.0-9B) | [ModelScope](https://www.modelscope.cn/models/TaichuAI/ZDTaichu5.0-9B)
|
| 17 |
+
|
| 18 |
+
ZDTaichu5.0-9B is a multimodal foundation model for general visual understanding, spatial reasoning, agentic tool use, and embodied-AI research. It combines a Qwen3.5-9B language backbone with a C-RADIOv4-H vision encoder, supports text, images and videos with any-resolution visual input.
|
| 19 |
+
|
| 20 |
+
Within the 9B-scale general-purpose VLMs compared in this release blog, ZDTaichu5.0-9B retains first-tier general visual understanding while supporting spatial reasoning, high-level embodied VLM reasoning, and agent tasks under the reported evaluation settings. Rather than trading broad visual competence for specialization, it layers a more comprehensive spatial, embodied, and agent capability profile on top of a strong general-vision foundation.
|
| 21 |
+
|
| 22 |
+
The model accepts text, one or more images, and video. It is designed for:
|
| 23 |
+
|
| 24 |
+
- general image, document, chart, diagram, and OCR understanding;
|
| 25 |
+
- visual mathematics and knowledge-grounded visual question answering;
|
| 26 |
+
- fine-grained 2D relations, multi-view association, 3D scene understanding, perspective taking, and mental transformation;
|
| 27 |
+
- multi-step and multi-turn tool use;
|
| 28 |
+
- spatial perception, affordance understanding, and planning for VLA and embodied-AI adaptation.
|
| 29 |
+
|
| 30 |
+
More demos and showcases are provided at [Project Page](https://taichu-ai.github.io/ZDTaichu5.0-9B/).
|
| 31 |
+
|
| 32 |
+
## Highlights
|
| 33 |
+
|
| 34 |
+
- **Strong general vision and broad capabilities:** remains in the leading group of 9B-scale general-purpose VLMs across images, documents, charts, diagrams, OCR, visual mathematics, multiple images and video, while extending to spatial reasoning, high-level embodied understanding and multi-step agent tasks.
|
| 35 |
+
- **Leading spatial reasoning and embodied understanding:** leads spatial capability among the compared 9B-scale general-purpose VLMs, with strong results on SparBench, ViewSpatial, MMSI-Bench and MindCube-tiny. Scores of 48 on ERQA and 56 on RoboSpatial cover scene reasoning, affordances and interaction-oriented understanding.
|
| 36 |
+
- **Strongest agent capability among the compared 9B-scale general-purpose VLMs:** leads the reported TAU2-Bench (87.7) and Claw-Eval (71.4) comparisons, and reaches 93.7 on IFEval.
|
| 37 |
+
- **Entropy-Gated Adaptive Recurrent Reasoning:** Dynamically allocates additional recurrent refinement steps in latent space to more challenging tokens, enabling greater computational depth where needed and improving reasoning performance on complex tasks.
|
| 38 |
+
|
| 39 |
+
## Model Overview
|
| 40 |
+
|
| 41 |
+
| Item | Specification |
|
| 42 |
+
|---|---|
|
| 43 |
+
| Model type | Multimodal causal language model with vision encoder |
|
| 44 |
+
| Language backbone | Qwen3.5-9B LLM Decoder|
|
| 45 |
+
| Vision backbone | C-RADIOv4-H |
|
| 46 |
+
| Context length | Up to 128K tokens |
|
| 47 |
+
| Vision resolution | Any-resolution visual input |
|
| 48 |
+
| Input modalities | Text, single image, multiple images, and video |
|
| 49 |
+
|
| 50 |
+
## Capabilities
|
| 51 |
+
|
| 52 |
+
### General visual understanding
|
| 53 |
+
|
| 54 |
+
The model can recognize objects, attributes, and scenes; read text in natural images and documents; interpret tables, forms, plots, and diagrams; and answer questions that combine visual evidence with language and world knowledge.
|
| 55 |
+
|
| 56 |
+
### Spatial perception and reasoning
|
| 57 |
+
|
| 58 |
+
Spatial training covers:
|
| 59 |
+
|
| 60 |
+
- left/right, above/below, front/behind, occlusion, containment, and relative distance;
|
| 61 |
+
- dense counting, fine-grained localization, points, coordinates, and bounding boxes;
|
| 62 |
+
- association across images and viewpoints;
|
| 63 |
+
- camera motion, relative pose, depth ordering, and room-scale layout;
|
| 64 |
+
- egocentric and allocentric perspective taking;
|
| 65 |
+
- 2D/3D rotation, paper folding, three-view projection, cross-sections, and part-motion reasoning;
|
| 66 |
+
- embodied affordances, manipulation semantics, and high-level action planning.
|
| 67 |
+
|
| 68 |
+
### Multiple images and video
|
| 69 |
+
|
| 70 |
+
ZDTaichu5.0-9B compares and reasons across multiple images and supports video understanding, including event tracking and detail retrieval from long footage within its 128K-token context window.
|
| 71 |
+
|
| 72 |
+
### Agentic tool use
|
| 73 |
+
|
| 74 |
+
The model is designed for multi-step and multi-turn tool-use tasks. Tool execution must be implemented, validated, and secured by the surrounding application; the model does not execute tools by itself.
|
| 75 |
+
|
| 76 |
+
## Benchmark Results
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
The two figures compare ZDTaichu5.0-9B with open and closed models across general visual understanding, spatial and embodied capabilities, and agent and text capabilities.
|
| 80 |
+
|
| 81 |
+
**Comparison with open models**
|
| 82 |
+
|
| 83 |
+

|
| 84 |
+
|
| 85 |
+
**Comparison with closed models**
|
| 86 |
+
|
| 87 |
+

|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
### Spatial and embodied reasoning
|
| 92 |
+
|
| 93 |
+
<table>
|
| 94 |
+
<thead>
|
| 95 |
+
<tr>
|
| 96 |
+
<th align="left">Area</th>
|
| 97 |
+
<th align="left">Benchmark</th>
|
| 98 |
+
<th align="right">ZDTaichu5.0-9B</th>
|
| 99 |
+
<th align="right">Qwen3.5-9B</th>
|
| 100 |
+
<th align="right">STEP3-VL-10B</th>
|
| 101 |
+
<th align="right">gemma4-8B-E4B</th>
|
| 102 |
+
<th align="right">Gemini 3 Pro</th>
|
| 103 |
+
<th align="right">Grok 4</th>
|
| 104 |
+
<th align="right">GPT-5.2</th>
|
| 105 |
+
</tr>
|
| 106 |
+
</thead>
|
| 107 |
+
<tbody>
|
| 108 |
+
<tr>
|
| 109 |
+
<td rowspan="3" align="left" valign="middle">Basic spatial perception</td>
|
| 110 |
+
<td align="left">CV-Bench</td>
|
| 111 |
+
<td align="right">86.82</td>
|
| 112 |
+
<td align="right"><strong>87.19</strong></td>
|
| 113 |
+
<td align="right">83.49</td>
|
| 114 |
+
<td align="right">68.10</td>
|
| 115 |
+
<td align="right"><ins>90.07</ins></td>
|
| 116 |
+
<td align="right">—</td>
|
| 117 |
+
<td align="right">86.84</td>
|
| 118 |
+
</tr>
|
| 119 |
+
<tr>
|
| 120 |
+
<td align="left">3DSRBench</td>
|
| 121 |
+
<td align="right"><strong>60.96</strong></td>
|
| 122 |
+
<td align="right">56.78</td>
|
| 123 |
+
<td align="right">55.01</td>
|
| 124 |
+
<td align="right">53.62</td>
|
| 125 |
+
<td align="right"><ins>68.92</ins></td>
|
| 126 |
+
<td align="right">54.93</td>
|
| 127 |
+
<td align="right">60.20</td>
|
| 128 |
+
</tr>
|
| 129 |
+
<tr>
|
| 130 |
+
<td align="left">SparBench</td>
|
| 131 |
+
<td align="right"><strong>51.82</strong></td>
|
| 132 |
+
<td align="right">50.79</td>
|
| 133 |
+
<td align="right">45.68</td>
|
| 134 |
+
<td align="right">28.50</td>
|
| 135 |
+
<td align="right">48.74</td>
|
| 136 |
+
<td align="right">44.76</td>
|
| 137 |
+
<td align="right"><ins>55.07</ins></td>
|
| 138 |
+
</tr>
|
| 139 |
+
<tr>
|
| 140 |
+
<td rowspan="3" align="left" valign="middle">Complex spatial reasoning</td>
|
| 141 |
+
<td align="left">ViewSpatial</td>
|
| 142 |
+
<td align="right"><strong><ins>62.50</ins></strong></td>
|
| 143 |
+
<td align="right">48.20</td>
|
| 144 |
+
<td align="right">46.14</td>
|
| 145 |
+
<td align="right">41.68</td>
|
| 146 |
+
<td align="right">50.36</td>
|
| 147 |
+
<td align="right">43.23</td>
|
| 148 |
+
<td align="right">47.30</td>
|
| 149 |
+
</tr>
|
| 150 |
+
<tr>
|
| 151 |
+
<td align="left">MMSI-Bench</td>
|
| 152 |
+
<td align="right"><strong><ins>47.20</ins></strong></td>
|
| 153 |
+
<td align="right">38.70</td>
|
| 154 |
+
<td align="right">32.18</td>
|
| 155 |
+
<td align="right">29.20</td>
|
| 156 |
+
<td align="right">45.20</td>
|
| 157 |
+
<td align="right">37.80</td>
|
| 158 |
+
<td align="right">41.30</td>
|
| 159 |
+
</tr>
|
| 160 |
+
<tr>
|
| 161 |
+
<td align="left">MindCube-tiny</td>
|
| 162 |
+
<td align="right"><strong><ins>78.27</ins></strong></td>
|
| 163 |
+
<td align="right">57.60</td>
|
| 164 |
+
<td align="right">62.81</td>
|
| 165 |
+
<td align="right">48.85</td>
|
| 166 |
+
<td align="right">70.87</td>
|
| 167 |
+
<td align="right">63.56</td>
|
| 168 |
+
<td align="right">60.38</td>
|
| 169 |
+
</tr>
|
| 170 |
+
<tr>
|
| 171 |
+
<td rowspan="3" align="left" valign="middle">Embodied interaction</td>
|
| 172 |
+
<td align="left">ERQA</td>
|
| 173 |
+
<td align="right"><strong>48.00</strong></td>
|
| 174 |
+
<td align="right">41.50</td>
|
| 175 |
+
<td align="right">47.75</td>
|
| 176 |
+
<td align="right">30.20</td>
|
| 177 |
+
<td align="right"><ins>66.00</ins></td>
|
| 178 |
+
<td align="right">—</td>
|
| 179 |
+
<td align="right">59.80</td>
|
| 180 |
+
</tr>
|
| 181 |
+
<tr>
|
| 182 |
+
<td align="left">RoboSpatial</td>
|
| 183 |
+
<td align="right"><strong>56.00</strong></td>
|
| 184 |
+
<td align="right">54.10</td>
|
| 185 |
+
<td align="right">52.86</td>
|
| 186 |
+
<td align="right">49.43</td>
|
| 187 |
+
<td align="right"><ins>57.40</ins></td>
|
| 188 |
+
<td align="right">—</td>
|
| 189 |
+
<td align="right">43.78</td>
|
| 190 |
+
</tr>
|
| 191 |
+
<tr>
|
| 192 |
+
<td align="left">VSI-Bench</td>
|
| 193 |
+
<td align="right"><strong><ins>59.69</ins></strong></td>
|
| 194 |
+
<td align="right">55.68</td>
|
| 195 |
+
<td align="right">42.42</td>
|
| 196 |
+
<td align="right">32.91</td>
|
| 197 |
+
<td align="right">52.51</td>
|
| 198 |
+
<td align="right">47.92</td>
|
| 199 |
+
<td align="right">54.49</td>
|
| 200 |
+
</tr>
|
| 201 |
+
</tbody>
|
| 202 |
+
</table>
|
| 203 |
+
|
| 204 |
+
### General visual understanding
|
| 205 |
+
|
| 206 |
+
<table>
|
| 207 |
+
<thead>
|
| 208 |
+
<tr>
|
| 209 |
+
<th align="left">Area</th>
|
| 210 |
+
<th align="left">Benchmark</th>
|
| 211 |
+
<th align="right">ZDTaichu5.0-9B</th>
|
| 212 |
+
<th align="right">Qwen3.5-9B</th>
|
| 213 |
+
<th align="right">STEP3-VL-10B</th>
|
| 214 |
+
<th align="right">gemma4-8B-E4B</th>
|
| 215 |
+
<th align="right">Gemini 3 Pro</th>
|
| 216 |
+
<th align="right">Grok 4</th>
|
| 217 |
+
<th align="right">GPT-5.2</th>
|
| 218 |
+
</tr>
|
| 219 |
+
</thead>
|
| 220 |
+
<tbody>
|
| 221 |
+
<tr>
|
| 222 |
+
<td align="left" rowspan="3" valign="middle">Multi modal Reasoning</td>
|
| 223 |
+
<td align="left">MathVista Mini</td>
|
| 224 |
+
<td align="right">84.50</td>
|
| 225 |
+
<td align="right"><strong>85.70</strong></td>
|
| 226 |
+
<td align="right">83.97</td>
|
| 227 |
+
<td align="right">65.30</td>
|
| 228 |
+
<td align="right"><ins>87.90</ins></td>
|
| 229 |
+
<td align="right">72.50</td>
|
| 230 |
+
<td align="right">83.10</td>
|
| 231 |
+
</tr>
|
| 232 |
+
<tr>
|
| 233 |
+
<td align="left">WeMath</td>
|
| 234 |
+
<td align="right"><strong>75.90</strong></td>
|
| 235 |
+
<td align="right">75.20</td>
|
| 236 |
+
<td align="right">73.03</td>
|
| 237 |
+
<td align="right">50.19</td>
|
| 238 |
+
<td align="right"><ins>86.90</ins></td>
|
| 239 |
+
<td align="right">—</td>
|
| 240 |
+
<td align="right">79.00</td>
|
| 241 |
+
</tr>
|
| 242 |
+
<tr>
|
| 243 |
+
<td align="left">MathVerse Mini Vision Only</td>
|
| 244 |
+
<td align="right">76.40</td>
|
| 245 |
+
<td align="right"><strong><ins>84.14</ins></strong></td>
|
| 246 |
+
<td align="right">74.60</td>
|
| 247 |
+
<td align="right">53.55</td>
|
| 248 |
+
<td align="right">—</td>
|
| 249 |
+
<td align="right">—</td>
|
| 250 |
+
<td align="right">—</td>
|
| 251 |
+
</tr>
|
| 252 |
+
<tr>
|
| 253 |
+
<td align="left" rowspan="3" valign="middle">General VQA</td>
|
| 254 |
+
<td align="left">MMStar</td>
|
| 255 |
+
<td align="right">76.80</td>
|
| 256 |
+
<td align="right"><strong>79.70</strong></td>
|
| 257 |
+
<td align="right">77.48</td>
|
| 258 |
+
<td align="right">62.00</td>
|
| 259 |
+
<td align="right"><ins>83.10</ins></td>
|
| 260 |
+
<td align="right">69.60</td>
|
| 261 |
+
<td align="right">77.10</td>
|
| 262 |
+
</tr>
|
| 263 |
+
<tr>
|
| 264 |
+
<td align="left">AI2D</td>
|
| 265 |
+
<td align="right"><strong>91.48</strong></td>
|
| 266 |
+
<td align="right">90.20</td>
|
| 267 |
+
<td align="right">89.35</td>
|
| 268 |
+
<td align="right">79.15</td>
|
| 269 |
+
<td align="right"><ins>94.10</ins></td>
|
| 270 |
+
<td align="right">—</td>
|
| 271 |
+
<td align="right">92.20</td>
|
| 272 |
+
</tr>
|
| 273 |
+
<tr>
|
| 274 |
+
<td align="left">RealWorldQA</td>
|
| 275 |
+
<td align="right">76.99</td>
|
| 276 |
+
<td align="right"><strong>80.30</strong></td>
|
| 277 |
+
<td align="right">74.44</td>
|
| 278 |
+
<td align="right">59.08</td>
|
| 279 |
+
<td align="right"><ins>83.30</ins></td>
|
| 280 |
+
<td align="right">—</td>
|
| 281 |
+
<td align="right"><ins>83.30</ins></td>
|
| 282 |
+
</tr>
|
| 283 |
+
<tr>
|
| 284 |
+
<td align="left" valign="middle">OCR</td>
|
| 285 |
+
<td align="left">OCRBench</td>
|
| 286 |
+
<td align="right">85.50</td>
|
| 287 |
+
<td align="right"><strong>89.20</strong></td>
|
| 288 |
+
<td align="right">86.75</td>
|
| 289 |
+
<td align="right">76.90</td>
|
| 290 |
+
<td align="right"><ins>90.40</ins></td>
|
| 291 |
+
<td align="right">—</td>
|
| 292 |
+
<td align="right">80.70</td>
|
| 293 |
+
</tr>
|
| 294 |
+
</tbody>
|
| 295 |
+
</table>
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
### Language, reasoning, and agents
|
| 300 |
+
|
| 301 |
+
<table>
|
| 302 |
+
<thead>
|
| 303 |
+
<tr>
|
| 304 |
+
<th align="left">Area</th>
|
| 305 |
+
<th align="left">Benchmark</th>
|
| 306 |
+
<th align="right">ZDTaichu5.0-9B</th>
|
| 307 |
+
<th align="right">Qwen3.5-9B</th>
|
| 308 |
+
<th align="right">STEP3-VL-10B</th>
|
| 309 |
+
<th align="right">gemma4-8B-E4B</th>
|
| 310 |
+
<th align="right">Gemini 3 Pro</th>
|
| 311 |
+
<th align="right">Grok 4</th>
|
| 312 |
+
<th align="right">GPT-5.2</th>
|
| 313 |
+
</tr>
|
| 314 |
+
</thead>
|
| 315 |
+
<tbody>
|
| 316 |
+
<tr>
|
| 317 |
+
<td rowspan="2" align="left" valign="middle">Knowledge</td>
|
| 318 |
+
<td align="left">MMLU-Pro</td>
|
| 319 |
+
<td align="right">77.20</td>
|
| 320 |
+
<td align="right"><strong>82.50</strong></td>
|
| 321 |
+
<td align="right">76.02</td>
|
| 322 |
+
<td align="right">69.40</td>
|
| 323 |
+
<td align="right"><ins>89.80</ins></td>
|
| 324 |
+
<td align="right">85.90</td>
|
| 325 |
+
<td align="right">87.40</td>
|
| 326 |
+
</tr>
|
| 327 |
+
<tr>
|
| 328 |
+
<td align="left">MMLU-Redux</td>
|
| 329 |
+
<td align="right">88.40</td>
|
| 330 |
+
<td align="right"><strong>91.10</strong></td>
|
| 331 |
+
<td align="right">86.50</td>
|
| 332 |
+
<td align="right">85.30</td>
|
| 333 |
+
<td align="right"><ins>95.90</ins></td>
|
| 334 |
+
<td align="right">86.22</td>
|
| 335 |
+
<td align="right">95.00</td>
|
| 336 |
+
</tr>
|
| 337 |
+
<tr>
|
| 338 |
+
<td rowspan="2" align="left" valign="middle">Instruction following</td>
|
| 339 |
+
<td align="left">IFEval</td>
|
| 340 |
+
<td align="right"><strong>93.70</strong></td>
|
| 341 |
+
<td align="right">88.72</td>
|
| 342 |
+
<td align="right">82.16</td>
|
| 343 |
+
<td align="right">87.80</td>
|
| 344 |
+
<td align="right">93.50</td>
|
| 345 |
+
<td align="right">92.80</td>
|
| 346 |
+
<td align="right"><ins>94.80</ins></td>
|
| 347 |
+
</tr>
|
| 348 |
+
<tr>
|
| 349 |
+
<td align="left">IFBench</td>
|
| 350 |
+
<td align="right"><strong>69.00</strong></td>
|
| 351 |
+
<td align="right">64.50</td>
|
| 352 |
+
<td align="right">41.49</td>
|
| 353 |
+
<td align="right">34.70</td>
|
| 354 |
+
<td align="right">70.40</td>
|
| 355 |
+
<td align="right">53.70</td>
|
| 356 |
+
<td align="right"><ins>75.40</ins></td>
|
| 357 |
+
</tr>
|
| 358 |
+
<tr>
|
| 359 |
+
<td rowspan="5" align="left" valign="middle">Reasoning and coding</td>
|
| 360 |
+
<td align="left">AIME 2025</td>
|
| 361 |
+
<td align="right">86.70</td>
|
| 362 |
+
<td align="right">83.75</td>
|
| 363 |
+
<td align="right"><strong>87.66</strong></td>
|
| 364 |
+
<td align="right">41.30</td>
|
| 365 |
+
<td align="right">95.00</td>
|
| 366 |
+
<td align="right">91.70</td>
|
| 367 |
+
<td align="right"><ins>100.00</ins></td>
|
| 368 |
+
</tr>
|
| 369 |
+
<tr>
|
| 370 |
+
<td align="left">AIME 2026</td>
|
| 371 |
+
<td align="right"><strong>89.20</strong></td>
|
| 372 |
+
<td align="right">87.92</td>
|
| 373 |
+
<td align="right">88.75</td>
|
| 374 |
+
<td align="right">42.50</td>
|
| 375 |
+
<td align="right">90.60</td>
|
| 376 |
+
<td align="right">—</td>
|
| 377 |
+
<td align="right"><ins>96.70</ins></td>
|
| 378 |
+
</tr>
|
| 379 |
+
<tr>
|
| 380 |
+
<td align="left">HMMT Feb 2025</td>
|
| 381 |
+
<td align="right"><strong>84.20</strong></td>
|
| 382 |
+
<td align="right">83.20</td>
|
| 383 |
+
<td align="right">78.18</td>
|
| 384 |
+
<td align="right">26.70</td>
|
| 385 |
+
<td align="right">97.30</td>
|
| 386 |
+
<td align="right">90.00</td>
|
| 387 |
+
<td align="right"><ins>99.40</ins></td>
|
| 388 |
+
</tr>
|
| 389 |
+
<tr>
|
| 390 |
+
<td align="left">HMMT Feb 2026</td>
|
| 391 |
+
<td align="right">72.70</td>
|
| 392 |
+
<td align="right"><strong>73.48</strong></td>
|
| 393 |
+
<td align="right">63.64</td>
|
| 394 |
+
<td align="right">33.70</td>
|
| 395 |
+
<td align="right">86.36</td>
|
| 396 |
+
<td align="right">—</td>
|
| 397 |
+
<td align="right"><ins>96.97</ins></td>
|
| 398 |
+
</tr>
|
| 399 |
+
<tr>
|
| 400 |
+
<td align="left">LiveCodeBench v6</td>
|
| 401 |
+
<td align="right"><strong>73.40</strong></td>
|
| 402 |
+
<td align="right">65.60</td>
|
| 403 |
+
<td align="right">58.86</td>
|
| 404 |
+
<td align="right">52.00</td>
|
| 405 |
+
<td align="right"><ins>90.70</ins></td>
|
| 406 |
+
<td align="right">—</td>
|
| 407 |
+
<td align="right">87.70</td>
|
| 408 |
+
</tr>
|
| 409 |
+
<tr>
|
| 410 |
+
<td rowspan="2" align="left" valign="middle">General agent</td>
|
| 411 |
+
<td align="left">TAU2-Bench†</td>
|
| 412 |
+
<td align="right"><strong><ins>87.70</ins></strong></td>
|
| 413 |
+
<td align="right">79.10</td>
|
| 414 |
+
<td align="right">81.70</td>
|
| 415 |
+
<td align="right">42.40</td>
|
| 416 |
+
<td align="right">85.40</td>
|
| 417 |
+
<td align="right">—</td>
|
| 418 |
+
<td align="right">87.10</td>
|
| 419 |
+
</tr>
|
| 420 |
+
<tr>
|
| 421 |
+
<td align="left">Claw-Eval<sub>general</sub> Avg†</td>
|
| 422 |
+
<td align="right"><strong><ins>71.40</ins></strong></td>
|
| 423 |
+
<td align="right">66.50</td>
|
| 424 |
+
<td align="right">66.60</td>
|
| 425 |
+
<td align="right">52.10</td>
|
| 426 |
+
<td align="right">—</td>
|
| 427 |
+
<td align="right">—</td>
|
| 428 |
+
<td align="right">—</td>
|
| 429 |
+
</tr>
|
| 430 |
+
</tbody>
|
| 431 |
+
</table>
|
| 432 |
+
|
| 433 |
+
<sub><strong>Bold</strong> indicates the best score among the listed open-source models; <ins>underlining</ins> indicates the best score among all listed models. Scores leading both comparisons are both bold and underlined. Tied best scores receive the same marking. Missing scores are excluded from the comparison.</sub>
|
| 434 |
+
|
| 435 |
+
|
| 436 |
+
<sub>† Local TAU2-Bench and Claw-Eval general evaluations use DeepSeek-V4-Flash-0731 as the simulated user and/or judge; externally reported scores follow the evaluation setup of their cited sources.</sub>
|
| 437 |
+
|
| 438 |
+
<sub>‡ Publicly reported external score. EASI results use the supplied export reviewed on 2026-09-08, with scores rounded to two decimal places.</sub>
|
| 439 |
+
|
| 440 |
+
<sub>For multi-image spatial reasoning evaluations such as ViewSpatial, MMSI-Bench, MindCube-tiny, and VSI-Bench, the following output-format requirement was added to the evaluation prompt: You FIRST think about the reasoning process as an internal monologue and then provide the final answer. The reasoning process MUST BE enclosed within <think> </think> tags. The final answer MUST BE put in \boxed{}.</sub>
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
## Quickstart
|
| 444 |
+
|
| 445 |
+
|
| 446 |
+
### Installation
|
| 447 |
+
|
| 448 |
+
Install a recent version of Hugging Face Transformers together with the standard multimodal dependencies:
|
| 449 |
+
|
| 450 |
+
```bash
|
| 451 |
+
pip install -U "transformers>=5.3.0" accelerate safetensors torch torchvision pillow
|
| 452 |
+
```
|
| 453 |
+
|
| 454 |
+
### Offline inference
|
| 455 |
+
|
| 456 |
+
```python
|
| 457 |
+
import os
|
| 458 |
+
|
| 459 |
+
import torch
|
| 460 |
+
from transformers import AutoModel, AutoProcessor
|
| 461 |
+
|
| 462 |
+
model_id = os.environ["ZDTAICHU_MODEL_ID"]
|
| 463 |
+
processor = AutoProcessor.from_pretrained(
|
| 464 |
+
model_id,
|
| 465 |
+
trust_remote_code=True,
|
| 466 |
+
use_fast=False,
|
| 467 |
+
)
|
| 468 |
+
model = AutoModel.from_pretrained(
|
| 469 |
+
model_id,
|
| 470 |
+
trust_remote_code=True,
|
| 471 |
+
torch_dtype=torch.bfloat16,
|
| 472 |
+
device_map="auto",
|
| 473 |
+
attn_implementation="sdpa",
|
| 474 |
+
).eval()
|
| 475 |
+
|
| 476 |
+
messages = [
|
| 477 |
+
{
|
| 478 |
+
"role": "user",
|
| 479 |
+
"content": [
|
| 480 |
+
{"type": "image", "image": "floorplan.png"},
|
| 481 |
+
{"type": "text", "text": "Which room is directly to the left of the kitchen?"},
|
| 482 |
+
],
|
| 483 |
+
}
|
| 484 |
+
]
|
| 485 |
+
inputs = processor.from_messages(messages, return_tensors="pt").to(model.device)
|
| 486 |
+
with torch.inference_mode():
|
| 487 |
+
output_ids = model.generate(**inputs, max_new_tokens=256, do_sample=False)
|
| 488 |
+
generated_ids = output_ids[:, inputs["input_ids"].shape[1] :]
|
| 489 |
+
print(processor.batch_decode(generated_ids, skip_special_tokens=True)[0])
|
| 490 |
+
```
|
| 491 |
+
|
| 492 |
+
### Online Serving
|
| 493 |
+
|
| 494 |
+
We adapted the v0.26.0 branch with the architecture, quantization, and speculative decoding
|
| 495 |
+
features required by ZDTaichu5.0, supporting both Docker and source deployment:
|
| 496 |
+
|
| 497 |
+
**Docker (recommended)**
|
| 498 |
+
|
| 499 |
+
- **Docker image:** `registry-dx.wair.ac.cn/taichu-public/vllm-openai:v0.26.0.zdtaichu_5_0`
|
| 500 |
+
|
| 501 |
+
```bash
|
| 502 |
+
docker run -d \
|
| 503 |
+
-e CUDA_VISIBLE_DEVICES=0 --gpus all \
|
| 504 |
+
--privileged --ipc=host \
|
| 505 |
+
-p 18050:8000 \
|
| 506 |
+
registry-dx.wair.ac.cn/taichu-public/vllm-openai:v0.26.0.zdtaichu_5_0 \
|
| 507 |
+
/path/to/ZDTaichu5.0-9B \
|
| 508 |
+
--max-model-len 220000 \
|
| 509 |
+
--mamba-ssm-cache-dtype float32 \
|
| 510 |
+
--gdn-prefill-backend triton \
|
| 511 |
+
--trust-remote-code \
|
| 512 |
+
--tensor-parallel-size 1 \
|
| 513 |
+
--generation-config vllm
|
| 514 |
+
```
|
| 515 |
+
|
| 516 |
+
**Install from source**
|
| 517 |
+
|
| 518 |
+
- **vLLM source (GitHub):** https://github.com/Taichu-AI/vllm · branch `v0.26.0-zdtaichu`
|
| 519 |
+
|
| 520 |
+
```bash
|
| 521 |
+
git clone -b v0.26.0-zdtaichu https://github.com/Taichu-AI/vllm.git
|
| 522 |
+
cd vllm
|
| 523 |
+
pip install -e .
|
| 524 |
+
|
| 525 |
+
vllm serve /path/to/ZDTaichu5.0-9B \
|
| 526 |
+
--max-model-len 220000 \
|
| 527 |
+
--mamba-ssm-cache-dtype float32 \
|
| 528 |
+
--gdn-prefill-backend triton \
|
| 529 |
+
--trust-remote-code \
|
| 530 |
+
--tensor-parallel-size 1 \
|
| 531 |
+
--generation-config vllm
|
| 532 |
+
```
|
| 533 |
+
|
| 534 |
+
The server exposes an OpenAI-compatible endpoint at `http://<host>:18050/v1`. The examples below use the
|
| 535 |
+
`requests` library (`pip install requests`):
|
| 536 |
+
|
| 537 |
+
**Setup**
|
| 538 |
+
|
| 539 |
+
```python
|
| 540 |
+
import base64
|
| 541 |
+
import requests
|
| 542 |
+
|
| 543 |
+
URL = "http://<host>:18050/v1/chat/completions"
|
| 544 |
+
|
| 545 |
+
|
| 546 |
+
def data_url(path: str, mime: str) -> str:
|
| 547 |
+
"""Encode a local file as a base64 data URI."""
|
| 548 |
+
with open(path, "rb") as f:
|
| 549 |
+
return f"data:{mime};base64," + base64.b64encode(f.read()).decode()
|
| 550 |
+
|
| 551 |
+
|
| 552 |
+
def chat(body: dict) -> str:
|
| 553 |
+
resp = requests.post(URL, json=body, timeout=600)
|
| 554 |
+
resp.raise_for_status()
|
| 555 |
+
return resp.json()["choices"][0]["message"]["content"]
|
| 556 |
+
|
| 557 |
+
# Text-only input
|
| 558 |
+
|
| 559 |
+
body = {
|
| 560 |
+
"model": "zdtaichu",
|
| 561 |
+
"messages": [{"role": "user", "content": "Hello"}],
|
| 562 |
+
"temperature": 1.0,
|
| 563 |
+
"top_p": 0.95,
|
| 564 |
+
"top_k": 20,
|
| 565 |
+
}
|
| 566 |
+
print(chat(body))
|
| 567 |
+
|
| 568 |
+
# Image input (local file, base64)
|
| 569 |
+
|
| 570 |
+
body = {
|
| 571 |
+
"model": "zdtaichu",
|
| 572 |
+
"messages": [
|
| 573 |
+
{
|
| 574 |
+
"role": "user",
|
| 575 |
+
"content": [
|
| 576 |
+
{"type": "text", "text": "Which room is directly to the left of the kitchen?"},
|
| 577 |
+
{"type": "image_url", "image_url": {"url": data_url("floorplan.png", "image/png")}},
|
| 578 |
+
],
|
| 579 |
+
}
|
| 580 |
+
],
|
| 581 |
+
"temperature": 0,
|
| 582 |
+
"top_p": 0.95,
|
| 583 |
+
"top_k": 20,
|
| 584 |
+
}
|
| 585 |
+
|
| 586 |
+
# Video input (local file, base64)
|
| 587 |
+
|
| 588 |
+
body = {
|
| 589 |
+
"model": "zdtaichu",
|
| 590 |
+
"messages": [
|
| 591 |
+
{
|
| 592 |
+
"role": "user",
|
| 593 |
+
"content": [
|
| 594 |
+
{"type": "text", "text": "Please describe the video."},
|
| 595 |
+
{"type": "video_url", "video_url": {"url": data_url("example.mp4", "video/mp4")}},
|
| 596 |
+
],
|
| 597 |
+
}
|
| 598 |
+
],
|
| 599 |
+
"media_io_kwargs": {
|
| 600 |
+
"video": {
|
| 601 |
+
"num_frames": 8,
|
| 602 |
+
},
|
| 603 |
+
},
|
| 604 |
+
}
|
| 605 |
+
print(chat(body))
|
| 606 |
+
```
|
| 607 |
+
|
| 608 |
+
`media_io_kwargs.video.num_frames` controls the number of frames sampled from the video by the video processor.
|
| 609 |
+
|
| 610 |
+
**Recommended sampling parameters**
|
| 611 |
+
|
| 612 |
+
| Task | temperature | top_p | top_k |
|
| 613 |
+
|---|---|---|---|
|
| 614 |
+
| Spatial reasoning and grounding | 0 | 0.95 | 20 |
|
| 615 |
+
| Other tasks | 1.0 | 0.95 | 20 |
|
| 616 |
+
|
| 617 |
+
**Reasoning and tool-call parsing arguments (optional)**
|
| 618 |
+
|
| 619 |
+
To enable reasoning output and tool calls, add the following arguments to the launch command:
|
| 620 |
+
|
| 621 |
+
```bash
|
| 622 |
+
--reasoning-parser qwen3 --enable-auto-tool-choice --tool-call-parser qwen3_coder
|
| 623 |
+
```
|
| 624 |
+
|
| 625 |
+
|
| 626 |
+
## License
|
| 627 |
+
|
| 628 |
+
The model weights in this repository are made available under the NVIDIA Open Model License Agreement, with the Qwen3.5 Apache-2.0 license and all other third-party notices retained. See `LICENSE`, `NOTICE`, and `THIRD_PARTY_LICENSES.md`.
|
| 629 |
+
|
| 630 |
+
## Acknowledgements
|
| 631 |
+
|
| 632 |
+
This model builds on the Qwen3.5 language architecture and NVIDIA C-RADIO vision encoder family. Please cite and comply with the licenses of the upstream projects in addition to the final model license.
|
| 633 |
+
|
| 634 |
+
## Citation
|
| 635 |
+
|
| 636 |
+
```bibtex
|
| 637 |
+
@misc{zdtaichu_5_0_9b,
|
| 638 |
+
title = {ZDTaichu5.0-9B: A Multimodal Foundation Model for Visual and Spatial Reasoning, Agents, and Embodied AI},
|
| 639 |
+
author = {{ZDTaichu5.0-9B Contributors}},
|
| 640 |
+
year = {2026},
|
| 641 |
+
note = {Open-weight model and public model card}
|
| 642 |
+
}
|
| 643 |
+
```
|
THIRD_PARTY_LICENSES.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Third-Party Licenses
|
| 2 |
+
|
| 3 |
+
This file records the principal third-party components in the ZDTaichu5.0-9B
|
| 4 |
+
Hugging Face weight repository. File-level notices take precedence over this
|
| 5 |
+
summary.
|
| 6 |
+
|
| 7 |
+
| Component | Scope | Upstream | Governing terms |
|
| 8 |
+
|---|---|---|---|
|
| 9 |
+
| Qwen3.5-9B | Language backbone, tokenizer, and architecture | [Qwen/Qwen3.5-9B](https://huggingface.co/Qwen/Qwen3.5-9B) | Apache License 2.0 |
|
| 10 |
+
| C-RADIOv4-H | Vision backbone and derivative-model obligations | [nvidia/C-RADIOv4-H](https://huggingface.co/nvidia/C-RADIOv4-H), revision `0057b339059c0b9e1b4ba996f975410ebbfdfcc8` | NVIDIA Open Model License Agreement |
|
| 11 |
+
| Hugging Face Transformers | Runtime interfaces and Qwen3.5 implementation | [huggingface/transformers](https://github.com/huggingface/transformers) | Apache License 2.0 |
|
| 12 |
+
|
| 13 |
+
## License boundaries
|
| 14 |
+
|
| 15 |
+
- The root `LICENSE` contains the NVIDIA Open Model License Agreement that
|
| 16 |
+
governs the C-RADIOv4-H model and applicable derivative-model obligations.
|
| 17 |
+
- Qwen3.5-9B artifacts remain under Apache License 2.0. A copy is provided in
|
| 18 |
+
`LICENSES/Apache-2.0.txt`.
|
| 19 |
+
- Standalone-inference source files authored for this repository (for example
|
| 20 |
+
`cradio_config.py` and `cradio_model.py`) are provided under the Apache
|
| 21 |
+
License 2.0, as stated in their file headers.
|
| 22 |
+
- Source files carrying their own copyright or license headers remain governed
|
| 23 |
+
by those file-level terms.
|
| 24 |
+
- Dependencies installed separately remain subject to their own licenses.
|
| 25 |
+
|
| 26 |
+
Redistribution must include the NVIDIA Open Model License Agreement and a
|
| 27 |
+
Notice file containing: `Licensed by NVIDIA Corporation under the NVIDIA Open
|
| 28 |
+
Model License`.
|
| 29 |
+
|
| 30 |
+
This summary is informational and does not replace the authoritative license
|
__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 2 |
+
"""Public Transformers reference implementation for ZDTaichu-5.0."""
|
| 3 |
+
|
| 4 |
+
from .configuration import ZDTaichu5_0_Config
|
| 5 |
+
from .image_processing import ZDTaichu5_0_ImageProcessor
|
| 6 |
+
from .modeling import ZDTaichu5_0_ForConditionalGeneration
|
| 7 |
+
from .processing import ZDTaichu5_0_Processor
|
| 8 |
+
|
| 9 |
+
__all__ = [
|
| 10 |
+
"ZDTaichu5_0_Config",
|
| 11 |
+
"ZDTaichu5_0_ForConditionalGeneration",
|
| 12 |
+
"ZDTaichu5_0_ImageProcessor",
|
| 13 |
+
"ZDTaichu5_0_Processor",
|
| 14 |
+
]
|
| 15 |
+
|
| 16 |
+
__version__ = "0.1.0"
|
assets/logos/gemini.png
ADDED
|
assets/logos/gemma.png
ADDED
|
assets/logos/grok.png
ADDED
|
assets/logos/qwen.png
ADDED
|
assets/logos/stepfun.png
ADDED
|
assets/logos/taichu.png
ADDED
|
assets/taichu-release-benchmark-comparison.svg
ADDED
|
|
assets/taichu-vs-closed-models.svg
ADDED
|
|
chat_template.jinja
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{%- set image_count = namespace(value=0) %}
|
| 2 |
+
{%- set video_count = namespace(value=0) %}
|
| 3 |
+
{%- macro render_content(content, do_vision_count, is_system_content=false) %}
|
| 4 |
+
{%- if content is string %}
|
| 5 |
+
{{- content }}
|
| 6 |
+
{%- elif content is iterable and content is not mapping %}
|
| 7 |
+
{%- for item in content %}
|
| 8 |
+
{%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
|
| 9 |
+
{%- if is_system_content %}
|
| 10 |
+
{{- raise_exception('System message cannot contain images.') }}
|
| 11 |
+
{%- endif %}
|
| 12 |
+
{%- if do_vision_count %}
|
| 13 |
+
{%- set image_count.value = image_count.value + 1 %}
|
| 14 |
+
{%- endif %}
|
| 15 |
+
{%- if add_vision_id %}
|
| 16 |
+
{{- 'Picture ' ~ image_count.value ~ ': ' }}
|
| 17 |
+
{%- endif %}
|
| 18 |
+
{{- '<|vision_start|><|image_pad|><|vision_end|>' }}
|
| 19 |
+
{%- elif 'video' in item or item.type == 'video' %}
|
| 20 |
+
{%- if is_system_content %}
|
| 21 |
+
{{- raise_exception('System message cannot contain videos.') }}
|
| 22 |
+
{%- endif %}
|
| 23 |
+
{%- if do_vision_count %}
|
| 24 |
+
{%- set video_count.value = video_count.value + 1 %}
|
| 25 |
+
{%- endif %}
|
| 26 |
+
{%- if add_vision_id %}
|
| 27 |
+
{{- 'Video ' ~ video_count.value ~ ': ' }}
|
| 28 |
+
{%- endif %}
|
| 29 |
+
{{- '<|vision_start|><|video_pad|><|vision_end|>' }}
|
| 30 |
+
{%- elif 'text' in item %}
|
| 31 |
+
{{- item.text }}
|
| 32 |
+
{%- else %}
|
| 33 |
+
{{- raise_exception('Unexpected item type in content.') }}
|
| 34 |
+
{%- endif %}
|
| 35 |
+
{%- endfor %}
|
| 36 |
+
{%- elif content is none or content is undefined %}
|
| 37 |
+
{{- '' }}
|
| 38 |
+
{%- else %}
|
| 39 |
+
{{- raise_exception('Unexpected content type.') }}
|
| 40 |
+
{%- endif %}
|
| 41 |
+
{%- endmacro %}
|
| 42 |
+
{%- if not messages %}
|
| 43 |
+
{{- raise_exception('No messages provided.') }}
|
| 44 |
+
{%- endif %}
|
| 45 |
+
{%- if tools and tools is iterable and tools is not mapping %}
|
| 46 |
+
{{- '<|im_start|>system\n' }}
|
| 47 |
+
{{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
|
| 48 |
+
{%- for tool in tools %}
|
| 49 |
+
{{- "\n" }}
|
| 50 |
+
{{- tool | tojson }}
|
| 51 |
+
{%- endfor %}
|
| 52 |
+
{{- "\n</tools>" }}
|
| 53 |
+
{{- '\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>' }}
|
| 54 |
+
{%- if messages[0].role == 'system' %}
|
| 55 |
+
{%- set content = render_content(messages[0].content, false, true)|trim %}
|
| 56 |
+
{%- if content %}
|
| 57 |
+
{{- '\n\n' + content }}
|
| 58 |
+
{%- endif %}
|
| 59 |
+
{%- endif %}
|
| 60 |
+
{{- '<|im_end|>\n' }}
|
| 61 |
+
{%- else %}
|
| 62 |
+
{%- if messages[0].role == 'system' %}
|
| 63 |
+
{%- set content = render_content(messages[0].content, false, true)|trim %}
|
| 64 |
+
{{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
|
| 65 |
+
{%- endif %}
|
| 66 |
+
{%- endif %}
|
| 67 |
+
{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
|
| 68 |
+
{%- for message in messages[::-1] %}
|
| 69 |
+
{%- set index = (messages|length - 1) - loop.index0 %}
|
| 70 |
+
{%- if ns.multi_step_tool and message.role == "user" %}
|
| 71 |
+
{%- set content = render_content(message.content, false)|trim %}
|
| 72 |
+
{%- if not(content.startswith('<tool_response>') and content.endswith('</tool_response>')) %}
|
| 73 |
+
{%- set ns.multi_step_tool = false %}
|
| 74 |
+
{%- set ns.last_query_index = index %}
|
| 75 |
+
{%- endif %}
|
| 76 |
+
{%- endif %}
|
| 77 |
+
{%- endfor %}
|
| 78 |
+
{%- if ns.multi_step_tool %}
|
| 79 |
+
{{- raise_exception('No user query found in messages.') }}
|
| 80 |
+
{%- endif %}
|
| 81 |
+
{%- for message in messages %}
|
| 82 |
+
{%- set content = render_content(message.content, true)|trim %}
|
| 83 |
+
{%- if message.role == "system" %}
|
| 84 |
+
{%- if not loop.first %}
|
| 85 |
+
{{- raise_exception('System message must be at the beginning.') }}
|
| 86 |
+
{%- endif %}
|
| 87 |
+
{%- elif message.role == "user" %}
|
| 88 |
+
{{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }}
|
| 89 |
+
{%- elif message.role == "assistant" %}
|
| 90 |
+
{%- set reasoning_content = '' %}
|
| 91 |
+
{%- if message.reasoning_content is string %}
|
| 92 |
+
{%- set reasoning_content = message.reasoning_content %}
|
| 93 |
+
{%- else %}
|
| 94 |
+
{%- if '</think>' in content %}
|
| 95 |
+
{%- set reasoning_content = content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
|
| 96 |
+
{%- set content = content.split('</think>')[-1].lstrip('\n') %}
|
| 97 |
+
{%- endif %}
|
| 98 |
+
{%- endif %}
|
| 99 |
+
{%- set reasoning_content = reasoning_content|trim %}
|
| 100 |
+
{%- if loop.index0 > ns.last_query_index %}
|
| 101 |
+
{{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
|
| 102 |
+
{%- else %}
|
| 103 |
+
{{- '<|im_start|>' + message.role + '\n' + content }}
|
| 104 |
+
{%- endif %}
|
| 105 |
+
{%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
|
| 106 |
+
{%- for tool_call in message.tool_calls %}
|
| 107 |
+
{%- if tool_call.function is defined %}
|
| 108 |
+
{%- set tool_call = tool_call.function %}
|
| 109 |
+
{%- endif %}
|
| 110 |
+
{%- if loop.first %}
|
| 111 |
+
{%- if content|trim %}
|
| 112 |
+
{{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
|
| 113 |
+
{%- else %}
|
| 114 |
+
{{- '<tool_call>\n<function=' + tool_call.name + '>\n' }}
|
| 115 |
+
{%- endif %}
|
| 116 |
+
{%- else %}
|
| 117 |
+
{{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
|
| 118 |
+
{%- endif %}
|
| 119 |
+
{%- if tool_call.arguments is defined %}
|
| 120 |
+
{%- for args_name, args_value in tool_call.arguments|items %}
|
| 121 |
+
{{- '<parameter=' + args_name + '>\n' }}
|
| 122 |
+
{%- 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 %}
|
| 123 |
+
{{- args_value }}
|
| 124 |
+
{{- '\n</parameter>\n' }}
|
| 125 |
+
{%- endfor %}
|
| 126 |
+
{%- endif %}
|
| 127 |
+
{{- '</function>\n</tool_call>' }}
|
| 128 |
+
{%- endfor %}
|
| 129 |
+
{%- endif %}
|
| 130 |
+
{{- '<|im_end|>\n' }}
|
| 131 |
+
{%- elif message.role == "tool" %}
|
| 132 |
+
{%- if loop.previtem and loop.previtem.role != "tool" %}
|
| 133 |
+
{{- '<|im_start|>user' }}
|
| 134 |
+
{%- endif %}
|
| 135 |
+
{{- '\n<tool_response>\n' }}
|
| 136 |
+
{{- content }}
|
| 137 |
+
{{- '\n</tool_response>' }}
|
| 138 |
+
{%- if not loop.last and loop.nextitem.role != "tool" %}
|
| 139 |
+
{{- '<|im_end|>\n' }}
|
| 140 |
+
{%- elif loop.last %}
|
| 141 |
+
{{- '<|im_end|>\n' }}
|
| 142 |
+
{%- endif %}
|
| 143 |
+
{%- else %}
|
| 144 |
+
{{- raise_exception('Unexpected message role.') }}
|
| 145 |
+
{%- endif %}
|
| 146 |
+
{%- endfor %}
|
| 147 |
+
{%- if add_generation_prompt %}
|
| 148 |
+
{{- '<|im_start|>assistant\n' }}
|
| 149 |
+
{%- if enable_thinking is defined and enable_thinking is false %}
|
| 150 |
+
{{- '<think>\n\n</think>\n\n' }}
|
| 151 |
+
{%- else %}
|
| 152 |
+
{{- '<think>\n' }}
|
| 153 |
+
{%- endif %}
|
| 154 |
+
{%- endif %}
|
config.json
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_model_size_label": "9B",
|
| 3 |
+
"architectures": [
|
| 4 |
+
"ZDTaichu5_0_ForConditionalGeneration"
|
| 5 |
+
],
|
| 6 |
+
"auto_map": {
|
| 7 |
+
"AutoConfig": "configuration.ZDTaichu5_0_Config",
|
| 8 |
+
"AutoImageProcessor": "image_processing.ZDTaichu5_0_ImageProcessor",
|
| 9 |
+
"AutoModel": "modeling.ZDTaichu5_0_ForConditionalGeneration",
|
| 10 |
+
"AutoModelForCausalLM": "modeling.ZDTaichu5_0_ForConditionalGeneration",
|
| 11 |
+
"AutoProcessor": "processing.ZDTaichu5_0_Processor"
|
| 12 |
+
},
|
| 13 |
+
"bos_token_id": null,
|
| 14 |
+
"downsample_ratio": 0.5,
|
| 15 |
+
"dtype": "bfloat16",
|
| 16 |
+
"eos_token_id": 248046,
|
| 17 |
+
"force_image_size": 512,
|
| 18 |
+
"hidden_size": 4096,
|
| 19 |
+
"image_tag_type": "internvl",
|
| 20 |
+
"img_context_token": "<|image_pad|>",
|
| 21 |
+
"img_context_token_id": 248056,
|
| 22 |
+
"img_end_token": "<|vision_end|>",
|
| 23 |
+
"img_start_token": "<|vision_start|>",
|
| 24 |
+
"keys_to_ignore_at_inference": [
|
| 25 |
+
"past_key_values"
|
| 26 |
+
],
|
| 27 |
+
"llm_config": {
|
| 28 |
+
"architectures": [
|
| 29 |
+
"Qwen3_5ForCausalLM"
|
| 30 |
+
],
|
| 31 |
+
"attention_bias": false,
|
| 32 |
+
"attention_dropout": 0.0,
|
| 33 |
+
"bos_token_id": null,
|
| 34 |
+
"dtype": "bfloat16",
|
| 35 |
+
"eos_token_id": null,
|
| 36 |
+
"full_attention_interval": 4,
|
| 37 |
+
"head_dim": 256,
|
| 38 |
+
"hidden_act": "silu",
|
| 39 |
+
"hidden_size": 4096,
|
| 40 |
+
"initializer_range": 0.02,
|
| 41 |
+
"intermediate_size": 12288,
|
| 42 |
+
"layer_types": [
|
| 43 |
+
"linear_attention",
|
| 44 |
+
"linear_attention",
|
| 45 |
+
"linear_attention",
|
| 46 |
+
"full_attention",
|
| 47 |
+
"linear_attention",
|
| 48 |
+
"linear_attention",
|
| 49 |
+
"linear_attention",
|
| 50 |
+
"full_attention",
|
| 51 |
+
"linear_attention",
|
| 52 |
+
"linear_attention",
|
| 53 |
+
"linear_attention",
|
| 54 |
+
"full_attention",
|
| 55 |
+
"linear_attention",
|
| 56 |
+
"linear_attention",
|
| 57 |
+
"linear_attention",
|
| 58 |
+
"full_attention",
|
| 59 |
+
"linear_attention",
|
| 60 |
+
"linear_attention",
|
| 61 |
+
"linear_attention",
|
| 62 |
+
"full_attention",
|
| 63 |
+
"linear_attention",
|
| 64 |
+
"linear_attention",
|
| 65 |
+
"linear_attention",
|
| 66 |
+
"full_attention",
|
| 67 |
+
"linear_attention",
|
| 68 |
+
"linear_attention",
|
| 69 |
+
"linear_attention",
|
| 70 |
+
"full_attention",
|
| 71 |
+
"linear_attention",
|
| 72 |
+
"linear_attention",
|
| 73 |
+
"linear_attention",
|
| 74 |
+
"full_attention"
|
| 75 |
+
],
|
| 76 |
+
"linear_conv_kernel_dim": 4,
|
| 77 |
+
"linear_key_head_dim": 128,
|
| 78 |
+
"linear_num_key_heads": 16,
|
| 79 |
+
"linear_num_value_heads": 32,
|
| 80 |
+
"linear_value_head_dim": 128,
|
| 81 |
+
"max_position_embeddings": 262144,
|
| 82 |
+
"model_type": "qwen3_5_text",
|
| 83 |
+
"mtp_loss_scaling_factor": 0.1,
|
| 84 |
+
"mtp_num_layers": 1,
|
| 85 |
+
"num_attention_heads": 16,
|
| 86 |
+
"num_hidden_layers": 32,
|
| 87 |
+
"num_key_value_heads": 4,
|
| 88 |
+
"pad_token_id": 248044,
|
| 89 |
+
"partial_rotary_factor": 0.25,
|
| 90 |
+
"rms_norm_eps": 1e-06,
|
| 91 |
+
"rope_parameters": {
|
| 92 |
+
"mrope_interleaved": true,
|
| 93 |
+
"mrope_section": [
|
| 94 |
+
11,
|
| 95 |
+
11,
|
| 96 |
+
10
|
| 97 |
+
],
|
| 98 |
+
"partial_rotary_factor": 0.25,
|
| 99 |
+
"rope_theta": 10000000,
|
| 100 |
+
"rope_type": "default"
|
| 101 |
+
},
|
| 102 |
+
"tie_word_embeddings": false,
|
| 103 |
+
"use_cache": false,
|
| 104 |
+
"mamba_ssm_dtype": "float32",
|
| 105 |
+
"vocab_size": 248320
|
| 106 |
+
},
|
| 107 |
+
"max_dynamic_patch": 12,
|
| 108 |
+
"min_dynamic_patch": 1,
|
| 109 |
+
"model_type": "zdtaichu5_0",
|
| 110 |
+
"pad_token_id": 248044,
|
| 111 |
+
"patch_size": 16,
|
| 112 |
+
"projector_hidden_size": 20480,
|
| 113 |
+
"ps_version": "v2",
|
| 114 |
+
"template": "qwen3_5",
|
| 115 |
+
"tie_word_embeddings": false,
|
| 116 |
+
"transformers_version": "5.3.0",
|
| 117 |
+
"use_thumbnail": true,
|
| 118 |
+
"video_context_token": "<|video_pad|>",
|
| 119 |
+
"video_context_token_id": 248057,
|
| 120 |
+
"vision_config": {
|
| 121 |
+
"adaptor_configs": {},
|
| 122 |
+
"adaptor_names": null,
|
| 123 |
+
"architectures": [
|
| 124 |
+
"RADIOModel"
|
| 125 |
+
],
|
| 126 |
+
"args": {
|
| 127 |
+
"aa": null,
|
| 128 |
+
"amp": true,
|
| 129 |
+
"amp_dtype": "bfloat16",
|
| 130 |
+
"amp_impl": "native",
|
| 131 |
+
"aug_repeats": 0,
|
| 132 |
+
"aug_splits": 0,
|
| 133 |
+
"auto_workload_inspector": false,
|
| 134 |
+
"bn_eps": null,
|
| 135 |
+
"bn_momentum": null,
|
| 136 |
+
"cache_dir": null,
|
| 137 |
+
"channels_last": false,
|
| 138 |
+
"checkpoint_folder": null,
|
| 139 |
+
"checkpoint_hist": 10,
|
| 140 |
+
"chk_keep_forever": 100,
|
| 141 |
+
"class_map": "",
|
| 142 |
+
"clip_grad": null,
|
| 143 |
+
"clip_mode": "norm",
|
| 144 |
+
"cls_token_per_teacher": true,
|
| 145 |
+
"coco_annotations_file": null,
|
| 146 |
+
"coco_image_dir": null,
|
| 147 |
+
"color_jitter": 0.4,
|
| 148 |
+
"cooldown_epochs": 0,
|
| 149 |
+
"cpe_max_size": 2048,
|
| 150 |
+
"cpe_num_registers": null,
|
| 151 |
+
"crd_loss": false,
|
| 152 |
+
"crd_loss_weight": 0.8,
|
| 153 |
+
"crop_pct": null,
|
| 154 |
+
"cutmix": 0.0,
|
| 155 |
+
"cutmix_minmax": null,
|
| 156 |
+
"dataset_download": false,
|
| 157 |
+
"debug_full_knn": false,
|
| 158 |
+
"decay_epochs": 90,
|
| 159 |
+
"decay_milestones": [
|
| 160 |
+
90,
|
| 161 |
+
180,
|
| 162 |
+
270
|
| 163 |
+
],
|
| 164 |
+
"decay_rate": 0.1,
|
| 165 |
+
"depchain": true,
|
| 166 |
+
"detect_anomaly": false,
|
| 167 |
+
"dist_bn": "reduce",
|
| 168 |
+
"dist_norm_weight": 0.0,
|
| 169 |
+
"distributed": true,
|
| 170 |
+
"drop": 0.0,
|
| 171 |
+
"drop_block": null,
|
| 172 |
+
"drop_connect": null,
|
| 173 |
+
"drop_path": null,
|
| 174 |
+
"dtype": "float32",
|
| 175 |
+
"epoch": 299,
|
| 176 |
+
"epoch_repeats": 0.0,
|
| 177 |
+
"eval": false,
|
| 178 |
+
"eval_metric": "knn_top1",
|
| 179 |
+
"eval_teacher": false,
|
| 180 |
+
"eval_teacher_only": false,
|
| 181 |
+
"eval_throughput": false,
|
| 182 |
+
"fast_norm": false,
|
| 183 |
+
"fd_loss_fn": "MSE",
|
| 184 |
+
"feature_normalization": "PHI_STANDARDIZE",
|
| 185 |
+
"feature_summarizer": "cls_token",
|
| 186 |
+
"feature_upscale_factor": null,
|
| 187 |
+
"force_disable_damp": false,
|
| 188 |
+
"force_disable_spectral_reparam": false,
|
| 189 |
+
"force_new_wandb_id": false,
|
| 190 |
+
"force_spectral_reparam": false,
|
| 191 |
+
"freeze_bn": false,
|
| 192 |
+
"fsdp": true,
|
| 193 |
+
"full_equivariance": false,
|
| 194 |
+
"fuser": "",
|
| 195 |
+
"gp": null,
|
| 196 |
+
"grad_accum_steps": 1,
|
| 197 |
+
"grad_checkpointing": false,
|
| 198 |
+
"head_init_bias": null,
|
| 199 |
+
"head_init_scale": null,
|
| 200 |
+
"head_lr": null,
|
| 201 |
+
"head_warmup": 3,
|
| 202 |
+
"head_weight_decay": 0.0005,
|
| 203 |
+
"hflip": 0.5,
|
| 204 |
+
"img_size": null,
|
| 205 |
+
"in_chans": null,
|
| 206 |
+
"initial_checkpoint": null,
|
| 207 |
+
"input_size": null,
|
| 208 |
+
"interpolation": "",
|
| 209 |
+
"layer_decay": null,
|
| 210 |
+
"local_rank": 0,
|
| 211 |
+
"log_interval": 50,
|
| 212 |
+
"log_mlflow": false,
|
| 213 |
+
"log_teacher_timings": true,
|
| 214 |
+
"log_train_metrics_per_epoch": true,
|
| 215 |
+
"log_train_metrics_per_log_interval": true,
|
| 216 |
+
"log_wandb": true,
|
| 217 |
+
"loss_auto_balance": false,
|
| 218 |
+
"lr_base": 0.1,
|
| 219 |
+
"lr_base_scale": "",
|
| 220 |
+
"lr_base_size": 256,
|
| 221 |
+
"lr_cycle_decay": 0.5,
|
| 222 |
+
"lr_cycle_limit": 1,
|
| 223 |
+
"lr_cycle_mul": 1.0,
|
| 224 |
+
"lr_k_decay": 1.0,
|
| 225 |
+
"lr_noise": null,
|
| 226 |
+
"lr_noise_pct": 0.67,
|
| 227 |
+
"lr_noise_std": 1.0,
|
| 228 |
+
"mean": null,
|
| 229 |
+
"mesa": false,
|
| 230 |
+
"min_lr": 1e-05,
|
| 231 |
+
"mixup": 0.0,
|
| 232 |
+
"mixup_mode": "batch",
|
| 233 |
+
"mixup_off_epoch": 0,
|
| 234 |
+
"mixup_prob": 1.0,
|
| 235 |
+
"mixup_switch_prob": 0.5,
|
| 236 |
+
"mlp_hidden_size": 1520,
|
| 237 |
+
"mlp_num_inner": 2,
|
| 238 |
+
"mlp_version": "v2",
|
| 239 |
+
"model": "vit_huge_patch16_224",
|
| 240 |
+
"model_kwargs": {},
|
| 241 |
+
"model_norm": false,
|
| 242 |
+
"momentum": 0.9,
|
| 243 |
+
"no_custom_validation": false,
|
| 244 |
+
"no_ddp_bb": true,
|
| 245 |
+
"no_knn": false,
|
| 246 |
+
"no_prefetcher": false,
|
| 247 |
+
"no_resume_opt": false,
|
| 248 |
+
"no_save_checkpoint": false,
|
| 249 |
+
"no_val": false,
|
| 250 |
+
"num_classes": null,
|
| 251 |
+
"on_demand_workload_inspector": false,
|
| 252 |
+
"one_logger_app_tag": "",
|
| 253 |
+
"one_logger_is_baseline": false,
|
| 254 |
+
"one_logger_run_name": "",
|
| 255 |
+
"onelogger": null,
|
| 256 |
+
"opt_betas": null,
|
| 257 |
+
"opt_eps": null,
|
| 258 |
+
"overfit": false,
|
| 259 |
+
"patience_epochs": 10,
|
| 260 |
+
"perf_test_no_aug": false,
|
| 261 |
+
"perf_test_no_decode": false,
|
| 262 |
+
"perf_test_no_io": false,
|
| 263 |
+
"perf_test_only_dataloader": false,
|
| 264 |
+
"perf_test_simple_aug": false,
|
| 265 |
+
"pin_mem": false,
|
| 266 |
+
"prefetcher": true,
|
| 267 |
+
"pretrained": false,
|
| 268 |
+
"processed_neck_outputs": null,
|
| 269 |
+
"profile_train_exit_after_profiling": false,
|
| 270 |
+
"profile_train_export_chrome_trace": true,
|
| 271 |
+
"profile_train_export_csv": false,
|
| 272 |
+
"profile_train_iterations": 0,
|
| 273 |
+
"qradio": false,
|
| 274 |
+
"qradio_max_tokens": 512,
|
| 275 |
+
"qradio_min_tokens": 32,
|
| 276 |
+
"qradio_patch_token_mask_initial_ratio": 0.95,
|
| 277 |
+
"qradio_progressive_2d": false,
|
| 278 |
+
"qradio_quantizer": null,
|
| 279 |
+
"qradio_ramp_alpha": 1.5,
|
| 280 |
+
"rank": 0,
|
| 281 |
+
"ratio": [
|
| 282 |
+
0.75,
|
| 283 |
+
1.3333333333333333
|
| 284 |
+
],
|
| 285 |
+
"recount": 1,
|
| 286 |
+
"recovery_interval": 0,
|
| 287 |
+
"register_multiple": 10,
|
| 288 |
+
"remode": "pixel",
|
| 289 |
+
"reprob": 0.0,
|
| 290 |
+
"reset_loss_state": true,
|
| 291 |
+
"resplit": false,
|
| 292 |
+
"sample_tracking": false,
|
| 293 |
+
"save_images": false,
|
| 294 |
+
"scale": [
|
| 295 |
+
0.5,
|
| 296 |
+
1.0
|
| 297 |
+
],
|
| 298 |
+
"sched": "cosine",
|
| 299 |
+
"seed": 42,
|
| 300 |
+
"shift_equivariance": false,
|
| 301 |
+
"smoothing": 0.1,
|
| 302 |
+
"source_tracking": false,
|
| 303 |
+
"spectral_heads": false,
|
| 304 |
+
"spectral_reparam": false,
|
| 305 |
+
"spectral_weight_decay": null,
|
| 306 |
+
"split_bn": false,
|
| 307 |
+
"start_epoch": null,
|
| 308 |
+
"std": null,
|
| 309 |
+
"stream_teachers": false,
|
| 310 |
+
"student_intermediate_indices": null,
|
| 311 |
+
"student_load_skip_state_dict_keys_regex": null,
|
| 312 |
+
"student_reinit_model_layers_regex": null,
|
| 313 |
+
"student_strict_load_ignore_mismatched_shape_keys_regex": null,
|
| 314 |
+
"student_strict_load_ignore_missing_keys_regex": null,
|
| 315 |
+
"student_strict_load_ignore_unexpected_keys_regex": null,
|
| 316 |
+
"student_strict_load_state_dict": false,
|
| 317 |
+
"sync_bn": false,
|
| 318 |
+
"sync_resolutions_across_ranks": true,
|
| 319 |
+
"synchronize_step": false,
|
| 320 |
+
"teachers": [
|
| 321 |
+
{
|
| 322 |
+
"model": "siglip2-g-384",
|
| 323 |
+
"name": "siglip2-g",
|
| 324 |
+
"spatial_mlp_version": "attn",
|
| 325 |
+
"type": "siglip2",
|
| 326 |
+
"use_summary": true
|
| 327 |
+
},
|
| 328 |
+
{
|
| 329 |
+
"model": "dinov3_vit7b16",
|
| 330 |
+
"name": "dino_v3_7b",
|
| 331 |
+
"type": "dino_v3",
|
| 332 |
+
"use_summary": true
|
| 333 |
+
},
|
| 334 |
+
{
|
| 335 |
+
"model": "default",
|
| 336 |
+
"name": "sam3",
|
| 337 |
+
"type": "sam3",
|
| 338 |
+
"use_summary": false
|
| 339 |
+
}
|
| 340 |
+
],
|
| 341 |
+
"timing_warmup_iters": 20,
|
| 342 |
+
"tokenizer_kwargs": {},
|
| 343 |
+
"tokenizer_type": null,
|
| 344 |
+
"tome": null,
|
| 345 |
+
"torchcompile": null,
|
| 346 |
+
"torchscript": false,
|
| 347 |
+
"train_interpolation": "random",
|
| 348 |
+
"train_split": "train",
|
| 349 |
+
"tta": 0,
|
| 350 |
+
"untie_neck_weights": false,
|
| 351 |
+
"use_coco": false,
|
| 352 |
+
"use_multi_epochs_loader": false,
|
| 353 |
+
"val_ema_only": false,
|
| 354 |
+
"val_split": "val",
|
| 355 |
+
"vflip": 0.0,
|
| 356 |
+
"vitdet_version": 1,
|
| 357 |
+
"wandb_entity": "",
|
| 358 |
+
"wandb_id": "",
|
| 359 |
+
"wandb_job_type": "",
|
| 360 |
+
"wandb_name": "",
|
| 361 |
+
"wandb_project": "",
|
| 362 |
+
"wandb_tags": null,
|
| 363 |
+
"warmup_lr": 1e-05,
|
| 364 |
+
"warmup_prefix": false,
|
| 365 |
+
"worker_seeding": "all",
|
| 366 |
+
"workers": 8,
|
| 367 |
+
"workload_inspector_analyze_nsys_traces": false,
|
| 368 |
+
"workload_inspector_baseline_start_iter": 1500,
|
| 369 |
+
"workload_inspector_major_slowdown_p95_factor": 10.0,
|
| 370 |
+
"workload_inspector_minor_slowdown_p95_factor": 3.0,
|
| 371 |
+
"workload_inspector_no_slowdown_check": false,
|
| 372 |
+
"workload_inspector_simulate_slowdown_num_times": 1,
|
| 373 |
+
"workload_inspector_simulate_slowdown_start_iter": null,
|
| 374 |
+
"world_size": 256
|
| 375 |
+
},
|
| 376 |
+
"auto_map": {
|
| 377 |
+
"AutoConfig": "cradio_config.RADIOConfig",
|
| 378 |
+
"AutoModel": "cradio_model.RADIOModel"
|
| 379 |
+
},
|
| 380 |
+
"dtype": "bfloat16",
|
| 381 |
+
"feature_normalizer_config": null,
|
| 382 |
+
"inter_feature_normalizer_config": null,
|
| 383 |
+
"max_resolution": 2048,
|
| 384 |
+
"model_type": "radio",
|
| 385 |
+
"patch_size": 16,
|
| 386 |
+
"preferred_resolution": [
|
| 387 |
+
512,
|
| 388 |
+
512
|
| 389 |
+
],
|
| 390 |
+
"use_flash_attn": false,
|
| 391 |
+
"version": "c-radio_v4-h",
|
| 392 |
+
"vitdet_window_size": null
|
| 393 |
+
},
|
| 394 |
+
"vit_hidden_size": 1280
|
| 395 |
+
}
|
configuration.py
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
# ============================================================================
|
| 16 |
+
# ZDTaichu-5.0 — Top-Level Configuration
|
| 17 |
+
#
|
| 18 |
+
# Architecture:
|
| 19 |
+
# - LLM backbone: Qwen3 (pure Transformer) → Qwen3.5 (hybrid DeltaNet/Transformer)
|
| 20 |
+
# · 3:1 linear-to-full attention ratio (Gated DeltaNet + full attention)
|
| 21 |
+
# · Custom Qwen3_5DynamicCache for hybrid KV / recurrent states
|
| 22 |
+
# · head_dim=256 (was 128), partial_rotary_factor=0.25
|
| 23 |
+
# · Interleaved M-RoPE with 4D position IDs
|
| 24 |
+
# · Attention output gating (sigmoid gate on q_proj)
|
| 25 |
+
# - Vision encoder: C-RADIOv4-H (unchanged)
|
| 26 |
+
# - Token IDs updated for Qwen3.5 vocabulary (vocab_size=248320)
|
| 27 |
+
# · img_context_token_id: 151655 → 248056 (<|image_pad|>)
|
| 28 |
+
# · video_context_token_id: 151656 → 248057 (<|video_pad|>)
|
| 29 |
+
# - Projector output adapts to Qwen3.5 hidden_size (4096 for 9B variant)
|
| 30 |
+
# ============================================================================
|
| 31 |
+
|
| 32 |
+
from transformers.configuration_utils import PretrainedConfig
|
| 33 |
+
from transformers.utils import logging
|
| 34 |
+
from .cradio_config import RADIOConfig
|
| 35 |
+
|
| 36 |
+
logger = logging.get_logger(__name__)
|
| 37 |
+
|
| 38 |
+
# ---------------------------------------------------------------------------
|
| 39 |
+
# Import Qwen3.5 text config — requires transformers >= 5.3.0
|
| 40 |
+
# ---------------------------------------------------------------------------
|
| 41 |
+
try:
|
| 42 |
+
from transformers.models.qwen3_5.configuration_qwen3_5 import Qwen3_5TextConfig
|
| 43 |
+
except ImportError:
|
| 44 |
+
Qwen3_5TextConfig = None
|
| 45 |
+
logger.warning(
|
| 46 |
+
"Could not import Qwen3_5TextConfig from transformers. "
|
| 47 |
+
"Ensure transformers >= 5.3.0 is installed. "
|
| 48 |
+
"Falling back to PretrainedConfig with manual attributes."
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
# ---------------------------------------------------------------------------
|
| 53 |
+
# Default Qwen3.5 text configuration (9B-class variant)
|
| 54 |
+
# ---------------------------------------------------------------------------
|
| 55 |
+
|
| 56 |
+
_LAYER_TYPES_32 = [
|
| 57 |
+
"linear_attention" if bool((i + 1) % 4) else "full_attention"
|
| 58 |
+
for i in range(32)
|
| 59 |
+
]
|
| 60 |
+
# Result: [lin, lin, lin, full, lin, lin, lin, full, ... lin, lin, lin, full]
|
| 61 |
+
# 24 linear + 8 full attention layers
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def _default_qwen3_5_text_dict() -> dict:
|
| 65 |
+
"""Return a dict of Qwen3.5 text config values (9B-class)."""
|
| 66 |
+
return dict(
|
| 67 |
+
vocab_size=248320,
|
| 68 |
+
hidden_size=4096,
|
| 69 |
+
intermediate_size=12288,
|
| 70 |
+
num_hidden_layers=32,
|
| 71 |
+
num_attention_heads=16,
|
| 72 |
+
num_key_value_heads=4,
|
| 73 |
+
head_dim=256,
|
| 74 |
+
hidden_act="silu",
|
| 75 |
+
max_position_embeddings=262144,
|
| 76 |
+
rms_norm_eps=1e-6,
|
| 77 |
+
use_cache=True,
|
| 78 |
+
tie_word_embeddings=False,
|
| 79 |
+
attention_bias=False,
|
| 80 |
+
attention_dropout=0.0,
|
| 81 |
+
torch_dtype="bfloat16",
|
| 82 |
+
# --- Hybrid layer architecture ---
|
| 83 |
+
layer_types=list(_LAYER_TYPES_32), # copy to avoid mutation
|
| 84 |
+
full_attention_interval=4,
|
| 85 |
+
# --- Linear attention (Gated DeltaNet) ---
|
| 86 |
+
linear_conv_kernel_dim=4,
|
| 87 |
+
linear_key_head_dim=128,
|
| 88 |
+
linear_value_head_dim=128,
|
| 89 |
+
linear_num_key_heads=16,
|
| 90 |
+
linear_num_value_heads=32,
|
| 91 |
+
# --- RoPE ---
|
| 92 |
+
rope_parameters={
|
| 93 |
+
"rope_type": "default",
|
| 94 |
+
"rope_theta": 10000000,
|
| 95 |
+
"partial_rotary_factor": 0.25,
|
| 96 |
+
"mrope_interleaved": True,
|
| 97 |
+
"mrope_section": [11, 11, 10],
|
| 98 |
+
},
|
| 99 |
+
)
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def _build_llm_config(cfg_dict: dict = None) -> PretrainedConfig:
|
| 103 |
+
"""
|
| 104 |
+
Construct the LLM sub-config from a dict or defaults.
|
| 105 |
+
|
| 106 |
+
Uses Qwen3_5TextConfig when available (transformers >= 5.3);
|
| 107 |
+
otherwise falls back to a plain PretrainedConfig with the correct
|
| 108 |
+
model_type so that AutoModelForCausalLM can still resolve it.
|
| 109 |
+
"""
|
| 110 |
+
if cfg_dict is None:
|
| 111 |
+
cfg_dict = _default_qwen3_5_text_dict()
|
| 112 |
+
|
| 113 |
+
if Qwen3_5TextConfig is not None:
|
| 114 |
+
return Qwen3_5TextConfig(**cfg_dict)
|
| 115 |
+
else:
|
| 116 |
+
config = PretrainedConfig(**cfg_dict)
|
| 117 |
+
config.model_type = "qwen3_5_text"
|
| 118 |
+
return config
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
class ZDTaichu5_0_Config(PretrainedConfig):
|
| 122 |
+
"""
|
| 123 |
+
Configuration for ZDTaichu-5.0-9B:
|
| 124 |
+
Vision encoder : C-RADIOv4-H (ViT-H/16, 653 M params)
|
| 125 |
+
LLM decoder : Qwen3.5 (hybrid DeltaNet/Transformer)
|
| 126 |
+
Projector : RMSNorm → Linear(5120→20480) → SquaredReLU → Linear(20480→H)
|
| 127 |
+
|
| 128 |
+
The projector input side is unchanged (C-RADIOv4-H ViT-H features at 1280,
|
| 129 |
+
pixel-shuffled to 5120). Only the final projection layer adapts to the
|
| 130 |
+
target LLM hidden_size (4096 for the 9B variant, vs 5120 for Qwen3-14B).
|
| 131 |
+
|
| 132 |
+
Qwen3.5 hybrid architecture
|
| 133 |
+
----------------------------
|
| 134 |
+
The text backbone alternates Gated DeltaNet (linear attention) and standard
|
| 135 |
+
multi-head attention layers in a 3:1 ratio. Linear layers use a causal 1D
|
| 136 |
+
convolution + gated delta rule recurrence for O(1) per-token memory during
|
| 137 |
+
generation, while every 4th layer uses full quadratic attention to preserve
|
| 138 |
+
global context. A custom DynamicCache handles both attention KV states and
|
| 139 |
+
recurrent states.
|
| 140 |
+
"""
|
| 141 |
+
|
| 142 |
+
model_type = "zdtaichu5_0"
|
| 143 |
+
is_composition = True
|
| 144 |
+
|
| 145 |
+
def __init__(
|
| 146 |
+
self,
|
| 147 |
+
vision_config=None,
|
| 148 |
+
llm_config=None,
|
| 149 |
+
force_image_size=None,
|
| 150 |
+
downsample_ratio=0.5,
|
| 151 |
+
template=None,
|
| 152 |
+
ps_version="v2",
|
| 153 |
+
image_tag_type="internvl",
|
| 154 |
+
projector_hidden_size=20480, # 4 × pixel_shuffle_dim (5120)
|
| 155 |
+
vit_hidden_size=1280, # ViT-H feature dim — same for C-RADIOv4-H
|
| 156 |
+
attn_implementation="flash_attention_2",
|
| 157 |
+
# Special token IDs for Qwen3.5 vocabulary (vocab_size=248320)
|
| 158 |
+
img_context_token_id: int = 248056, # <|image_pad|>
|
| 159 |
+
video_context_token_id: int = 248057, # <|video_pad|>
|
| 160 |
+
**kwargs,
|
| 161 |
+
):
|
| 162 |
+
|
| 163 |
+
# ------------------------------------------------------------------
|
| 164 |
+
# Transformers 5.5.x compatibility:
|
| 165 |
+
# PretrainedConfig.__init__ may call self.get_text_config()
|
| 166 |
+
# during token-id validation. Therefore llm_config must exist
|
| 167 |
+
# before calling super().__init__().
|
| 168 |
+
# ------------------------------------------------------------------
|
| 169 |
+
|
| 170 |
+
# ── Vision encoder ───────────────────────────────────────────────────
|
| 171 |
+
if vision_config is not None:
|
| 172 |
+
if isinstance(vision_config, dict):
|
| 173 |
+
self.vision_config = RADIOConfig(**vision_config)
|
| 174 |
+
else:
|
| 175 |
+
self.vision_config = vision_config
|
| 176 |
+
else:
|
| 177 |
+
self.vision_config = RADIOConfig(version="c-radio_v4-h")
|
| 178 |
+
|
| 179 |
+
# ── Language model (Qwen3.5 hybrid) ──────────────────────────────────
|
| 180 |
+
if llm_config is not None:
|
| 181 |
+
if isinstance(llm_config, PretrainedConfig):
|
| 182 |
+
self.llm_config = llm_config
|
| 183 |
+
elif isinstance(llm_config, dict):
|
| 184 |
+
self.llm_config = _build_llm_config(llm_config)
|
| 185 |
+
else:
|
| 186 |
+
raise TypeError(
|
| 187 |
+
f"llm_config must be a dict or PretrainedConfig, got {type(llm_config)}"
|
| 188 |
+
)
|
| 189 |
+
else:
|
| 190 |
+
self.llm_config = _build_llm_config(None)
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
# Make tokenizer/generation token ids visible early.
|
| 194 |
+
# Transformers 5.5.x may validate these during super().__init__().
|
| 195 |
+
kwargs.setdefault("bos_token_id", getattr(self.llm_config, "bos_token_id", 248040))
|
| 196 |
+
kwargs.setdefault("eos_token_id", getattr(self.llm_config, "eos_token_id", 248044))
|
| 197 |
+
kwargs.setdefault("pad_token_id", getattr(self.llm_config, "pad_token_id", 248040))
|
| 198 |
+
super().__init__(**kwargs)
|
| 199 |
+
|
| 200 |
+
self.tie_word_embeddings = getattr(self.llm_config, "tie_word_embeddings", False)
|
| 201 |
+
|
| 202 |
+
# ── VL configuration ─────────────────────────────────────────────────
|
| 203 |
+
self.force_image_size = force_image_size
|
| 204 |
+
self.downsample_ratio = downsample_ratio
|
| 205 |
+
self.template = template
|
| 206 |
+
self.ps_version = ps_version
|
| 207 |
+
self.image_tag_type = image_tag_type
|
| 208 |
+
self.projector_hidden_size = projector_hidden_size
|
| 209 |
+
self.vit_hidden_size = vit_hidden_size
|
| 210 |
+
|
| 211 |
+
# Special token IDs
|
| 212 |
+
self.img_context_token_id = img_context_token_id
|
| 213 |
+
self.video_context_token_id = video_context_token_id
|
| 214 |
+
|
| 215 |
+
# Attention implementation propagation
|
| 216 |
+
self._attn_implementation = attn_implementation
|
| 217 |
+
self.vision_config.use_flash_attn = (
|
| 218 |
+
self._attn_implementation is not None
|
| 219 |
+
and "flash_attention" in self._attn_implementation
|
| 220 |
+
)
|
| 221 |
+
self.llm_config._attn_implementation = self._attn_implementation
|
| 222 |
+
|
| 223 |
+
def get_text_config(self, decoder=False):
|
| 224 |
+
# Robust fallback for Transformers 5.5.x validation.
|
| 225 |
+
if hasattr(self, "llm_config"):
|
| 226 |
+
return self.llm_config
|
| 227 |
+
return _build_llm_config(None)
|
| 228 |
+
|
| 229 |
+
@property
|
| 230 |
+
def text_config(self):
|
| 231 |
+
return self.get_text_config(decoder=True)
|
cradio_config.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
| 2 |
+
# Copyright (c) 2026, ZDTaichu-5.0-9B Contributors. 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 |
+
#
|
| 16 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 17 |
+
|
| 18 |
+
"""Standalone inference configuration for the C-RADIO vision tower."""
|
| 19 |
+
|
| 20 |
+
from typing import Dict, List, Optional, Tuple, Union
|
| 21 |
+
from transformers import PretrainedConfig
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class RADIOConfig(PretrainedConfig):
|
| 25 |
+
model_type = "radio"
|
| 26 |
+
|
| 27 |
+
def __init__(
|
| 28 |
+
self,
|
| 29 |
+
args: Optional[dict] = None,
|
| 30 |
+
version: str = "c-radio_v4-h",
|
| 31 |
+
patch_size: int = 16,
|
| 32 |
+
max_resolution: int = 2048,
|
| 33 |
+
preferred_resolution: Tuple[int, int] = (768, 768),
|
| 34 |
+
adaptor_names: Union[str, List[str], None] = None,
|
| 35 |
+
adaptor_configs: Optional[Dict] = None,
|
| 36 |
+
vitdet_window_size: Optional[int] = None,
|
| 37 |
+
feature_normalizer_config: Optional[dict] = None,
|
| 38 |
+
inter_feature_normalizer_config: Optional[dict] = None,
|
| 39 |
+
**kwargs,
|
| 40 |
+
):
|
| 41 |
+
self.args = args or {}
|
| 42 |
+
self.version = version
|
| 43 |
+
self.patch_size = patch_size
|
| 44 |
+
self.max_resolution = max_resolution
|
| 45 |
+
self.preferred_resolution = preferred_resolution
|
| 46 |
+
self.adaptor_names = adaptor_names
|
| 47 |
+
self.adaptor_configs = adaptor_configs
|
| 48 |
+
self.vitdet_window_size = vitdet_window_size
|
| 49 |
+
self.feature_normalizer_config = feature_normalizer_config
|
| 50 |
+
self.inter_feature_normalizer_config = inter_feature_normalizer_config
|
| 51 |
+
super().__init__(**kwargs)
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
__all__ = ["RADIOConfig"]
|
cradio_model.py
ADDED
|
@@ -0,0 +1,699 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
| 2 |
+
# Copyright (c) 2026, ZDTaichu-5.0-9B Contributors. 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 |
+
#
|
| 16 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 17 |
+
|
| 18 |
+
"""Standalone inference-only C-RADIO ViT vision tower.
|
| 19 |
+
|
| 20 |
+
This file intentionally contains the small subset of C-RADIO needed by the
|
| 21 |
+
ZDTaichu-5.0-9B checkpoint. It does not depend on the cradio_v4 package.
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
from __future__ import annotations
|
| 25 |
+
|
| 26 |
+
import math
|
| 27 |
+
from contextlib import contextmanager
|
| 28 |
+
from types import MethodType
|
| 29 |
+
from typing import Callable, Iterable, List, NamedTuple, Optional, Tuple, Union
|
| 30 |
+
|
| 31 |
+
import torch
|
| 32 |
+
import torch.nn.functional as F
|
| 33 |
+
from torch import nn
|
| 34 |
+
from transformers import PreTrainedModel
|
| 35 |
+
|
| 36 |
+
try:
|
| 37 |
+
from timm.models import VisionTransformer, checkpoint_seq
|
| 38 |
+
except ImportError as exc: # pragma: no cover - import-time dependency guard
|
| 39 |
+
raise ImportError("cradio_model.py requires timm to build the C-RADIO ViT tower") from exc
|
| 40 |
+
|
| 41 |
+
from .cradio_config import RADIOConfig
|
| 42 |
+
|
| 43 |
+
class Resolution(NamedTuple):
|
| 44 |
+
height: int
|
| 45 |
+
width: int
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
class RadioOutput(NamedTuple):
|
| 49 |
+
summary: Optional[torch.Tensor]
|
| 50 |
+
features: Optional[torch.Tensor]
|
| 51 |
+
|
| 52 |
+
def to(self, *args, **kwargs) -> "RadioOutput":
|
| 53 |
+
return RadioOutput(
|
| 54 |
+
self.summary.to(*args, **kwargs) if self.summary is not None else None,
|
| 55 |
+
self.features.to(*args, **kwargs) if self.features is not None else None,
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class InputConditioner(nn.Module):
|
| 60 |
+
def __init__(
|
| 61 |
+
self,
|
| 62 |
+
input_scale: float,
|
| 63 |
+
norm_mean: Union[Tuple[float, float, float], torch.Tensor],
|
| 64 |
+
norm_std: Union[Tuple[float, float, float], torch.Tensor],
|
| 65 |
+
dtype: Optional[torch.dtype] = None,
|
| 66 |
+
) -> None:
|
| 67 |
+
super().__init__()
|
| 68 |
+
self.dtype = dtype
|
| 69 |
+
self.register_buffer("norm_mean", torch.as_tensor(norm_mean, dtype=torch.float32).view(-1, 1, 1) / input_scale)
|
| 70 |
+
self.register_buffer("norm_std", torch.as_tensor(norm_std, dtype=torch.float32).view(-1, 1, 1) / input_scale)
|
| 71 |
+
|
| 72 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 73 |
+
y = (x - self.norm_mean) / self.norm_std
|
| 74 |
+
if self.dtype is not None:
|
| 75 |
+
y = y.to(self.dtype)
|
| 76 |
+
return y
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def get_default_conditioner() -> InputConditioner:
|
| 80 |
+
from timm.data.constants import OPENAI_CLIP_MEAN, OPENAI_CLIP_STD
|
| 81 |
+
|
| 82 |
+
return InputConditioner(1.0, OPENAI_CLIP_MEAN, OPENAI_CLIP_STD)
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
class ClsToken(nn.Module):
|
| 86 |
+
def __init__(
|
| 87 |
+
self,
|
| 88 |
+
ndim: int,
|
| 89 |
+
num_tokens: int = 1,
|
| 90 |
+
enabled: bool = True,
|
| 91 |
+
register_multiple: Optional[int] = None,
|
| 92 |
+
num_registers: Optional[int] = None,
|
| 93 |
+
) -> None:
|
| 94 |
+
super().__init__()
|
| 95 |
+
self.ndim = ndim
|
| 96 |
+
self.enabled = enabled
|
| 97 |
+
self.num_registers = 0
|
| 98 |
+
self.num_tokens = num_tokens
|
| 99 |
+
if enabled:
|
| 100 |
+
if num_registers:
|
| 101 |
+
self.num_registers = num_registers
|
| 102 |
+
elif register_multiple:
|
| 103 |
+
self.num_registers = register_multiple - (num_tokens % register_multiple)
|
| 104 |
+
scale = ndim ** -0.5
|
| 105 |
+
self.token = nn.Parameter(torch.randn(num_tokens + self.num_registers, ndim) * scale)
|
| 106 |
+
else:
|
| 107 |
+
self.token = None
|
| 108 |
+
self.num_patches = self.num_tokens + self.num_registers
|
| 109 |
+
|
| 110 |
+
def disable(self) -> None:
|
| 111 |
+
self.token = None
|
| 112 |
+
self.enabled = False
|
| 113 |
+
|
| 114 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 115 |
+
if self.token is None:
|
| 116 |
+
return x
|
| 117 |
+
token = self.token.unsqueeze(0).expand(x.shape[0], -1, -1)
|
| 118 |
+
return torch.cat([token, x], dim=1)
|
| 119 |
+
|
| 120 |
+
def no_weight_decay(self) -> List[str]:
|
| 121 |
+
return ["token"]
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
class Im2Patches(nn.Module):
|
| 125 |
+
def __init__(self, patch_size: int) -> None:
|
| 126 |
+
super().__init__()
|
| 127 |
+
self.patch_size = patch_size
|
| 128 |
+
|
| 129 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 130 |
+
if self.patch_size == 1:
|
| 131 |
+
return x.flatten(2).transpose(1, 2)
|
| 132 |
+
return F.unfold(x, kernel_size=self.patch_size, stride=self.patch_size).transpose(1, 2)
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
class ViTPatchLinear(nn.Linear):
|
| 136 |
+
def __init__(self, patch_size: int, embed_dim: int, bias: bool = False, **factory) -> None:
|
| 137 |
+
super().__init__(3 * (patch_size ** 2), embed_dim, bias=bias, **factory)
|
| 138 |
+
self.patch_size = patch_size
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
class ViTPatchGenerator(nn.Module):
|
| 142 |
+
def __init__(
|
| 143 |
+
self,
|
| 144 |
+
patch_size: int,
|
| 145 |
+
embed_dim: int,
|
| 146 |
+
input_dims: Union[int, Tuple[int, int]],
|
| 147 |
+
abs_pos: bool = True,
|
| 148 |
+
normalize_patches: bool = False,
|
| 149 |
+
cls_token: bool = False,
|
| 150 |
+
max_input_dims: Optional[Union[int, Tuple[int, int]]] = None,
|
| 151 |
+
pos_dropout: float = 0.0,
|
| 152 |
+
return_pos_enc: bool = False,
|
| 153 |
+
num_cls_tokens: int = 1,
|
| 154 |
+
register_multiple: Optional[int] = None,
|
| 155 |
+
num_registers: Optional[int] = None,
|
| 156 |
+
patch_bias: bool = False,
|
| 157 |
+
device=None,
|
| 158 |
+
dtype=None,
|
| 159 |
+
) -> None:
|
| 160 |
+
super().__init__()
|
| 161 |
+
if isinstance(input_dims, int):
|
| 162 |
+
input_dims = (input_dims, input_dims)
|
| 163 |
+
if max_input_dims is None:
|
| 164 |
+
max_input_dims = input_dims
|
| 165 |
+
if isinstance(max_input_dims, int):
|
| 166 |
+
max_input_dims = (max_input_dims, max_input_dims)
|
| 167 |
+
|
| 168 |
+
max_input_dims = tuple(int(math.ceil(d / patch_size) * patch_size) for d in max_input_dims)
|
| 169 |
+
factory = dict(device=device, dtype=dtype)
|
| 170 |
+
|
| 171 |
+
self.cpe_mode = max_input_dims != input_dims
|
| 172 |
+
self.pos_dropout = pos_dropout
|
| 173 |
+
self.return_pos_enc = return_pos_enc
|
| 174 |
+
self.patch_size = patch_size
|
| 175 |
+
self.abs_pos = abs_pos
|
| 176 |
+
self.embed_dim = embed_dim
|
| 177 |
+
self.num_rows = max_input_dims[0] // patch_size
|
| 178 |
+
self.num_cols = max_input_dims[1] // patch_size
|
| 179 |
+
self.input_dims = tuple(d // patch_size for d in input_dims)
|
| 180 |
+
self.num_patches = self.num_rows * self.num_cols
|
| 181 |
+
self.max_input_dims = max_input_dims
|
| 182 |
+
self.im_to_patches = Im2Patches(patch_size)
|
| 183 |
+
self.embedder = ViTPatchLinear(patch_size, embed_dim, bias=patch_bias, **factory)
|
| 184 |
+
if abs_pos:
|
| 185 |
+
scale = embed_dim ** -0.5
|
| 186 |
+
self.pos_embed = nn.Parameter(torch.randn(1, self.num_patches, embed_dim, **factory) * scale)
|
| 187 |
+
self.cls_token = ClsToken(
|
| 188 |
+
embed_dim,
|
| 189 |
+
num_tokens=num_cls_tokens,
|
| 190 |
+
enabled=cls_token,
|
| 191 |
+
register_multiple=register_multiple,
|
| 192 |
+
num_registers=num_registers,
|
| 193 |
+
)
|
| 194 |
+
self.patch_normalizer = nn.LayerNorm(embed_dim) if normalize_patches else nn.Identity()
|
| 195 |
+
self.num_video_frames = None
|
| 196 |
+
|
| 197 |
+
@property
|
| 198 |
+
def apply_cls_token(self) -> bool:
|
| 199 |
+
return self.cls_token.enabled
|
| 200 |
+
|
| 201 |
+
@property
|
| 202 |
+
def num_cls_tokens(self) -> int:
|
| 203 |
+
return self.cls_token.num_tokens
|
| 204 |
+
|
| 205 |
+
@property
|
| 206 |
+
def num_cls_patches(self) -> int:
|
| 207 |
+
return self.cls_token.num_patches
|
| 208 |
+
|
| 209 |
+
@property
|
| 210 |
+
def num_registers(self) -> int:
|
| 211 |
+
return self.cls_token.num_registers
|
| 212 |
+
|
| 213 |
+
@property
|
| 214 |
+
def num_skip(self) -> int:
|
| 215 |
+
return self.num_cls_tokens + self.num_registers
|
| 216 |
+
|
| 217 |
+
def no_weight_decay(self) -> List[str]:
|
| 218 |
+
return ["pos_embed"]
|
| 219 |
+
|
| 220 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 221 |
+
patches = self.embedder(self.im_to_patches(x))
|
| 222 |
+
patches, pos_enc = self.apply_pos_enc(patches, input_size=x.shape[2:])
|
| 223 |
+
patches = self.cls_token(patches)
|
| 224 |
+
patches = self.patch_normalizer(patches)
|
| 225 |
+
if self.return_pos_enc:
|
| 226 |
+
return patches, pos_enc
|
| 227 |
+
return patches
|
| 228 |
+
|
| 229 |
+
def apply_pos_enc(
|
| 230 |
+
self,
|
| 231 |
+
patches: torch.Tensor,
|
| 232 |
+
patch_idxs: Optional[torch.Tensor] = None,
|
| 233 |
+
input_size: Optional[Tuple[int, int]] = None,
|
| 234 |
+
) -> Tuple[torch.Tensor, torch.Tensor]:
|
| 235 |
+
if not self.abs_pos:
|
| 236 |
+
return patches, torch.empty(0, device=patches.device, dtype=patches.dtype)
|
| 237 |
+
pos_enc = self.get_pos_enc(patches.shape[0], patch_idxs, input_size)
|
| 238 |
+
if self.training and self.pos_dropout > 0:
|
| 239 |
+
keeps = torch.rand(patches.shape[0], 1, 1, dtype=pos_enc.dtype, device=pos_enc.device) > self.pos_dropout
|
| 240 |
+
pos_enc_drop = torch.where(keeps, pos_enc, 0)
|
| 241 |
+
else:
|
| 242 |
+
pos_enc_drop = pos_enc
|
| 243 |
+
return patches + pos_enc_drop, pos_enc
|
| 244 |
+
|
| 245 |
+
def get_pos_enc(
|
| 246 |
+
self,
|
| 247 |
+
batch_size: int,
|
| 248 |
+
patch_idxs: Optional[torch.Tensor] = None,
|
| 249 |
+
input_size: Optional[Tuple[int, int]] = None,
|
| 250 |
+
) -> torch.Tensor:
|
| 251 |
+
input_dims = self.input_dims if input_size is None else tuple(d // self.patch_size for d in input_size)
|
| 252 |
+
pos_embed = self._get_pos_embeddings(batch_size, input_dims)
|
| 253 |
+
if patch_idxs is None:
|
| 254 |
+
return pos_embed
|
| 255 |
+
exp_patch_idxs = patch_idxs.unsqueeze(-1).expand(-1, -1, pos_embed.shape[-1])
|
| 256 |
+
return torch.gather(pos_embed.expand(patch_idxs.shape[0], -1, -1), dim=1, index=exp_patch_idxs)
|
| 257 |
+
|
| 258 |
+
def _get_pos_embeddings(self, batch_size: int, input_dims: Tuple[int, int]) -> torch.Tensor:
|
| 259 |
+
if (self.num_rows, self.num_cols) == input_dims:
|
| 260 |
+
return self.pos_embed
|
| 261 |
+
|
| 262 |
+
pos_embed = self.pos_embed.reshape(1, self.num_rows, self.num_cols, -1).permute(0, 3, 1, 2)
|
| 263 |
+
|
| 264 |
+
def window_select(pe: torch.Tensor) -> torch.Tensor:
|
| 265 |
+
if input_dims[0] < pe.shape[-2]:
|
| 266 |
+
pe = pe[..., :input_dims[0], :]
|
| 267 |
+
if input_dims[1] < pe.shape[-1]:
|
| 268 |
+
pe = pe[..., :, :input_dims[1]]
|
| 269 |
+
return pe
|
| 270 |
+
|
| 271 |
+
if self.cpe_mode:
|
| 272 |
+
if self.training:
|
| 273 |
+
if self.num_video_frames is not None:
|
| 274 |
+
if batch_size % self.num_video_frames != 0:
|
| 275 |
+
raise ValueError(
|
| 276 |
+
f"Batch size {batch_size} must be divisible by num_video_frames "
|
| 277 |
+
f"{self.num_video_frames} for CPE mode."
|
| 278 |
+
)
|
| 279 |
+
batch_size //= self.num_video_frames
|
| 280 |
+
|
| 281 |
+
min_scale = math.sqrt(0.1)
|
| 282 |
+
scale = torch.rand(batch_size, 1, 1, device=pos_embed.device) * (1 - min_scale) + min_scale
|
| 283 |
+
aspect_min = math.log(3 / 4)
|
| 284 |
+
aspect = torch.exp(torch.rand(batch_size, 1, 1, device=pos_embed.device) * (-2 * aspect_min) + aspect_min)
|
| 285 |
+
scale_xy = torch.stack([scale * aspect, scale / aspect], dim=-1).clamp_(0, 1)
|
| 286 |
+
pos_xy = torch.rand(batch_size, 1, 1, 2, device=pos_embed.device) * (1 - scale_xy)
|
| 287 |
+
lin_x = torch.linspace(0, 1, steps=input_dims[1], device=pos_embed.device)[None, None].expand(batch_size, input_dims[0], -1)
|
| 288 |
+
lin_y = torch.linspace(0, 1, steps=input_dims[0], device=pos_embed.device)[None, :, None].expand(batch_size, -1, input_dims[1])
|
| 289 |
+
grid_xy = torch.stack([lin_x, lin_y], dim=-1) * scale_xy + pos_xy
|
| 290 |
+
grid_xy.mul_(2).sub_(1)
|
| 291 |
+
pos_embed = F.grid_sample(
|
| 292 |
+
pos_embed.float().expand(batch_size, -1, -1, -1),
|
| 293 |
+
grid=grid_xy,
|
| 294 |
+
mode="bilinear",
|
| 295 |
+
padding_mode="zeros",
|
| 296 |
+
align_corners=True,
|
| 297 |
+
).to(pos_embed.dtype)
|
| 298 |
+
if self.num_video_frames is not None:
|
| 299 |
+
pos_embed = torch.repeat_interleave(pos_embed, self.num_video_frames, dim=0)
|
| 300 |
+
else:
|
| 301 |
+
max_dim = max(input_dims)
|
| 302 |
+
pos_embed = F.interpolate(pos_embed.float(), size=(max_dim, max_dim), align_corners=False, mode="bilinear").to(pos_embed.dtype)
|
| 303 |
+
pos_embed = window_select(pos_embed)
|
| 304 |
+
else:
|
| 305 |
+
pos_embed = window_select(pos_embed)
|
| 306 |
+
|
| 307 |
+
if pos_embed.shape[-2:] != input_dims:
|
| 308 |
+
pos_embed = F.interpolate(pos_embed.float(), size=input_dims, align_corners=False, mode="bilinear").to(pos_embed.dtype)
|
| 309 |
+
return pos_embed.flatten(2).permute(0, 2, 1)
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
def _forward_cpe(self: VisionTransformer, x: torch.Tensor) -> torch.Tensor:
|
| 313 |
+
x = self.patch_generator(x)
|
| 314 |
+
if getattr(self, "grad_checkpointing", False) and not torch.jit.is_scripting():
|
| 315 |
+
x = checkpoint_seq(self.blocks, x)
|
| 316 |
+
else:
|
| 317 |
+
x = self.blocks(x)
|
| 318 |
+
x = self.norm(x)
|
| 319 |
+
return x
|
| 320 |
+
|
| 321 |
+
|
| 322 |
+
@contextmanager
|
| 323 |
+
def _video_mode(self: VisionTransformer, t: int):
|
| 324 |
+
original_num_frames = self.patch_generator.num_video_frames
|
| 325 |
+
self.patch_generator.num_video_frames = t
|
| 326 |
+
try:
|
| 327 |
+
yield
|
| 328 |
+
finally:
|
| 329 |
+
self.patch_generator.num_video_frames = original_num_frames
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
def enable_cpe(
|
| 333 |
+
model: VisionTransformer,
|
| 334 |
+
max_img_size: Union[int, Tuple[int, int]] = 1024,
|
| 335 |
+
num_cls_tokens: int = 1,
|
| 336 |
+
pos_dropout: float = 0.1,
|
| 337 |
+
register_multiple: Optional[int] = None,
|
| 338 |
+
num_registers: Optional[int] = None,
|
| 339 |
+
) -> None:
|
| 340 |
+
if not isinstance(model, VisionTransformer):
|
| 341 |
+
raise ValueError(f"CPE only supports timm VisionTransformer models, got {type(model)}")
|
| 342 |
+
|
| 343 |
+
patch_size = model.patch_embed.patch_size[0]
|
| 344 |
+
embed_dim = model.embed_dim
|
| 345 |
+
input_dims = model.patch_embed.img_size
|
| 346 |
+
normalize_patches = not isinstance(model.patch_embed.norm, nn.Identity)
|
| 347 |
+
cls_token = model.cls_token is not None
|
| 348 |
+
if isinstance(max_img_size, int):
|
| 349 |
+
max_img_size = int(round(max_img_size / patch_size) * patch_size)
|
| 350 |
+
else:
|
| 351 |
+
max_img_size = tuple(int(round(d / patch_size) * patch_size) for d in max_img_size)
|
| 352 |
+
|
| 353 |
+
model.patch_generator = ViTPatchGenerator(
|
| 354 |
+
patch_size=patch_size,
|
| 355 |
+
embed_dim=embed_dim,
|
| 356 |
+
input_dims=input_dims,
|
| 357 |
+
normalize_patches=normalize_patches,
|
| 358 |
+
cls_token=cls_token,
|
| 359 |
+
max_input_dims=max_img_size,
|
| 360 |
+
pos_dropout=pos_dropout,
|
| 361 |
+
num_cls_tokens=num_cls_tokens,
|
| 362 |
+
register_multiple=register_multiple,
|
| 363 |
+
num_registers=num_registers,
|
| 364 |
+
)
|
| 365 |
+
model.patch_embed = None
|
| 366 |
+
model.cls_token = None
|
| 367 |
+
model.pos_embed = None
|
| 368 |
+
model.pos_drop = None
|
| 369 |
+
model.patch_size = patch_size
|
| 370 |
+
model.num_cls_tokens = num_cls_tokens
|
| 371 |
+
model.num_registers = model.patch_generator.num_registers
|
| 372 |
+
model.forward_features = MethodType(_forward_cpe, model)
|
| 373 |
+
model.cpe_video_mode = MethodType(_video_mode, model)
|
| 374 |
+
|
| 375 |
+
|
| 376 |
+
class FeatureNormalizer(nn.Module):
|
| 377 |
+
def __init__(self, embed_dim: int, dtype: torch.dtype = torch.float32) -> None:
|
| 378 |
+
super().__init__()
|
| 379 |
+
self.register_buffer("mean", torch.zeros(embed_dim, dtype=dtype))
|
| 380 |
+
self.register_buffer("tx", torch.eye(embed_dim, dtype=dtype))
|
| 381 |
+
|
| 382 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 383 |
+
if x.ndim <= 3:
|
| 384 |
+
return (x - self.mean) @ self.tx.T
|
| 385 |
+
if x.ndim == 4:
|
| 386 |
+
kernel = self.tx.reshape(*self.tx.shape, 1, 1)
|
| 387 |
+
return F.conv2d(x - self.mean.reshape(1, -1, 1, 1), weight=kernel, bias=None, stride=1, padding=0)
|
| 388 |
+
raise ValueError(f"Unsupported input dimension: {x.ndim}, shape: {x.shape}")
|
| 389 |
+
|
| 390 |
+
|
| 391 |
+
class InnerRADIOModel(nn.Module):
|
| 392 |
+
def __init__(
|
| 393 |
+
self,
|
| 394 |
+
model: nn.Module,
|
| 395 |
+
input_conditioner: nn.Module,
|
| 396 |
+
patch_size: int,
|
| 397 |
+
max_resolution: int,
|
| 398 |
+
preferred_resolution: Resolution,
|
| 399 |
+
summary_idxs: Optional[torch.Tensor] = None,
|
| 400 |
+
feature_normalizer: Optional[nn.Module] = None,
|
| 401 |
+
window_size: Optional[int] = None,
|
| 402 |
+
) -> None:
|
| 403 |
+
super().__init__()
|
| 404 |
+
self.model = model
|
| 405 |
+
self.input_conditioner = input_conditioner
|
| 406 |
+
if summary_idxs is not None:
|
| 407 |
+
self.register_buffer("summary_idxs", summary_idxs)
|
| 408 |
+
else:
|
| 409 |
+
self.summary_idxs = None
|
| 410 |
+
self._preferred_resolution = preferred_resolution
|
| 411 |
+
self._patch_size = patch_size
|
| 412 |
+
self._max_resolution = max_resolution
|
| 413 |
+
self._window_size = window_size
|
| 414 |
+
self.feature_normalizer = feature_normalizer if feature_normalizer is not None else nn.Identity()
|
| 415 |
+
|
| 416 |
+
@property
|
| 417 |
+
def num_summary_tokens(self) -> int:
|
| 418 |
+
patch_gen = getattr(self.model, "patch_generator", None)
|
| 419 |
+
if patch_gen is not None:
|
| 420 |
+
return patch_gen.num_skip
|
| 421 |
+
if getattr(self.model, "global_pool", None) == "avg":
|
| 422 |
+
return 0
|
| 423 |
+
return 1
|
| 424 |
+
|
| 425 |
+
@property
|
| 426 |
+
def num_cls_tokens(self) -> int:
|
| 427 |
+
patch_gen = getattr(self.model, "patch_generator", None)
|
| 428 |
+
if patch_gen is not None:
|
| 429 |
+
return patch_gen.num_cls_tokens
|
| 430 |
+
if getattr(self.model, "global_pool", None) == "avg":
|
| 431 |
+
return 0
|
| 432 |
+
return 1
|
| 433 |
+
|
| 434 |
+
@property
|
| 435 |
+
def patch_size(self) -> int:
|
| 436 |
+
if self._patch_size is not None:
|
| 437 |
+
return self._patch_size
|
| 438 |
+
if hasattr(self.model, "patch_size"):
|
| 439 |
+
return self.model.patch_size
|
| 440 |
+
patch_gen = getattr(self.model, "patch_generator", None)
|
| 441 |
+
if patch_gen is not None:
|
| 442 |
+
return patch_gen.patch_size
|
| 443 |
+
raise AttributeError("Unable to infer patch_size from RADIO vision model")
|
| 444 |
+
|
| 445 |
+
@property
|
| 446 |
+
def max_resolution(self) -> int:
|
| 447 |
+
return self._max_resolution
|
| 448 |
+
|
| 449 |
+
@property
|
| 450 |
+
def preferred_resolution(self) -> Resolution:
|
| 451 |
+
return self._preferred_resolution
|
| 452 |
+
|
| 453 |
+
@property
|
| 454 |
+
def window_size(self) -> Optional[int]:
|
| 455 |
+
return self._window_size
|
| 456 |
+
|
| 457 |
+
@property
|
| 458 |
+
def min_resolution_step(self) -> int:
|
| 459 |
+
res = self.patch_size
|
| 460 |
+
if self.window_size is not None:
|
| 461 |
+
res *= self.window_size
|
| 462 |
+
return res
|
| 463 |
+
|
| 464 |
+
@property
|
| 465 |
+
def blocks(self) -> Iterable[nn.Module]:
|
| 466 |
+
return getattr(self.model, "blocks", None)
|
| 467 |
+
|
| 468 |
+
@property
|
| 469 |
+
def embed_dim(self) -> int:
|
| 470 |
+
return self.model.embed_dim
|
| 471 |
+
|
| 472 |
+
@property
|
| 473 |
+
def summary_dim(self) -> int:
|
| 474 |
+
embed_dim = self.embed_dim
|
| 475 |
+
if self.summary_idxs is not None:
|
| 476 |
+
embed_dim *= self.summary_idxs.shape[0]
|
| 477 |
+
return embed_dim
|
| 478 |
+
|
| 479 |
+
def make_preprocessor_external(self) -> Callable[[torch.Tensor], torch.Tensor]:
|
| 480 |
+
ret = self.input_conditioner
|
| 481 |
+
self.input_conditioner = nn.Identity()
|
| 482 |
+
return ret
|
| 483 |
+
|
| 484 |
+
def get_nearest_supported_resolution(self, height: int, width: int) -> Resolution:
|
| 485 |
+
height = int(round(height / self.min_resolution_step) * self.min_resolution_step)
|
| 486 |
+
width = int(round(width / self.min_resolution_step) * self.min_resolution_step)
|
| 487 |
+
return Resolution(max(height, self.min_resolution_step), max(width, self.min_resolution_step))
|
| 488 |
+
|
| 489 |
+
def switch_to_deploy(self) -> None:
|
| 490 |
+
fn = getattr(self.model, "switch_to_deploy", None)
|
| 491 |
+
if fn is not None:
|
| 492 |
+
fn()
|
| 493 |
+
|
| 494 |
+
def cpe_video_mode(self, t: int):
|
| 495 |
+
return self.model.cpe_video_mode(t)
|
| 496 |
+
|
| 497 |
+
def forward(self, x: torch.Tensor, feature_fmt: str = "NLC") -> RadioOutput:
|
| 498 |
+
res_step = self.min_resolution_step
|
| 499 |
+
if res_step is not None and (x.shape[-2] % res_step != 0 or x.shape[-1] % res_step != 0):
|
| 500 |
+
raise ValueError(
|
| 501 |
+
"The input resolution must be a multiple of self.min_resolution_step. "
|
| 502 |
+
f"Input: {x.shape[-2:]}, Nearest: {self.get_nearest_supported_resolution(*x.shape[-2:])}"
|
| 503 |
+
)
|
| 504 |
+
x = self.input_conditioner(x)
|
| 505 |
+
y = self.model.forward_features(x)
|
| 506 |
+
return self._extract_final(x, y, feature_fmt=feature_fmt)
|
| 507 |
+
|
| 508 |
+
def _extract_final(self, x: torch.Tensor, y: torch.Tensor, feature_fmt: str = "NLC") -> RadioOutput:
|
| 509 |
+
patch_gen = getattr(self.model, "patch_generator", None)
|
| 510 |
+
if patch_gen is not None:
|
| 511 |
+
all_summary = y[:, : patch_gen.num_cls_tokens]
|
| 512 |
+
bb_summary = all_summary[:, self.summary_idxs] if self.summary_idxs is not None else all_summary
|
| 513 |
+
all_feat = y[:, patch_gen.num_skip :]
|
| 514 |
+
elif getattr(self.model, "global_pool", None) == "avg":
|
| 515 |
+
all_summary = y[:, self.model.num_prefix_tokens :].mean(dim=1)
|
| 516 |
+
bb_summary = all_summary
|
| 517 |
+
all_feat = y
|
| 518 |
+
else:
|
| 519 |
+
all_summary = y[:, 0]
|
| 520 |
+
bb_summary = all_summary
|
| 521 |
+
all_feat = y[:, 1:]
|
| 522 |
+
|
| 523 |
+
all_feat = self.feature_normalizer(all_feat)
|
| 524 |
+
if feature_fmt == "NCHW":
|
| 525 |
+
fmt_feat = all_feat.reshape(
|
| 526 |
+
all_feat.shape[0],
|
| 527 |
+
x.shape[-2] // self.patch_size,
|
| 528 |
+
x.shape[-1] // self.patch_size,
|
| 529 |
+
all_feat.shape[2],
|
| 530 |
+
).permute(0, 3, 1, 2)
|
| 531 |
+
elif feature_fmt == "NLC":
|
| 532 |
+
fmt_feat = all_feat
|
| 533 |
+
else:
|
| 534 |
+
raise ValueError(f"Unsupported feature_fmt: {feature_fmt}. Must be one of ['NLC', 'NCHW']")
|
| 535 |
+
return RadioOutput(bb_summary.flatten(1), fmt_feat)
|
| 536 |
+
|
| 537 |
+
|
| 538 |
+
def _as_namespace(value):
|
| 539 |
+
if value is None:
|
| 540 |
+
return type("RADIOArgs", (), {})()
|
| 541 |
+
if isinstance(value, dict):
|
| 542 |
+
ns = type("RADIOArgs", (), {})()
|
| 543 |
+
for k, v in value.items():
|
| 544 |
+
setattr(ns, k, v)
|
| 545 |
+
return ns
|
| 546 |
+
return value
|
| 547 |
+
|
| 548 |
+
|
| 549 |
+
def _dtype_from_config(config: RADIOConfig) -> torch.dtype:
|
| 550 |
+
dtype_name = getattr(config, "dtype", None) or getattr(config, "amp_dtype", None)
|
| 551 |
+
if isinstance(dtype_name, torch.dtype):
|
| 552 |
+
return dtype_name
|
| 553 |
+
if isinstance(dtype_name, str) and hasattr(torch, dtype_name):
|
| 554 |
+
return getattr(torch, dtype_name)
|
| 555 |
+
return torch.float32
|
| 556 |
+
|
| 557 |
+
|
| 558 |
+
def create_vit_from_config(config: RADIOConfig) -> VisionTransformer:
|
| 559 |
+
args = _as_namespace(getattr(config, "args", {}))
|
| 560 |
+
model_name = getattr(args, "model", None) or "vit_huge_patch16_224"
|
| 561 |
+
if model_name != "vit_huge_patch16_224":
|
| 562 |
+
raise ValueError(
|
| 563 |
+
"This standalone cradio_model.py keeps only the ZDTaichu ViT-H/16 structure. "
|
| 564 |
+
f"Unsupported RADIO args.model={model_name!r}."
|
| 565 |
+
)
|
| 566 |
+
|
| 567 |
+
model = VisionTransformer(
|
| 568 |
+
img_size=224,
|
| 569 |
+
patch_size=16,
|
| 570 |
+
embed_dim=1280,
|
| 571 |
+
depth=32,
|
| 572 |
+
num_heads=16,
|
| 573 |
+
mlp_ratio=4.0,
|
| 574 |
+
qkv_bias=True,
|
| 575 |
+
num_classes=0,
|
| 576 |
+
global_pool="",
|
| 577 |
+
)
|
| 578 |
+
|
| 579 |
+
# The ZDTaichu checkpoint was exported after RADIO removed the final ViT norm/head
|
| 580 |
+
# and replaced patch embedding, cls token, and absolute pos embedding with CPE.
|
| 581 |
+
if hasattr(model, "norm") and not getattr(args, "model_norm", False):
|
| 582 |
+
model.norm = nn.Identity()
|
| 583 |
+
model.head = nn.Identity()
|
| 584 |
+
|
| 585 |
+
cpe_max_size = getattr(args, "cpe_max_size", None) or getattr(config, "max_resolution", None)
|
| 586 |
+
if cpe_max_size is not None:
|
| 587 |
+
teachers = getattr(args, "teachers", []) or []
|
| 588 |
+
teacher_names = {t.get("name") for t in teachers if isinstance(t, dict) and t.get("name")}
|
| 589 |
+
num_cls_tokens = len(teacher_names) if getattr(args, "cls_token_per_teacher", False) and teacher_names else 1
|
| 590 |
+
enable_cpe(
|
| 591 |
+
model,
|
| 592 |
+
cpe_max_size,
|
| 593 |
+
num_cls_tokens=num_cls_tokens,
|
| 594 |
+
register_multiple=getattr(args, "register_multiple", None),
|
| 595 |
+
num_registers=getattr(args, "cpe_num_registers", None),
|
| 596 |
+
)
|
| 597 |
+
return model
|
| 598 |
+
|
| 599 |
+
|
| 600 |
+
class RADIOModel(PreTrainedModel):
|
| 601 |
+
"""Inference-only HuggingFace wrapper for the ZDTaichu C-RADIO ViT tower."""
|
| 602 |
+
|
| 603 |
+
config_class = RADIOConfig
|
| 604 |
+
base_model_prefix = "radio_model"
|
| 605 |
+
main_input_name = "pixel_values"
|
| 606 |
+
supports_gradient_checkpointing = False
|
| 607 |
+
|
| 608 |
+
def __init__(self, config: RADIOConfig) -> None:
|
| 609 |
+
super().__init__(config)
|
| 610 |
+
args = _as_namespace(getattr(config, "args", {}))
|
| 611 |
+
dtype = _dtype_from_config(config)
|
| 612 |
+
vit = create_vit_from_config(config)
|
| 613 |
+
|
| 614 |
+
summary_idxs = None
|
| 615 |
+
if getattr(args, "cls_token_per_teacher", False):
|
| 616 |
+
teachers = getattr(args, "teachers", []) or []
|
| 617 |
+
if teachers:
|
| 618 |
+
summary_idxs = torch.tensor(
|
| 619 |
+
[i for i, t in enumerate(teachers) if not isinstance(t, dict) or t.get("use_summary", True)],
|
| 620 |
+
dtype=torch.int64,
|
| 621 |
+
)
|
| 622 |
+
|
| 623 |
+
feature_normalizer = None
|
| 624 |
+
fn_cfg = getattr(config, "feature_normalizer_config", None)
|
| 625 |
+
if fn_cfg is not None:
|
| 626 |
+
embed_dim = fn_cfg.get("embed_dim", vit.embed_dim) if isinstance(fn_cfg, dict) else vit.embed_dim
|
| 627 |
+
feature_normalizer = FeatureNormalizer(embed_dim, dtype=torch.float32)
|
| 628 |
+
|
| 629 |
+
pref = getattr(config, "preferred_resolution", (512, 512))
|
| 630 |
+
self.radio_model = InnerRADIOModel(
|
| 631 |
+
model=vit,
|
| 632 |
+
input_conditioner=get_default_conditioner(),
|
| 633 |
+
patch_size=getattr(config, "patch_size", 16),
|
| 634 |
+
max_resolution=getattr(config, "max_resolution", 2048),
|
| 635 |
+
preferred_resolution=Resolution(int(pref[0]), int(pref[1])),
|
| 636 |
+
summary_idxs=summary_idxs,
|
| 637 |
+
feature_normalizer=feature_normalizer,
|
| 638 |
+
window_size=getattr(config, "vitdet_window_size", None),
|
| 639 |
+
)
|
| 640 |
+
if dtype is not torch.float32:
|
| 641 |
+
self.radio_model = self.radio_model.to(dtype=dtype)
|
| 642 |
+
|
| 643 |
+
@property
|
| 644 |
+
def adaptors(self):
|
| 645 |
+
return nn.ModuleDict()
|
| 646 |
+
|
| 647 |
+
@property
|
| 648 |
+
def model(self) -> nn.Module:
|
| 649 |
+
return self.radio_model.model
|
| 650 |
+
|
| 651 |
+
@property
|
| 652 |
+
def input_conditioner(self) -> nn.Module:
|
| 653 |
+
return self.radio_model.input_conditioner
|
| 654 |
+
|
| 655 |
+
@property
|
| 656 |
+
def num_summary_tokens(self) -> int:
|
| 657 |
+
return self.radio_model.num_summary_tokens
|
| 658 |
+
|
| 659 |
+
@property
|
| 660 |
+
def patch_size(self) -> int:
|
| 661 |
+
return self.radio_model.patch_size
|
| 662 |
+
|
| 663 |
+
@property
|
| 664 |
+
def max_resolution(self) -> int:
|
| 665 |
+
return self.radio_model.max_resolution
|
| 666 |
+
|
| 667 |
+
@property
|
| 668 |
+
def preferred_resolution(self) -> Resolution:
|
| 669 |
+
return self.radio_model.preferred_resolution
|
| 670 |
+
|
| 671 |
+
@property
|
| 672 |
+
def window_size(self) -> Optional[int]:
|
| 673 |
+
return self.radio_model.window_size
|
| 674 |
+
|
| 675 |
+
@property
|
| 676 |
+
def min_resolution_step(self) -> int:
|
| 677 |
+
return self.radio_model.min_resolution_step
|
| 678 |
+
|
| 679 |
+
def make_preprocessor_external(self) -> Callable[[torch.Tensor], torch.Tensor]:
|
| 680 |
+
return self.radio_model.make_preprocessor_external()
|
| 681 |
+
|
| 682 |
+
def get_nearest_supported_resolution(self, height: int, width: int) -> Resolution:
|
| 683 |
+
return self.radio_model.get_nearest_supported_resolution(height, width)
|
| 684 |
+
|
| 685 |
+
def switch_to_deploy(self) -> None:
|
| 686 |
+
self.radio_model.switch_to_deploy()
|
| 687 |
+
|
| 688 |
+
def forward(self, pixel_values: torch.Tensor, feature_fmt: str = "NLC", **kwargs) -> RadioOutput:
|
| 689 |
+
return self.radio_model(pixel_values, feature_fmt=feature_fmt)
|
| 690 |
+
|
| 691 |
+
|
| 692 |
+
__all__ = [
|
| 693 |
+
"RADIOModel",
|
| 694 |
+
"RADIOConfig",
|
| 695 |
+
"RadioOutput",
|
| 696 |
+
"Resolution",
|
| 697 |
+
"InputConditioner",
|
| 698 |
+
"ViTPatchGenerator",
|
| 699 |
+
]
|
generation_config.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_from_model_config": true,
|
| 3 |
+
"bos_token_id": 248040,
|
| 4 |
+
"do_sample": true,
|
| 5 |
+
"eos_token_id": [
|
| 6 |
+
248044,
|
| 7 |
+
248040,
|
| 8 |
+
248046
|
| 9 |
+
],
|
| 10 |
+
"pad_token_id": 248040,
|
| 11 |
+
"repetition_penalty": 1.0,
|
| 12 |
+
"temperature": 1.0,
|
| 13 |
+
"top_k": 20,
|
| 14 |
+
"top_p": 0.95,
|
| 15 |
+
"transformers_version": "5.3.0"
|
| 16 |
+
}
|
image_processing.py
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
from typing import List, Optional, Union, Any, Dict, Tuple
|
| 15 |
+
|
| 16 |
+
from PIL import Image
|
| 17 |
+
import torch
|
| 18 |
+
from transformers.image_processing_base import BatchFeature
|
| 19 |
+
from transformers.image_processing_utils_fast import BaseImageProcessorFast
|
| 20 |
+
from transformers.image_utils import make_list_of_images, get_image_type, ImageInput, ImageType
|
| 21 |
+
from transformers.utils import TensorType
|
| 22 |
+
import torchvision.transforms as T
|
| 23 |
+
|
| 24 |
+
import math
|
| 25 |
+
|
| 26 |
+
class ZDTaichu5_0_ImageProcessor(BaseImageProcessorFast):
|
| 27 |
+
model_input_names = ["pixel_values", "image_grid_thw"]
|
| 28 |
+
|
| 29 |
+
def __init__(self, image_size=512, max_num_tiles=12, use_thumbnail=True, norm_mean=None, norm_std=None, do_rescale=True, patch_size=16, downsample_ratio=0.5, merge_size=1, **kwargs):
|
| 30 |
+
super().__init__(**kwargs)
|
| 31 |
+
self.image_size = image_size
|
| 32 |
+
self.max_num_tiles = max_num_tiles
|
| 33 |
+
self.use_thumbnail = use_thumbnail
|
| 34 |
+
self.norm_mean = norm_mean
|
| 35 |
+
self.norm_std = norm_std
|
| 36 |
+
self.do_rescale = do_rescale
|
| 37 |
+
self.merge_size = merge_size
|
| 38 |
+
self.num_image_token = int((image_size // patch_size) ** 2 * (downsample_ratio ** 2))
|
| 39 |
+
|
| 40 |
+
def _process_image(
|
| 41 |
+
self,
|
| 42 |
+
image: ImageInput,
|
| 43 |
+
**kwargs,
|
| 44 |
+
) -> torch.Tensor:
|
| 45 |
+
image_type = get_image_type(image)
|
| 46 |
+
if image_type == ImageType.PIL:
|
| 47 |
+
if image.mode != 'RGB':
|
| 48 |
+
image = image.convert('RGB')
|
| 49 |
+
# Keep PIL input through tiling so resize order matches vLLM.
|
| 50 |
+
return image
|
| 51 |
+
|
| 52 |
+
def _preprocess(
|
| 53 |
+
self,
|
| 54 |
+
images: List[torch.Tensor],
|
| 55 |
+
image_size: int = None,
|
| 56 |
+
max_num_tiles: int = None,
|
| 57 |
+
use_thumbnail: bool = None,
|
| 58 |
+
do_rescale: bool = None,
|
| 59 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 60 |
+
**kwargs,
|
| 61 |
+
) -> List[torch.Tensor]:
|
| 62 |
+
image_size = image_size if image_size is not None else self.image_size
|
| 63 |
+
max_num_tiles = max_num_tiles if max_num_tiles is not None else self.max_num_tiles
|
| 64 |
+
use_thumbnail = use_thumbnail if use_thumbnail is not None else self.use_thumbnail
|
| 65 |
+
do_rescale = do_rescale if do_rescale is not None else self.do_rescale
|
| 66 |
+
|
| 67 |
+
images = make_list_of_images(images)
|
| 68 |
+
|
| 69 |
+
all_patches = []
|
| 70 |
+
num_patches = []
|
| 71 |
+
image_grid_thw = []
|
| 72 |
+
for image in images:
|
| 73 |
+
patches, tile_rows, tile_cols = dynamic_preprocess(image, image_size, max_num_tiles, use_thumbnail)
|
| 74 |
+
all_patches.extend(patches)
|
| 75 |
+
num_patches.append(len(patches))
|
| 76 |
+
image_grid_thw.append([1, tile_rows, tile_cols])
|
| 77 |
+
|
| 78 |
+
# vLLM converts each already-cropped PIL tile with ToTensor.
|
| 79 |
+
pixel_values = torch.stack([T.ToTensor()(patch) for patch in all_patches], dim=0)
|
| 80 |
+
norm_mean = torch.Tensor(self.norm_mean).view(1, 3, 1, 1)
|
| 81 |
+
norm_std = torch.Tensor(self.norm_std).view(1, 3, 1, 1)
|
| 82 |
+
pixel_values = (pixel_values - norm_mean) / norm_std
|
| 83 |
+
pixel_values = pixel_values.to(torch.bfloat16)
|
| 84 |
+
return BatchFeature(
|
| 85 |
+
data={
|
| 86 |
+
"pixel_values": pixel_values,
|
| 87 |
+
"num_patches": num_patches,
|
| 88 |
+
"image_grid_thw": image_grid_thw,
|
| 89 |
+
},
|
| 90 |
+
tensor_type=return_tensors,
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def get_internvl_target_ratios(
|
| 95 |
+
min_num: int,
|
| 96 |
+
max_num: int,
|
| 97 |
+
) -> list[tuple[int, int]]:
|
| 98 |
+
target_ratios = {(i, j)
|
| 99 |
+
for n in range(min_num, max_num + 1)
|
| 100 |
+
for i in range(1, n + 1)
|
| 101 |
+
for j in range(1, n + 1) if min_num <= i * j <= max_num}
|
| 102 |
+
return sorted(target_ratios, key=lambda x: x[0] * x[1])
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
# From https://github.com/OpenGVLab/InternVL/blob/c62fa4f7c850165d7386bdc48ac6bc5a6fab0864/internvl_chat/internvl/train/dataset.py#L685
|
| 106 |
+
# Copyright (c) 2023 OpenGVLab.
|
| 107 |
+
def find_closest_aspect_ratio(
|
| 108 |
+
aspect_ratio: float,
|
| 109 |
+
target_ratios: list[tuple[int, int]],
|
| 110 |
+
width: int,
|
| 111 |
+
height: int,
|
| 112 |
+
image_size: int,
|
| 113 |
+
) -> tuple[int, int]:
|
| 114 |
+
best_ratio_diff = float("inf")
|
| 115 |
+
best_ratio = (1, 1)
|
| 116 |
+
area = width * height
|
| 117 |
+
for ratio in target_ratios:
|
| 118 |
+
target_aspect_ratio = ratio[0] / ratio[1]
|
| 119 |
+
ratio_diff = abs(aspect_ratio - target_aspect_ratio)
|
| 120 |
+
if ratio_diff < best_ratio_diff:
|
| 121 |
+
best_ratio_diff = ratio_diff
|
| 122 |
+
best_ratio = ratio
|
| 123 |
+
elif ratio_diff == best_ratio_diff:
|
| 124 |
+
if area > 0.5 * image_size * image_size * ratio[0] * ratio[1]:
|
| 125 |
+
best_ratio = ratio
|
| 126 |
+
return best_ratio
|
| 127 |
+
|
| 128 |
+
def select_tile_grid(
|
| 129 |
+
*,
|
| 130 |
+
orig_width: int,
|
| 131 |
+
orig_height: int,
|
| 132 |
+
image_size: int,
|
| 133 |
+
min_num_tiles: int,
|
| 134 |
+
max_num_tiles: int,
|
| 135 |
+
) -> Tuple[int, int, int, int]:
|
| 136 |
+
"""
|
| 137 |
+
Choose (rw, rh) tile grid with small-image and aspect-sanity guards.
|
| 138 |
+
|
| 139 |
+
Returns (num_grid_blocks, target_width, target_height, effective_max_tiles).
|
| 140 |
+
num_grid_blocks = rw * rh (does NOT include the optional thumbnail).
|
| 141 |
+
|
| 142 |
+
Guards:
|
| 143 |
+
1. Area cap: don't create more tiles than the source has pixels for.
|
| 144 |
+
2. Aspect-sanity: drop candidates whose ratio differs from source by >3x.
|
| 145 |
+
"""
|
| 146 |
+
# ── Guard 1: area cap ─────────────────────────────────────────────────
|
| 147 |
+
src_pixels = orig_width * orig_height
|
| 148 |
+
tile_pixels = image_size * image_size
|
| 149 |
+
area_max_tiles = max(1, math.ceil(src_pixels / tile_pixels))
|
| 150 |
+
effective_max = min(max_num_tiles, area_max_tiles)
|
| 151 |
+
effective_max = max(effective_max, min_num_tiles)
|
| 152 |
+
|
| 153 |
+
target_ratios = get_internvl_target_ratios(min_num_tiles, effective_max)
|
| 154 |
+
|
| 155 |
+
# ── Guard 2: aspect-sanity ────────────────────────────────────────────
|
| 156 |
+
src_ar = orig_width / orig_height
|
| 157 |
+
filtered = [
|
| 158 |
+
(rw, rh) for (rw, rh) in target_ratios
|
| 159 |
+
if (1.0 / 3.0) <= (rw / rh) / src_ar <= 3.0
|
| 160 |
+
]
|
| 161 |
+
# Fall back to unfiltered set for extreme panoramas / long strips where
|
| 162 |
+
# no candidate is within 3x — better to pick *something* than error.
|
| 163 |
+
if filtered:
|
| 164 |
+
target_ratios = filtered
|
| 165 |
+
|
| 166 |
+
# ── Pick best ratio ───────────────────────────────────────────────────
|
| 167 |
+
rw, rh = find_closest_aspect_ratio(
|
| 168 |
+
src_ar, target_ratios,
|
| 169 |
+
width=orig_width, height=orig_height, image_size=image_size,
|
| 170 |
+
)
|
| 171 |
+
|
| 172 |
+
target_width = image_size * rw
|
| 173 |
+
target_height = image_size * rh
|
| 174 |
+
num_grid_blocks = rw * rh
|
| 175 |
+
|
| 176 |
+
return num_grid_blocks, target_width, target_height, effective_max
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
def count_tiles(
|
| 180 |
+
*,
|
| 181 |
+
orig_width: int,
|
| 182 |
+
orig_height: int,
|
| 183 |
+
image_size: int,
|
| 184 |
+
min_num_tiles: int,
|
| 185 |
+
max_num_tiles: int,
|
| 186 |
+
use_thumbnail: bool,
|
| 187 |
+
) -> int:
|
| 188 |
+
"""
|
| 189 |
+
Total number of tiles (grid blocks + optional thumbnail) for this image.
|
| 190 |
+
This MUST match what the actual tiling produces, or prompt expansion and
|
| 191 |
+
embedding count will diverge.
|
| 192 |
+
"""
|
| 193 |
+
n_grid, _, _, _ = select_tile_grid(
|
| 194 |
+
orig_width=orig_width, orig_height=orig_height,
|
| 195 |
+
image_size=image_size,
|
| 196 |
+
min_num_tiles=min_num_tiles, max_num_tiles=max_num_tiles,
|
| 197 |
+
)
|
| 198 |
+
if use_thumbnail and n_grid != 1:
|
| 199 |
+
return n_grid + 1
|
| 200 |
+
return n_grid
|
| 201 |
+
|
| 202 |
+
def calculate_targets(
|
| 203 |
+
orig_width: int,
|
| 204 |
+
orig_height: int,
|
| 205 |
+
target_ratios: list[tuple[int, int]],
|
| 206 |
+
image_size: int,
|
| 207 |
+
) -> tuple[int, int, int]:
|
| 208 |
+
aspect_ratio = orig_width / orig_height
|
| 209 |
+
|
| 210 |
+
# find the closest aspect ratio to the target
|
| 211 |
+
target_aspect_ratio = find_closest_aspect_ratio(
|
| 212 |
+
aspect_ratio,
|
| 213 |
+
target_ratios,
|
| 214 |
+
width=orig_width,
|
| 215 |
+
height=orig_height,
|
| 216 |
+
image_size=image_size,
|
| 217 |
+
)
|
| 218 |
+
|
| 219 |
+
# calculate the target width and height
|
| 220 |
+
target_width = image_size * target_aspect_ratio[0]
|
| 221 |
+
target_height = image_size * target_aspect_ratio[1]
|
| 222 |
+
blocks = target_aspect_ratio[0] * target_aspect_ratio[1]
|
| 223 |
+
|
| 224 |
+
return blocks, target_width, target_height
|
| 225 |
+
|
| 226 |
+
def dynamic_preprocess(image, image_size=512, max_num_tiles=12, use_thumbnail=True, min_num_tiles=1):
|
| 227 |
+
"""Split a PIL image using vLLM's resize/crop order."""
|
| 228 |
+
if isinstance(image, torch.Tensor):
|
| 229 |
+
image = T.ToPILImage()(image)
|
| 230 |
+
elif not isinstance(image, Image.Image):
|
| 231 |
+
image = Image.fromarray(image)
|
| 232 |
+
if image.mode != 'RGB':
|
| 233 |
+
image = image.convert('RGB')
|
| 234 |
+
orig_width, orig_height = image.size
|
| 235 |
+
|
| 236 |
+
n_grid, target_width, target_height, _ = select_tile_grid(
|
| 237 |
+
orig_width=orig_width,
|
| 238 |
+
orig_height=orig_height,
|
| 239 |
+
image_size=image_size,
|
| 240 |
+
min_num_tiles=min_num_tiles,
|
| 241 |
+
max_num_tiles=max_num_tiles,
|
| 242 |
+
)
|
| 243 |
+
|
| 244 |
+
# Tile grid dimensions (rows × cols of the InternVL tiling)
|
| 245 |
+
tile_rows = target_height // image_size
|
| 246 |
+
tile_cols = target_width // image_size
|
| 247 |
+
|
| 248 |
+
resized_img = image.resize((target_width, target_height), Image.BICUBIC)
|
| 249 |
+
cols = target_width // image_size
|
| 250 |
+
patches = []
|
| 251 |
+
for i in range(n_grid):
|
| 252 |
+
col = i % cols
|
| 253 |
+
row = i // cols
|
| 254 |
+
patches.append(
|
| 255 |
+
resized_img.crop(
|
| 256 |
+
(col * image_size, row * image_size,
|
| 257 |
+
(col + 1) * image_size, (row + 1) * image_size)
|
| 258 |
+
)
|
| 259 |
+
)
|
| 260 |
+
assert len(patches) == n_grid
|
| 261 |
+
|
| 262 |
+
if use_thumbnail and n_grid != 1:
|
| 263 |
+
thumbnail = image.resize((image_size, image_size), Image.BICUBIC)
|
| 264 |
+
patches.append(thumbnail)
|
| 265 |
+
|
| 266 |
+
#print(orig_height, orig_width, target_width, target_height, len(patches))
|
| 267 |
+
|
| 268 |
+
return patches, tile_rows, tile_cols
|
model-1-of-5.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b24abf3449d27be6ef4fa946645fce51367c88b416d52f6e7cffb6b960a8dbcd
|
| 3 |
+
size 4268658872
|
model-2-of-5.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e4bdaef762f9bb5390bdb048335224540ccfd98e54d99e8642617083e369aa51
|
| 3 |
+
size 4265727128
|
model-3-of-5.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:492fa6e31164aef91b421f30427a6265b8e54b2b4872673c0663773a63ea4c90
|
| 3 |
+
size 4215379968
|
model-4-of-5.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:173356de7e662da8de2193bb5d7bc46f05e33c41d8a0c53131b5595b7785708b
|
| 3 |
+
size 3123658752
|
model-5-of-5.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2dc98857aceb6617a438370292f7bb3572ef61967b31b2cd19096370e60fe16f
|
| 3 |
+
size 3715076700
|
model.safetensors.index.json
ADDED
|
@@ -0,0 +1,827 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"metadata": {
|
| 3 |
+
"total_size": 19588395036
|
| 4 |
+
},
|
| 5 |
+
"weight_map": {
|
| 6 |
+
"language_model.model.layers.22.linear_attn.in_proj_qkv.weight": "model-3-of-5.safetensors",
|
| 7 |
+
"language_model.model.layers.28.linear_attn.norm.weight": "model-4-of-5.safetensors",
|
| 8 |
+
"vision_model.radio_model.model.blocks.31.norm2.bias": "model-5-of-5.safetensors",
|
| 9 |
+
"vision_model.radio_model.model.blocks.5.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 10 |
+
"language_model.model.layers.21.mlp.down_proj.weight": "model-3-of-5.safetensors",
|
| 11 |
+
"language_model.model.layers.25.input_layernorm.weight": "model-4-of-5.safetensors",
|
| 12 |
+
"language_model.model.layers.15.self_attn.k_proj.weight": "model-3-of-5.safetensors",
|
| 13 |
+
"language_model.model.layers.18.input_layernorm.weight": "model-3-of-5.safetensors",
|
| 14 |
+
"language_model.model.layers.18.linear_attn.in_proj_z.weight": "model-3-of-5.safetensors",
|
| 15 |
+
"vision_model.radio_model.model.blocks.27.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 16 |
+
"language_model.model.layers.8.linear_attn.A_log": "model-2-of-5.safetensors",
|
| 17 |
+
"language_model.model.layers.19.post_attention_layernorm.weight": "model-3-of-5.safetensors",
|
| 18 |
+
"language_model.model.layers.3.post_attention_layernorm.weight": "model-1-of-5.safetensors",
|
| 19 |
+
"vision_model.radio_model.model.blocks.28.norm1.bias": "model-5-of-5.safetensors",
|
| 20 |
+
"vision_model.radio_model.model.blocks.17.norm2.bias": "model-5-of-5.safetensors",
|
| 21 |
+
"language_model.model.layers.23.input_layernorm.weight": "model-3-of-5.safetensors",
|
| 22 |
+
"vision_model.radio_model.model.blocks.3.attn.proj.weight": "model-5-of-5.safetensors",
|
| 23 |
+
"vision_model.radio_model.model.blocks.6.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 24 |
+
"vision_model.radio_model.model.blocks.15.attn.proj.bias": "model-5-of-5.safetensors",
|
| 25 |
+
"vision_model.radio_model.model.blocks.15.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 26 |
+
"vision_model.radio_model.model.blocks.2.attn.proj.weight": "model-5-of-5.safetensors",
|
| 27 |
+
"language_model.model.layers.14.mlp.gate_proj.weight": "model-2-of-5.safetensors",
|
| 28 |
+
"language_model.model.layers.29.linear_attn.A_log": "model-4-of-5.safetensors",
|
| 29 |
+
"vision_model.radio_model.model.blocks.14.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 30 |
+
"language_model.model.layers.9.linear_attn.in_proj_b.weight": "model-2-of-5.safetensors",
|
| 31 |
+
"vision_model.radio_model.model.blocks.9.norm1.bias": "model-5-of-5.safetensors",
|
| 32 |
+
"vision_model.radio_model.model.blocks.31.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 33 |
+
"language_model.model.layers.24.linear_attn.in_proj_a.weight": "model-3-of-5.safetensors",
|
| 34 |
+
"vision_model.radio_model.model.blocks.15.norm2.weight": "model-5-of-5.safetensors",
|
| 35 |
+
"vision_model.radio_model.model.blocks.14.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 36 |
+
"vision_model.radio_model.model.blocks.8.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 37 |
+
"language_model.model.layers.29.input_layernorm.weight": "model-4-of-5.safetensors",
|
| 38 |
+
"language_model.model.layers.24.linear_attn.in_proj_z.weight": "model-3-of-5.safetensors",
|
| 39 |
+
"language_model.model.layers.7.input_layernorm.weight": "model-2-of-5.safetensors",
|
| 40 |
+
"language_model.model.layers.9.linear_attn.in_proj_a.weight": "model-2-of-5.safetensors",
|
| 41 |
+
"language_model.model.layers.5.linear_attn.in_proj_z.weight": "model-2-of-5.safetensors",
|
| 42 |
+
"language_model.model.layers.4.linear_attn.in_proj_z.weight": "model-1-of-5.safetensors",
|
| 43 |
+
"language_model.model.layers.23.post_attention_layernorm.weight": "model-3-of-5.safetensors",
|
| 44 |
+
"vision_model.radio_model.model.blocks.18.norm2.weight": "model-5-of-5.safetensors",
|
| 45 |
+
"vision_model.radio_model.model.blocks.5.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 46 |
+
"language_model.model.layers.10.linear_attn.in_proj_qkv.weight": "model-2-of-5.safetensors",
|
| 47 |
+
"vision_model.radio_model.model.blocks.7.norm1.weight": "model-5-of-5.safetensors",
|
| 48 |
+
"vision_model.radio_model.model.blocks.16.attn.proj.bias": "model-5-of-5.safetensors",
|
| 49 |
+
"vision_model.radio_model.model.blocks.1.norm2.bias": "model-5-of-5.safetensors",
|
| 50 |
+
"vision_model.radio_model.model.blocks.18.norm1.weight": "model-5-of-5.safetensors",
|
| 51 |
+
"language_model.model.layers.15.input_layernorm.weight": "model-2-of-5.safetensors",
|
| 52 |
+
"language_model.model.layers.14.linear_attn.A_log": "model-2-of-5.safetensors",
|
| 53 |
+
"vision_model.radio_model.model.blocks.31.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 54 |
+
"vision_model.radio_model.model.blocks.8.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 55 |
+
"language_model.model.layers.30.mlp.gate_proj.weight": "model-4-of-5.safetensors",
|
| 56 |
+
"vision_model.radio_model.model.blocks.9.attn.proj.bias": "model-5-of-5.safetensors",
|
| 57 |
+
"vision_model.radio_model.model.blocks.1.attn.proj.weight": "model-5-of-5.safetensors",
|
| 58 |
+
"vision_model.radio_model.model.blocks.29.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 59 |
+
"language_model.model.layers.26.linear_attn.A_log": "model-4-of-5.safetensors",
|
| 60 |
+
"vision_model.radio_model.model.blocks.14.norm2.weight": "model-5-of-5.safetensors",
|
| 61 |
+
"language_model.model.layers.12.linear_attn.in_proj_z.weight": "model-2-of-5.safetensors",
|
| 62 |
+
"language_model.model.layers.10.input_layernorm.weight": "model-2-of-5.safetensors",
|
| 63 |
+
"language_model.model.layers.1.linear_attn.A_log": "model-1-of-5.safetensors",
|
| 64 |
+
"language_model.model.layers.12.input_layernorm.weight": "model-2-of-5.safetensors",
|
| 65 |
+
"language_model.model.layers.23.mlp.gate_proj.weight": "model-3-of-5.safetensors",
|
| 66 |
+
"vision_model.radio_model.model.blocks.6.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 67 |
+
"vision_model.radio_model.model.blocks.25.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 68 |
+
"language_model.model.layers.27.self_attn.k_proj.weight": "model-4-of-5.safetensors",
|
| 69 |
+
"language_model.model.layers.2.post_attention_layernorm.weight": "model-1-of-5.safetensors",
|
| 70 |
+
"language_model.model.layers.25.linear_attn.in_proj_b.weight": "model-4-of-5.safetensors",
|
| 71 |
+
"language_model.model.layers.20.linear_attn.in_proj_qkv.weight": "model-3-of-5.safetensors",
|
| 72 |
+
"vision_model.radio_model.model.blocks.27.norm2.bias": "model-5-of-5.safetensors",
|
| 73 |
+
"vision_model.radio_model.model.blocks.0.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 74 |
+
"language_model.model.layers.12.linear_attn.dt_bias": "model-2-of-5.safetensors",
|
| 75 |
+
"vision_model.radio_model.model.blocks.18.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 76 |
+
"vision_model.radio_model.model.blocks.29.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 77 |
+
"language_model.model.layers.30.linear_attn.in_proj_z.weight": "model-4-of-5.safetensors",
|
| 78 |
+
"vision_model.radio_model.model.blocks.15.norm2.bias": "model-5-of-5.safetensors",
|
| 79 |
+
"language_model.model.layers.2.mlp.up_proj.weight": "model-1-of-5.safetensors",
|
| 80 |
+
"vision_model.radio_model.model.blocks.16.norm1.bias": "model-5-of-5.safetensors",
|
| 81 |
+
"language_model.model.layers.19.input_layernorm.weight": "model-3-of-5.safetensors",
|
| 82 |
+
"vision_model.radio_model.model.blocks.27.attn.proj.weight": "model-5-of-5.safetensors",
|
| 83 |
+
"language_model.model.layers.3.input_layernorm.weight": "model-1-of-5.safetensors",
|
| 84 |
+
"vision_model.radio_model.model.blocks.20.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 85 |
+
"language_model.model.layers.17.linear_attn.norm.weight": "model-3-of-5.safetensors",
|
| 86 |
+
"vision_model.radio_model.model.blocks.31.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 87 |
+
"language_model.model.layers.8.linear_attn.in_proj_b.weight": "model-2-of-5.safetensors",
|
| 88 |
+
"language_model.model.layers.1.input_layernorm.weight": "model-1-of-5.safetensors",
|
| 89 |
+
"language_model.model.layers.17.mlp.up_proj.weight": "model-3-of-5.safetensors",
|
| 90 |
+
"language_model.model.layers.16.post_attention_layernorm.weight": "model-3-of-5.safetensors",
|
| 91 |
+
"vision_model.radio_model.model.blocks.30.norm2.bias": "model-5-of-5.safetensors",
|
| 92 |
+
"vision_model.radio_model.model.blocks.22.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 93 |
+
"language_model.model.layers.14.linear_attn.dt_bias": "model-2-of-5.safetensors",
|
| 94 |
+
"language_model.model.layers.5.linear_attn.out_proj.weight": "model-2-of-5.safetensors",
|
| 95 |
+
"vision_model.radio_model.model.blocks.12.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 96 |
+
"vision_model.radio_model.model.blocks.16.norm2.bias": "model-5-of-5.safetensors",
|
| 97 |
+
"language_model.model.layers.28.linear_attn.conv1d.weight": "model-4-of-5.safetensors",
|
| 98 |
+
"vision_model.radio_model.model.blocks.29.attn.proj.bias": "model-5-of-5.safetensors",
|
| 99 |
+
"language_model.model.layers.2.linear_attn.in_proj_b.weight": "model-1-of-5.safetensors",
|
| 100 |
+
"language_model.model.layers.28.mlp.down_proj.weight": "model-4-of-5.safetensors",
|
| 101 |
+
"language_model.model.layers.9.linear_attn.in_proj_qkv.weight": "model-2-of-5.safetensors",
|
| 102 |
+
"language_model.model.layers.3.mlp.up_proj.weight": "model-1-of-5.safetensors",
|
| 103 |
+
"vision_model.radio_model.model.blocks.26.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 104 |
+
"language_model.model.layers.12.linear_attn.in_proj_b.weight": "model-2-of-5.safetensors",
|
| 105 |
+
"language_model.model.layers.2.linear_attn.dt_bias": "model-1-of-5.safetensors",
|
| 106 |
+
"language_model.model.layers.6.mlp.down_proj.weight": "model-2-of-5.safetensors",
|
| 107 |
+
"vision_model.radio_model.model.blocks.25.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 108 |
+
"vision_model.radio_model.model.blocks.8.norm2.bias": "model-5-of-5.safetensors",
|
| 109 |
+
"vision_model.radio_model.model.blocks.11.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 110 |
+
"language_model.model.layers.4.post_attention_layernorm.weight": "model-1-of-5.safetensors",
|
| 111 |
+
"vision_model.radio_model.model.blocks.24.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 112 |
+
"language_model.model.layers.17.mlp.down_proj.weight": "model-3-of-5.safetensors",
|
| 113 |
+
"vision_model.radio_model.model.blocks.23.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 114 |
+
"language_model.model.layers.1.linear_attn.out_proj.weight": "model-1-of-5.safetensors",
|
| 115 |
+
"language_model.model.layers.14.linear_attn.norm.weight": "model-2-of-5.safetensors",
|
| 116 |
+
"vision_model.radio_model.model.blocks.21.norm1.bias": "model-5-of-5.safetensors",
|
| 117 |
+
"vision_model.radio_model.model.blocks.9.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 118 |
+
"language_model.model.layers.24.input_layernorm.weight": "model-3-of-5.safetensors",
|
| 119 |
+
"vision_model.radio_model.model.blocks.17.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 120 |
+
"vision_model.radio_model.model.blocks.21.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 121 |
+
"vision_model.radio_model.model.blocks.3.norm2.bias": "model-5-of-5.safetensors",
|
| 122 |
+
"language_model.model.layers.29.linear_attn.in_proj_qkv.weight": "model-4-of-5.safetensors",
|
| 123 |
+
"language_model.model.layers.30.linear_attn.conv1d.weight": "model-4-of-5.safetensors",
|
| 124 |
+
"language_model.model.layers.15.mlp.down_proj.weight": "model-3-of-5.safetensors",
|
| 125 |
+
"vision_model.radio_model.model.blocks.26.norm1.bias": "model-5-of-5.safetensors",
|
| 126 |
+
"language_model.model.layers.26.linear_attn.in_proj_qkv.weight": "model-4-of-5.safetensors",
|
| 127 |
+
"vision_model.radio_model.model.blocks.30.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 128 |
+
"vision_model.radio_model.model.blocks.31.norm2.weight": "model-5-of-5.safetensors",
|
| 129 |
+
"vision_model.radio_model.model.blocks.15.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 130 |
+
"vision_model.radio_model.model.blocks.14.norm2.bias": "model-5-of-5.safetensors",
|
| 131 |
+
"vision_model.radio_model.model.blocks.23.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 132 |
+
"vision_model.radio_model.model.blocks.20.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 133 |
+
"vision_model.radio_model.model.blocks.22.norm2.bias": "model-5-of-5.safetensors",
|
| 134 |
+
"vision_model.radio_model.model.blocks.8.norm1.weight": "model-5-of-5.safetensors",
|
| 135 |
+
"language_model.model.layers.28.linear_attn.in_proj_z.weight": "model-4-of-5.safetensors",
|
| 136 |
+
"language_model.model.layers.10.linear_attn.in_proj_b.weight": "model-2-of-5.safetensors",
|
| 137 |
+
"language_model.model.layers.10.linear_attn.conv1d.weight": "model-2-of-5.safetensors",
|
| 138 |
+
"language_model.model.layers.8.linear_attn.dt_bias": "model-2-of-5.safetensors",
|
| 139 |
+
"language_model.model.layers.16.mlp.gate_proj.weight": "model-3-of-5.safetensors",
|
| 140 |
+
"language_model.model.layers.22.post_attention_layernorm.weight": "model-3-of-5.safetensors",
|
| 141 |
+
"vision_model.radio_model.model.blocks.21.attn.proj.weight": "model-5-of-5.safetensors",
|
| 142 |
+
"language_model.model.layers.1.linear_attn.in_proj_qkv.weight": "model-1-of-5.safetensors",
|
| 143 |
+
"language_model.model.layers.7.post_attention_layernorm.weight": "model-2-of-5.safetensors",
|
| 144 |
+
"language_model.model.layers.15.post_attention_layernorm.weight": "model-3-of-5.safetensors",
|
| 145 |
+
"language_model.model.layers.18.linear_attn.norm.weight": "model-3-of-5.safetensors",
|
| 146 |
+
"vision_model.radio_model.model.blocks.24.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 147 |
+
"language_model.model.layers.12.post_attention_layernorm.weight": "model-2-of-5.safetensors",
|
| 148 |
+
"vision_model.radio_model.model.blocks.28.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 149 |
+
"vision_model.radio_model.model.blocks.13.norm2.weight": "model-5-of-5.safetensors",
|
| 150 |
+
"vision_model.radio_model.model.blocks.14.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 151 |
+
"vision_model.radio_model.model.blocks.28.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 152 |
+
"vision_model.radio_model.model.blocks.16.norm1.weight": "model-5-of-5.safetensors",
|
| 153 |
+
"vision_model.radio_model.model.blocks.7.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 154 |
+
"vision_model.radio_model.model.blocks.3.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 155 |
+
"language_model.model.layers.8.mlp.up_proj.weight": "model-2-of-5.safetensors",
|
| 156 |
+
"language_model.model.layers.7.self_attn.q_norm.weight": "model-2-of-5.safetensors",
|
| 157 |
+
"language_model.model.layers.18.linear_attn.A_log": "model-3-of-5.safetensors",
|
| 158 |
+
"language_model.model.layers.2.linear_attn.in_proj_z.weight": "model-1-of-5.safetensors",
|
| 159 |
+
"vision_model.radio_model.model.blocks.10.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 160 |
+
"language_model.model.layers.27.self_attn.o_proj.weight": "model-4-of-5.safetensors",
|
| 161 |
+
"language_model.model.layers.22.linear_attn.dt_bias": "model-3-of-5.safetensors",
|
| 162 |
+
"vision_model.radio_model.model.blocks.24.norm2.bias": "model-5-of-5.safetensors",
|
| 163 |
+
"vision_model.radio_model.model.blocks.30.norm1.bias": "model-5-of-5.safetensors",
|
| 164 |
+
"language_model.model.layers.5.linear_attn.dt_bias": "model-1-of-5.safetensors",
|
| 165 |
+
"language_model.model.layers.23.self_attn.v_proj.weight": "model-3-of-5.safetensors",
|
| 166 |
+
"vision_model.radio_model.model.blocks.10.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 167 |
+
"language_model.model.layers.4.mlp.gate_proj.weight": "model-1-of-5.safetensors",
|
| 168 |
+
"language_model.model.layers.17.linear_attn.dt_bias": "model-3-of-5.safetensors",
|
| 169 |
+
"language_model.model.layers.8.post_attention_layernorm.weight": "model-2-of-5.safetensors",
|
| 170 |
+
"vision_model.radio_model.model.blocks.14.attn.proj.weight": "model-5-of-5.safetensors",
|
| 171 |
+
"vision_model.radio_model.model.blocks.12.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 172 |
+
"language_model.model.layers.19.mlp.gate_proj.weight": "model-3-of-5.safetensors",
|
| 173 |
+
"vision_model.radio_model.model.blocks.15.norm1.bias": "model-5-of-5.safetensors",
|
| 174 |
+
"vision_model.radio_model.model.blocks.16.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 175 |
+
"language_model.model.layers.9.mlp.down_proj.weight": "model-2-of-5.safetensors",
|
| 176 |
+
"vision_model.radio_model.model.blocks.19.norm1.bias": "model-5-of-5.safetensors",
|
| 177 |
+
"language_model.model.layers.2.mlp.down_proj.weight": "model-1-of-5.safetensors",
|
| 178 |
+
"language_model.model.layers.7.self_attn.o_proj.weight": "model-2-of-5.safetensors",
|
| 179 |
+
"vision_model.radio_model.model.blocks.20.norm1.bias": "model-5-of-5.safetensors",
|
| 180 |
+
"language_model.model.layers.31.mlp.down_proj.weight": "model-4-of-5.safetensors",
|
| 181 |
+
"language_model.model.layers.29.linear_attn.dt_bias": "model-4-of-5.safetensors",
|
| 182 |
+
"vision_model.radio_model.model.blocks.9.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 183 |
+
"vision_model.radio_model.model.blocks.20.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 184 |
+
"language_model.model.layers.28.linear_attn.A_log": "model-4-of-5.safetensors",
|
| 185 |
+
"vision_model.radio_model.model.blocks.11.attn.proj.weight": "model-5-of-5.safetensors",
|
| 186 |
+
"vision_model.radio_model.model.blocks.31.norm1.bias": "model-5-of-5.safetensors",
|
| 187 |
+
"vision_model.radio_model.model.blocks.24.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 188 |
+
"language_model.model.layers.22.linear_attn.in_proj_b.weight": "model-3-of-5.safetensors",
|
| 189 |
+
"language_model.model.layers.6.linear_attn.in_proj_qkv.weight": "model-2-of-5.safetensors",
|
| 190 |
+
"language_model.model.layers.25.linear_attn.conv1d.weight": "model-4-of-5.safetensors",
|
| 191 |
+
"vision_model.radio_model.model.blocks.4.norm2.weight": "model-5-of-5.safetensors",
|
| 192 |
+
"vision_model.radio_model.model.blocks.10.norm1.bias": "model-5-of-5.safetensors",
|
| 193 |
+
"vision_model.radio_model.model.blocks.23.attn.proj.bias": "model-5-of-5.safetensors",
|
| 194 |
+
"vision_model.radio_model.model.blocks.9.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 195 |
+
"vision_model.radio_model.input_conditioner.norm_std": "model-5-of-5.safetensors",
|
| 196 |
+
"language_model.model.layers.11.self_attn.o_proj.weight": "model-2-of-5.safetensors",
|
| 197 |
+
"language_model.model.layers.7.self_attn.k_proj.weight": "model-2-of-5.safetensors",
|
| 198 |
+
"language_model.model.layers.4.linear_attn.in_proj_b.weight": "model-1-of-5.safetensors",
|
| 199 |
+
"vision_model.radio_model.model.blocks.16.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 200 |
+
"language_model.model.layers.9.input_layernorm.weight": "model-2-of-5.safetensors",
|
| 201 |
+
"language_model.model.layers.10.linear_attn.in_proj_z.weight": "model-2-of-5.safetensors",
|
| 202 |
+
"language_model.model.layers.31.post_attention_layernorm.weight": "model-4-of-5.safetensors",
|
| 203 |
+
"mlp1.1.weight": "model-5-of-5.safetensors",
|
| 204 |
+
"language_model.model.layers.18.linear_attn.dt_bias": "model-3-of-5.safetensors",
|
| 205 |
+
"vision_model.radio_model.model.blocks.17.norm2.weight": "model-5-of-5.safetensors",
|
| 206 |
+
"language_model.model.layers.20.linear_attn.norm.weight": "model-3-of-5.safetensors",
|
| 207 |
+
"language_model.model.layers.7.self_attn.v_proj.weight": "model-2-of-5.safetensors",
|
| 208 |
+
"vision_model.radio_model.model.blocks.28.attn.proj.bias": "model-5-of-5.safetensors",
|
| 209 |
+
"vision_model.radio_model.model.blocks.12.norm1.bias": "model-5-of-5.safetensors",
|
| 210 |
+
"language_model.model.layers.8.linear_attn.in_proj_a.weight": "model-2-of-5.safetensors",
|
| 211 |
+
"vision_model.radio_model.model.blocks.8.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 212 |
+
"vision_model.radio_model.model.blocks.16.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 213 |
+
"vision_model.radio_model.model.blocks.21.norm2.weight": "model-5-of-5.safetensors",
|
| 214 |
+
"language_model.model.layers.26.linear_attn.in_proj_a.weight": "model-4-of-5.safetensors",
|
| 215 |
+
"language_model.model.layers.11.self_attn.k_proj.weight": "model-2-of-5.safetensors",
|
| 216 |
+
"vision_model.radio_model.model.blocks.18.norm2.bias": "model-5-of-5.safetensors",
|
| 217 |
+
"language_model.model.layers.12.mlp.down_proj.weight": "model-2-of-5.safetensors",
|
| 218 |
+
"vision_model.radio_model.model.blocks.9.attn.proj.weight": "model-5-of-5.safetensors",
|
| 219 |
+
"language_model.model.layers.0.mlp.up_proj.weight": "model-1-of-5.safetensors",
|
| 220 |
+
"language_model.model.layers.9.mlp.up_proj.weight": "model-2-of-5.safetensors",
|
| 221 |
+
"language_model.model.layers.19.self_attn.q_norm.weight": "model-3-of-5.safetensors",
|
| 222 |
+
"language_model.model.layers.28.mlp.up_proj.weight": "model-4-of-5.safetensors",
|
| 223 |
+
"language_model.model.layers.20.mlp.down_proj.weight": "model-3-of-5.safetensors",
|
| 224 |
+
"language_model.model.layers.17.linear_attn.in_proj_a.weight": "model-3-of-5.safetensors",
|
| 225 |
+
"vision_model.radio_model.model.blocks.5.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 226 |
+
"language_model.model.layers.24.mlp.down_proj.weight": "model-3-of-5.safetensors",
|
| 227 |
+
"vision_model.radio_model.model.blocks.19.norm1.weight": "model-5-of-5.safetensors",
|
| 228 |
+
"language_model.model.layers.25.linear_attn.in_proj_z.weight": "model-4-of-5.safetensors",
|
| 229 |
+
"vision_model.radio_model.model.blocks.19.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 230 |
+
"language_model.model.layers.14.mlp.up_proj.weight": "model-2-of-5.safetensors",
|
| 231 |
+
"vision_model.radio_model.model.blocks.22.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 232 |
+
"language_model.model.layers.6.mlp.gate_proj.weight": "model-2-of-5.safetensors",
|
| 233 |
+
"vision_model.radio_model.model.blocks.2.norm1.weight": "model-5-of-5.safetensors",
|
| 234 |
+
"language_model.model.layers.28.linear_attn.out_proj.weight": "model-4-of-5.safetensors",
|
| 235 |
+
"language_model.model.layers.30.linear_attn.norm.weight": "model-4-of-5.safetensors",
|
| 236 |
+
"language_model.model.layers.11.mlp.up_proj.weight": "model-2-of-5.safetensors",
|
| 237 |
+
"language_model.model.layers.23.mlp.up_proj.weight": "model-3-of-5.safetensors",
|
| 238 |
+
"language_model.model.layers.14.mlp.down_proj.weight": "model-2-of-5.safetensors",
|
| 239 |
+
"vision_model.radio_model.model.blocks.17.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 240 |
+
"vision_model.radio_model.model.blocks.17.attn.proj.weight": "model-5-of-5.safetensors",
|
| 241 |
+
"vision_model.radio_model.model.blocks.5.norm2.bias": "model-5-of-5.safetensors",
|
| 242 |
+
"language_model.model.layers.6.linear_attn.dt_bias": "model-2-of-5.safetensors",
|
| 243 |
+
"language_model.model.layers.22.linear_attn.out_proj.weight": "model-3-of-5.safetensors",
|
| 244 |
+
"language_model.model.layers.30.linear_attn.dt_bias": "model-4-of-5.safetensors",
|
| 245 |
+
"vision_model.radio_model.model.blocks.13.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 246 |
+
"language_model.model.layers.18.linear_attn.out_proj.weight": "model-3-of-5.safetensors",
|
| 247 |
+
"language_model.model.layers.9.linear_attn.in_proj_z.weight": "model-2-of-5.safetensors",
|
| 248 |
+
"vision_model.radio_model.model.blocks.31.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 249 |
+
"language_model.model.layers.3.self_attn.k_proj.weight": "model-1-of-5.safetensors",
|
| 250 |
+
"language_model.model.layers.19.self_attn.k_proj.weight": "model-3-of-5.safetensors",
|
| 251 |
+
"vision_model.radio_model.model.blocks.27.norm1.weight": "model-5-of-5.safetensors",
|
| 252 |
+
"vision_model.radio_model.model.blocks.27.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 253 |
+
"language_model.model.layers.29.linear_attn.in_proj_z.weight": "model-4-of-5.safetensors",
|
| 254 |
+
"vision_model.radio_model.model.blocks.28.attn.proj.weight": "model-5-of-5.safetensors",
|
| 255 |
+
"vision_model.radio_model.model.blocks.6.attn.proj.bias": "model-5-of-5.safetensors",
|
| 256 |
+
"language_model.model.layers.15.self_attn.q_proj.weight": "model-3-of-5.safetensors",
|
| 257 |
+
"language_model.model.layers.25.linear_attn.out_proj.weight": "model-4-of-5.safetensors",
|
| 258 |
+
"language_model.model.layers.28.input_layernorm.weight": "model-4-of-5.safetensors",
|
| 259 |
+
"vision_model.radio_model.model.blocks.15.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 260 |
+
"vision_model.radio_model.model.blocks.14.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 261 |
+
"vision_model.radio_model.model.blocks.18.attn.proj.weight": "model-5-of-5.safetensors",
|
| 262 |
+
"vision_model.radio_model.model.blocks.5.norm2.weight": "model-5-of-5.safetensors",
|
| 263 |
+
"language_model.model.layers.21.linear_attn.conv1d.weight": "model-3-of-5.safetensors",
|
| 264 |
+
"vision_model.radio_model.model.blocks.9.norm2.weight": "model-5-of-5.safetensors",
|
| 265 |
+
"language_model.model.layers.12.linear_attn.conv1d.weight": "model-2-of-5.safetensors",
|
| 266 |
+
"language_model.model.layers.24.linear_attn.A_log": "model-3-of-5.safetensors",
|
| 267 |
+
"vision_model.radio_model.model.blocks.18.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 268 |
+
"vision_model.radio_model.model.blocks.10.attn.proj.weight": "model-5-of-5.safetensors",
|
| 269 |
+
"language_model.model.embed_tokens.weight": "model-1-of-5.safetensors",
|
| 270 |
+
"vision_model.radio_model.model.blocks.0.norm1.weight": "model-5-of-5.safetensors",
|
| 271 |
+
"vision_model.radio_model.model.blocks.23.norm1.weight": "model-5-of-5.safetensors",
|
| 272 |
+
"language_model.model.layers.26.linear_attn.norm.weight": "model-4-of-5.safetensors",
|
| 273 |
+
"language_model.model.layers.13.linear_attn.conv1d.weight": "model-2-of-5.safetensors",
|
| 274 |
+
"language_model.model.layers.15.mlp.gate_proj.weight": "model-3-of-5.safetensors",
|
| 275 |
+
"language_model.model.layers.26.linear_attn.out_proj.weight": "model-4-of-5.safetensors",
|
| 276 |
+
"vision_model.radio_model.model.blocks.11.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 277 |
+
"language_model.model.layers.15.mlp.up_proj.weight": "model-3-of-5.safetensors",
|
| 278 |
+
"language_model.model.layers.0.linear_attn.in_proj_z.weight": "model-1-of-5.safetensors",
|
| 279 |
+
"language_model.model.layers.20.linear_attn.in_proj_b.weight": "model-3-of-5.safetensors",
|
| 280 |
+
"vision_model.radio_model.model.blocks.0.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 281 |
+
"language_model.model.layers.4.mlp.up_proj.weight": "model-1-of-5.safetensors",
|
| 282 |
+
"language_model.model.layers.10.linear_attn.norm.weight": "model-2-of-5.safetensors",
|
| 283 |
+
"vision_model.radio_model.model.blocks.22.norm1.bias": "model-5-of-5.safetensors",
|
| 284 |
+
"vision_model.radio_model.model.blocks.1.norm1.bias": "model-5-of-5.safetensors",
|
| 285 |
+
"vision_model.radio_model.model.blocks.4.attn.proj.weight": "model-5-of-5.safetensors",
|
| 286 |
+
"vision_model.radio_model.model.blocks.28.norm2.weight": "model-5-of-5.safetensors",
|
| 287 |
+
"language_model.model.layers.20.input_layernorm.weight": "model-3-of-5.safetensors",
|
| 288 |
+
"language_model.model.layers.20.mlp.up_proj.weight": "model-3-of-5.safetensors",
|
| 289 |
+
"language_model.model.layers.1.linear_attn.in_proj_z.weight": "model-1-of-5.safetensors",
|
| 290 |
+
"language_model.model.layers.7.mlp.down_proj.weight": "model-2-of-5.safetensors",
|
| 291 |
+
"language_model.model.layers.8.linear_attn.out_proj.weight": "model-2-of-5.safetensors",
|
| 292 |
+
"vision_model.radio_model.model.blocks.12.norm2.weight": "model-5-of-5.safetensors",
|
| 293 |
+
"vision_model.radio_model.model.blocks.31.attn.proj.weight": "model-5-of-5.safetensors",
|
| 294 |
+
"language_model.model.layers.27.mlp.gate_proj.weight": "model-4-of-5.safetensors",
|
| 295 |
+
"vision_model.radio_model.model.blocks.21.norm2.bias": "model-5-of-5.safetensors",
|
| 296 |
+
"vision_model.radio_model.model.blocks.17.norm1.weight": "model-5-of-5.safetensors",
|
| 297 |
+
"language_model.model.layers.26.input_layernorm.weight": "model-4-of-5.safetensors",
|
| 298 |
+
"vision_model.radio_model.model.blocks.18.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 299 |
+
"language_model.model.layers.26.mlp.up_proj.weight": "model-4-of-5.safetensors",
|
| 300 |
+
"language_model.model.layers.26.mlp.gate_proj.weight": "model-4-of-5.safetensors",
|
| 301 |
+
"language_model.model.layers.26.linear_attn.in_proj_b.weight": "model-4-of-5.safetensors",
|
| 302 |
+
"vision_model.radio_model.model.blocks.4.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 303 |
+
"language_model.model.layers.17.mlp.gate_proj.weight": "model-3-of-5.safetensors",
|
| 304 |
+
"language_model.model.layers.26.linear_attn.conv1d.weight": "model-4-of-5.safetensors",
|
| 305 |
+
"vision_model.radio_model.model.blocks.14.attn.proj.bias": "model-5-of-5.safetensors",
|
| 306 |
+
"language_model.model.layers.2.linear_attn.norm.weight": "model-1-of-5.safetensors",
|
| 307 |
+
"language_model.model.layers.9.linear_attn.norm.weight": "model-2-of-5.safetensors",
|
| 308 |
+
"language_model.model.layers.19.self_attn.v_proj.weight": "model-3-of-5.safetensors",
|
| 309 |
+
"vision_model.radio_model.model.blocks.2.norm2.weight": "model-5-of-5.safetensors",
|
| 310 |
+
"language_model.model.layers.4.linear_attn.conv1d.weight": "model-1-of-5.safetensors",
|
| 311 |
+
"language_model.model.layers.0.linear_attn.in_proj_b.weight": "model-1-of-5.safetensors",
|
| 312 |
+
"language_model.model.layers.16.linear_attn.norm.weight": "model-3-of-5.safetensors",
|
| 313 |
+
"vision_model.radio_model.model.blocks.31.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 314 |
+
"vision_model.radio_model.model.blocks.31.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 315 |
+
"vision_model.radio_model.model.blocks.2.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 316 |
+
"vision_model.radio_model.model.blocks.18.attn.proj.bias": "model-5-of-5.safetensors",
|
| 317 |
+
"language_model.model.layers.25.linear_attn.A_log": "model-4-of-5.safetensors",
|
| 318 |
+
"vision_model.radio_model.model.blocks.8.norm1.bias": "model-5-of-5.safetensors",
|
| 319 |
+
"language_model.model.layers.28.linear_attn.in_proj_a.weight": "model-4-of-5.safetensors",
|
| 320 |
+
"mlp1.3.weight": "model-5-of-5.safetensors",
|
| 321 |
+
"language_model.model.layers.0.post_attention_layernorm.weight": "model-1-of-5.safetensors",
|
| 322 |
+
"language_model.model.layers.15.self_attn.q_norm.weight": "model-3-of-5.safetensors",
|
| 323 |
+
"vision_model.radio_model.model.blocks.3.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 324 |
+
"vision_model.radio_model.model.blocks.13.attn.proj.bias": "model-5-of-5.safetensors",
|
| 325 |
+
"vision_model.radio_model.model.blocks.26.attn.proj.weight": "model-5-of-5.safetensors",
|
| 326 |
+
"language_model.model.layers.30.linear_attn.in_proj_b.weight": "model-4-of-5.safetensors",
|
| 327 |
+
"language_model.model.layers.25.mlp.up_proj.weight": "model-4-of-5.safetensors",
|
| 328 |
+
"vision_model.radio_model.model.blocks.18.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 329 |
+
"language_model.model.layers.6.linear_attn.out_proj.weight": "model-2-of-5.safetensors",
|
| 330 |
+
"vision_model.radio_model.model.blocks.17.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 331 |
+
"vision_model.radio_model.summary_idxs": "model-5-of-5.safetensors",
|
| 332 |
+
"vision_model.radio_model.model.blocks.0.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 333 |
+
"language_model.model.layers.11.mlp.down_proj.weight": "model-2-of-5.safetensors",
|
| 334 |
+
"language_model.model.layers.12.mlp.gate_proj.weight": "model-2-of-5.safetensors",
|
| 335 |
+
"language_model.model.layers.21.linear_attn.A_log": "model-3-of-5.safetensors",
|
| 336 |
+
"vision_model.radio_model.model.blocks.25.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 337 |
+
"vision_model.radio_model.model.blocks.23.norm2.weight": "model-5-of-5.safetensors",
|
| 338 |
+
"vision_model.radio_model.model.blocks.10.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 339 |
+
"language_model.model.layers.9.mlp.gate_proj.weight": "model-2-of-5.safetensors",
|
| 340 |
+
"language_model.model.layers.2.input_layernorm.weight": "model-1-of-5.safetensors",
|
| 341 |
+
"vision_model.radio_model.model.blocks.7.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 342 |
+
"language_model.model.layers.27.self_attn.v_proj.weight": "model-4-of-5.safetensors",
|
| 343 |
+
"vision_model.radio_model.model.blocks.25.attn.proj.bias": "model-5-of-5.safetensors",
|
| 344 |
+
"language_model.model.layers.5.linear_attn.in_proj_b.weight": "model-1-of-5.safetensors",
|
| 345 |
+
"vision_model.radio_model.model.blocks.3.norm1.bias": "model-5-of-5.safetensors",
|
| 346 |
+
"language_model.model.layers.0.linear_attn.conv1d.weight": "model-1-of-5.safetensors",
|
| 347 |
+
"language_model.model.layers.20.linear_attn.in_proj_z.weight": "model-3-of-5.safetensors",
|
| 348 |
+
"vision_model.radio_model.model.blocks.25.norm2.bias": "model-5-of-5.safetensors",
|
| 349 |
+
"language_model.model.layers.16.linear_attn.out_proj.weight": "model-3-of-5.safetensors",
|
| 350 |
+
"language_model.model.layers.17.linear_attn.out_proj.weight": "model-3-of-5.safetensors",
|
| 351 |
+
"vision_model.radio_model.model.blocks.10.norm2.weight": "model-5-of-5.safetensors",
|
| 352 |
+
"vision_model.radio_model.model.blocks.15.norm1.weight": "model-5-of-5.safetensors",
|
| 353 |
+
"vision_model.radio_model.model.blocks.12.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 354 |
+
"vision_model.radio_model.model.blocks.29.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 355 |
+
"language_model.model.layers.3.self_attn.q_proj.weight": "model-1-of-5.safetensors",
|
| 356 |
+
"vision_model.radio_model.model.blocks.13.norm1.bias": "model-5-of-5.safetensors",
|
| 357 |
+
"language_model.model.layers.19.self_attn.q_proj.weight": "model-3-of-5.safetensors",
|
| 358 |
+
"language_model.model.layers.30.mlp.up_proj.weight": "model-4-of-5.safetensors",
|
| 359 |
+
"vision_model.radio_model.model.blocks.30.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 360 |
+
"vision_model.radio_model.model.blocks.21.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 361 |
+
"vision_model.radio_model.model.blocks.29.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 362 |
+
"language_model.model.layers.27.post_attention_layernorm.weight": "model-4-of-5.safetensors",
|
| 363 |
+
"vision_model.radio_model.model.blocks.28.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 364 |
+
"vision_model.radio_model.model.blocks.7.attn.proj.bias": "model-5-of-5.safetensors",
|
| 365 |
+
"vision_model.radio_model.model.blocks.6.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 366 |
+
"vision_model.radio_model.model.blocks.11.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 367 |
+
"language_model.model.layers.0.linear_attn.in_proj_qkv.weight": "model-1-of-5.safetensors",
|
| 368 |
+
"language_model.model.layers.12.linear_attn.A_log": "model-2-of-5.safetensors",
|
| 369 |
+
"language_model.model.layers.27.self_attn.k_norm.weight": "model-4-of-5.safetensors",
|
| 370 |
+
"vision_model.radio_model.model.patch_generator.pos_embed": "model-5-of-5.safetensors",
|
| 371 |
+
"language_model.model.layers.14.linear_attn.in_proj_qkv.weight": "model-2-of-5.safetensors",
|
| 372 |
+
"language_model.model.layers.23.self_attn.k_norm.weight": "model-3-of-5.safetensors",
|
| 373 |
+
"language_model.model.layers.1.mlp.down_proj.weight": "model-1-of-5.safetensors",
|
| 374 |
+
"language_model.model.layers.13.mlp.up_proj.weight": "model-2-of-5.safetensors",
|
| 375 |
+
"vision_model.radio_model.model.blocks.29.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 376 |
+
"vision_model.radio_model.input_conditioner.norm_mean": "model-5-of-5.safetensors",
|
| 377 |
+
"vision_model.radio_model.model.blocks.0.attn.proj.bias": "model-5-of-5.safetensors",
|
| 378 |
+
"language_model.model.layers.5.mlp.gate_proj.weight": "model-2-of-5.safetensors",
|
| 379 |
+
"language_model.model.layers.11.self_attn.k_norm.weight": "model-2-of-5.safetensors",
|
| 380 |
+
"vision_model.radio_model.model.blocks.18.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 381 |
+
"vision_model.radio_model.model.blocks.15.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 382 |
+
"vision_model.radio_model.model.blocks.14.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 383 |
+
"vision_model.radio_model.model.blocks.13.attn.proj.weight": "model-5-of-5.safetensors",
|
| 384 |
+
"vision_model.radio_model.model.blocks.26.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 385 |
+
"language_model.model.layers.31.mlp.gate_proj.weight": "model-4-of-5.safetensors",
|
| 386 |
+
"vision_model.radio_model.model.blocks.10.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 387 |
+
"language_model.model.layers.10.post_attention_layernorm.weight": "model-2-of-5.safetensors",
|
| 388 |
+
"language_model.model.layers.31.mlp.up_proj.weight": "model-4-of-5.safetensors",
|
| 389 |
+
"vision_model.radio_model.model.blocks.16.norm2.weight": "model-5-of-5.safetensors",
|
| 390 |
+
"vision_model.radio_model.model.blocks.14.norm1.bias": "model-5-of-5.safetensors",
|
| 391 |
+
"vision_model.radio_model.model.patch_generator.embedder.weight": "model-5-of-5.safetensors",
|
| 392 |
+
"language_model.model.layers.20.mlp.gate_proj.weight": "model-3-of-5.safetensors",
|
| 393 |
+
"vision_model.radio_model.model.blocks.18.norm1.bias": "model-5-of-5.safetensors",
|
| 394 |
+
"language_model.model.layers.28.linear_attn.dt_bias": "model-4-of-5.safetensors",
|
| 395 |
+
"vision_model.radio_model.model.blocks.28.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 396 |
+
"language_model.model.layers.20.post_attention_layernorm.weight": "model-3-of-5.safetensors",
|
| 397 |
+
"language_model.model.layers.21.linear_attn.in_proj_a.weight": "model-3-of-5.safetensors",
|
| 398 |
+
"language_model.model.layers.24.post_attention_layernorm.weight": "model-4-of-5.safetensors",
|
| 399 |
+
"language_model.model.layers.4.linear_attn.in_proj_a.weight": "model-1-of-5.safetensors",
|
| 400 |
+
"language_model.model.layers.16.linear_attn.in_proj_b.weight": "model-3-of-5.safetensors",
|
| 401 |
+
"vision_model.radio_model.model.blocks.5.norm1.bias": "model-5-of-5.safetensors",
|
| 402 |
+
"vision_model.radio_model.model.blocks.17.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 403 |
+
"vision_model.radio_model.model.blocks.11.norm2.bias": "model-5-of-5.safetensors",
|
| 404 |
+
"vision_model.radio_model.model.blocks.11.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 405 |
+
"language_model.model.layers.10.linear_attn.in_proj_a.weight": "model-2-of-5.safetensors",
|
| 406 |
+
"language_model.model.layers.3.self_attn.v_proj.weight": "model-1-of-5.safetensors",
|
| 407 |
+
"language_model.model.layers.20.linear_attn.conv1d.weight": "model-3-of-5.safetensors",
|
| 408 |
+
"vision_model.radio_model.model.blocks.22.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 409 |
+
"vision_model.radio_model.model.blocks.1.attn.proj.bias": "model-5-of-5.safetensors",
|
| 410 |
+
"vision_model.radio_model.model.blocks.27.attn.proj.bias": "model-5-of-5.safetensors",
|
| 411 |
+
"vision_model.radio_model.model.blocks.0.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 412 |
+
"vision_model.radio_model.model.blocks.9.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 413 |
+
"language_model.model.layers.4.linear_attn.out_proj.weight": "model-1-of-5.safetensors",
|
| 414 |
+
"vision_model.radio_model.model.blocks.15.attn.proj.weight": "model-5-of-5.safetensors",
|
| 415 |
+
"language_model.model.layers.9.linear_attn.out_proj.weight": "model-2-of-5.safetensors",
|
| 416 |
+
"vision_model.radio_model.model.blocks.5.attn.proj.weight": "model-5-of-5.safetensors",
|
| 417 |
+
"language_model.model.layers.22.mlp.gate_proj.weight": "model-3-of-5.safetensors",
|
| 418 |
+
"language_model.model.layers.10.mlp.gate_proj.weight": "model-2-of-5.safetensors",
|
| 419 |
+
"language_model.model.layers.7.self_attn.q_proj.weight": "model-2-of-5.safetensors",
|
| 420 |
+
"vision_model.radio_model.model.blocks.28.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 421 |
+
"language_model.model.layers.28.linear_attn.in_proj_b.weight": "model-4-of-5.safetensors",
|
| 422 |
+
"language_model.model.layers.21.linear_attn.dt_bias": "model-3-of-5.safetensors",
|
| 423 |
+
"language_model.model.layers.1.linear_attn.in_proj_b.weight": "model-1-of-5.safetensors",
|
| 424 |
+
"vision_model.radio_model.model.blocks.24.norm1.bias": "model-5-of-5.safetensors",
|
| 425 |
+
"language_model.model.layers.24.linear_attn.in_proj_qkv.weight": "model-3-of-5.safetensors",
|
| 426 |
+
"vision_model.radio_model.model.blocks.0.norm2.bias": "model-5-of-5.safetensors",
|
| 427 |
+
"language_model.model.layers.27.self_attn.q_proj.weight": "model-4-of-5.safetensors",
|
| 428 |
+
"vision_model.radio_model.model.blocks.29.norm2.weight": "model-5-of-5.safetensors",
|
| 429 |
+
"vision_model.radio_model.model.blocks.5.attn.proj.bias": "model-5-of-5.safetensors",
|
| 430 |
+
"language_model.model.layers.11.self_attn.q_proj.weight": "model-2-of-5.safetensors",
|
| 431 |
+
"vision_model.radio_model.model.blocks.0.norm2.weight": "model-5-of-5.safetensors",
|
| 432 |
+
"vision_model.radio_model.model.blocks.1.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 433 |
+
"vision_model.radio_model.model.blocks.8.norm2.weight": "model-5-of-5.safetensors",
|
| 434 |
+
"vision_model.radio_model.model.blocks.22.attn.proj.bias": "model-5-of-5.safetensors",
|
| 435 |
+
"language_model.model.layers.13.linear_attn.dt_bias": "model-2-of-5.safetensors",
|
| 436 |
+
"vision_model.radio_model.model.blocks.17.attn.proj.bias": "model-5-of-5.safetensors",
|
| 437 |
+
"vision_model.radio_model.model.blocks.13.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 438 |
+
"language_model.model.layers.28.post_attention_layernorm.weight": "model-4-of-5.safetensors",
|
| 439 |
+
"language_model.model.layers.9.linear_attn.A_log": "model-2-of-5.safetensors",
|
| 440 |
+
"language_model.model.layers.12.mlp.up_proj.weight": "model-2-of-5.safetensors",
|
| 441 |
+
"vision_model.radio_model.model.blocks.9.norm2.bias": "model-5-of-5.safetensors",
|
| 442 |
+
"language_model.model.layers.18.linear_attn.conv1d.weight": "model-3-of-5.safetensors",
|
| 443 |
+
"vision_model.radio_model.model.blocks.7.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 444 |
+
"language_model.model.layers.30.linear_attn.A_log": "model-4-of-5.safetensors",
|
| 445 |
+
"language_model.model.layers.16.linear_attn.dt_bias": "model-3-of-5.safetensors",
|
| 446 |
+
"vision_model.radio_model.model.blocks.24.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 447 |
+
"language_model.model.layers.18.linear_attn.in_proj_b.weight": "model-3-of-5.safetensors",
|
| 448 |
+
"language_model.model.layers.6.linear_attn.in_proj_a.weight": "model-2-of-5.safetensors",
|
| 449 |
+
"vision_model.radio_model.model.blocks.7.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 450 |
+
"vision_model.radio_model.model.blocks.19.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 451 |
+
"language_model.model.layers.24.linear_attn.dt_bias": "model-3-of-5.safetensors",
|
| 452 |
+
"language_model.model.layers.21.linear_attn.norm.weight": "model-3-of-5.safetensors",
|
| 453 |
+
"language_model.model.layers.0.linear_attn.norm.weight": "model-1-of-5.safetensors",
|
| 454 |
+
"language_model.model.layers.17.input_layernorm.weight": "model-3-of-5.safetensors",
|
| 455 |
+
"vision_model.radio_model.model.blocks.5.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 456 |
+
"vision_model.radio_model.model.blocks.26.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 457 |
+
"language_model.model.layers.20.linear_attn.in_proj_a.weight": "model-3-of-5.safetensors",
|
| 458 |
+
"vision_model.radio_model.model.blocks.29.attn.proj.weight": "model-5-of-5.safetensors",
|
| 459 |
+
"language_model.model.layers.19.mlp.up_proj.weight": "model-3-of-5.safetensors",
|
| 460 |
+
"vision_model.radio_model.model.blocks.7.norm2.bias": "model-5-of-5.safetensors",
|
| 461 |
+
"vision_model.radio_model.model.blocks.12.norm2.bias": "model-5-of-5.safetensors",
|
| 462 |
+
"vision_model.radio_model.model.blocks.7.norm2.weight": "model-5-of-5.safetensors",
|
| 463 |
+
"vision_model.radio_model.model.blocks.6.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 464 |
+
"language_model.model.layers.21.input_layernorm.weight": "model-3-of-5.safetensors",
|
| 465 |
+
"vision_model.radio_model.model.blocks.31.norm1.weight": "model-5-of-5.safetensors",
|
| 466 |
+
"language_model.model.layers.0.mlp.down_proj.weight": "model-1-of-5.safetensors",
|
| 467 |
+
"vision_model.radio_model.model.blocks.12.attn.proj.bias": "model-5-of-5.safetensors",
|
| 468 |
+
"language_model.model.layers.18.mlp.down_proj.weight": "model-3-of-5.safetensors",
|
| 469 |
+
"language_model.model.layers.11.input_layernorm.weight": "model-2-of-5.safetensors",
|
| 470 |
+
"vision_model.radio_model.model.blocks.29.norm1.bias": "model-5-of-5.safetensors",
|
| 471 |
+
"language_model.model.layers.30.mlp.down_proj.weight": "model-4-of-5.safetensors",
|
| 472 |
+
"vision_model.radio_model.model.blocks.8.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 473 |
+
"vision_model.radio_model.model.blocks.2.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 474 |
+
"language_model.model.layers.1.mlp.gate_proj.weight": "model-1-of-5.safetensors",
|
| 475 |
+
"language_model.model.layers.27.input_layernorm.weight": "model-4-of-5.safetensors",
|
| 476 |
+
"vision_model.radio_model.model.blocks.25.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 477 |
+
"vision_model.radio_model.model.blocks.25.attn.proj.weight": "model-5-of-5.safetensors",
|
| 478 |
+
"language_model.model.layers.13.mlp.down_proj.weight": "model-2-of-5.safetensors",
|
| 479 |
+
"language_model.model.layers.18.mlp.up_proj.weight": "model-3-of-5.safetensors",
|
| 480 |
+
"vision_model.radio_model.model.blocks.6.norm2.bias": "model-5-of-5.safetensors",
|
| 481 |
+
"vision_model.radio_model.model.blocks.30.norm2.weight": "model-5-of-5.safetensors",
|
| 482 |
+
"vision_model.radio_model.model.blocks.5.norm1.weight": "model-5-of-5.safetensors",
|
| 483 |
+
"language_model.model.layers.5.post_attention_layernorm.weight": "model-2-of-5.safetensors",
|
| 484 |
+
"language_model.model.layers.16.input_layernorm.weight": "model-3-of-5.safetensors",
|
| 485 |
+
"language_model.model.layers.23.self_attn.o_proj.weight": "model-3-of-5.safetensors",
|
| 486 |
+
"language_model.model.layers.6.linear_attn.conv1d.weight": "model-2-of-5.safetensors",
|
| 487 |
+
"language_model.model.layers.6.post_attention_layernorm.weight": "model-2-of-5.safetensors",
|
| 488 |
+
"vision_model.radio_model.model.blocks.20.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 489 |
+
"language_model.model.layers.23.mlp.down_proj.weight": "model-3-of-5.safetensors",
|
| 490 |
+
"vision_model.radio_model.model.blocks.2.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 491 |
+
"language_model.model.layers.14.linear_attn.out_proj.weight": "model-2-of-5.safetensors",
|
| 492 |
+
"language_model.model.layers.4.linear_attn.A_log": "model-1-of-5.safetensors",
|
| 493 |
+
"language_model.model.layers.22.input_layernorm.weight": "model-3-of-5.safetensors",
|
| 494 |
+
"language_model.model.layers.5.linear_attn.conv1d.weight": "model-1-of-5.safetensors",
|
| 495 |
+
"vision_model.radio_model.model.blocks.19.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 496 |
+
"vision_model.radio_model.model.blocks.7.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 497 |
+
"vision_model.radio_model.model.blocks.4.norm2.bias": "model-5-of-5.safetensors",
|
| 498 |
+
"language_model.lm_head.weight": "model-5-of-5.safetensors",
|
| 499 |
+
"language_model.model.layers.13.mlp.gate_proj.weight": "model-2-of-5.safetensors",
|
| 500 |
+
"vision_model.radio_model.model.blocks.10.attn.proj.bias": "model-5-of-5.safetensors",
|
| 501 |
+
"language_model.model.layers.18.post_attention_layernorm.weight": "model-3-of-5.safetensors",
|
| 502 |
+
"language_model.model.layers.1.post_attention_layernorm.weight": "model-1-of-5.safetensors",
|
| 503 |
+
"vision_model.radio_model.model.blocks.12.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 504 |
+
"vision_model.radio_model.model.blocks.22.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 505 |
+
"language_model.model.layers.5.linear_attn.in_proj_a.weight": "model-1-of-5.safetensors",
|
| 506 |
+
"language_model.model.layers.4.linear_attn.norm.weight": "model-1-of-5.safetensors",
|
| 507 |
+
"vision_model.radio_model.model.blocks.6.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 508 |
+
"vision_model.radio_model.model.blocks.11.norm2.weight": "model-5-of-5.safetensors",
|
| 509 |
+
"vision_model.radio_model.model.blocks.1.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 510 |
+
"language_model.model.layers.0.mlp.gate_proj.weight": "model-1-of-5.safetensors",
|
| 511 |
+
"vision_model.radio_model.model.blocks.5.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 512 |
+
"language_model.model.layers.12.linear_attn.in_proj_a.weight": "model-2-of-5.safetensors",
|
| 513 |
+
"language_model.model.layers.8.mlp.down_proj.weight": "model-2-of-5.safetensors",
|
| 514 |
+
"vision_model.radio_model.model.blocks.2.norm2.bias": "model-5-of-5.safetensors",
|
| 515 |
+
"language_model.model.layers.13.linear_attn.in_proj_qkv.weight": "model-2-of-5.safetensors",
|
| 516 |
+
"language_model.model.layers.7.self_attn.k_norm.weight": "model-2-of-5.safetensors",
|
| 517 |
+
"language_model.model.layers.26.linear_attn.dt_bias": "model-4-of-5.safetensors",
|
| 518 |
+
"vision_model.radio_model.model.blocks.29.norm2.bias": "model-5-of-5.safetensors",
|
| 519 |
+
"vision_model.radio_model.model.blocks.23.norm2.bias": "model-5-of-5.safetensors",
|
| 520 |
+
"vision_model.radio_model.model.blocks.13.norm2.bias": "model-5-of-5.safetensors",
|
| 521 |
+
"vision_model.radio_model.model.blocks.16.attn.proj.weight": "model-5-of-5.safetensors",
|
| 522 |
+
"vision_model.radio_model.model.blocks.22.norm1.weight": "model-5-of-5.safetensors",
|
| 523 |
+
"vision_model.radio_model.model.blocks.0.attn.proj.weight": "model-5-of-5.safetensors",
|
| 524 |
+
"vision_model.radio_model.model.blocks.20.attn.proj.bias": "model-5-of-5.safetensors",
|
| 525 |
+
"vision_model.radio_model.model.blocks.26.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 526 |
+
"vision_model.radio_model.model.blocks.20.norm2.weight": "model-5-of-5.safetensors",
|
| 527 |
+
"language_model.model.layers.31.self_attn.k_norm.weight": "model-4-of-5.safetensors",
|
| 528 |
+
"vision_model.radio_model.model.blocks.19.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 529 |
+
"vision_model.radio_model.model.blocks.23.attn.proj.weight": "model-5-of-5.safetensors",
|
| 530 |
+
"vision_model.radio_model.model.blocks.3.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 531 |
+
"language_model.model.layers.20.linear_attn.out_proj.weight": "model-3-of-5.safetensors",
|
| 532 |
+
"language_model.model.layers.1.linear_attn.norm.weight": "model-1-of-5.safetensors",
|
| 533 |
+
"language_model.model.layers.14.post_attention_layernorm.weight": "model-2-of-5.safetensors",
|
| 534 |
+
"vision_model.radio_model.model.blocks.19.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 535 |
+
"vision_model.radio_model.model.blocks.1.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 536 |
+
"vision_model.radio_model.model.blocks.13.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 537 |
+
"vision_model.radio_model.model.blocks.2.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 538 |
+
"language_model.model.layers.15.self_attn.v_proj.weight": "model-3-of-5.safetensors",
|
| 539 |
+
"vision_model.radio_model.model.blocks.15.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 540 |
+
"language_model.model.layers.5.linear_attn.A_log": "model-1-of-5.safetensors",
|
| 541 |
+
"vision_model.radio_model.model.blocks.4.norm1.weight": "model-5-of-5.safetensors",
|
| 542 |
+
"language_model.model.layers.5.linear_attn.in_proj_qkv.weight": "model-1-of-5.safetensors",
|
| 543 |
+
"vision_model.radio_model.model.blocks.11.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 544 |
+
"language_model.model.layers.22.linear_attn.A_log": "model-3-of-5.safetensors",
|
| 545 |
+
"vision_model.radio_model.model.blocks.28.norm1.weight": "model-5-of-5.safetensors",
|
| 546 |
+
"language_model.model.layers.4.linear_attn.dt_bias": "model-1-of-5.safetensors",
|
| 547 |
+
"language_model.model.layers.14.linear_attn.in_proj_b.weight": "model-2-of-5.safetensors",
|
| 548 |
+
"language_model.model.layers.25.mlp.gate_proj.weight": "model-4-of-5.safetensors",
|
| 549 |
+
"language_model.model.layers.22.mlp.up_proj.weight": "model-3-of-5.safetensors",
|
| 550 |
+
"language_model.model.norm.weight": "model-4-of-5.safetensors",
|
| 551 |
+
"vision_model.radio_model.model.blocks.13.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 552 |
+
"language_model.model.layers.8.linear_attn.in_proj_qkv.weight": "model-2-of-5.safetensors",
|
| 553 |
+
"vision_model.radio_model.model.blocks.3.norm2.weight": "model-5-of-5.safetensors",
|
| 554 |
+
"vision_model.radio_model.model.blocks.11.attn.proj.bias": "model-5-of-5.safetensors",
|
| 555 |
+
"vision_model.radio_model.model.blocks.26.attn.proj.bias": "model-5-of-5.safetensors",
|
| 556 |
+
"language_model.model.layers.6.mlp.up_proj.weight": "model-2-of-5.safetensors",
|
| 557 |
+
"vision_model.radio_model.model.blocks.8.attn.proj.weight": "model-5-of-5.safetensors",
|
| 558 |
+
"language_model.model.layers.16.linear_attn.in_proj_z.weight": "model-3-of-5.safetensors",
|
| 559 |
+
"language_model.model.layers.1.linear_attn.conv1d.weight": "model-1-of-5.safetensors",
|
| 560 |
+
"language_model.model.layers.18.linear_attn.in_proj_a.weight": "model-3-of-5.safetensors",
|
| 561 |
+
"language_model.model.layers.31.self_attn.k_proj.weight": "model-4-of-5.safetensors",
|
| 562 |
+
"language_model.model.layers.22.mlp.down_proj.weight": "model-3-of-5.safetensors",
|
| 563 |
+
"vision_model.radio_model.model.patch_generator.cls_token.token": "model-5-of-5.safetensors",
|
| 564 |
+
"vision_model.radio_model.model.blocks.27.norm1.bias": "model-5-of-5.safetensors",
|
| 565 |
+
"vision_model.radio_model.model.blocks.11.norm1.weight": "model-5-of-5.safetensors",
|
| 566 |
+
"language_model.model.layers.25.linear_attn.dt_bias": "model-4-of-5.safetensors",
|
| 567 |
+
"vision_model.radio_model.model.blocks.12.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 568 |
+
"vision_model.radio_model.model.blocks.20.norm1.weight": "model-5-of-5.safetensors",
|
| 569 |
+
"vision_model.radio_model.model.blocks.20.norm2.bias": "model-5-of-5.safetensors",
|
| 570 |
+
"language_model.model.layers.18.mlp.gate_proj.weight": "model-3-of-5.safetensors",
|
| 571 |
+
"language_model.model.layers.16.mlp.up_proj.weight": "model-3-of-5.safetensors",
|
| 572 |
+
"vision_model.radio_model.model.blocks.26.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 573 |
+
"language_model.model.layers.10.mlp.down_proj.weight": "model-2-of-5.safetensors",
|
| 574 |
+
"language_model.model.layers.28.linear_attn.in_proj_qkv.weight": "model-4-of-5.safetensors",
|
| 575 |
+
"language_model.model.layers.31.self_attn.v_proj.weight": "model-4-of-5.safetensors",
|
| 576 |
+
"mlp1.0.weight": "model-5-of-5.safetensors",
|
| 577 |
+
"language_model.model.layers.11.mlp.gate_proj.weight": "model-2-of-5.safetensors",
|
| 578 |
+
"vision_model.radio_model.model.blocks.4.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 579 |
+
"vision_model.radio_model.model.blocks.8.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 580 |
+
"language_model.model.layers.23.self_attn.k_proj.weight": "model-3-of-5.safetensors",
|
| 581 |
+
"vision_model.radio_model.model.blocks.30.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 582 |
+
"vision_model.radio_model.model.blocks.10.norm1.weight": "model-5-of-5.safetensors",
|
| 583 |
+
"vision_model.radio_model.model.blocks.1.norm1.weight": "model-5-of-5.safetensors",
|
| 584 |
+
"language_model.model.layers.13.post_attention_layernorm.weight": "model-2-of-5.safetensors",
|
| 585 |
+
"vision_model.radio_model.model.blocks.10.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 586 |
+
"vision_model.radio_model.model.blocks.19.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 587 |
+
"vision_model.radio_model.model.blocks.1.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 588 |
+
"vision_model.radio_model.model.blocks.20.attn.proj.weight": "model-5-of-5.safetensors",
|
| 589 |
+
"vision_model.radio_model.model.blocks.19.norm2.bias": "model-5-of-5.safetensors",
|
| 590 |
+
"language_model.model.layers.30.linear_attn.out_proj.weight": "model-4-of-5.safetensors",
|
| 591 |
+
"vision_model.radio_model.model.blocks.1.norm2.weight": "model-5-of-5.safetensors",
|
| 592 |
+
"language_model.model.layers.16.linear_attn.conv1d.weight": "model-3-of-5.safetensors",
|
| 593 |
+
"vision_model.radio_model.model.blocks.21.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 594 |
+
"vision_model.radio_model.model.blocks.5.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 595 |
+
"language_model.model.layers.16.mlp.down_proj.weight": "model-3-of-5.safetensors",
|
| 596 |
+
"vision_model.radio_model.model.blocks.30.attn.proj.bias": "model-5-of-5.safetensors",
|
| 597 |
+
"language_model.model.layers.9.post_attention_layernorm.weight": "model-2-of-5.safetensors",
|
| 598 |
+
"vision_model.radio_model.model.blocks.20.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 599 |
+
"vision_model.radio_model.model.blocks.13.norm1.weight": "model-5-of-5.safetensors",
|
| 600 |
+
"language_model.model.layers.30.linear_attn.in_proj_a.weight": "model-4-of-5.safetensors",
|
| 601 |
+
"vision_model.radio_model.model.blocks.31.attn.proj.bias": "model-5-of-5.safetensors",
|
| 602 |
+
"vision_model.radio_model.model.blocks.16.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 603 |
+
"vision_model.radio_model.model.blocks.16.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 604 |
+
"language_model.model.layers.27.self_attn.q_norm.weight": "model-4-of-5.safetensors",
|
| 605 |
+
"language_model.model.layers.3.mlp.gate_proj.weight": "model-1-of-5.safetensors",
|
| 606 |
+
"language_model.model.layers.19.mlp.down_proj.weight": "model-3-of-5.safetensors",
|
| 607 |
+
"vision_model.radio_model.model.blocks.6.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 608 |
+
"language_model.model.layers.29.mlp.down_proj.weight": "model-4-of-5.safetensors",
|
| 609 |
+
"language_model.model.layers.17.linear_attn.in_proj_z.weight": "model-3-of-5.safetensors",
|
| 610 |
+
"language_model.model.layers.17.post_attention_layernorm.weight": "model-3-of-5.safetensors",
|
| 611 |
+
"language_model.model.layers.13.linear_attn.in_proj_z.weight": "model-2-of-5.safetensors",
|
| 612 |
+
"language_model.model.layers.6.linear_attn.norm.weight": "model-2-of-5.safetensors",
|
| 613 |
+
"vision_model.radio_model.model.blocks.23.norm1.bias": "model-5-of-5.safetensors",
|
| 614 |
+
"language_model.model.layers.22.linear_attn.in_proj_z.weight": "model-3-of-5.safetensors",
|
| 615 |
+
"vision_model.radio_model.model.blocks.0.norm1.bias": "model-5-of-5.safetensors",
|
| 616 |
+
"vision_model.radio_model.model.blocks.17.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 617 |
+
"vision_model.radio_model.model.blocks.17.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 618 |
+
"language_model.model.layers.12.linear_attn.out_proj.weight": "model-2-of-5.safetensors",
|
| 619 |
+
"language_model.model.layers.24.linear_attn.out_proj.weight": "model-3-of-5.safetensors",
|
| 620 |
+
"language_model.model.layers.0.linear_attn.out_proj.weight": "model-1-of-5.safetensors",
|
| 621 |
+
"vision_model.radio_model.model.blocks.3.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 622 |
+
"language_model.model.layers.2.linear_attn.in_proj_qkv.weight": "model-1-of-5.safetensors",
|
| 623 |
+
"vision_model.radio_model.model.blocks.20.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 624 |
+
"language_model.model.layers.12.linear_attn.norm.weight": "model-2-of-5.safetensors",
|
| 625 |
+
"language_model.model.layers.0.input_layernorm.weight": "model-1-of-5.safetensors",
|
| 626 |
+
"language_model.model.layers.31.self_attn.q_norm.weight": "model-4-of-5.safetensors",
|
| 627 |
+
"vision_model.radio_model.model.blocks.23.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 628 |
+
"language_model.model.layers.2.linear_attn.in_proj_a.weight": "model-1-of-5.safetensors",
|
| 629 |
+
"language_model.model.layers.2.mlp.gate_proj.weight": "model-1-of-5.safetensors",
|
| 630 |
+
"language_model.model.layers.27.mlp.up_proj.weight": "model-4-of-5.safetensors",
|
| 631 |
+
"language_model.model.layers.11.self_attn.v_proj.weight": "model-2-of-5.safetensors",
|
| 632 |
+
"language_model.model.layers.20.linear_attn.A_log": "model-3-of-5.safetensors",
|
| 633 |
+
"vision_model.radio_model.model.blocks.12.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 634 |
+
"language_model.model.layers.4.input_layernorm.weight": "model-1-of-5.safetensors",
|
| 635 |
+
"vision_model.radio_model.model.blocks.30.attn.proj.weight": "model-5-of-5.safetensors",
|
| 636 |
+
"language_model.model.layers.16.linear_attn.in_proj_qkv.weight": "model-3-of-5.safetensors",
|
| 637 |
+
"language_model.model.layers.22.linear_attn.in_proj_a.weight": "model-3-of-5.safetensors",
|
| 638 |
+
"language_model.model.layers.22.linear_attn.norm.weight": "model-3-of-5.safetensors",
|
| 639 |
+
"language_model.model.layers.10.linear_attn.dt_bias": "model-2-of-5.safetensors",
|
| 640 |
+
"language_model.model.layers.17.linear_attn.in_proj_b.weight": "model-3-of-5.safetensors",
|
| 641 |
+
"vision_model.radio_model.model.blocks.24.attn.proj.bias": "model-5-of-5.safetensors",
|
| 642 |
+
"language_model.model.layers.30.input_layernorm.weight": "model-4-of-5.safetensors",
|
| 643 |
+
"language_model.model.layers.19.self_attn.k_norm.weight": "model-3-of-5.safetensors",
|
| 644 |
+
"language_model.model.layers.14.linear_attn.in_proj_a.weight": "model-2-of-5.safetensors",
|
| 645 |
+
"vision_model.radio_model.model.blocks.29.norm1.weight": "model-5-of-5.safetensors",
|
| 646 |
+
"language_model.model.layers.21.mlp.gate_proj.weight": "model-3-of-5.safetensors",
|
| 647 |
+
"language_model.model.layers.15.self_attn.o_proj.weight": "model-3-of-5.safetensors",
|
| 648 |
+
"vision_model.radio_model.model.blocks.9.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 649 |
+
"language_model.model.layers.6.linear_attn.in_proj_z.weight": "model-2-of-5.safetensors",
|
| 650 |
+
"language_model.model.layers.24.mlp.gate_proj.weight": "model-3-of-5.safetensors",
|
| 651 |
+
"vision_model.radio_model.model.blocks.24.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 652 |
+
"vision_model.radio_model.model.blocks.30.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 653 |
+
"vision_model.radio_model.model.blocks.26.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 654 |
+
"vision_model.radio_model.model.blocks.12.norm1.weight": "model-5-of-5.safetensors",
|
| 655 |
+
"vision_model.radio_model.model.blocks.23.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 656 |
+
"language_model.model.layers.7.mlp.up_proj.weight": "model-2-of-5.safetensors",
|
| 657 |
+
"vision_model.radio_model.model.blocks.22.attn.proj.weight": "model-5-of-5.safetensors",
|
| 658 |
+
"vision_model.radio_model.model.blocks.21.attn.proj.bias": "model-5-of-5.safetensors",
|
| 659 |
+
"vision_model.radio_model.model.blocks.4.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 660 |
+
"vision_model.radio_model.model.blocks.6.norm1.weight": "model-5-of-5.safetensors",
|
| 661 |
+
"vision_model.radio_model.model.blocks.24.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 662 |
+
"language_model.model.layers.0.linear_attn.dt_bias": "model-1-of-5.safetensors",
|
| 663 |
+
"language_model.model.layers.31.self_attn.o_proj.weight": "model-4-of-5.safetensors",
|
| 664 |
+
"language_model.model.layers.30.post_attention_layernorm.weight": "model-4-of-5.safetensors",
|
| 665 |
+
"vision_model.radio_model.model.blocks.27.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 666 |
+
"language_model.model.layers.14.linear_attn.in_proj_z.weight": "model-2-of-5.safetensors",
|
| 667 |
+
"language_model.model.layers.15.self_attn.k_norm.weight": "model-3-of-5.safetensors",
|
| 668 |
+
"vision_model.radio_model.model.blocks.0.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 669 |
+
"language_model.model.layers.8.linear_attn.norm.weight": "model-2-of-5.safetensors",
|
| 670 |
+
"vision_model.radio_model.model.blocks.11.norm1.bias": "model-5-of-5.safetensors",
|
| 671 |
+
"vision_model.radio_model.model.blocks.30.norm1.weight": "model-5-of-5.safetensors",
|
| 672 |
+
"vision_model.radio_model.model.blocks.24.norm1.weight": "model-5-of-5.safetensors",
|
| 673 |
+
"vision_model.radio_model.model.blocks.23.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 674 |
+
"language_model.model.layers.21.post_attention_layernorm.weight": "model-3-of-5.safetensors",
|
| 675 |
+
"vision_model.radio_model.model.blocks.25.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 676 |
+
"language_model.model.layers.13.linear_attn.in_proj_a.weight": "model-2-of-5.safetensors",
|
| 677 |
+
"vision_model.radio_model.model.blocks.7.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 678 |
+
"language_model.model.layers.27.mlp.down_proj.weight": "model-4-of-5.safetensors",
|
| 679 |
+
"vision_model.radio_model.model.blocks.24.norm2.weight": "model-5-of-5.safetensors",
|
| 680 |
+
"vision_model.radio_model.model.blocks.21.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 681 |
+
"vision_model.radio_model.model.blocks.19.norm2.weight": "model-5-of-5.safetensors",
|
| 682 |
+
"language_model.model.layers.2.linear_attn.conv1d.weight": "model-1-of-5.safetensors",
|
| 683 |
+
"vision_model.radio_model.model.blocks.1.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 684 |
+
"language_model.model.layers.0.linear_attn.in_proj_a.weight": "model-1-of-5.safetensors",
|
| 685 |
+
"vision_model.radio_model.model.blocks.10.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 686 |
+
"vision_model.radio_model.model.blocks.25.norm1.weight": "model-5-of-5.safetensors",
|
| 687 |
+
"vision_model.radio_model.model.blocks.17.norm1.bias": "model-5-of-5.safetensors",
|
| 688 |
+
"vision_model.radio_model.model.blocks.2.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 689 |
+
"vision_model.radio_model.model.blocks.21.norm1.weight": "model-5-of-5.safetensors",
|
| 690 |
+
"vision_model.radio_model.model.blocks.6.attn.proj.weight": "model-5-of-5.safetensors",
|
| 691 |
+
"language_model.model.layers.3.self_attn.o_proj.weight": "model-1-of-5.safetensors",
|
| 692 |
+
"language_model.model.layers.9.linear_attn.dt_bias": "model-2-of-5.safetensors",
|
| 693 |
+
"language_model.model.layers.5.input_layernorm.weight": "model-1-of-5.safetensors",
|
| 694 |
+
"vision_model.radio_model.model.blocks.27.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 695 |
+
"vision_model.radio_model.model.blocks.18.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 696 |
+
"vision_model.radio_model.model.blocks.27.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 697 |
+
"vision_model.radio_model.model.blocks.22.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 698 |
+
"vision_model.radio_model.model.blocks.13.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 699 |
+
"vision_model.radio_model.model.blocks.8.attn.proj.bias": "model-5-of-5.safetensors",
|
| 700 |
+
"language_model.model.layers.3.mlp.down_proj.weight": "model-1-of-5.safetensors",
|
| 701 |
+
"vision_model.radio_model.model.blocks.1.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 702 |
+
"vision_model.radio_model.model.blocks.13.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 703 |
+
"vision_model.radio_model.model.blocks.29.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 704 |
+
"vision_model.radio_model.model.blocks.25.norm1.bias": "model-5-of-5.safetensors",
|
| 705 |
+
"language_model.model.layers.1.linear_attn.in_proj_a.weight": "model-1-of-5.safetensors",
|
| 706 |
+
"language_model.model.layers.12.linear_attn.in_proj_qkv.weight": "model-2-of-5.safetensors",
|
| 707 |
+
"language_model.model.layers.26.post_attention_layernorm.weight": "model-4-of-5.safetensors",
|
| 708 |
+
"vision_model.radio_model.model.blocks.30.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 709 |
+
"vision_model.radio_model.model.blocks.27.norm2.weight": "model-5-of-5.safetensors",
|
| 710 |
+
"language_model.model.layers.25.mlp.down_proj.weight": "model-4-of-5.safetensors",
|
| 711 |
+
"language_model.model.layers.25.linear_attn.in_proj_qkv.weight": "model-4-of-5.safetensors",
|
| 712 |
+
"language_model.model.layers.6.linear_attn.in_proj_b.weight": "model-2-of-5.safetensors",
|
| 713 |
+
"language_model.model.layers.18.linear_attn.in_proj_qkv.weight": "model-3-of-5.safetensors",
|
| 714 |
+
"language_model.model.layers.24.mlp.up_proj.weight": "model-4-of-5.safetensors",
|
| 715 |
+
"vision_model.radio_model.model.blocks.22.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 716 |
+
"language_model.model.layers.10.mlp.up_proj.weight": "model-2-of-5.safetensors",
|
| 717 |
+
"language_model.model.layers.10.linear_attn.A_log": "model-2-of-5.safetensors",
|
| 718 |
+
"language_model.model.layers.19.self_attn.o_proj.weight": "model-3-of-5.safetensors",
|
| 719 |
+
"vision_model.radio_model.model.blocks.14.norm1.weight": "model-5-of-5.safetensors",
|
| 720 |
+
"language_model.model.layers.24.linear_attn.in_proj_b.weight": "model-3-of-5.safetensors",
|
| 721 |
+
"language_model.model.layers.21.linear_attn.out_proj.weight": "model-3-of-5.safetensors",
|
| 722 |
+
"language_model.model.layers.31.input_layernorm.weight": "model-4-of-5.safetensors",
|
| 723 |
+
"vision_model.radio_model.model.blocks.8.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 724 |
+
"language_model.model.layers.26.linear_attn.in_proj_z.weight": "model-4-of-5.safetensors",
|
| 725 |
+
"vision_model.radio_model.model.blocks.3.norm1.weight": "model-5-of-5.safetensors",
|
| 726 |
+
"vision_model.radio_model.model.blocks.22.norm2.weight": "model-5-of-5.safetensors",
|
| 727 |
+
"language_model.model.layers.13.input_layernorm.weight": "model-2-of-5.safetensors",
|
| 728 |
+
"language_model.model.layers.25.linear_attn.norm.weight": "model-4-of-5.safetensors",
|
| 729 |
+
"vision_model.radio_model.model.blocks.6.norm2.weight": "model-5-of-5.safetensors",
|
| 730 |
+
"language_model.model.layers.23.self_attn.q_proj.weight": "model-3-of-5.safetensors",
|
| 731 |
+
"vision_model.radio_model.model.blocks.28.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 732 |
+
"language_model.model.layers.13.linear_attn.A_log": "model-2-of-5.safetensors",
|
| 733 |
+
"language_model.model.layers.28.mlp.gate_proj.weight": "model-4-of-5.safetensors",
|
| 734 |
+
"vision_model.radio_model.model.blocks.9.norm1.weight": "model-5-of-5.safetensors",
|
| 735 |
+
"vision_model.radio_model.model.blocks.25.norm2.weight": "model-5-of-5.safetensors",
|
| 736 |
+
"language_model.model.layers.11.self_attn.q_norm.weight": "model-2-of-5.safetensors",
|
| 737 |
+
"language_model.model.layers.20.linear_attn.dt_bias": "model-3-of-5.safetensors",
|
| 738 |
+
"vision_model.radio_model.model.blocks.4.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 739 |
+
"language_model.model.layers.16.linear_attn.A_log": "model-3-of-5.safetensors",
|
| 740 |
+
"language_model.model.layers.9.linear_attn.conv1d.weight": "model-2-of-5.safetensors",
|
| 741 |
+
"language_model.model.layers.10.linear_attn.out_proj.weight": "model-2-of-5.safetensors",
|
| 742 |
+
"language_model.model.layers.16.linear_attn.in_proj_a.weight": "model-3-of-5.safetensors",
|
| 743 |
+
"vision_model.radio_model.model.blocks.9.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 744 |
+
"language_model.model.layers.17.linear_attn.in_proj_qkv.weight": "model-3-of-5.safetensors",
|
| 745 |
+
"language_model.model.layers.24.linear_attn.norm.weight": "model-3-of-5.safetensors",
|
| 746 |
+
"language_model.model.layers.14.input_layernorm.weight": "model-2-of-5.safetensors",
|
| 747 |
+
"language_model.model.layers.8.input_layernorm.weight": "model-2-of-5.safetensors",
|
| 748 |
+
"language_model.model.layers.3.self_attn.k_norm.weight": "model-1-of-5.safetensors",
|
| 749 |
+
"vision_model.radio_model.model.blocks.11.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 750 |
+
"language_model.model.layers.17.linear_attn.A_log": "model-3-of-5.safetensors",
|
| 751 |
+
"vision_model.radio_model.model.blocks.10.norm2.bias": "model-5-of-5.safetensors",
|
| 752 |
+
"vision_model.radio_model.model.blocks.28.norm2.bias": "model-5-of-5.safetensors",
|
| 753 |
+
"vision_model.radio_model.model.blocks.3.attn.proj.bias": "model-5-of-5.safetensors",
|
| 754 |
+
"language_model.model.layers.11.post_attention_layernorm.weight": "model-2-of-5.safetensors",
|
| 755 |
+
"language_model.model.layers.13.linear_attn.in_proj_b.weight": "model-2-of-5.safetensors",
|
| 756 |
+
"vision_model.radio_model.model.blocks.19.attn.proj.weight": "model-5-of-5.safetensors",
|
| 757 |
+
"language_model.model.layers.2.linear_attn.out_proj.weight": "model-1-of-5.safetensors",
|
| 758 |
+
"language_model.model.layers.13.linear_attn.out_proj.weight": "model-2-of-5.safetensors",
|
| 759 |
+
"language_model.model.layers.26.mlp.down_proj.weight": "model-4-of-5.safetensors",
|
| 760 |
+
"language_model.model.layers.6.linear_attn.A_log": "model-2-of-5.safetensors",
|
| 761 |
+
"vision_model.radio_model.model.blocks.15.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 762 |
+
"language_model.model.layers.0.linear_attn.A_log": "model-1-of-5.safetensors",
|
| 763 |
+
"language_model.model.layers.17.linear_attn.conv1d.weight": "model-3-of-5.safetensors",
|
| 764 |
+
"language_model.model.layers.21.linear_attn.in_proj_b.weight": "model-3-of-5.safetensors",
|
| 765 |
+
"language_model.model.layers.8.linear_attn.in_proj_z.weight": "model-2-of-5.safetensors",
|
| 766 |
+
"language_model.model.layers.29.linear_attn.out_proj.weight": "model-4-of-5.safetensors",
|
| 767 |
+
"language_model.model.layers.29.linear_attn.norm.weight": "model-4-of-5.safetensors",
|
| 768 |
+
"language_model.model.layers.5.mlp.up_proj.weight": "model-2-of-5.safetensors",
|
| 769 |
+
"vision_model.radio_model.model.blocks.30.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 770 |
+
"vision_model.radio_model.model.blocks.4.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 771 |
+
"vision_model.radio_model.model.blocks.4.mlp.fc2.bias": "model-5-of-5.safetensors",
|
| 772 |
+
"language_model.model.layers.29.linear_attn.in_proj_b.weight": "model-4-of-5.safetensors",
|
| 773 |
+
"vision_model.radio_model.model.blocks.14.mlp.fc2.weight": "model-5-of-5.safetensors",
|
| 774 |
+
"language_model.model.layers.4.mlp.down_proj.weight": "model-1-of-5.safetensors",
|
| 775 |
+
"language_model.model.layers.1.linear_attn.dt_bias": "model-1-of-5.safetensors",
|
| 776 |
+
"vision_model.radio_model.model.blocks.4.attn.proj.bias": "model-5-of-5.safetensors",
|
| 777 |
+
"vision_model.radio_model.model.blocks.7.attn.proj.weight": "model-5-of-5.safetensors",
|
| 778 |
+
"language_model.model.layers.24.linear_attn.conv1d.weight": "model-3-of-5.safetensors",
|
| 779 |
+
"language_model.model.layers.29.mlp.up_proj.weight": "model-4-of-5.safetensors",
|
| 780 |
+
"language_model.model.layers.30.linear_attn.in_proj_qkv.weight": "model-4-of-5.safetensors",
|
| 781 |
+
"vision_model.radio_model.model.blocks.6.norm1.bias": "model-5-of-5.safetensors",
|
| 782 |
+
"vision_model.radio_model.model.blocks.3.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 783 |
+
"vision_model.radio_model.model.blocks.4.norm1.bias": "model-5-of-5.safetensors",
|
| 784 |
+
"vision_model.radio_model.model.blocks.3.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 785 |
+
"language_model.model.layers.29.mlp.gate_proj.weight": "model-4-of-5.safetensors",
|
| 786 |
+
"language_model.model.layers.7.mlp.gate_proj.weight": "model-2-of-5.safetensors",
|
| 787 |
+
"language_model.model.layers.8.linear_attn.conv1d.weight": "model-2-of-5.safetensors",
|
| 788 |
+
"language_model.model.layers.22.linear_attn.conv1d.weight": "model-3-of-5.safetensors",
|
| 789 |
+
"vision_model.radio_model.model.blocks.24.attn.proj.weight": "model-5-of-5.safetensors",
|
| 790 |
+
"language_model.model.layers.29.linear_attn.in_proj_a.weight": "model-4-of-5.safetensors",
|
| 791 |
+
"language_model.model.layers.29.linear_attn.conv1d.weight": "model-4-of-5.safetensors",
|
| 792 |
+
"vision_model.radio_model.model.blocks.26.norm2.bias": "model-5-of-5.safetensors",
|
| 793 |
+
"vision_model.radio_model.model.blocks.7.norm1.bias": "model-5-of-5.safetensors",
|
| 794 |
+
"vision_model.radio_model.model.blocks.12.attn.proj.weight": "model-5-of-5.safetensors",
|
| 795 |
+
"language_model.model.layers.1.mlp.up_proj.weight": "model-1-of-5.safetensors",
|
| 796 |
+
"language_model.model.layers.3.self_attn.q_norm.weight": "model-1-of-5.safetensors",
|
| 797 |
+
"language_model.model.layers.13.linear_attn.norm.weight": "model-2-of-5.safetensors",
|
| 798 |
+
"language_model.model.layers.5.mlp.down_proj.weight": "model-2-of-5.safetensors",
|
| 799 |
+
"vision_model.radio_model.model.blocks.0.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 800 |
+
"language_model.model.layers.21.linear_attn.in_proj_z.weight": "model-3-of-5.safetensors",
|
| 801 |
+
"language_model.model.layers.21.linear_attn.in_proj_qkv.weight": "model-3-of-5.safetensors",
|
| 802 |
+
"vision_model.radio_model.model.blocks.16.mlp.fc1.weight": "model-5-of-5.safetensors",
|
| 803 |
+
"vision_model.radio_model.model.blocks.25.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 804 |
+
"vision_model.radio_model.model.blocks.21.mlp.fc1.bias": "model-5-of-5.safetensors",
|
| 805 |
+
"vision_model.radio_model.model.blocks.23.attn.qkv.weight": "model-5-of-5.safetensors",
|
| 806 |
+
"language_model.model.layers.4.linear_attn.in_proj_qkv.weight": "model-1-of-5.safetensors",
|
| 807 |
+
"language_model.model.layers.14.linear_attn.conv1d.weight": "model-2-of-5.safetensors",
|
| 808 |
+
"vision_model.radio_model.model.blocks.2.attn.proj.bias": "model-5-of-5.safetensors",
|
| 809 |
+
"language_model.model.layers.8.mlp.gate_proj.weight": "model-2-of-5.safetensors",
|
| 810 |
+
"language_model.model.layers.6.input_layernorm.weight": "model-2-of-5.safetensors",
|
| 811 |
+
"language_model.model.layers.31.self_attn.q_proj.weight": "model-4-of-5.safetensors",
|
| 812 |
+
"vision_model.radio_model.model.blocks.2.norm1.bias": "model-5-of-5.safetensors",
|
| 813 |
+
"language_model.model.layers.23.self_attn.q_norm.weight": "model-3-of-5.safetensors",
|
| 814 |
+
"vision_model.radio_model.model.blocks.26.norm1.weight": "model-5-of-5.safetensors",
|
| 815 |
+
"language_model.model.layers.2.linear_attn.A_log": "model-1-of-5.safetensors",
|
| 816 |
+
"vision_model.radio_model.model.blocks.27.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 817 |
+
"vision_model.radio_model.model.blocks.21.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 818 |
+
"language_model.model.layers.25.linear_attn.in_proj_a.weight": "model-4-of-5.safetensors",
|
| 819 |
+
"vision_model.radio_model.model.blocks.2.attn.qkv.bias": "model-5-of-5.safetensors",
|
| 820 |
+
"language_model.model.layers.21.mlp.up_proj.weight": "model-3-of-5.safetensors",
|
| 821 |
+
"vision_model.radio_model.model.blocks.26.norm2.weight": "model-5-of-5.safetensors",
|
| 822 |
+
"language_model.model.layers.29.post_attention_layernorm.weight": "model-4-of-5.safetensors",
|
| 823 |
+
"language_model.model.layers.5.linear_attn.norm.weight": "model-2-of-5.safetensors",
|
| 824 |
+
"language_model.model.layers.25.post_attention_layernorm.weight": "model-4-of-5.safetensors",
|
| 825 |
+
"vision_model.radio_model.model.blocks.19.attn.proj.bias": "model-5-of-5.safetensors"
|
| 826 |
+
}
|
| 827 |
+
}
|
modeling.py
ADDED
|
@@ -0,0 +1,1109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
# ============================================================================
|
| 16 |
+
# ZDTaichu-5.0 — Main Model
|
| 17 |
+
#
|
| 18 |
+
# Architecture
|
| 19 |
+
# ────────────
|
| 20 |
+
# Vision encoder : C-RADIOv4-H (ViT-H/16, 653 M)
|
| 21 |
+
# Projector : RMSNorm → Linear(5120→20480) → SquaredReLU → Linear(20480→H)
|
| 22 |
+
# LLM decoder : Qwen3.5 hybrid (Gated DeltaNet + full attention, 3:1 ratio)
|
| 23 |
+
#
|
| 24 |
+
# Position encoding (M-RoPE)
|
| 25 |
+
# ──────────────────────────
|
| 26 |
+
# Vision tokens receive 3D position IDs (temporal, height, width) computed
|
| 27 |
+
# from the InternVL-style tile grid via ``get_rope_index()``. Text tokens
|
| 28 |
+
# receive standard 1D positions (all three M-RoPE channels are identical).
|
| 29 |
+
#
|
| 30 |
+
# This matches the official Qwen3.5 VL pipeline where ``Qwen3_5Model.forward()``
|
| 31 |
+
# calls ``compute_3d_position_ids()`` → ``get_rope_index()`` before forwarding
|
| 32 |
+
# to ``Qwen3_5TextModel``. The resulting ``position_ids`` of shape ``(3, B, S)``
|
| 33 |
+
# are consumed directly by ``Qwen3_5TextRotaryEmbedding``, which applies
|
| 34 |
+
# interleaved M-RoPE across temporal / height / width frequency bands.
|
| 35 |
+
#
|
| 36 |
+
# Generation
|
| 37 |
+
# ──────────
|
| 38 |
+
# This model inherits from ``GenerationMixin``, owning the generation loop
|
| 39 |
+
# (like ``Qwen3_5ForConditionalGeneration``). Key overrides:
|
| 40 |
+
# - ``_prepare_position_ids_for_generation``: computes 3D ``position_ids``
|
| 41 |
+
# on the prefill step and caches ``rope_deltas``; applies ``rope_deltas``
|
| 42 |
+
# on subsequent decode steps.
|
| 43 |
+
# - ``prepare_inputs_for_generation``: clears ``pixel_values`` /
|
| 44 |
+
# ``pixel_values_videos`` after the first step (vision features are
|
| 45 |
+
# already embedded in the KV cache).
|
| 46 |
+
#
|
| 47 |
+
# Cache handling
|
| 48 |
+
# ──────────────
|
| 49 |
+
# ``Qwen3_5DynamicCache`` is created internally by ``Qwen3_5TextModel`` when
|
| 50 |
+
# ``use_cache=True``. It stores KV states for full-attention layers and
|
| 51 |
+
# ``conv_states`` + ``recurrent_states`` for Gated DeltaNet layers.
|
| 52 |
+
# ============================================================================
|
| 53 |
+
|
| 54 |
+
import itertools
|
| 55 |
+
import warnings
|
| 56 |
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
| 57 |
+
|
| 58 |
+
import torch
|
| 59 |
+
import transformers
|
| 60 |
+
from torch import nn
|
| 61 |
+
from torch.nn import CrossEntropyLoss
|
| 62 |
+
from transformers import AutoModel, GenerationConfig
|
| 63 |
+
from transformers.generation import GenerationMixin
|
| 64 |
+
from transformers.modeling_outputs import CausalLMOutputWithPast
|
| 65 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 66 |
+
from transformers.utils import logging
|
| 67 |
+
|
| 68 |
+
from .configuration import ZDTaichu5_0_Config
|
| 69 |
+
from .cradio_model import RADIOModel
|
| 70 |
+
|
| 71 |
+
logger = logging.get_logger(__name__)
|
| 72 |
+
|
| 73 |
+
# ---------------------------------------------------------------------------
|
| 74 |
+
# Import Qwen3.5 model classes — requires transformers >= 5.3.0
|
| 75 |
+
# ---------------------------------------------------------------------------
|
| 76 |
+
|
| 77 |
+
_MIN_TRANSFORMERS = "5.3.0"
|
| 78 |
+
|
| 79 |
+
try:
|
| 80 |
+
from transformers.models.qwen3_5.modeling_qwen3_5 import Qwen3_5ForCausalLM
|
| 81 |
+
from transformers.cache_utils import DynamicCache as Qwen3_5DynamicCache
|
| 82 |
+
_HAS_QWEN3_5 = True
|
| 83 |
+
except Exception as e:
|
| 84 |
+
_HAS_QWEN3_5 = False
|
| 85 |
+
Qwen3_5ForCausalLM = None
|
| 86 |
+
Qwen3_5DynamicCache = None
|
| 87 |
+
logger.warning(
|
| 88 |
+
f"Could not import Qwen3_5ForCausalLM from transformers. "
|
| 89 |
+
f"Import error: {e!r}"
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def _version_ge(v1, v2):
|
| 94 |
+
"""Check if version v1 >= v2."""
|
| 95 |
+
from packaging import version
|
| 96 |
+
return version.parse(v1) >= version.parse(v2)
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 100 |
+
# Projector components
|
| 101 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 102 |
+
|
| 103 |
+
class SquaredReLU(nn.Module):
|
| 104 |
+
"""Squared ReLU activation — same non-linearity used in the projector."""
|
| 105 |
+
def forward(self, x):
|
| 106 |
+
return torch.pow(torch.nn.functional.relu(x), 2)
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
class RMSNorm(nn.Module):
|
| 110 |
+
"""
|
| 111 |
+
Standard RMSNorm for the projector (NOT the Qwen3.5 LLM variant).
|
| 112 |
+
|
| 113 |
+
Qwen3.5's internal ``Qwen3_5RMSNorm`` uses zero-initialized weight with
|
| 114 |
+
``output * (1 + weight)``. The projector uses ones-initialized weight
|
| 115 |
+
with ``output * weight`` — the standard formulation.
|
| 116 |
+
"""
|
| 117 |
+
def __init__(self, hidden_size: int, eps: float = 1e-5):
|
| 118 |
+
super().__init__()
|
| 119 |
+
self.weight = nn.Parameter(torch.ones(hidden_size))
|
| 120 |
+
self.eps = eps
|
| 121 |
+
|
| 122 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 123 |
+
input_dtype = hidden_states.dtype
|
| 124 |
+
hidden_states = hidden_states.to(torch.float32)
|
| 125 |
+
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
| 126 |
+
hidden_states = hidden_states * torch.rsqrt(variance + self.eps)
|
| 127 |
+
return (self.weight.to(torch.float32) * hidden_states).to(input_dtype)
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 131 |
+
# Main model
|
| 132 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 133 |
+
|
| 134 |
+
class ZDTaichu5_0_ForConditionalGeneration(PreTrainedModel, GenerationMixin):
|
| 135 |
+
"""
|
| 136 |
+
ZDTaichu-5.0: C-RADIOv4-H vision encoder + Qwen3.5 language decoder.
|
| 137 |
+
|
| 138 |
+
Architecture overview::
|
| 139 |
+
|
| 140 |
+
pixel_values
|
| 141 |
+
└─► C-RADIOv4-H (ViT-H/16, 653 M)
|
| 142 |
+
└─► pixel_shuffle(0.5)
|
| 143 |
+
└─► mlp1: RMSNorm → Linear → SquaredReLU → Linear
|
| 144 |
+
└─► inject into Qwen3.5 embeddings at <image> positions
|
| 145 |
+
└─► Qwen3.5 (hybrid DeltaNet / Transformer)
|
| 146 |
+
"""
|
| 147 |
+
|
| 148 |
+
config_class = ZDTaichu5_0_Config
|
| 149 |
+
main_input_name = "input_ids"
|
| 150 |
+
_tied_weights_keys = None#["language_model.lm_head.weight"]
|
| 151 |
+
_keys_to_ignore_on_load_unexpected = [
|
| 152 |
+
# The RADIO input_conditioner registers norm_mean / norm_std as
|
| 153 |
+
# buffers, but make_preprocessor_external() removes the conditioner
|
| 154 |
+
# at init time (normalization is handled by the image processor).
|
| 155 |
+
# The build script still saves these from the source checkpoint, so
|
| 156 |
+
# they appear as unexpected keys during loading — safe to ignore.
|
| 157 |
+
r"vision_model\.radio_model\.input_conditioner\..*",
|
| 158 |
+
r"^mtp\..*",
|
| 159 |
+
]
|
| 160 |
+
|
| 161 |
+
_supports_flash_attn_2 = True
|
| 162 |
+
_supports_flash_attention_2 = True
|
| 163 |
+
_supports_flash_attn = True
|
| 164 |
+
_supports_sdpa = True
|
| 165 |
+
_no_split_modules = ["Qwen3_5DecoderLayer"]
|
| 166 |
+
_is_stateful = True
|
| 167 |
+
supports_gradient_checkpointing = True
|
| 168 |
+
|
| 169 |
+
def __init__(self, config: ZDTaichu5_0_Config):
|
| 170 |
+
super().__init__(config)
|
| 171 |
+
|
| 172 |
+
# Guard for bleeding-edge transformers (>= 4.57.0.dev) where
|
| 173 |
+
# _finalize_model_loading reads all_tied_weights_keys but
|
| 174 |
+
# PreTrainedModel.__init__ may not yet initialise it.
|
| 175 |
+
if not hasattr(self, "all_tied_weights_keys"):
|
| 176 |
+
self.all_tied_weights_keys = {}
|
| 177 |
+
|
| 178 |
+
assert _version_ge(transformers.__version__, _MIN_TRANSFORMERS), (
|
| 179 |
+
f"Qwen3.5 support requires transformers >= {_MIN_TRANSFORMERS} "
|
| 180 |
+
f"(found {transformers.__version__})"
|
| 181 |
+
)
|
| 182 |
+
assert _HAS_QWEN3_5, (
|
| 183 |
+
"Qwen3_5ForCausalLM is not available. "
|
| 184 |
+
f"Ensure transformers >= {_MIN_TRANSFORMERS} is installed."
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
image_size = config.force_image_size
|
| 188 |
+
patch_size = config.vision_config.patch_size
|
| 189 |
+
self.patch_size = patch_size
|
| 190 |
+
self.template = config.template
|
| 191 |
+
self.num_image_token = int(
|
| 192 |
+
(image_size // patch_size) ** 2 * (config.downsample_ratio ** 2)
|
| 193 |
+
)
|
| 194 |
+
self.downsample_ratio = config.downsample_ratio
|
| 195 |
+
self.ps_version = config.ps_version
|
| 196 |
+
self.image_tag_type = config.image_tag_type
|
| 197 |
+
self.img_context_token_id = config.img_context_token_id
|
| 198 |
+
self.video_context_token_id = config.video_context_token_id
|
| 199 |
+
|
| 200 |
+
# Per-tile token dimensions (e.g. 14×14 for 448px, patch=16, ds=0.5)
|
| 201 |
+
self.tile_h = int((image_size // patch_size) * config.downsample_ratio)
|
| 202 |
+
self.tile_w = self.tile_h
|
| 203 |
+
|
| 204 |
+
logger.info(f"num_image_token: {self.num_image_token}")
|
| 205 |
+
logger.info(f"tile_h={self.tile_h}, tile_w={self.tile_w}")
|
| 206 |
+
logger.info(f"ps_version: {self.ps_version}")
|
| 207 |
+
logger.info(f"Vision encoder: {config.vision_config.version}")
|
| 208 |
+
logger.info(
|
| 209 |
+
f"LLM: Qwen3.5 ({config.llm_config.num_hidden_layers} layers, "
|
| 210 |
+
f"hidden={config.llm_config.hidden_size}, "
|
| 211 |
+
f"hybrid="
|
| 212 |
+
f"{sum(1 for t in config.llm_config.layer_types if t == 'linear_attention')} linear + "
|
| 213 |
+
f"{sum(1 for t in config.llm_config.layer_types if t == 'full_attention')} full)"
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
# ── Language model ───────────────────────────────────────────────────
|
| 217 |
+
self.language_model = Qwen3_5ForCausalLM(config.llm_config)
|
| 218 |
+
|
| 219 |
+
# ── Vision encoder ───────────────────────────────────────────────────
|
| 220 |
+
self.vision_model = RADIOModel(config.vision_config)
|
| 221 |
+
self.vision_model.model._initialize_weights = (
|
| 222 |
+
self.vision_model.model._init_weights
|
| 223 |
+
)
|
| 224 |
+
self.vision_model.radio_model.make_preprocessor_external()
|
| 225 |
+
self.vision_model = self.vision_model.to(
|
| 226 |
+
self.language_model.config.torch_dtype
|
| 227 |
+
)
|
| 228 |
+
|
| 229 |
+
self.drop_vision_class_token = True
|
| 230 |
+
|
| 231 |
+
# ── MLP projector ────────────────────────────────────────────────────
|
| 232 |
+
vit_hidden_size = config.vit_hidden_size
|
| 233 |
+
proj_hidden = config.projector_hidden_size
|
| 234 |
+
llm_hidden = config.llm_config.hidden_size
|
| 235 |
+
pixel_shuffle_dim = vit_hidden_size * int(1 / self.downsample_ratio) ** 2
|
| 236 |
+
|
| 237 |
+
self.mlp1 = nn.Sequential(
|
| 238 |
+
RMSNorm(pixel_shuffle_dim, eps=1e-5),
|
| 239 |
+
nn.Linear(pixel_shuffle_dim, proj_hidden, bias=False),
|
| 240 |
+
SquaredReLU(),
|
| 241 |
+
nn.Linear(proj_hidden, llm_hidden, bias=False),
|
| 242 |
+
)
|
| 243 |
+
self.mlp1 = self.mlp1.to(self.language_model.config.torch_dtype)
|
| 244 |
+
|
| 245 |
+
# Cached rope_deltas for multi-step generation
|
| 246 |
+
self.rope_deltas = None
|
| 247 |
+
|
| 248 |
+
# ── Embedding accessors (required by GenerationMixin) ─────────────────
|
| 249 |
+
|
| 250 |
+
def get_input_embeddings(self):
|
| 251 |
+
return self.language_model.get_input_embeddings()
|
| 252 |
+
|
| 253 |
+
def set_input_embeddings(self, value):
|
| 254 |
+
self.language_model.set_input_embeddings(value)
|
| 255 |
+
|
| 256 |
+
def get_output_embeddings(self):
|
| 257 |
+
return self.language_model.lm_head
|
| 258 |
+
|
| 259 |
+
def set_output_embeddings(self, new_embeddings):
|
| 260 |
+
self.language_model.lm_head = new_embeddings
|
| 261 |
+
|
| 262 |
+
def gradient_checkpointing_enable(self, gradient_checkpointing_kwargs=None):
|
| 263 |
+
# 大头在 LLM:直接委托给内层 Qwen3.5(它原生支持 GC)
|
| 264 |
+
self.language_model.gradient_checkpointing_enable(
|
| 265 |
+
gradient_checkpointing_kwargs=gradient_checkpointing_kwargs
|
| 266 |
+
)
|
| 267 |
+
# 视觉塔可选:支持就开,不支持就跳过(不影响主显存)
|
| 268 |
+
vm = getattr(self, "vision_model", None)
|
| 269 |
+
if vm is not None and getattr(vm, "supports_gradient_checkpointing", False):
|
| 270 |
+
try:
|
| 271 |
+
vm.gradient_checkpointing_enable(
|
| 272 |
+
gradient_checkpointing_kwargs=gradient_checkpointing_kwargs
|
| 273 |
+
)
|
| 274 |
+
except Exception:
|
| 275 |
+
pass
|
| 276 |
+
|
| 277 |
+
def gradient_checkpointing_disable(self):
|
| 278 |
+
self.language_model.gradient_checkpointing_disable()
|
| 279 |
+
vm = getattr(self, "vision_model", None)
|
| 280 |
+
if vm is not None and hasattr(vm, "gradient_checkpointing_disable"):
|
| 281 |
+
try:
|
| 282 |
+
vm.gradient_checkpointing_disable()
|
| 283 |
+
except Exception:
|
| 284 |
+
pass
|
| 285 |
+
|
| 286 |
+
# ─────────────────────────────────────────────────────────────────────────
|
| 287 |
+
# Vision helpers
|
| 288 |
+
# ─────────────────────────────────────────────────────────────────────────
|
| 289 |
+
|
| 290 |
+
def pixel_shuffle(
|
| 291 |
+
self, x: torch.Tensor, scale_factor: float = 0.5
|
| 292 |
+
) -> torch.Tensor:
|
| 293 |
+
"""Space-to-depth rearrangement (ps_version='v2' = corrected layout)."""
|
| 294 |
+
n, w, h, c = x.size()
|
| 295 |
+
x = x.view(n, w, int(h * scale_factor), int(c / scale_factor))
|
| 296 |
+
x = x.permute(0, 2, 1, 3).contiguous()
|
| 297 |
+
x = x.view(
|
| 298 |
+
n, int(h * scale_factor), int(w * scale_factor),
|
| 299 |
+
int(c / (scale_factor * scale_factor)),
|
| 300 |
+
)
|
| 301 |
+
if self.ps_version == "v1":
|
| 302 |
+
warnings.warn(
|
| 303 |
+
"ps_version='v1' produces a transposed spatial layout. "
|
| 304 |
+
"Use ps_version='v2' for correct output."
|
| 305 |
+
)
|
| 306 |
+
else:
|
| 307 |
+
x = x.permute(0, 2, 1, 3).contiguous()
|
| 308 |
+
return x
|
| 309 |
+
|
| 310 |
+
def extract_feature(self, pixel_values: torch.Tensor) -> torch.Tensor:
|
| 311 |
+
"""Run pixels through C-RADIOv4-H → pixel_shuffle → MLP projector."""
|
| 312 |
+
vit_embeds = self.vision_model(pixel_values).features
|
| 313 |
+
vit_embeds = vit_embeds.to(dtype=torch.bfloat16)
|
| 314 |
+
|
| 315 |
+
h = w = int(vit_embeds.shape[1] ** 0.5)
|
| 316 |
+
vit_embeds = vit_embeds.reshape(vit_embeds.shape[0], h, w, -1)
|
| 317 |
+
vit_embeds = self.pixel_shuffle(
|
| 318 |
+
vit_embeds, scale_factor=self.downsample_ratio
|
| 319 |
+
)
|
| 320 |
+
vit_embeds = vit_embeds.reshape(
|
| 321 |
+
vit_embeds.shape[0], -1, vit_embeds.shape[-1]
|
| 322 |
+
)
|
| 323 |
+
vit_embeds = self.mlp1(vit_embeds)
|
| 324 |
+
return vit_embeds
|
| 325 |
+
|
| 326 |
+
# ─────────────────────────────────────────────────────────────────────────
|
| 327 |
+
# 3D M-RoPE position IDs
|
| 328 |
+
# ─────────────────────────────────────────────────────────────────────────
|
| 329 |
+
|
| 330 |
+
def get_vision_position_ids(
|
| 331 |
+
self,
|
| 332 |
+
start_position: int,
|
| 333 |
+
tile_rows: int,
|
| 334 |
+
tile_cols: int,
|
| 335 |
+
has_thumbnail: bool = True,
|
| 336 |
+
device: torch.device = None,
|
| 337 |
+
) -> torch.LongTensor:
|
| 338 |
+
"""
|
| 339 |
+
Compute 3D (temporal, height, width) position IDs for vision tokens
|
| 340 |
+
from a single InternVL-style tiled image.
|
| 341 |
+
|
| 342 |
+
Token layout (flattened order expected by the model):
|
| 343 |
+
1. Grid tiles in raster order: tile(0,0), tile(0,1), …, tile(R-1,C-1).
|
| 344 |
+
Each tile has ``tile_h × tile_w`` tokens in raster order.
|
| 345 |
+
2. Thumbnail tile (optional): a single tile covering the full image
|
| 346 |
+
at reduced resolution.
|
| 347 |
+
|
| 348 |
+
Args:
|
| 349 |
+
start_position: Offset added to all positional indices.
|
| 350 |
+
tile_rows: Number of tile rows in the image grid.
|
| 351 |
+
tile_cols: Number of tile columns in the image grid.
|
| 352 |
+
has_thumbnail: Whether a thumbnail tile is appended after grid tiles.
|
| 353 |
+
device: Target device.
|
| 354 |
+
|
| 355 |
+
Returns:
|
| 356 |
+
``torch.LongTensor`` of shape ``(3, num_vision_tokens)``.
|
| 357 |
+
"""
|
| 358 |
+
tile_h, tile_w = self.tile_h, self.tile_w
|
| 359 |
+
npt = tile_h * tile_w # num tokens per tile
|
| 360 |
+
|
| 361 |
+
# ── Grid tiles ───────────────────────────────────────────────────────
|
| 362 |
+
num_grid_tiles = tile_rows * tile_cols
|
| 363 |
+
tile_idx = torch.arange(num_grid_tiles, device=device)
|
| 364 |
+
tr = tile_idx // tile_cols
|
| 365 |
+
tc = tile_idx % tile_cols
|
| 366 |
+
|
| 367 |
+
local_idx = torch.arange(npt, device=device)
|
| 368 |
+
lr = local_idx // tile_w
|
| 369 |
+
lc = local_idx % tile_w
|
| 370 |
+
|
| 371 |
+
# (num_grid_tiles, npt) → flatten
|
| 372 |
+
global_h = (tr[:, None] * tile_h + lr[None, :]).reshape(-1).long()
|
| 373 |
+
global_w = (tc[:, None] * tile_w + lc[None, :]).reshape(-1).long()
|
| 374 |
+
|
| 375 |
+
total_grid = num_grid_tiles * npt
|
| 376 |
+
pos_t = torch.full(
|
| 377 |
+
(total_grid,), start_position, device=device, dtype=torch.long
|
| 378 |
+
)
|
| 379 |
+
pos_h = start_position + global_h
|
| 380 |
+
pos_w = start_position + global_w
|
| 381 |
+
|
| 382 |
+
# ── Thumbnail tile ───────────────────────────────────────────────────
|
| 383 |
+
if has_thumbnail:
|
| 384 |
+
# Map thumbnail local(r, c) → global(r * tile_rows, c * tile_cols)
|
| 385 |
+
# so its positions overlay the grid at coarser resolution.
|
| 386 |
+
thumb_h = (lr * tile_rows).long()
|
| 387 |
+
thumb_w = (lc * tile_cols).long()
|
| 388 |
+
pos_t = torch.cat([
|
| 389 |
+
pos_t,
|
| 390 |
+
torch.full(
|
| 391 |
+
(npt,), start_position, device=device, dtype=torch.long
|
| 392 |
+
),
|
| 393 |
+
])
|
| 394 |
+
pos_h = torch.cat([pos_h, start_position + thumb_h])
|
| 395 |
+
pos_w = torch.cat([pos_w, start_position + thumb_w])
|
| 396 |
+
|
| 397 |
+
return torch.stack([pos_t, pos_h, pos_w], dim=0)
|
| 398 |
+
|
| 399 |
+
def get_rope_index(
|
| 400 |
+
self,
|
| 401 |
+
input_ids: torch.LongTensor,
|
| 402 |
+
mm_token_type_ids: torch.IntTensor,
|
| 403 |
+
image_grid_thw: Optional[torch.LongTensor] = None,
|
| 404 |
+
video_grid_thw: Optional[torch.LongTensor] = None,
|
| 405 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 406 |
+
**kwargs,
|
| 407 |
+
) -> Tuple[torch.Tensor, torch.Tensor]:
|
| 408 |
+
"""
|
| 409 |
+
Compute 3D M-RoPE position IDs for a mixed vision + text sequence.
|
| 410 |
+
|
| 411 |
+
Follows the same structure as ``Qwen3_5Model.get_rope_index``:
|
| 412 |
+
uses ``mm_token_type_ids`` to group tokens by modality
|
| 413 |
+
(text=0, image=1, video=2) via ``itertools.groupby``. Vision
|
| 414 |
+
tokens receive spatial position IDs (temporal, height, width)
|
| 415 |
+
while text tokens receive standard 1D positions.
|
| 416 |
+
|
| 417 |
+
Args:
|
| 418 |
+
input_ids: ``(B, S)`` token IDs.
|
| 419 |
+
mm_token_type_ids: ``(B, S)`` modality labels —
|
| 420 |
+
0 = text, 1 = image, 2 = video.
|
| 421 |
+
image_grid_thw: ``(num_images, 3)`` — each row
|
| 422 |
+
``(T=1, tile_rows, tile_cols)`` for InternVL-style tiled images.
|
| 423 |
+
video_grid_thw: ``(num_videos, 3)`` — each row
|
| 424 |
+
``(num_frames, 1, 1)``.
|
| 425 |
+
attention_mask: ``(B, S)`` binary mask.
|
| 426 |
+
|
| 427 |
+
Returns:
|
| 428 |
+
``position_ids``: ``(3, B, S)``
|
| 429 |
+
``mrope_position_deltas``: ``(B, 1)``
|
| 430 |
+
"""
|
| 431 |
+
tile_h, tile_w = self.tile_h, self.tile_w
|
| 432 |
+
npt = tile_h * tile_w
|
| 433 |
+
|
| 434 |
+
B, S = input_ids.shape
|
| 435 |
+
device = input_ids.device
|
| 436 |
+
|
| 437 |
+
position_ids = torch.zeros(3, B, S, dtype=input_ids.dtype, device=device)
|
| 438 |
+
mrope_position_deltas = []
|
| 439 |
+
|
| 440 |
+
# ------------------------------------------------------------------
|
| 441 |
+
# video-as-image compatibility for verl / vLLM rollout.
|
| 442 |
+
# ------------------------------------------------------------------
|
| 443 |
+
if mm_token_type_ids is not None and video_grid_thw is None and torch.any(mm_token_type_ids == 2).item():
|
| 444 |
+
mm_token_type_ids = mm_token_type_ids.clone()
|
| 445 |
+
|
| 446 |
+
if image_grid_thw is not None:
|
| 447 |
+
# Count contiguous visual groups, because get_rope_index consumes
|
| 448 |
+
# one grid_thw row per contiguous image/video segment.
|
| 449 |
+
total_visual_groups = 0
|
| 450 |
+
for b in range(mm_token_type_ids.shape[0]):
|
| 451 |
+
cur_types = mm_token_type_ids[b]
|
| 452 |
+
if attention_mask is not None:
|
| 453 |
+
cur_types = cur_types[attention_mask[b].bool()]
|
| 454 |
+
|
| 455 |
+
prev_type = None
|
| 456 |
+
for t in cur_types.tolist():
|
| 457 |
+
if t in (1, 2) and t != prev_type:
|
| 458 |
+
total_visual_groups += 1
|
| 459 |
+
prev_type = t
|
| 460 |
+
|
| 461 |
+
num_image_grids = image_grid_thw.shape[0]
|
| 462 |
+
|
| 463 |
+
if total_visual_groups <= num_image_grids:
|
| 464 |
+
# True video-as-image case: consume image_grid_thw for both image and video types.
|
| 465 |
+
mm_token_type_ids[mm_token_type_ids == 2] = 1
|
| 466 |
+
|
| 467 |
+
if "logger" in globals():
|
| 468 |
+
logger.warning_once(
|
| 469 |
+
"Converting mm_token_type_ids type 2 to type 1 because "
|
| 470 |
+
"video_grid_thw is None and image_grid_thw has enough grids. "
|
| 471 |
+
"This matches video-as-image processing."
|
| 472 |
+
)
|
| 473 |
+
else:
|
| 474 |
+
# Some type-2 tokens are likely generated orphan <|video_pad|> tokens.
|
| 475 |
+
# Treat them as text to avoid consuming non-existent grids.
|
| 476 |
+
mm_token_type_ids[mm_token_type_ids == 2] = 0
|
| 477 |
+
|
| 478 |
+
if "logger" in globals():
|
| 479 |
+
logger.warning_once(
|
| 480 |
+
"mm_token_type_ids contains type 2 but video_grid_thw is None, "
|
| 481 |
+
"and image_grid_thw does not have enough grids. Treating type 2 "
|
| 482 |
+
"as text. This likely means the model generated orphan <|video_pad|> tokens."
|
| 483 |
+
)
|
| 484 |
+
else:
|
| 485 |
+
# No visual grid exists, so type 2 cannot represent valid visual tokens.
|
| 486 |
+
mm_token_type_ids[mm_token_type_ids == 2] = 0
|
| 487 |
+
|
| 488 |
+
if "logger" in globals():
|
| 489 |
+
logger.warning_once(
|
| 490 |
+
"mm_token_type_ids contains type 2, but both video_grid_thw and "
|
| 491 |
+
"image_grid_thw are None. Treating type 2 as text."
|
| 492 |
+
)
|
| 493 |
+
|
| 494 |
+
grid_iters = {
|
| 495 |
+
1: iter(image_grid_thw) if image_grid_thw is not None else None,
|
| 496 |
+
2: iter(video_grid_thw) if video_grid_thw is not None else None,
|
| 497 |
+
}
|
| 498 |
+
|
| 499 |
+
for batch_idx, current_input_ids in enumerate(input_ids):
|
| 500 |
+
input_token_type = mm_token_type_ids[batch_idx]
|
| 501 |
+
if attention_mask is not None:
|
| 502 |
+
current_input_ids = current_input_ids[attention_mask[batch_idx].bool()]
|
| 503 |
+
input_token_type = input_token_type[attention_mask[batch_idx].bool()]
|
| 504 |
+
|
| 505 |
+
# Group contiguous runs of the same modality type
|
| 506 |
+
input_type_group = []
|
| 507 |
+
for key, group in itertools.groupby(
|
| 508 |
+
enumerate(input_token_type.tolist()), lambda x: x[1]
|
| 509 |
+
):
|
| 510 |
+
group = list(group)
|
| 511 |
+
start_index = group[0][0]
|
| 512 |
+
end_index = group[-1][0] + 1
|
| 513 |
+
input_type_group.append((key, start_index, end_index))
|
| 514 |
+
|
| 515 |
+
current_pos = 0
|
| 516 |
+
llm_pos_ids_list: List[torch.Tensor] = []
|
| 517 |
+
|
| 518 |
+
# ── Per-video state machine ──────────────────────────────────────
|
| 519 |
+
# Mirrors the Megatron-side implementation in
|
| 520 |
+
# modeling.py: a single video_grid_thw entry
|
| 521 |
+
# of [num_frames, 1, 1] is consumed across multiple non-contiguous
|
| 522 |
+
# type-2 runs (one per <|video_pad|> block, separated by frame
|
| 523 |
+
# header text).
|
| 524 |
+
#
|
| 525 |
+
# Within a video, every frame's tokens use:
|
| 526 |
+
# t = vid_spatial_start + frame_idx (anchored at video start)
|
| 527 |
+
# h = vid_spatial_start + local_row (constant across frames)
|
| 528 |
+
# w = vid_spatial_start + local_col (constant across frames)
|
| 529 |
+
#
|
| 530 |
+
# Text between frames advances ``current_pos`` normally — those
|
| 531 |
+
# text positions live in a different range than the video frame
|
| 532 |
+
# positions, which is fine for M-RoPE (RoPE requires no
|
| 533 |
+
# monotonicity, only consistent training/inference).
|
| 534 |
+
vid_active = False
|
| 535 |
+
vid_num_frames = 0
|
| 536 |
+
vid_frame_idx = 0
|
| 537 |
+
vid_spatial_start = 0
|
| 538 |
+
|
| 539 |
+
for modality_type, start_idx, end_idx in input_type_group:
|
| 540 |
+
# text == 0
|
| 541 |
+
if modality_type == 0:
|
| 542 |
+
text_len = end_idx - start_idx
|
| 543 |
+
llm_pos_ids_list.append(
|
| 544 |
+
torch.arange(text_len, device=device).view(1, -1).expand(3, -1)
|
| 545 |
+
+ current_pos
|
| 546 |
+
)
|
| 547 |
+
current_pos += text_len
|
| 548 |
+
|
| 549 |
+
# image == 1
|
| 550 |
+
elif modality_type == 1:
|
| 551 |
+
seg_len = end_idx - start_idx
|
| 552 |
+
grid = next(grid_iters[1])
|
| 553 |
+
tile_rows = grid[1].item()
|
| 554 |
+
tile_cols = grid[2].item()
|
| 555 |
+
grid_tokens = tile_rows * tile_cols * npt
|
| 556 |
+
has_thumbnail = seg_len > grid_tokens
|
| 557 |
+
|
| 558 |
+
vpos = self.get_vision_position_ids(
|
| 559 |
+
start_position=current_pos,
|
| 560 |
+
tile_rows=tile_rows,
|
| 561 |
+
tile_cols=tile_cols,
|
| 562 |
+
has_thumbnail=has_thumbnail,
|
| 563 |
+
device=device,
|
| 564 |
+
)
|
| 565 |
+
assert vpos.shape[1] == seg_len, (
|
| 566 |
+
f"Position count ({vpos.shape[1]}) ≠ image token count "
|
| 567 |
+
f"({seg_len}) for grid=({tile_rows},{tile_cols}), "
|
| 568 |
+
f"thumbnail={has_thumbnail}"
|
| 569 |
+
)
|
| 570 |
+
llm_pos_ids_list.append(vpos)
|
| 571 |
+
current_pos += max(tile_rows * tile_h, tile_cols * tile_w)
|
| 572 |
+
|
| 573 |
+
# video == 2
|
| 574 |
+
elif modality_type == 2:
|
| 575 |
+
seg_len = end_idx - start_idx
|
| 576 |
+
|
| 577 |
+
# Activate per-video state on the FIRST type-2 run for
|
| 578 |
+
# this video. Subsequent type-2 runs (one per frame
|
| 579 |
+
# block, separated by frame-header text) reuse the same
|
| 580 |
+
# vid_spatial_start anchor.
|
| 581 |
+
if not vid_active:
|
| 582 |
+
grid = next(grid_iters[2])
|
| 583 |
+
vid_num_frames = grid[0].item()
|
| 584 |
+
vid_active = True
|
| 585 |
+
vid_frame_idx = 0
|
| 586 |
+
vid_spatial_start = current_pos
|
| 587 |
+
|
| 588 |
+
# Each frame contributes exactly ``npt`` tokens.
|
| 589 |
+
if seg_len % npt != 0:
|
| 590 |
+
raise ValueError(
|
| 591 |
+
f"Video segment length {seg_len} is not a "
|
| 592 |
+
f"multiple of npt={npt} (tile_h*tile_w). "
|
| 593 |
+
f"Check that the processor produced one "
|
| 594 |
+
f"<|video_pad|> block per frame with exactly "
|
| 595 |
+
f"npt tokens each."
|
| 596 |
+
)
|
| 597 |
+
frames_in_run = seg_len // npt
|
| 598 |
+
|
| 599 |
+
# Sanity guard against malformed grids — never consume
|
| 600 |
+
# more frames than the grid declared.
|
| 601 |
+
if vid_frame_idx + frames_in_run > vid_num_frames:
|
| 602 |
+
raise ValueError(
|
| 603 |
+
f"Video has {vid_num_frames} frames but "
|
| 604 |
+
f"input_ids contain at least "
|
| 605 |
+
f"{vid_frame_idx + frames_in_run} frame blocks. "
|
| 606 |
+
f"Check the processor's video_grid_thw against "
|
| 607 |
+
f"the actual <|video_pad|> count."
|
| 608 |
+
)
|
| 609 |
+
|
| 610 |
+
local_idx = torch.arange(npt, device=device)
|
| 611 |
+
lr = local_idx // tile_w
|
| 612 |
+
lc = local_idx % tile_w
|
| 613 |
+
|
| 614 |
+
all_t, all_h, all_w = [], [], []
|
| 615 |
+
for _ in range(frames_in_run):
|
| 616 |
+
# Temporal: anchored at video_start, advances by frame_idx.
|
| 617 |
+
all_t.append(torch.full(
|
| 618 |
+
(npt,),
|
| 619 |
+
vid_spatial_start + vid_frame_idx,
|
| 620 |
+
device=device, dtype=torch.long,
|
| 621 |
+
))
|
| 622 |
+
# Spatial: constant base across frames within this video.
|
| 623 |
+
all_h.append((vid_spatial_start + lr).long())
|
| 624 |
+
all_w.append((vid_spatial_start + lc).long())
|
| 625 |
+
vid_frame_idx += 1
|
| 626 |
+
# Advance current_pos by one frame's spatial extent so
|
| 627 |
+
# subsequent text positions stay strictly above any
|
| 628 |
+
# h/w position used by this video. After all frames,
|
| 629 |
+
# current_pos has advanced by num_frames * max(tile_h, tile_w),
|
| 630 |
+
# which always exceeds vid_spatial_start + max(num_frames, tile_h, tile_w)
|
| 631 |
+
# for num_frames >= 1 (so text after the video sees
|
| 632 |
+
# positions strictly greater than every video token).
|
| 633 |
+
current_pos += max(tile_h, tile_w)
|
| 634 |
+
|
| 635 |
+
vpos = torch.stack([
|
| 636 |
+
torch.cat(all_t), torch.cat(all_h), torch.cat(all_w),
|
| 637 |
+
], dim=0)
|
| 638 |
+
assert vpos.shape[1] == seg_len, (
|
| 639 |
+
f"Position count ({vpos.shape[1]}) ≠ video token "
|
| 640 |
+
f"count ({seg_len})"
|
| 641 |
+
)
|
| 642 |
+
llm_pos_ids_list.append(vpos)
|
| 643 |
+
|
| 644 |
+
# End the video once all declared frames have been
|
| 645 |
+
# consumed; reset state so the next video (if any) gets
|
| 646 |
+
# a fresh grid pull.
|
| 647 |
+
if vid_frame_idx >= vid_num_frames:
|
| 648 |
+
vid_active = False
|
| 649 |
+
vid_num_frames = 0
|
| 650 |
+
vid_frame_idx = 0
|
| 651 |
+
vid_spatial_start = 0
|
| 652 |
+
|
| 653 |
+
# Sanity check: if a video's last frame isn't followed by any text,
|
| 654 |
+
# the loop ends with vid_active=False (we already reset on the
|
| 655 |
+
# final frame). But if the input is malformed and the type-2
|
| 656 |
+
# runs don't cover all declared frames, surface that loudly
|
| 657 |
+
# rather than silently advancing the iterator the next time we
|
| 658 |
+
# see another video.
|
| 659 |
+
if vid_active:
|
| 660 |
+
raise ValueError(
|
| 661 |
+
f"Reached end of input with video state still active: "
|
| 662 |
+
f"consumed {vid_frame_idx}/{vid_num_frames} frames. "
|
| 663 |
+
f"video_grid_thw declares more frames than the "
|
| 664 |
+
f"<|video_pad|> blocks contain."
|
| 665 |
+
)
|
| 666 |
+
|
| 667 |
+
llm_positions = torch.cat(llm_pos_ids_list, dim=1).reshape(3, -1)
|
| 668 |
+
if attention_mask is not None:
|
| 669 |
+
position_ids[:, batch_idx, attention_mask[batch_idx].bool()] = (
|
| 670 |
+
llm_positions.to(position_ids.device)
|
| 671 |
+
)
|
| 672 |
+
else:
|
| 673 |
+
position_ids[:, batch_idx] = llm_positions.to(position_ids.device)
|
| 674 |
+
|
| 675 |
+
mrope_position_deltas.append(
|
| 676 |
+
llm_positions.max() + 1 - len(current_input_ids)
|
| 677 |
+
)
|
| 678 |
+
|
| 679 |
+
mrope_position_deltas = torch.tensor(
|
| 680 |
+
mrope_position_deltas, device=device
|
| 681 |
+
).unsqueeze(1)
|
| 682 |
+
return position_ids, mrope_position_deltas
|
| 683 |
+
|
| 684 |
+
def _build_text_position_ids(
|
| 685 |
+
self,
|
| 686 |
+
input_ids: torch.LongTensor,
|
| 687 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 688 |
+
) -> torch.LongTensor:
|
| 689 |
+
"""
|
| 690 |
+
Build text position ids of shape (B, S).
|
| 691 |
+
For padding mask, positions are 0,1,2,... on valid tokens.
|
| 692 |
+
Padding positions stay 0.
|
| 693 |
+
"""
|
| 694 |
+
batch_size, seq_len = input_ids.shape
|
| 695 |
+
device = input_ids.device
|
| 696 |
+
|
| 697 |
+
if attention_mask is not None:
|
| 698 |
+
valid = attention_mask > 0
|
| 699 |
+
text_position_ids = valid.long().cumsum(-1) - 1
|
| 700 |
+
text_position_ids = text_position_ids.masked_fill(~valid, 0)
|
| 701 |
+
else:
|
| 702 |
+
text_position_ids = torch.arange(
|
| 703 |
+
seq_len, device=device, dtype=torch.long
|
| 704 |
+
).unsqueeze(0).expand(batch_size, -1)
|
| 705 |
+
|
| 706 |
+
return text_position_ids.contiguous()
|
| 707 |
+
def _prepend_text_position_channel(
|
| 708 |
+
self,
|
| 709 |
+
input_ids: torch.LongTensor,
|
| 710 |
+
vision_position_ids: torch.LongTensor,
|
| 711 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 712 |
+
) -> torch.LongTensor:
|
| 713 |
+
"""
|
| 714 |
+
Convert vision M-RoPE position ids from (3, B, S) to Qwen3.5-compatible
|
| 715 |
+
position ids of shape (4, B, S):
|
| 716 |
+
|
| 717 |
+
channel 0 : text positions, used for causal mask / FA2 varlen logic
|
| 718 |
+
channel 1-3 : temporal / height / width vision M-RoPE positions
|
| 719 |
+
"""
|
| 720 |
+
if vision_position_ids is None:
|
| 721 |
+
return None
|
| 722 |
+
|
| 723 |
+
if vision_position_ids.dim() == 3 and vision_position_ids.shape[0] == 4:
|
| 724 |
+
return vision_position_ids.contiguous()
|
| 725 |
+
|
| 726 |
+
assert vision_position_ids.dim() == 3 and vision_position_ids.shape[0] == 3, (
|
| 727 |
+
f"Expected vision_position_ids shape (3, B, S), got "
|
| 728 |
+
f"{tuple(vision_position_ids.shape)}"
|
| 729 |
+
)
|
| 730 |
+
|
| 731 |
+
text_position_ids = self._build_text_position_ids(
|
| 732 |
+
input_ids=input_ids,
|
| 733 |
+
attention_mask=attention_mask,
|
| 734 |
+
).to(device=vision_position_ids.device)
|
| 735 |
+
|
| 736 |
+
position_ids = torch.cat(
|
| 737 |
+
[
|
| 738 |
+
text_position_ids.unsqueeze(0), # (1, B, S)
|
| 739 |
+
vision_position_ids, # (3, B, S)
|
| 740 |
+
],
|
| 741 |
+
dim=0,
|
| 742 |
+
)
|
| 743 |
+
return position_ids.contiguous()
|
| 744 |
+
|
| 745 |
+
def _compute_position_ids(
|
| 746 |
+
self,
|
| 747 |
+
input_ids: Optional[torch.LongTensor],
|
| 748 |
+
inputs_embeds: torch.FloatTensor,
|
| 749 |
+
image_grid_thw: Optional[torch.LongTensor],
|
| 750 |
+
video_grid_thw: Optional[torch.LongTensor],
|
| 751 |
+
attention_mask: Optional[torch.Tensor],
|
| 752 |
+
past_key_values=None,
|
| 753 |
+
mm_token_type_ids: Optional[torch.IntTensor] = None,
|
| 754 |
+
use_cache: Optional[bool] = None,
|
| 755 |
+
) -> Optional[torch.Tensor]:
|
| 756 |
+
"""
|
| 757 |
+
Mirror of ``Qwen3_5Model.compute_3d_position_ids``.
|
| 758 |
+
|
| 759 |
+
- Vision info available + first forward → ``get_rope_index``, cache
|
| 760 |
+
``rope_deltas``.
|
| 761 |
+
- ``rope_deltas`` cached (decode step) → derive from attention_mask +
|
| 762 |
+
``rope_deltas``.
|
| 763 |
+
- Pure text → return ``None`` (``Qwen3_5TextModel`` auto-generates).
|
| 764 |
+
"""
|
| 765 |
+
past_length = 0
|
| 766 |
+
if past_key_values is not None:
|
| 767 |
+
past_length = past_key_values.get_seq_length()
|
| 768 |
+
|
| 769 |
+
can_compute = (
|
| 770 |
+
input_ids is not None
|
| 771 |
+
and mm_token_type_ids is not None
|
| 772 |
+
and (image_grid_thw is not None or video_grid_thw is not None)
|
| 773 |
+
)
|
| 774 |
+
|
| 775 |
+
if can_compute and past_length == 0:
|
| 776 |
+
vision_position_ids, rope_deltas = self.get_rope_index(
|
| 777 |
+
input_ids,
|
| 778 |
+
mm_token_type_ids=mm_token_type_ids,
|
| 779 |
+
image_grid_thw=image_grid_thw,
|
| 780 |
+
video_grid_thw=video_grid_thw,
|
| 781 |
+
attention_mask=attention_mask,
|
| 782 |
+
)
|
| 783 |
+
|
| 784 |
+
# Training / log-prob forward should not keep rope_deltas across batches.
|
| 785 |
+
# Generation prefill can keep it for decode.
|
| 786 |
+
if use_cache:
|
| 787 |
+
self.rope_deltas = rope_deltas
|
| 788 |
+
else:
|
| 789 |
+
self.rope_deltas = None
|
| 790 |
+
|
| 791 |
+
return self._prepend_text_position_channel(
|
| 792 |
+
input_ids=input_ids,
|
| 793 |
+
vision_position_ids=vision_position_ids,
|
| 794 |
+
attention_mask=attention_mask,
|
| 795 |
+
)
|
| 796 |
+
|
| 797 |
+
elif self.rope_deltas is not None and past_length != 0:
|
| 798 |
+
batch_size, seq_length = inputs_embeds.shape[:2]
|
| 799 |
+
|
| 800 |
+
if attention_mask is not None:
|
| 801 |
+
text_position_ids = attention_mask.long().cumsum(-1) - 1
|
| 802 |
+
text_position_ids = text_position_ids.masked_fill(attention_mask == 0, 0)
|
| 803 |
+
text_position_ids = text_position_ids[:, -seq_length:]
|
| 804 |
+
else:
|
| 805 |
+
text_position_ids = torch.arange(
|
| 806 |
+
past_length,
|
| 807 |
+
past_length + seq_length,
|
| 808 |
+
device=inputs_embeds.device,
|
| 809 |
+
dtype=torch.long,
|
| 810 |
+
).unsqueeze(0).expand(batch_size, -1)
|
| 811 |
+
|
| 812 |
+
delta = self.rope_deltas.repeat_interleave(
|
| 813 |
+
batch_size // self.rope_deltas.shape[0], dim=0
|
| 814 |
+
).to(device=inputs_embeds.device)
|
| 815 |
+
|
| 816 |
+
# Decode step follows generation convention: (1, B, S)
|
| 817 |
+
position_ids = text_position_ids.unsqueeze(0) + delta.view(1, batch_size, 1)
|
| 818 |
+
return position_ids.contiguous()
|
| 819 |
+
|
| 820 |
+
return None
|
| 821 |
+
|
| 822 |
+
# ─────────────────────────────────────────────────────────────────────────
|
| 823 |
+
# Forward
|
| 824 |
+
# ─────────────────────────────────────────────────────────────────────────
|
| 825 |
+
|
| 826 |
+
def forward(
|
| 827 |
+
self,
|
| 828 |
+
input_ids: torch.LongTensor = None,
|
| 829 |
+
pixel_values: Optional[torch.FloatTensor] = None,
|
| 830 |
+
pixel_values_videos: Optional[torch.FloatTensor] = None,
|
| 831 |
+
num_patches = None,
|
| 832 |
+
image_flags: Optional[torch.LongTensor] = None,
|
| 833 |
+
image_grid_thw: Optional[torch.LongTensor] = None,
|
| 834 |
+
video_grid_thw: Optional[torch.LongTensor] = None,
|
| 835 |
+
mm_token_type_ids: Optional[torch.IntTensor] = None,
|
| 836 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 837 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 838 |
+
past_key_values=None,
|
| 839 |
+
labels: Optional[torch.LongTensor] = None,
|
| 840 |
+
inputs_embeds: Optional[torch.FloatTensor] = None,
|
| 841 |
+
use_cache: Optional[bool] = None,
|
| 842 |
+
cache_position: Optional[torch.LongTensor] = None,
|
| 843 |
+
output_attentions: Optional[bool] = None,
|
| 844 |
+
output_hidden_states: Optional[bool] = None,
|
| 845 |
+
return_dict: Optional[bool] = None,
|
| 846 |
+
**kwargs,
|
| 847 |
+
) -> Union[Tuple, CausalLMOutputWithPast]:
|
| 848 |
+
"""
|
| 849 |
+
Forward pass for training and generation steps.
|
| 850 |
+
|
| 851 |
+
Args:
|
| 852 |
+
input_ids: ``(B, S)`` token IDs.
|
| 853 |
+
pixel_values: ``(total_tiles, C, H, W)`` image tiles from C-RADIOv4-H.
|
| 854 |
+
pixel_values_videos: ``(total_frames, C, H, W)`` video frames.
|
| 855 |
+
image_flags: ``(B, max_tiles)`` — 1 for real tiles, 0 for padding.
|
| 856 |
+
image_grid_thw: ``(num_images, 3)`` — ``(T=1, tile_rows, tile_cols)``
|
| 857 |
+
per image. Required for correct M-RoPE spatial positions.
|
| 858 |
+
video_grid_thw: ``(num_videos, 3)`` — ``(num_frames, 1, 1)`` per video.
|
| 859 |
+
mm_token_type_ids: ``(B, S)`` modality labels —
|
| 860 |
+
0 = text, 1 = image, 2 = video. Required for computing
|
| 861 |
+
3D M-RoPE position IDs. Produced by the processor.
|
| 862 |
+
attention_mask: ``(B, S)`` binary mask. Must be 2-D; the
|
| 863 |
+
``Qwen3_5TextModel`` internally creates the 4-D causal mask
|
| 864 |
+
for full-attention layers and the 2-D mask for DeltaNet layers.
|
| 865 |
+
position_ids: ``(3, B, S)`` or ``None``. If ``None`` and vision
|
| 866 |
+
tokens are present, computed via ``get_rope_index()``.
|
| 867 |
+
"""
|
| 868 |
+
return_dict = (
|
| 869 |
+
return_dict if return_dict is not None
|
| 870 |
+
else self.config.use_return_dict
|
| 871 |
+
)
|
| 872 |
+
|
| 873 |
+
# ── Embed tokens ─────────────────────────────────────────────────────
|
| 874 |
+
if inputs_embeds is None:
|
| 875 |
+
inputs_embeds = self.get_input_embeddings()(input_ids)
|
| 876 |
+
|
| 877 |
+
# ── Inject image features ────────────────────────────────────────────
|
| 878 |
+
if pixel_values is not None:
|
| 879 |
+
if image_flags is None:
|
| 880 |
+
image_flags = torch.ones(
|
| 881 |
+
pixel_values.shape[0], dtype=torch.long,
|
| 882 |
+
device=pixel_values.device,
|
| 883 |
+
)
|
| 884 |
+
image_flags_sq = image_flags.squeeze(-1)
|
| 885 |
+
vit_embeds = self.extract_feature(pixel_values)
|
| 886 |
+
vit_embeds = vit_embeds[image_flags_sq == 1]
|
| 887 |
+
del pixel_values
|
| 888 |
+
|
| 889 |
+
B, N, C = inputs_embeds.shape
|
| 890 |
+
flat = inputs_embeds.reshape(B * N, C)
|
| 891 |
+
ids_flat = input_ids.reshape(B * N)
|
| 892 |
+
selected = ids_flat == self.img_context_token_id
|
| 893 |
+
|
| 894 |
+
try:
|
| 895 |
+
flat[selected] = flat[selected] * 0.0 + vit_embeds.reshape(-1, C)
|
| 896 |
+
except Exception as e:
|
| 897 |
+
vit_flat = vit_embeds.reshape(-1, C)
|
| 898 |
+
logger.warning(
|
| 899 |
+
f"Image injection shape mismatch: {e}. "
|
| 900 |
+
f"selected={selected.sum()}, vit={vit_flat.shape}"
|
| 901 |
+
)
|
| 902 |
+
n_tok = selected.sum()
|
| 903 |
+
flat[selected] = flat[selected] * 0.0 + vit_flat[:n_tok]
|
| 904 |
+
del vit_embeds
|
| 905 |
+
inputs_embeds = flat.reshape(B, N, C)
|
| 906 |
+
|
| 907 |
+
# ── Inject video features ────────────────────────────────────────────
|
| 908 |
+
if pixel_values_videos is not None:
|
| 909 |
+
video_vit = self.extract_feature(pixel_values_videos)
|
| 910 |
+
del pixel_values_videos
|
| 911 |
+
|
| 912 |
+
B, N, C = inputs_embeds.shape
|
| 913 |
+
flat = inputs_embeds.reshape(B * N, C)
|
| 914 |
+
ids_flat = input_ids.reshape(B * N)
|
| 915 |
+
vmask = ids_flat == self.video_context_token_id
|
| 916 |
+
|
| 917 |
+
flat[vmask] = (
|
| 918 |
+
flat[vmask] * 0.0
|
| 919 |
+
+ video_vit.reshape(-1, C).to(flat.device, flat.dtype)
|
| 920 |
+
)
|
| 921 |
+
inputs_embeds = flat.reshape(B, N, C)
|
| 922 |
+
|
| 923 |
+
del video_vit
|
| 924 |
+
|
| 925 |
+
# GRPO actor/ref training and log-prob computation should not use cache.
|
| 926 |
+
if labels is not None:
|
| 927 |
+
use_cache = False
|
| 928 |
+
self.rope_deltas = None
|
| 929 |
+
|
| 930 |
+
# ── 3D position IDs ──────────────────────────────────────────────────
|
| 931 |
+
if position_ids is None:
|
| 932 |
+
position_ids = self._compute_position_ids(
|
| 933 |
+
input_ids=input_ids,
|
| 934 |
+
inputs_embeds=inputs_embeds,
|
| 935 |
+
image_grid_thw=image_grid_thw,
|
| 936 |
+
video_grid_thw=video_grid_thw,
|
| 937 |
+
attention_mask=attention_mask,
|
| 938 |
+
past_key_values=past_key_values,
|
| 939 |
+
mm_token_type_ids=mm_token_type_ids,
|
| 940 |
+
use_cache=use_cache,
|
| 941 |
+
)
|
| 942 |
+
|
| 943 |
+
if position_ids is not None:
|
| 944 |
+
position_ids = position_ids.contiguous()
|
| 945 |
+
|
| 946 |
+
# ── LLM forward ─────────────────────────────────────────────────────
|
| 947 |
+
outputs = self.language_model(
|
| 948 |
+
input_ids=None,
|
| 949 |
+
inputs_embeds=inputs_embeds,
|
| 950 |
+
attention_mask=attention_mask,
|
| 951 |
+
position_ids=position_ids,
|
| 952 |
+
past_key_values=past_key_values,
|
| 953 |
+
use_cache=use_cache,
|
| 954 |
+
cache_position=cache_position,
|
| 955 |
+
output_attentions=output_attentions,
|
| 956 |
+
output_hidden_states=output_hidden_states,
|
| 957 |
+
return_dict=return_dict,
|
| 958 |
+
)
|
| 959 |
+
logits = outputs.logits
|
| 960 |
+
|
| 961 |
+
loss = None
|
| 962 |
+
if labels is not None:
|
| 963 |
+
shift_logits = logits[..., :-1, :].contiguous()
|
| 964 |
+
shift_labels = labels[..., 1:].contiguous()
|
| 965 |
+
loss_fct = CrossEntropyLoss()
|
| 966 |
+
shift_logits = shift_logits.view(
|
| 967 |
+
-1, self.language_model.config.vocab_size
|
| 968 |
+
)
|
| 969 |
+
shift_labels = shift_labels.view(-1).to(shift_logits.device)
|
| 970 |
+
loss = loss_fct(shift_logits, shift_labels)
|
| 971 |
+
|
| 972 |
+
if not return_dict:
|
| 973 |
+
output = (logits,) + outputs[1:]
|
| 974 |
+
return (loss,) + output if loss is not None else output
|
| 975 |
+
|
| 976 |
+
return CausalLMOutputWithPast(
|
| 977 |
+
loss=loss,
|
| 978 |
+
logits=logits,
|
| 979 |
+
past_key_values=outputs.past_key_values,
|
| 980 |
+
hidden_states=outputs.hidden_states,
|
| 981 |
+
attentions=outputs.attentions,
|
| 982 |
+
)
|
| 983 |
+
|
| 984 |
+
# ─────────────────────────────────────────────────────────────────────────
|
| 985 |
+
# GenerationMixin overrides
|
| 986 |
+
# ─────────────────────────────────────────────────────────────────────────
|
| 987 |
+
|
| 988 |
+
def prepare_inputs_for_generation(
|
| 989 |
+
self,
|
| 990 |
+
input_ids,
|
| 991 |
+
past_key_values=None,
|
| 992 |
+
attention_mask=None,
|
| 993 |
+
inputs_embeds=None,
|
| 994 |
+
cache_position=None,
|
| 995 |
+
position_ids=None,
|
| 996 |
+
use_cache=True,
|
| 997 |
+
pixel_values=None,
|
| 998 |
+
pixel_values_videos=None,
|
| 999 |
+
num_patches=None,
|
| 1000 |
+
image_flags=None,
|
| 1001 |
+
image_grid_thw=None,
|
| 1002 |
+
video_grid_thw=None,
|
| 1003 |
+
mm_token_type_ids=None,
|
| 1004 |
+
is_first_iteration=False,
|
| 1005 |
+
**kwargs,
|
| 1006 |
+
):
|
| 1007 |
+
"""
|
| 1008 |
+
Prepare inputs for each generation step.
|
| 1009 |
+
|
| 1010 |
+
After the first iteration, ``pixel_values`` / ``pixel_values_videos``
|
| 1011 |
+
are cleared because vision features are already in the KV cache.
|
| 1012 |
+
"""
|
| 1013 |
+
model_inputs = super().prepare_inputs_for_generation(
|
| 1014 |
+
input_ids,
|
| 1015 |
+
past_key_values=past_key_values,
|
| 1016 |
+
attention_mask=attention_mask,
|
| 1017 |
+
inputs_embeds=inputs_embeds,
|
| 1018 |
+
cache_position=cache_position,
|
| 1019 |
+
position_ids=position_ids,
|
| 1020 |
+
pixel_values=pixel_values,
|
| 1021 |
+
pixel_values_videos=pixel_values_videos,
|
| 1022 |
+
num_patches=num_patches,
|
| 1023 |
+
image_flags=image_flags,
|
| 1024 |
+
image_grid_thw=image_grid_thw,
|
| 1025 |
+
video_grid_thw=video_grid_thw,
|
| 1026 |
+
mm_token_type_ids=mm_token_type_ids,
|
| 1027 |
+
use_cache=use_cache,
|
| 1028 |
+
is_first_iteration=is_first_iteration,
|
| 1029 |
+
**kwargs,
|
| 1030 |
+
)
|
| 1031 |
+
|
| 1032 |
+
if not is_first_iteration and use_cache:
|
| 1033 |
+
model_inputs["pixel_values"] = None
|
| 1034 |
+
model_inputs["pixel_values_videos"] = None
|
| 1035 |
+
|
| 1036 |
+
return model_inputs
|
| 1037 |
+
|
| 1038 |
+
def _prepare_position_ids_for_generation(self, inputs_tensor, model_kwargs):
|
| 1039 |
+
"""
|
| 1040 |
+
Override to compute 3D M-RoPE position IDs during generation.
|
| 1041 |
+
|
| 1042 |
+
Mirrors ``Qwen3_5ForConditionalGeneration._prepare_position_ids_for_generation``:
|
| 1043 |
+
- Prefill step: compute 3D positions via ``get_rope_index``, cache
|
| 1044 |
+
``rope_deltas``.
|
| 1045 |
+
- Decode steps: apply cached ``rope_deltas`` to sequential text positions.
|
| 1046 |
+
|
| 1047 |
+
Returns position_ids of shape ``(4, B, S)`` on the prefill step
|
| 1048 |
+
(text + 3D vision channels) or ``(1, B, S)`` on decode steps
|
| 1049 |
+
(text + rope_deltas).
|
| 1050 |
+
When ``Qwen3_5TextModel`` receives ``shape[0]==4``, it splits into
|
| 1051 |
+
``text_position_ids = [0]`` (for causal mask) and
|
| 1052 |
+
``position_ids = [1:]`` (for rotary embedding).
|
| 1053 |
+
When ``shape[0]!=4``, it sets ``text_position_ids=None``.
|
| 1054 |
+
"""
|
| 1055 |
+
text_positions = super()._prepare_position_ids_for_generation(
|
| 1056 |
+
inputs_tensor, model_kwargs
|
| 1057 |
+
)
|
| 1058 |
+
|
| 1059 |
+
# Decode step — apply rope_deltas
|
| 1060 |
+
past_length = 0
|
| 1061 |
+
cache = model_kwargs.get("past_key_values")
|
| 1062 |
+
if cache is not None:
|
| 1063 |
+
past_length = cache.get_seq_length()
|
| 1064 |
+
if past_length != 0 and self.rope_deltas is not None:
|
| 1065 |
+
position_ids = text_positions[None, ...] + self.rope_deltas
|
| 1066 |
+
return position_ids
|
| 1067 |
+
|
| 1068 |
+
# Prefill step — compute 3D vision positions
|
| 1069 |
+
if "input_ids" in model_kwargs and model_kwargs["input_ids"].shape[1] > 0:
|
| 1070 |
+
inputs_tensor = model_kwargs["input_ids"]
|
| 1071 |
+
|
| 1072 |
+
is_input_ids = (
|
| 1073 |
+
len(inputs_tensor.shape) == 2
|
| 1074 |
+
and inputs_tensor.dtype in [torch.int, torch.long]
|
| 1075 |
+
)
|
| 1076 |
+
has_vision = (
|
| 1077 |
+
model_kwargs.get("mm_token_type_ids") is not None
|
| 1078 |
+
and (
|
| 1079 |
+
model_kwargs.get("image_grid_thw") is not None
|
| 1080 |
+
or model_kwargs.get("video_grid_thw") is not None
|
| 1081 |
+
)
|
| 1082 |
+
)
|
| 1083 |
+
|
| 1084 |
+
if is_input_ids and has_vision:
|
| 1085 |
+
vision_positions, rope_deltas = self.get_rope_index(
|
| 1086 |
+
inputs_tensor,
|
| 1087 |
+
mm_token_type_ids=model_kwargs.get("mm_token_type_ids"),
|
| 1088 |
+
image_grid_thw=model_kwargs.get("image_grid_thw"),
|
| 1089 |
+
video_grid_thw=model_kwargs.get("video_grid_thw"),
|
| 1090 |
+
attention_mask=model_kwargs.get("attention_mask"),
|
| 1091 |
+
)
|
| 1092 |
+
self.rope_deltas = rope_deltas
|
| 1093 |
+
else:
|
| 1094 |
+
vision_positions = text_positions.unsqueeze(0).expand(3, -1, -1)
|
| 1095 |
+
self.rope_deltas = torch.zeros(
|
| 1096 |
+
inputs_tensor.shape[0], 1,
|
| 1097 |
+
dtype=torch.long, device=inputs_tensor.device,
|
| 1098 |
+
)
|
| 1099 |
+
|
| 1100 |
+
# Concatenate text + vision → (4, B, S)
|
| 1101 |
+
# Channel 0 = text positions → used by create_causal_mask
|
| 1102 |
+
# Channels 1-3 = vision positions → used by rotary embedding
|
| 1103 |
+
# This matches Qwen3_5ForConditionalGeneration's convention.
|
| 1104 |
+
text_positions = text_positions[None, ...] # (1, B, S)
|
| 1105 |
+
position_ids = torch.cat(
|
| 1106 |
+
[text_positions, vision_positions], dim=0
|
| 1107 |
+
) # (4, B, S)
|
| 1108 |
+
#print(f"{position_ids.permute(1, 2, 0).cpu().tolist()}")
|
| 1109 |
+
return position_ids
|
preprocessor_config.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"auto_map": {
|
| 3 |
+
"AutoImageProcessor": "image_processing.ZDTaichu5_0_ImageProcessor",
|
| 4 |
+
"AutoProcessor": "processing.ZDTaichu5_0_Processor"
|
| 5 |
+
},
|
| 6 |
+
"data_format": "channels_first",
|
| 7 |
+
"do_rescale": true,
|
| 8 |
+
"image_processor_type": "ZDTaichu5_0_ImageProcessor",
|
| 9 |
+
"image_size": 512,
|
| 10 |
+
"max_num_tiles": 12,
|
| 11 |
+
"merge_size": 1,
|
| 12 |
+
"norm_mean": [
|
| 13 |
+
0.485,
|
| 14 |
+
0.456,
|
| 15 |
+
0.406
|
| 16 |
+
],
|
| 17 |
+
"norm_std": [
|
| 18 |
+
0.229,
|
| 19 |
+
0.224,
|
| 20 |
+
0.225
|
| 21 |
+
],
|
| 22 |
+
"num_image_token": 256,
|
| 23 |
+
"rescale_factor": 0.00392156862745098,
|
| 24 |
+
"use_thumbnail": true
|
| 25 |
+
}
|
processing.py
ADDED
|
@@ -0,0 +1,530 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
from typing import Optional, Union, List
|
| 15 |
+
|
| 16 |
+
import numpy as np
|
| 17 |
+
import torch
|
| 18 |
+
|
| 19 |
+
from transformers.feature_extraction_utils import BatchFeature
|
| 20 |
+
from transformers.image_utils import ImageInput
|
| 21 |
+
from transformers.processing_utils import ImagesKwargs, MultiModalData, ProcessingKwargs, ProcessorMixin, Unpack, VideosKwargs
|
| 22 |
+
from transformers.tokenization_utils_base import PreTokenizedInput, TextInput
|
| 23 |
+
from transformers.video_utils import VideoInput
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
class ZDTaichu5_0_ImagesKwargs(ImagesKwargs):
|
| 27 |
+
min_pixels: Optional[int]
|
| 28 |
+
max_pixels: Optional[int]
|
| 29 |
+
patch_size: Optional[int]
|
| 30 |
+
temporal_patch_size: Optional[int]
|
| 31 |
+
merge_size: Optional[int]
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class ZDTaichu5_0_ProcessorKwargs(ProcessingKwargs, total=False):
|
| 35 |
+
images_kwargs: ZDTaichu5_0_ImagesKwargs
|
| 36 |
+
videos_kwargs: VideosKwargs
|
| 37 |
+
_defaults = {
|
| 38 |
+
"text_kwargs": {
|
| 39 |
+
"padding": False,
|
| 40 |
+
},
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
class ZDTaichu5_0_Processor(ProcessorMixin):
|
| 45 |
+
r"""
|
| 46 |
+
Constructs a ZDTaichu-5.0 processor which wraps an image processor and a tokenizer into a single processor.
|
| 47 |
+
[`ZDTaichu5_0_Processor`] offers all the functionalities of the image processor and tokenizer. See the
|
| 48 |
+
[`~ZDTaichu5_0_Processor.__call__`] and [`~ZDTaichu5_0_Processor.decode`] for more information.
|
| 49 |
+
Args:
|
| 50 |
+
image_processor ([`AutoImageProcessor`], *optional*):
|
| 51 |
+
The image processor is a required input.
|
| 52 |
+
tokenizer ([`AutoTokenizer`], *optional*):
|
| 53 |
+
The tokenizer is a required input.
|
| 54 |
+
chat_template (`str`, *optional*): A Jinja template which will be used to convert lists of messages
|
| 55 |
+
in a chat into a tokenizable string.
|
| 56 |
+
"""
|
| 57 |
+
|
| 58 |
+
attributes = ["image_processor", "tokenizer"]
|
| 59 |
+
|
| 60 |
+
image_processor_class = "AutoImageProcessor"
|
| 61 |
+
video_processor_class = "AutoVideoProcessor"
|
| 62 |
+
tokenizer_class = ("AutoTokenizer")
|
| 63 |
+
|
| 64 |
+
def __init__(self, image_processor=None, tokenizer=None, chat_template=None, **kwargs):
|
| 65 |
+
# Defaults to Qwen3's built-in vision tokens; overridden by tokenizer_config.json attributes.
|
| 66 |
+
self.image_token = getattr(tokenizer, "image_token", "<|image_pad|>")
|
| 67 |
+
self.video_token = getattr(tokenizer, "video_token", "<|video_pad|>")
|
| 68 |
+
self.image_start_token = getattr(tokenizer, "image_start_token", "<|vision_start|>")
|
| 69 |
+
self.image_end_token = getattr(tokenizer, "image_end_token", "<|vision_end|>")
|
| 70 |
+
self.image_token_id = (
|
| 71 |
+
tokenizer.image_token_id
|
| 72 |
+
if getattr(tokenizer, "image_token_id", None)
|
| 73 |
+
else tokenizer.convert_tokens_to_ids(self.image_token)
|
| 74 |
+
)
|
| 75 |
+
self.video_token_id = (
|
| 76 |
+
tokenizer.video_token_id
|
| 77 |
+
if getattr(tokenizer, "video_token_id", None)
|
| 78 |
+
else tokenizer.convert_tokens_to_ids(self.video_token)
|
| 79 |
+
)
|
| 80 |
+
super().__init__(image_processor, tokenizer, chat_template=chat_template)
|
| 81 |
+
|
| 82 |
+
def __call__(
|
| 83 |
+
self,
|
| 84 |
+
images: ImageInput = None,
|
| 85 |
+
text: Union[TextInput, PreTokenizedInput, List[TextInput], List[PreTokenizedInput]] = None,
|
| 86 |
+
videos: VideoInput = None,
|
| 87 |
+
**kwargs: Unpack[ZDTaichu5_0_ProcessorKwargs],
|
| 88 |
+
) -> BatchFeature:
|
| 89 |
+
"""
|
| 90 |
+
Main method to prepare multimodal inputs (text, images, videos) for the model. This method processes text by
|
| 91 |
+
replacing image/video tokens with appropriate placeholder sequences, processes images and videos through the
|
| 92 |
+
image processor, and tokenizes the final text.
|
| 93 |
+
|
| 94 |
+
Video-as-multi-image convention
|
| 95 |
+
───────────────────────────────
|
| 96 |
+
Videos are NOT processed as a separate temporal stream. Each frame is
|
| 97 |
+
passed through the *image* pipeline with `max_num_tiles=1`, producing
|
| 98 |
+
one 512x512 tile per frame, and the frame tile tensors are then
|
| 99 |
+
APPENDED to the image stream (`pixel_values` / `num_patches` /
|
| 100 |
+
`image_grid_thw`). The downstream model therefore sees a single
|
| 101 |
+
uniform image batch with no separate video path.
|
| 102 |
+
|
| 103 |
+
In the rendered prompt every frame is wrapped in
|
| 104 |
+
`<|vision_start|> ... <|image_pad|> ... <|vision_end|>` — *image*
|
| 105 |
+
tokens, not video tokens — and prefaced by a per-frame
|
| 106 |
+
"Frame N sampled at T.TT seconds:" header. After tokenisation
|
| 107 |
+
`mm_token_type_ids` therefore has no type=2 entries.
|
| 108 |
+
|
| 109 |
+
The method performs the following key operations:
|
| 110 |
+
1. Processes images using the image processor to get pixel values and patch counts
|
| 111 |
+
2. Processes videos as multi-image (max_num_tiles=1) and appends frame data
|
| 112 |
+
into the same pixel_values / num_patches / image_grid_thw containers
|
| 113 |
+
3. Replaces `<|image_pad|>` tokens in text with `<|vision_start|>` + image tokens + `<|vision_end|>` sequences
|
| 114 |
+
4. Replaces `<|video_pad|>` tokens in text with frame-by-frame descriptions including timestamps (if metadata provided)
|
| 115 |
+
5. Tokenizes the processed text and combines all outputs
|
| 116 |
+
|
| 117 |
+
Args:
|
| 118 |
+
images (`PIL.Image.Image`, `np.ndarray`, `torch.Tensor`, `List[PIL.Image.Image]`, `List[np.ndarray]`, `List[torch.Tensor]`, *optional*):
|
| 119 |
+
The image or batch of images to be prepared. Each image can be a PIL image, NumPy array or PyTorch
|
| 120 |
+
tensor. Both channels-first and channels-last formats are supported.
|
| 121 |
+
text (`str`, `List[str]`, *optional*):
|
| 122 |
+
The sequence or batch of sequences to be encoded. Each sequence should be a string. The text can contain
|
| 123 |
+
special tokens `<|image_pad|>` and `<|video_pad|>` that will be replaced with appropriate token sequences.
|
| 124 |
+
videos (`np.ndarray`, `torch.Tensor`, `List[np.ndarray]`, `List[torch.Tensor]`, *optional*):
|
| 125 |
+
The video or batch of videos to be prepared. Each video should be a 4D NumPy array or PyTorch
|
| 126 |
+
tensor with shape (num_frames, channels, height, width). Both channels-first and channels-last formats
|
| 127 |
+
are supported. Note: Currently only supports batch size of 1 for videos.
|
| 128 |
+
images_kwargs (`Dict`, *optional*):
|
| 129 |
+
Additional keyword arguments for image processing, including:
|
| 130 |
+
- `min_pixels` (`int`, *optional*): Minimum number of pixels for image processing
|
| 131 |
+
- `max_pixels` (`int`, *optional*): Maximum number of pixels for image processing
|
| 132 |
+
- `patch_size` (`int`, *optional*): Size of patches for image processing
|
| 133 |
+
- `temporal_patch_size` (`int`, *optional*): Size of temporal patches
|
| 134 |
+
- `merge_size` (`int`, *optional*): Size for merging patches
|
| 135 |
+
videos_kwargs (`Dict`, *optional*):
|
| 136 |
+
Additional keyword arguments for video processing, including:
|
| 137 |
+
- `video_metadata` (`VideoMetadata`, *optional*): Metadata containing fps information for timestamp calculation
|
| 138 |
+
text_kwargs (`Dict`, *optional*):
|
| 139 |
+
Additional keyword arguments for text tokenization, including:
|
| 140 |
+
- `return_tensors` (`str` or [`~utils.TensorType`], *optional*): Framework for returned tensors ('tf', 'pt', 'np', 'jax')
|
| 141 |
+
- `padding` (`bool`, *optional*): Whether to pad sequences (defaults to False)
|
| 142 |
+
|
| 143 |
+
Returns:
|
| 144 |
+
[`BatchFeature`]: A [`BatchFeature`] with the following fields:
|
| 145 |
+
|
| 146 |
+
- **input_ids** -- List of token ids to be fed to a model. Returned when `text` is not `None`.
|
| 147 |
+
- **attention_mask** -- List of indices specifying which tokens should be attended to by the model.
|
| 148 |
+
- **pixel_values** -- Concatenated tile pixel values from BOTH real images and video frames,
|
| 149 |
+
in the order they appear in `input_ids` (real images first, then video frames). Returned
|
| 150 |
+
when `images` is not `None` or `videos` is not `None`.
|
| 151 |
+
- **num_patches** -- List of tile counts, one entry per real image followed by one entry per
|
| 152 |
+
video frame (frame entries are always 1 because max_num_tiles=1).
|
| 153 |
+
- **image_grid_thw** -- LongTensor[N_images + N_frames, 3] with [1, tile_rows, tile_cols] per
|
| 154 |
+
real image and [1, 1, 1] per video frame.
|
| 155 |
+
- **mm_token_type_ids** -- Per-token modality classification (0=text, 1=image incl. frames).
|
| 156 |
+
|
| 157 |
+
Raises:
|
| 158 |
+
AssertionError: If videos are provided with batch size > 1 (not currently supported).
|
| 159 |
+
|
| 160 |
+
Note:
|
| 161 |
+
- Image tokens `<|image_pad|>` in text are replaced with `<|vision_start|>` + repeated image tokens + `<|vision_end|>`
|
| 162 |
+
- Video tokens `<|video_pad|>` in text are replaced with frame-by-frame descriptions, each frame using `<|image_pad|>` slots
|
| 163 |
+
- When video metadata with fps is provided, frame descriptions include timestamps
|
| 164 |
+
- Videos are processed with max_num_tiles=1 regardless of the images setting
|
| 165 |
+
"""
|
| 166 |
+
output_kwargs = self._merge_kwargs(
|
| 167 |
+
ZDTaichu5_0_ProcessorKwargs,
|
| 168 |
+
tokenizer_init_kwargs=self.tokenizer.init_kwargs,
|
| 169 |
+
**kwargs,
|
| 170 |
+
)
|
| 171 |
+
# Initialise as independent dicts so later `**image_inputs` merging
|
| 172 |
+
# is well-defined whether or not images / videos are provided.
|
| 173 |
+
image_inputs: dict = {}
|
| 174 |
+
image_grid_thw = None
|
| 175 |
+
# Frame counts default to empty so the video-text-expansion loop is a
|
| 176 |
+
# no-op when `videos` is None.
|
| 177 |
+
video_num_patches: list = []
|
| 178 |
+
|
| 179 |
+
if images is not None:
|
| 180 |
+
image_inputs = self.image_processor(images=images, **output_kwargs["images_kwargs"])
|
| 181 |
+
image_num_patches = image_inputs["num_patches"]
|
| 182 |
+
# image_grid_thw: list of [T=1, tile_rows, tile_cols] per image
|
| 183 |
+
image_grid_thw = image_inputs.pop("image_grid_thw")
|
| 184 |
+
image_pixel_values = image_inputs["pixel_values"]
|
| 185 |
+
else:
|
| 186 |
+
image_num_patches = []
|
| 187 |
+
|
| 188 |
+
if videos is not None:
|
| 189 |
+
# ── Multi-image treatment of video ─────────────────────────────────
|
| 190 |
+
# Every video frame is processed by the *image* pipeline with
|
| 191 |
+
# max_num_tiles=1 so that one frame = one 512x512 tile = num_image_token
|
| 192 |
+
# (e.g. 256) tokens. Frame tile tensors are then APPENDED to the
|
| 193 |
+
# real-image stream:
|
| 194 |
+
#
|
| 195 |
+
# pixel_values : torch.cat([images, frames]) (total_tiles, C, H, W)
|
| 196 |
+
# num_patches : image_num_patches + [1] * N_frames List[int]
|
| 197 |
+
# image_grid_thw : torch.cat([image_grids, frame_grids], dim=0)
|
| 198 |
+
#
|
| 199 |
+
# Order matters: text expansion below replaces image tokens
|
| 200 |
+
# before video tokens, so frame slots come *after* real-image
|
| 201 |
+
# slots in input_ids — these tensors must follow the same order.
|
| 202 |
+
#
|
| 203 |
+
# In the rendered prompt every frame is wrapped in
|
| 204 |
+
# <|vision_start|> ... <|image_pad|> x num_image_token ... <|vision_end|>
|
| 205 |
+
# (image tokens, NOT video tokens) and prefaced by a per-frame
|
| 206 |
+
# "Frame N sampled at T.TT seconds:" header. After tokenisation
|
| 207 |
+
# mm_token_type_ids therefore has *no* type=2 entries — every
|
| 208 |
+
# visual slot is type=1. The downstream model sees a single
|
| 209 |
+
# uniform image stream and does not need a separate video path.
|
| 210 |
+
orig_tiles = self.image_processor.max_num_tiles
|
| 211 |
+
self.image_processor.max_num_tiles = 1
|
| 212 |
+
try:
|
| 213 |
+
frame_inputs = self.image_processor(
|
| 214 |
+
images=videos, **output_kwargs["images_kwargs"]
|
| 215 |
+
)
|
| 216 |
+
finally:
|
| 217 |
+
self.image_processor.max_num_tiles = orig_tiles
|
| 218 |
+
|
| 219 |
+
frame_pixel_values = frame_inputs["pixel_values"] # (N_frames, C, H, W)
|
| 220 |
+
frame_num_patches = list(frame_inputs["num_patches"])
|
| 221 |
+
frame_grid_thw = frame_inputs["image_grid_thw"] # (N_frames, 3) list/tensor
|
| 222 |
+
video_num_patches = frame_num_patches # for text expansion below
|
| 223 |
+
|
| 224 |
+
# Normalise grid containers to LongTensor so torch.cat works
|
| 225 |
+
# whether the image processor returned lists or tensors.
|
| 226 |
+
def _to_long_tensor(x):
|
| 227 |
+
return x if isinstance(x, torch.Tensor) else torch.tensor(x, dtype=torch.long)
|
| 228 |
+
|
| 229 |
+
if image_inputs:
|
| 230 |
+
# Real images + video frames — concat along batch dim.
|
| 231 |
+
image_inputs["pixel_values"] = torch.cat(
|
| 232 |
+
[image_inputs["pixel_values"], frame_pixel_values], dim=0
|
| 233 |
+
)
|
| 234 |
+
image_inputs["num_patches"] = (
|
| 235 |
+
list(image_inputs["num_patches"]) + frame_num_patches
|
| 236 |
+
)
|
| 237 |
+
image_grid_thw = torch.cat(
|
| 238 |
+
[_to_long_tensor(image_grid_thw), _to_long_tensor(frame_grid_thw)],
|
| 239 |
+
dim=0,
|
| 240 |
+
)
|
| 241 |
+
image_num_patches = image_inputs["num_patches"]
|
| 242 |
+
else:
|
| 243 |
+
# Video-only — frames become the entire image stream.
|
| 244 |
+
image_inputs = {
|
| 245 |
+
"pixel_values": frame_pixel_values,
|
| 246 |
+
"num_patches": frame_num_patches,
|
| 247 |
+
}
|
| 248 |
+
image_grid_thw = _to_long_tensor(frame_grid_thw)
|
| 249 |
+
image_num_patches = frame_num_patches
|
| 250 |
+
|
| 251 |
+
if not isinstance(text, list):
|
| 252 |
+
text = [text]
|
| 253 |
+
final_image_pixel_values = []
|
| 254 |
+
final_image_num_patches = []
|
| 255 |
+
final_image_grid_thw = []
|
| 256 |
+
text = text.copy() # below lines change text in-place
|
| 257 |
+
if images is not None:
|
| 258 |
+
index = 0
|
| 259 |
+
wrapped_token = self.image_start_token + self.image_token + self.image_end_token
|
| 260 |
+
|
| 261 |
+
for i in range(len(text)):
|
| 262 |
+
while self.image_token in text[i]:
|
| 263 |
+
expansion = (
|
| 264 |
+
self.image_start_token
|
| 265 |
+
+ "<|placeholder|>" * image_num_patches[index] * self.image_processor.num_image_token
|
| 266 |
+
+ self.image_end_token
|
| 267 |
+
)
|
| 268 |
+
# If the chat template already wrapped it, replace the whole
|
| 269 |
+
# <vision_start><image_pad><vision_end> span — avoids double wrapping.
|
| 270 |
+
# Otherwise fall back to replacing the bare <image_pad> token.
|
| 271 |
+
search = wrapped_token if wrapped_token in text[i] else self.image_token
|
| 272 |
+
text[i] = text[i].replace(search, expansion, 1)
|
| 273 |
+
index += 1
|
| 274 |
+
#final_image_pixel_values.append(image_pixel_values[index])
|
| 275 |
+
#final_image_num_patches.append(i)
|
| 276 |
+
text[i] = text[i].replace("<|placeholder|>", self.image_token)
|
| 277 |
+
if videos is not None:
|
| 278 |
+
assert len(text) == 1, "Video is not supported for batch size > 1"
|
| 279 |
+
video_metadata = output_kwargs.get("videos_kwargs", {}).get("video_metadata", None)
|
| 280 |
+
i = 0
|
| 281 |
+
wrapped_token = self.image_start_token + self.video_token + self.image_end_token
|
| 282 |
+
if self.video_token in text[i]:
|
| 283 |
+
each_frame = (
|
| 284 |
+
self.image_start_token
|
| 285 |
+
+ "<|placeholder|>" * self.image_processor.num_image_token
|
| 286 |
+
+ self.image_end_token
|
| 287 |
+
)
|
| 288 |
+
video_prompt = "This is a video:\n"
|
| 289 |
+
# One iteration per frame. video_num_patches has length N_frames
|
| 290 |
+
# (always 1 per frame because max_num_tiles=1 was forced above),
|
| 291 |
+
# so its length is the authoritative frame count even when
|
| 292 |
+
# `images` is None and `image_num_patches` is unset.
|
| 293 |
+
n_frames = len(video_num_patches)
|
| 294 |
+
for j in range(n_frames):
|
| 295 |
+
if video_metadata is not None and video_metadata.fps is not None:
|
| 296 |
+
timestamp = j / video_metadata.fps
|
| 297 |
+
video_prompt += f"Frame {j+1} sampled at {timestamp:.2f} seconds: {each_frame}\n"
|
| 298 |
+
else:
|
| 299 |
+
# Fallback to original format without timestamps
|
| 300 |
+
video_prompt += f"Frame {j+1}: {each_frame}\n"
|
| 301 |
+
# Strip the chat-template-applied <|vision_start|>...<|vision_end|>
|
| 302 |
+
# wrapping if present; otherwise replace the bare <|video_pad|>
|
| 303 |
+
# token. The fallback is video_token (NOT image_token), since by
|
| 304 |
+
# this point image expansion has already consumed every
|
| 305 |
+
# <|image_pad|> in the prompt.
|
| 306 |
+
search = wrapped_token if wrapped_token in text[i] else self.video_token
|
| 307 |
+
text[i] = text[i].replace(search, video_prompt, 1)
|
| 308 |
+
text[i] = text[i].replace("<|placeholder|>", self.image_token)
|
| 309 |
+
|
| 310 |
+
return_tensors = output_kwargs["text_kwargs"].pop("return_tensors", None)
|
| 311 |
+
text_inputs = self.tokenizer(text, **output_kwargs["text_kwargs"])
|
| 312 |
+
|
| 313 |
+
# ── Build mm_token_type_ids from tokenized input_ids ─────────────
|
| 314 |
+
# 0 = text, 1 = image. type=2 (video) is unreachable under the
|
| 315 |
+
# multi-image-as-video convention because every frame gets expanded
|
| 316 |
+
# to <|image_pad|> tokens — but we keep the video_token branch as a
|
| 317 |
+
# defensive fallback for any tokenizer-injected video_pad token.
|
| 318 |
+
input_ids = text_inputs["input_ids"]
|
| 319 |
+
if isinstance(input_ids, list):
|
| 320 |
+
mm_token_type_ids = []
|
| 321 |
+
for ids in input_ids:
|
| 322 |
+
tt = [0] * len(ids)
|
| 323 |
+
for j, tok_id in enumerate(ids):
|
| 324 |
+
if tok_id == self.image_token_id:
|
| 325 |
+
tt[j] = 1
|
| 326 |
+
elif tok_id == self.video_token_id:
|
| 327 |
+
tt[j] = 2
|
| 328 |
+
mm_token_type_ids.append(tt)
|
| 329 |
+
else:
|
| 330 |
+
# Already a tensor (when return_tensors is set before tokenizer call)
|
| 331 |
+
mm_token_type_ids = torch.zeros_like(input_ids)
|
| 332 |
+
mm_token_type_ids[input_ids == self.image_token_id] = 1
|
| 333 |
+
mm_token_type_ids[input_ids == self.video_token_id] = 2
|
| 334 |
+
|
| 335 |
+
# ── Assemble output ──────────────────────────────────────────────
|
| 336 |
+
# Note: video frames have already been merged into image_inputs above,
|
| 337 |
+
# so there are no separate `pixel_values_videos` / `video_grid_thw`
|
| 338 |
+
# outputs. Downstream code consumes a single image stream.
|
| 339 |
+
data = {**text_inputs, **image_inputs}
|
| 340 |
+
data["mm_token_type_ids"] = mm_token_type_ids
|
| 341 |
+
if image_grid_thw is not None:
|
| 342 |
+
data["image_grid_thw"] = image_grid_thw
|
| 343 |
+
|
| 344 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 345 |
+
|
| 346 |
+
def _get_num_multimodal_tokens(self, image_sizes=None, video_sizes=None, **kwargs):
|
| 347 |
+
"""
|
| 348 |
+
Computes the number of placeholder tokens needed for multimodal inputs with the given sizes.
|
| 349 |
+
Args:
|
| 350 |
+
image_sizes (`list[list[int]]`, *optional*):
|
| 351 |
+
The input sizes formatted as (height, width) per each image.
|
| 352 |
+
video_sizes (`list[list[int]]`, *optional*):
|
| 353 |
+
The input sizes formatted as (num_frames, height, width) per each video.
|
| 354 |
+
Returns:
|
| 355 |
+
`MultiModalData`: A `MultiModalData` object holding number of tokens per each of the provided
|
| 356 |
+
input modalities, along with other useful data.
|
| 357 |
+
"""
|
| 358 |
+
|
| 359 |
+
vision_data = {}
|
| 360 |
+
if image_sizes is not None:
|
| 361 |
+
images_kwargs = ZDTaichu5_0_ProcessorKwargs._defaults.get("images_kwargs", {})
|
| 362 |
+
images_kwargs.update(kwargs)
|
| 363 |
+
merge_size = images_kwargs.get("merge_size", None) or self.image_processor.merge_size
|
| 364 |
+
|
| 365 |
+
num_image_patches = [
|
| 366 |
+
self.image_processor.get_number_of_image_patches(*image_size, images_kwargs)
|
| 367 |
+
for image_size in image_sizes
|
| 368 |
+
]
|
| 369 |
+
num_image_tokens = [(num_patches // merge_size**2) for num_patches in num_image_patches]
|
| 370 |
+
vision_data.update({"num_image_tokens": num_image_tokens, "num_image_patches": num_image_patches})
|
| 371 |
+
return MultiModalData(**vision_data)
|
| 372 |
+
|
| 373 |
+
def batch_decode(self, *args, **kwargs):
|
| 374 |
+
"""
|
| 375 |
+
This method forwards all its arguments to the tokenizer's [`~PreTrainedTokenizer.batch_decode`]. Please
|
| 376 |
+
refer to the docstring of this method for more information.
|
| 377 |
+
"""
|
| 378 |
+
return self.tokenizer.batch_decode(*args, **kwargs)
|
| 379 |
+
|
| 380 |
+
def decode(self, *args, **kwargs):
|
| 381 |
+
"""
|
| 382 |
+
This method forwards all its arguments to the tokenizer's [`~PreTrainedTokenizer.decode`]. Please refer to
|
| 383 |
+
the docstring of this method for more information.
|
| 384 |
+
"""
|
| 385 |
+
return self.tokenizer.decode(*args, **kwargs)
|
| 386 |
+
|
| 387 |
+
def post_process_image_text_to_text(
|
| 388 |
+
self, generated_outputs, skip_special_tokens=True, clean_up_tokenization_spaces=False, **kwargs
|
| 389 |
+
):
|
| 390 |
+
"""
|
| 391 |
+
Post-process the output of the model to decode the text.
|
| 392 |
+
|
| 393 |
+
Args:
|
| 394 |
+
generated_outputs (`torch.Tensor` or `np.ndarray`):
|
| 395 |
+
The output of the model `generate` function. The output is expected to be a tensor of shape `(batch_size, sequence_length)`
|
| 396 |
+
or `(sequence_length,)`.
|
| 397 |
+
skip_special_tokens (`bool`, *optional*, defaults to `True`):
|
| 398 |
+
Whether or not to remove special tokens in the output. Argument passed to the tokenizer's `batch_decode` method.
|
| 399 |
+
clean_up_tokenization_spaces (`bool`, *optional*, defaults to `False`):
|
| 400 |
+
Whether or not to clean up the tokenization spaces. Argument passed to the tokenizer's `batch_decode` method.
|
| 401 |
+
**kwargs:
|
| 402 |
+
Additional arguments to be passed to the tokenizer's `batch_decode method`.
|
| 403 |
+
|
| 404 |
+
Returns:
|
| 405 |
+
`list[str]`: The decoded text.
|
| 406 |
+
"""
|
| 407 |
+
return self.tokenizer.batch_decode(
|
| 408 |
+
generated_outputs,
|
| 409 |
+
skip_special_tokens=skip_special_tokens,
|
| 410 |
+
clean_up_tokenization_spaces=clean_up_tokenization_spaces,
|
| 411 |
+
**kwargs,
|
| 412 |
+
)
|
| 413 |
+
|
| 414 |
+
@property
|
| 415 |
+
def model_input_names(self):
|
| 416 |
+
tokenizer_input_names = self.tokenizer.model_input_names
|
| 417 |
+
image_processor_input_names = self.image_processor.model_input_names
|
| 418 |
+
names_from_processor = list(dict.fromkeys(tokenizer_input_names + image_processor_input_names))
|
| 419 |
+
# Note: video_grid_thw is NOT emitted under multi-image-as-video —
|
| 420 |
+
# frame data lives in image_grid_thw alongside real images.
|
| 421 |
+
return names_from_processor + ["mm_token_type_ids"]
|
| 422 |
+
|
| 423 |
+
|
| 424 |
+
def from_messages(
|
| 425 |
+
self,
|
| 426 |
+
messages: list,
|
| 427 |
+
return_tensors: str = "pt",
|
| 428 |
+
add_vision_id: bool = True,
|
| 429 |
+
**kwargs,
|
| 430 |
+
) -> BatchFeature:
|
| 431 |
+
"""
|
| 432 |
+
Prepare model inputs directly from Qwen-style structured messages.
|
| 433 |
+
|
| 434 |
+
This is the high-level entry point that handles the full pipeline:
|
| 435 |
+
structured messages → vision loading → chat template → tokenization.
|
| 436 |
+
|
| 437 |
+
Supports messages with typed content lists::
|
| 438 |
+
|
| 439 |
+
messages = [
|
| 440 |
+
{"role": "user", "content": [
|
| 441 |
+
{"type": "image", "image": "photo.jpg"},
|
| 442 |
+
{"type": "text", "text": "What's in this image?"},
|
| 443 |
+
]},
|
| 444 |
+
]
|
| 445 |
+
|
| 446 |
+
Video inputs (file path, URL, or list of frame paths)::
|
| 447 |
+
|
| 448 |
+
messages = [
|
| 449 |
+
{"role": "user", "content": [
|
| 450 |
+
{"type": "video", "video": "clip.mp4", "fps": 2.0},
|
| 451 |
+
{"type": "text", "text": "Describe this video."},
|
| 452 |
+
]},
|
| 453 |
+
]
|
| 454 |
+
|
| 455 |
+
Multi-image with automatic labelling::
|
| 456 |
+
|
| 457 |
+
messages = [
|
| 458 |
+
{"role": "user", "content": [
|
| 459 |
+
{"type": "image", "image": "a.jpg"},
|
| 460 |
+
{"type": "image", "image": "b.jpg"},
|
| 461 |
+
{"type": "text", "text": "Compare them."},
|
| 462 |
+
]},
|
| 463 |
+
]
|
| 464 |
+
# With add_vision_id=True (default), the prompt includes:
|
| 465 |
+
# Picture 1: <|vision_start|><|image_pad|><|vision_end|>
|
| 466 |
+
# Picture 2: <|vision_start|><|image_pad|><|vision_end|>
|
| 467 |
+
# Compare them.
|
| 468 |
+
|
| 469 |
+
Args:
|
| 470 |
+
messages: List of message dicts with structured ``content``.
|
| 471 |
+
return_tensors: Framework for returned tensors (default ``"pt"``).
|
| 472 |
+
add_vision_id: If ``True`` (default), the chat template prepends
|
| 473 |
+
``Picture N:`` / ``Video N:`` labels before each vision token.
|
| 474 |
+
Set to ``False`` to omit labels.
|
| 475 |
+
**kwargs: Forwarded to ``self.__call__``.
|
| 476 |
+
|
| 477 |
+
Returns:
|
| 478 |
+
``BatchFeature`` ready for ``model.generate(**inputs)``.
|
| 479 |
+
"""
|
| 480 |
+
from .vision_utils import process_vision_info
|
| 481 |
+
|
| 482 |
+
# 1. Load images and videos from the structured messages
|
| 483 |
+
image_inputs, video_inputs, video_kwargs = process_vision_info(messages)
|
| 484 |
+
|
| 485 |
+
# 2. Apply chat template — pass structured messages directly so the
|
| 486 |
+
# template can iterate typed content dicts, count vision elements,
|
| 487 |
+
# and emit "Picture N:" / "Video N:" labels when add_vision_id=True.
|
| 488 |
+
prompt = self.tokenizer.apply_chat_template(
|
| 489 |
+
messages,
|
| 490 |
+
tokenize=False,
|
| 491 |
+
add_generation_prompt=True,
|
| 492 |
+
add_vision_id=add_vision_id,
|
| 493 |
+
)
|
| 494 |
+
|
| 495 |
+
# 3. Prepare video inputs and metadata for timestamps
|
| 496 |
+
videos_kwargs = {}
|
| 497 |
+
flat_videos = None
|
| 498 |
+
if video_inputs is not None:
|
| 499 |
+
if len(video_inputs) > 1:
|
| 500 |
+
raise ValueError(
|
| 501 |
+
"Multiple videos in a single message batch are not yet "
|
| 502 |
+
"supported. Please use one video per call."
|
| 503 |
+
)
|
| 504 |
+
flat_videos = video_inputs[0] # List[Image.Image]
|
| 505 |
+
|
| 506 |
+
if video_kwargs.get("metadata_list"):
|
| 507 |
+
meta = video_kwargs["metadata_list"][0]
|
| 508 |
+
fps = meta.get("sample_fps") or meta.get("fps")
|
| 509 |
+
if fps:
|
| 510 |
+
from transformers.video_utils import VideoMetadata
|
| 511 |
+
videos_kwargs["video_metadata"] = VideoMetadata(
|
| 512 |
+
fps=fps,
|
| 513 |
+
total_num_frames=len(flat_videos),
|
| 514 |
+
)
|
| 515 |
+
|
| 516 |
+
return self(
|
| 517 |
+
images=image_inputs,
|
| 518 |
+
text=prompt,
|
| 519 |
+
videos=flat_videos,
|
| 520 |
+
return_tensors=return_tensors,
|
| 521 |
+
videos_kwargs=videos_kwargs,
|
| 522 |
+
**kwargs,
|
| 523 |
+
)
|
| 524 |
+
|
| 525 |
+
@property
|
| 526 |
+
def ctx_image_token_id(self) -> int:
|
| 527 |
+
return self.image_token_id
|
| 528 |
+
|
| 529 |
+
|
| 530 |
+
__all__ = ["ZDTaichu5_0_Processor"]
|
processor_config.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"auto_map": {
|
| 3 |
+
"AutoProcessor": "processing.ZDTaichu5_0_Processor"
|
| 4 |
+
},
|
| 5 |
+
"image_processor": {
|
| 6 |
+
"auto_map": {
|
| 7 |
+
"AutoImageProcessor": "image_processing.ZDTaichu5_0_ImageProcessor",
|
| 8 |
+
"AutoProcessor": "processing.ZDTaichu5_0_Processor"
|
| 9 |
+
},
|
| 10 |
+
"data_format": "channels_first",
|
| 11 |
+
"do_rescale": true,
|
| 12 |
+
"image_processor_type": "ZDTaichu5_0_ImageProcessor",
|
| 13 |
+
"image_size": 512,
|
| 14 |
+
"max_num_tiles": 12,
|
| 15 |
+
"merge_size": 1,
|
| 16 |
+
"norm_mean": [
|
| 17 |
+
0.485,
|
| 18 |
+
0.456,
|
| 19 |
+
0.406
|
| 20 |
+
],
|
| 21 |
+
"norm_std": [
|
| 22 |
+
0.229,
|
| 23 |
+
0.224,
|
| 24 |
+
0.225
|
| 25 |
+
],
|
| 26 |
+
"num_image_token": 256,
|
| 27 |
+
"rescale_factor": 0.00392156862745098,
|
| 28 |
+
"use_thumbnail": true
|
| 29 |
+
},
|
| 30 |
+
"processor_class": "ZDTaichu5_0_Processor"
|
| 31 |
+
}
|
tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:87a7830d63fcf43bf241c3c5242e96e62dd3fdc29224ca26fed8ea333db72de4
|
| 3 |
+
size 19989343
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"add_prefix_space": false,
|
| 3 |
+
"auto_map": {
|
| 4 |
+
"AutoProcessor": "processing.ZDTaichu5_0_Processor"
|
| 5 |
+
},
|
| 6 |
+
"backend": "tokenizers",
|
| 7 |
+
"bos_token": null,
|
| 8 |
+
"clean_up_tokenization_spaces": false,
|
| 9 |
+
"eos_token": "<|im_end|>",
|
| 10 |
+
"errors": "replace",
|
| 11 |
+
"image_end_token": "<|vision_end|>",
|
| 12 |
+
"image_start_token": "<|vision_start|>",
|
| 13 |
+
"image_token": "<|image_pad|>",
|
| 14 |
+
"image_token_id": 248056,
|
| 15 |
+
"is_local": true,
|
| 16 |
+
"model_max_length": 262144,
|
| 17 |
+
"pad_token": "<|endoftext|>",
|
| 18 |
+
"pretokenize_regex": "(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\\r\\n\\p{L}\\p{N}]?[\\p{L}\\p{M}]+|\\p{N}| ?[^\\s\\p{L}\\p{M}\\p{N}]+[\\r\\n]*|\\s*[\\r\\n]+|\\s+(?!\\S)|\\s+",
|
| 19 |
+
"processor_class": "ZDTaichu5_0_Processor",
|
| 20 |
+
"split_special_tokens": false,
|
| 21 |
+
"tokenizer_class": "TokenizersBackend",
|
| 22 |
+
"unk_token": null,
|
| 23 |
+
"video_token": "<|video_pad|>",
|
| 24 |
+
"video_token_id": 248057,
|
| 25 |
+
"vision_bos_token": "<|vision_start|>",
|
| 26 |
+
"vision_eos_token": "<|vision_end|>"
|
| 27 |
+
}
|
vision_utils.py
ADDED
|
@@ -0,0 +1,583 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
# ============================================================================
|
| 16 |
+
# Vision utilities for ZDTaichu-5.0
|
| 17 |
+
#
|
| 18 |
+
# Provides ``process_vision_info()`` to extract images and videos from
|
| 19 |
+
# Qwen-style structured messages, following the conventions established
|
| 20 |
+
# by ``qwen_vl_utils``. This allows the model to accept messages like:
|
| 21 |
+
#
|
| 22 |
+
# messages = [
|
| 23 |
+
# {"role": "user", "content": [
|
| 24 |
+
# {"type": "video", "video": "path/to/video.mp4", "fps": 2.0},
|
| 25 |
+
# {"type": "text", "text": "Describe this video."},
|
| 26 |
+
# ]}
|
| 27 |
+
# ]
|
| 28 |
+
#
|
| 29 |
+
# Supported input formats:
|
| 30 |
+
# - Images: local path, ``file://`` URI, ``http(s)://`` URL, base64 data
|
| 31 |
+
# URI, ``PIL.Image.Image`` object
|
| 32 |
+
# - Videos: local path, ``file://`` URI, ``http(s)://`` URL (string),
|
| 33 |
+
# or a list of image paths/URLs (treated as pre-extracted frames)
|
| 34 |
+
#
|
| 35 |
+
# Video decoding backends (auto-detected, in priority order):
|
| 36 |
+
# 1. decord — fastest, recommended
|
| 37 |
+
# 2. torchvision — fallback, always available
|
| 38 |
+
#
|
| 39 |
+
# Frame sampling follows the same ``smart_nframes`` logic as qwen_vl_utils:
|
| 40 |
+
# - Default: 2 FPS, clamped to [4, 768] frames, rounded to factor of 2
|
| 41 |
+
# - Override via ``fps``, ``nframes``, ``min_frames``, ``max_frames``
|
| 42 |
+
# - Temporal trimming via ``video_start`` / ``video_end`` (seconds)
|
| 43 |
+
# ============================================================================
|
| 44 |
+
|
| 45 |
+
import base64
|
| 46 |
+
import copy
|
| 47 |
+
import logging
|
| 48 |
+
import math
|
| 49 |
+
import os
|
| 50 |
+
import sys
|
| 51 |
+
import time
|
| 52 |
+
import warnings
|
| 53 |
+
from functools import lru_cache
|
| 54 |
+
from io import BytesIO
|
| 55 |
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
| 56 |
+
|
| 57 |
+
import numpy as np
|
| 58 |
+
import requests
|
| 59 |
+
import torch
|
| 60 |
+
from PIL import Image
|
| 61 |
+
|
| 62 |
+
logger = logging.getLogger(__name__)
|
| 63 |
+
|
| 64 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 65 |
+
# Constants (aligned with qwen_vl_utils defaults)
|
| 66 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 67 |
+
|
| 68 |
+
FPS = 2.0 # default sampling rate
|
| 69 |
+
FRAME_FACTOR = 2 # frame count must be divisible by this
|
| 70 |
+
FPS_MIN_FRAMES = 4 # minimum sampled frames
|
| 71 |
+
FPS_MAX_FRAMES = 768 # maximum sampled frames
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 75 |
+
# Rounding helpers
|
| 76 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 77 |
+
|
| 78 |
+
def round_by_factor(number: float, factor: int) -> int:
|
| 79 |
+
"""Closest integer to *number* divisible by *factor*."""
|
| 80 |
+
return round(number / factor) * factor
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def ceil_by_factor(number: float, factor: int) -> int:
|
| 84 |
+
"""Smallest integer ≥ *number* divisible by *factor*."""
|
| 85 |
+
return math.ceil(number / factor) * factor
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def floor_by_factor(number: float, factor: int) -> int:
|
| 89 |
+
"""Largest integer ≤ *number* divisible by *factor*."""
|
| 90 |
+
return math.floor(number / factor) * factor
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 94 |
+
# Image loading
|
| 95 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 96 |
+
|
| 97 |
+
def fetch_image(ele: Dict[str, Any]) -> Image.Image:
|
| 98 |
+
"""
|
| 99 |
+
Load a single image from various sources.
|
| 100 |
+
|
| 101 |
+
Supported formats for ``ele["image"]``:
|
| 102 |
+
- ``PIL.Image.Image`` instance
|
| 103 |
+
- Local file path (``/path/to/img.jpg``)
|
| 104 |
+
- ``file://`` URI
|
| 105 |
+
- ``http://`` or ``https://`` URL
|
| 106 |
+
- Base64 data URI (``data:image/...;base64,...``)
|
| 107 |
+
|
| 108 |
+
Returns:
|
| 109 |
+
PIL.Image.Image in RGB mode.
|
| 110 |
+
"""
|
| 111 |
+
image = ele.get("image") or ele.get("image_url")
|
| 112 |
+
if image is None:
|
| 113 |
+
raise ValueError("Element must contain 'image' or 'image_url' key")
|
| 114 |
+
|
| 115 |
+
image_obj = None
|
| 116 |
+
if isinstance(image, Image.Image):
|
| 117 |
+
image_obj = image
|
| 118 |
+
elif image.startswith("http://") or image.startswith("https://"):
|
| 119 |
+
with requests.get(image, stream=True, timeout=30) as resp:
|
| 120 |
+
resp.raise_for_status()
|
| 121 |
+
image_obj = copy.deepcopy(Image.open(BytesIO(resp.content)))
|
| 122 |
+
elif image.startswith("file://"):
|
| 123 |
+
image_obj = Image.open(image[7:])
|
| 124 |
+
elif image.startswith("data:image"):
|
| 125 |
+
if "base64," in image:
|
| 126 |
+
_, b64 = image.split("base64,", 1)
|
| 127 |
+
image_obj = copy.deepcopy(Image.open(BytesIO(base64.b64decode(b64))))
|
| 128 |
+
else:
|
| 129 |
+
# Treat as local file path
|
| 130 |
+
image_obj = Image.open(image)
|
| 131 |
+
|
| 132 |
+
if image_obj is None:
|
| 133 |
+
raise ValueError(
|
| 134 |
+
f"Unrecognised image input. Supported: local path, file:// URI, "
|
| 135 |
+
f"http(s) URL, base64 data URI, PIL.Image. Got: {image!r:.120}"
|
| 136 |
+
)
|
| 137 |
+
|
| 138 |
+
# Convert to RGB
|
| 139 |
+
if image_obj.mode == "RGBA":
|
| 140 |
+
bg = Image.new("RGB", image_obj.size, (255, 255, 255))
|
| 141 |
+
bg.paste(image_obj, mask=image_obj.split()[3])
|
| 142 |
+
return bg
|
| 143 |
+
return image_obj.convert("RGB")
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 147 |
+
# Frame sampling
|
| 148 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 149 |
+
|
| 150 |
+
def smart_nframes(
|
| 151 |
+
ele: Dict[str, Any],
|
| 152 |
+
total_frames: int,
|
| 153 |
+
video_fps: float,
|
| 154 |
+
) -> int:
|
| 155 |
+
"""
|
| 156 |
+
Compute the number of frames to sample from a video.
|
| 157 |
+
|
| 158 |
+
Follows the same logic as ``qwen_vl_utils.smart_nframes``:
|
| 159 |
+
- If ``ele["nframes"]`` is set, use it directly (rounded to FRAME_FACTOR).
|
| 160 |
+
- Otherwise, sample at ``ele.get("fps", 2.0)`` FPS, clamped to
|
| 161 |
+
``[min_frames, max_frames]`` and rounded down to FRAME_FACTOR.
|
| 162 |
+
|
| 163 |
+
Args:
|
| 164 |
+
ele: Dict with optional keys ``fps``, ``nframes``, ``min_frames``,
|
| 165 |
+
``max_frames``.
|
| 166 |
+
total_frames: Total frames in the (possibly trimmed) video.
|
| 167 |
+
video_fps: Original video FPS.
|
| 168 |
+
|
| 169 |
+
Returns:
|
| 170 |
+
Number of frames to sample.
|
| 171 |
+
"""
|
| 172 |
+
assert not ("fps" in ele and "nframes" in ele), (
|
| 173 |
+
"Only accept either `fps` or `nframes`, not both"
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
if "nframes" in ele:
|
| 177 |
+
nframes = round_by_factor(ele["nframes"], FRAME_FACTOR)
|
| 178 |
+
else:
|
| 179 |
+
fps = ele.get("fps", FPS)
|
| 180 |
+
min_frames = ceil_by_factor(
|
| 181 |
+
ele.get("min_frames", FPS_MIN_FRAMES), FRAME_FACTOR
|
| 182 |
+
)
|
| 183 |
+
max_frames = floor_by_factor(
|
| 184 |
+
ele.get("max_frames", min(FPS_MAX_FRAMES, total_frames)), FRAME_FACTOR
|
| 185 |
+
)
|
| 186 |
+
nframes = total_frames / video_fps * fps
|
| 187 |
+
if nframes > total_frames:
|
| 188 |
+
logger.warning(
|
| 189 |
+
f"smart_nframes: computed nframes ({nframes:.1f}) > "
|
| 190 |
+
f"total_frames ({total_frames})"
|
| 191 |
+
)
|
| 192 |
+
nframes = min(min(max(nframes, min_frames), max_frames), total_frames)
|
| 193 |
+
nframes = floor_by_factor(nframes, FRAME_FACTOR)
|
| 194 |
+
|
| 195 |
+
if not (FRAME_FACTOR <= nframes <= total_frames):
|
| 196 |
+
raise ValueError(
|
| 197 |
+
f"nframes should be in [{FRAME_FACTOR}, {total_frames}], "
|
| 198 |
+
f"got {nframes}."
|
| 199 |
+
)
|
| 200 |
+
return nframes
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
def calculate_video_frame_range(
|
| 204 |
+
ele: Dict[str, Any],
|
| 205 |
+
total_frames: int,
|
| 206 |
+
video_fps: float,
|
| 207 |
+
) -> Tuple[int, int, int]:
|
| 208 |
+
"""
|
| 209 |
+
Calculate start/end frame indices from optional ``video_start``/``video_end``
|
| 210 |
+
keys (in seconds).
|
| 211 |
+
|
| 212 |
+
Returns:
|
| 213 |
+
(start_frame, end_frame, frame_count) — end_frame is inclusive.
|
| 214 |
+
"""
|
| 215 |
+
if video_fps <= 0:
|
| 216 |
+
raise ValueError("video_fps must be positive")
|
| 217 |
+
if total_frames <= 0:
|
| 218 |
+
raise ValueError("total_frames must be positive")
|
| 219 |
+
|
| 220 |
+
video_start = ele.get("video_start")
|
| 221 |
+
video_end = ele.get("video_end")
|
| 222 |
+
|
| 223 |
+
if video_start is None and video_end is None:
|
| 224 |
+
return 0, total_frames - 1, total_frames
|
| 225 |
+
|
| 226 |
+
max_duration = total_frames / video_fps
|
| 227 |
+
|
| 228 |
+
if video_start is not None:
|
| 229 |
+
start_sec = max(0.0, min(video_start, max_duration))
|
| 230 |
+
start_frame = math.ceil(start_sec * video_fps)
|
| 231 |
+
else:
|
| 232 |
+
start_frame = 0
|
| 233 |
+
|
| 234 |
+
if video_end is not None:
|
| 235 |
+
end_sec = max(0.0, min(video_end, max_duration))
|
| 236 |
+
end_frame = min(math.floor(end_sec * video_fps), total_frames - 1)
|
| 237 |
+
else:
|
| 238 |
+
end_frame = total_frames - 1
|
| 239 |
+
|
| 240 |
+
if start_frame >= end_frame:
|
| 241 |
+
raise ValueError(
|
| 242 |
+
f"Invalid time range: start_frame={start_frame} >= end_frame={end_frame}. "
|
| 243 |
+
f"Video: {max_duration:.2f}s ({total_frames} frames @ {video_fps:.1f}fps)"
|
| 244 |
+
)
|
| 245 |
+
|
| 246 |
+
return start_frame, end_frame, end_frame - start_frame + 1
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 250 |
+
# Video decoding backends
|
| 251 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 252 |
+
|
| 253 |
+
def _read_video_decord(
|
| 254 |
+
ele: Dict[str, Any],
|
| 255 |
+
) -> Tuple[torch.Tensor, dict, float]:
|
| 256 |
+
"""Read video with decord. Returns (video_TCHW, metadata, sample_fps)."""
|
| 257 |
+
import decord
|
| 258 |
+
|
| 259 |
+
video_path = ele["video"]
|
| 260 |
+
if video_path.startswith("file://"):
|
| 261 |
+
video_path = video_path[7:]
|
| 262 |
+
|
| 263 |
+
st = time.time()
|
| 264 |
+
vr = decord.VideoReader(video_path)
|
| 265 |
+
total_frames, video_fps = len(vr), vr.get_avg_fps()
|
| 266 |
+
|
| 267 |
+
start_frame, end_frame, total_frames = calculate_video_frame_range(
|
| 268 |
+
ele, total_frames, video_fps
|
| 269 |
+
)
|
| 270 |
+
nframes = smart_nframes(ele, total_frames=total_frames, video_fps=video_fps)
|
| 271 |
+
idx = torch.linspace(start_frame, end_frame, nframes).round().long().tolist()
|
| 272 |
+
sample_fps = nframes / max(total_frames, 1e-6) * video_fps
|
| 273 |
+
|
| 274 |
+
video = torch.from_numpy(vr.get_batch(idx).asnumpy()).permute(0, 3, 1, 2) # TCHW
|
| 275 |
+
logger.info(
|
| 276 |
+
f"decord: {video_path}, {total_frames} frames, "
|
| 277 |
+
f"{video_fps:.1f} fps, sampled {nframes}, "
|
| 278 |
+
f"time={time.time() - st:.3f}s"
|
| 279 |
+
)
|
| 280 |
+
|
| 281 |
+
metadata = dict(
|
| 282 |
+
fps=video_fps,
|
| 283 |
+
sample_fps=sample_fps,
|
| 284 |
+
frames_indices=idx,
|
| 285 |
+
total_num_frames=total_frames,
|
| 286 |
+
video_backend="decord",
|
| 287 |
+
)
|
| 288 |
+
return video, metadata, sample_fps
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
def _read_video_torchvision(
|
| 292 |
+
ele: Dict[str, Any],
|
| 293 |
+
) -> Tuple[torch.Tensor, dict, float]:
|
| 294 |
+
"""Read video with torchvision. Returns (video_TCHW, metadata, sample_fps)."""
|
| 295 |
+
from torchvision import io as tio
|
| 296 |
+
|
| 297 |
+
video_path = ele["video"]
|
| 298 |
+
if video_path.startswith("file://"):
|
| 299 |
+
video_path = video_path[7:]
|
| 300 |
+
|
| 301 |
+
st = time.time()
|
| 302 |
+
video, _audio, info = tio.read_video(
|
| 303 |
+
video_path,
|
| 304 |
+
start_pts=ele.get("video_start", 0.0),
|
| 305 |
+
end_pts=ele.get("video_end"),
|
| 306 |
+
pts_unit="sec",
|
| 307 |
+
output_format="TCHW",
|
| 308 |
+
)
|
| 309 |
+
total_frames, video_fps = video.size(0), info["video_fps"]
|
| 310 |
+
|
| 311 |
+
nframes = smart_nframes(ele, total_frames=total_frames, video_fps=video_fps)
|
| 312 |
+
idx = torch.linspace(0, total_frames - 1, nframes).round().long()
|
| 313 |
+
sample_fps = nframes / max(total_frames, 1e-6) * video_fps
|
| 314 |
+
video = video[idx]
|
| 315 |
+
|
| 316 |
+
logger.info(
|
| 317 |
+
f"torchvision: {video_path}, {total_frames} frames, "
|
| 318 |
+
f"{video_fps:.1f} fps, sampled {nframes}, "
|
| 319 |
+
f"time={time.time() - st:.3f}s"
|
| 320 |
+
)
|
| 321 |
+
|
| 322 |
+
metadata = dict(
|
| 323 |
+
fps=video_fps,
|
| 324 |
+
sample_fps=sample_fps,
|
| 325 |
+
frames_indices=idx.tolist(),
|
| 326 |
+
total_num_frames=total_frames,
|
| 327 |
+
video_backend="torchvision",
|
| 328 |
+
)
|
| 329 |
+
return video, metadata, sample_fps
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
def _is_decord_available() -> bool:
|
| 333 |
+
import importlib.util
|
| 334 |
+
return importlib.util.find_spec("decord") is not None
|
| 335 |
+
|
| 336 |
+
|
| 337 |
+
@lru_cache(maxsize=1)
|
| 338 |
+
def _get_video_backend() -> str:
|
| 339 |
+
forced = os.getenv("TAICHU_VIDEO_READER")
|
| 340 |
+
if forced is not None:
|
| 341 |
+
backend = forced
|
| 342 |
+
elif _is_decord_available():
|
| 343 |
+
backend = "decord"
|
| 344 |
+
else:
|
| 345 |
+
backend = "torchvision"
|
| 346 |
+
print(
|
| 347 |
+
f"ZDTaichu-5.0 utilities using {backend} to read video.",
|
| 348 |
+
file=sys.stderr,
|
| 349 |
+
)
|
| 350 |
+
return backend
|
| 351 |
+
|
| 352 |
+
|
| 353 |
+
_VIDEO_BACKENDS = {
|
| 354 |
+
"decord": _read_video_decord,
|
| 355 |
+
"torchvision": _read_video_torchvision,
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
|
| 359 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 360 |
+
# fetch_video — main entry point for video loading
|
| 361 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 362 |
+
|
| 363 |
+
def fetch_video(
|
| 364 |
+
ele: Dict[str, Any],
|
| 365 |
+
) -> Tuple[List[Image.Image], float, dict]:
|
| 366 |
+
"""
|
| 367 |
+
Load and sample frames from a video.
|
| 368 |
+
|
| 369 |
+
The ``ele["video"]`` value can be:
|
| 370 |
+
- A string path / URI → decoded with decord or torchvision
|
| 371 |
+
- A list of image paths → loaded as pre-extracted frames
|
| 372 |
+
|
| 373 |
+
Returns:
|
| 374 |
+
(frames, sample_fps, metadata)
|
| 375 |
+
- frames: list of PIL.Image.Image in RGB (one per sampled frame)
|
| 376 |
+
- sample_fps: effective sampling rate after frame selection
|
| 377 |
+
- metadata: dict with ``fps``, ``sample_fps``, ``total_num_frames``,
|
| 378 |
+
``frames_indices``, ``video_backend``
|
| 379 |
+
"""
|
| 380 |
+
if isinstance(ele["video"], str):
|
| 381 |
+
# ── Decode from video file ──────────────────────────────────���────
|
| 382 |
+
backend = _get_video_backend()
|
| 383 |
+
try:
|
| 384 |
+
video_tensor, metadata, sample_fps = _VIDEO_BACKENDS[backend](ele)
|
| 385 |
+
except Exception as exc:
|
| 386 |
+
if backend != "torchvision":
|
| 387 |
+
logger.warning(
|
| 388 |
+
f"{backend} failed ({exc}), falling back to torchvision"
|
| 389 |
+
)
|
| 390 |
+
video_tensor, metadata, sample_fps = _read_video_torchvision(ele)
|
| 391 |
+
else:
|
| 392 |
+
raise
|
| 393 |
+
|
| 394 |
+
# Convert TCHW tensor → list of PIL images
|
| 395 |
+
frames = []
|
| 396 |
+
for i in range(video_tensor.size(0)):
|
| 397 |
+
frame_np = video_tensor[i].permute(1, 2, 0).numpy().astype(np.uint8) # HWC
|
| 398 |
+
frames.append(Image.fromarray(frame_np, "RGB"))
|
| 399 |
+
|
| 400 |
+
elif isinstance(ele["video"], (list, tuple)):
|
| 401 |
+
# ── Pre-extracted frames (paths or PIL images) ───────────────────
|
| 402 |
+
frame_elements = ele["video"]
|
| 403 |
+
frames = []
|
| 404 |
+
for item in frame_elements:
|
| 405 |
+
frames.append(fetch_image({"image": item}))
|
| 406 |
+
|
| 407 |
+
# Pad to FRAME_FACTOR multiple
|
| 408 |
+
nframes = ceil_by_factor(len(frames), FRAME_FACTOR)
|
| 409 |
+
while len(frames) < nframes:
|
| 410 |
+
frames.append(frames[-1].copy())
|
| 411 |
+
|
| 412 |
+
sample_fps = ele.get("fps", FPS)
|
| 413 |
+
raw_fps = ele.get("raw_fps", sample_fps)
|
| 414 |
+
metadata = dict(
|
| 415 |
+
fps=raw_fps,
|
| 416 |
+
sample_fps=sample_fps,
|
| 417 |
+
frames_indices=list(range(len(frames))),
|
| 418 |
+
total_num_frames=len(frames),
|
| 419 |
+
video_backend="frames_list",
|
| 420 |
+
)
|
| 421 |
+
else:
|
| 422 |
+
raise TypeError(
|
| 423 |
+
f"ele['video'] must be a string (path) or list (frames), "
|
| 424 |
+
f"got {type(ele['video'])}"
|
| 425 |
+
)
|
| 426 |
+
|
| 427 |
+
return frames, sample_fps, metadata
|
| 428 |
+
|
| 429 |
+
|
| 430 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 431 |
+
# Message parsing
|
| 432 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 433 |
+
|
| 434 |
+
def extract_vision_info(
|
| 435 |
+
conversations: Union[List[Dict[str, Any]], List[List[Dict[str, Any]]]],
|
| 436 |
+
) -> List[Dict[str, Any]]:
|
| 437 |
+
"""
|
| 438 |
+
Extract all vision elements (image / video dicts) from Qwen-style
|
| 439 |
+
structured messages.
|
| 440 |
+
|
| 441 |
+
Args:
|
| 442 |
+
conversations: Either a single conversation (list of message dicts)
|
| 443 |
+
or a batch of conversations.
|
| 444 |
+
|
| 445 |
+
Returns:
|
| 446 |
+
Flat list of vision element dicts, in order of appearance.
|
| 447 |
+
"""
|
| 448 |
+
# Normalise to batch format
|
| 449 |
+
if isinstance(conversations[0], dict):
|
| 450 |
+
conversations = [conversations]
|
| 451 |
+
|
| 452 |
+
vision_infos = []
|
| 453 |
+
for conversation in conversations:
|
| 454 |
+
for message in conversation:
|
| 455 |
+
content = message.get("content")
|
| 456 |
+
if not isinstance(content, list):
|
| 457 |
+
continue
|
| 458 |
+
for ele in content:
|
| 459 |
+
if (
|
| 460 |
+
"image" in ele
|
| 461 |
+
or "image_url" in ele
|
| 462 |
+
or "video" in ele
|
| 463 |
+
or ele.get("type") in ("image", "image_url", "video")
|
| 464 |
+
):
|
| 465 |
+
vision_infos.append(ele)
|
| 466 |
+
return vision_infos
|
| 467 |
+
|
| 468 |
+
|
| 469 |
+
def process_vision_info(
|
| 470 |
+
conversations: Union[List[Dict[str, Any]], List[List[Dict[str, Any]]]],
|
| 471 |
+
) -> Tuple[Optional[List[Image.Image]], Optional[List[List[Image.Image]]], Optional[Dict[str, Any]]]:
|
| 472 |
+
"""
|
| 473 |
+
Extract and load all images and videos from structured messages.
|
| 474 |
+
|
| 475 |
+
This is the main entry point — equivalent to
|
| 476 |
+
``qwen_vl_utils.process_vision_info`` — adapted for ZDTaichu-5.0.
|
| 477 |
+
|
| 478 |
+
Args:
|
| 479 |
+
conversations: Qwen-style messages with structured ``content`` lists
|
| 480 |
+
containing ``{"type": "image", "image": ...}`` and/or
|
| 481 |
+
``{"type": "video", "video": ...}`` elements.
|
| 482 |
+
|
| 483 |
+
Returns:
|
| 484 |
+
(image_inputs, video_inputs, video_kwargs)
|
| 485 |
+
- image_inputs: list of PIL images, or None
|
| 486 |
+
- video_inputs: list of frame-lists (each is ``List[PIL.Image]``),
|
| 487 |
+
or None
|
| 488 |
+
- video_kwargs: dict with ``sample_fps_list`` and ``metadata_list``
|
| 489 |
+
|
| 490 |
+
Example::
|
| 491 |
+
|
| 492 |
+
from vision_utils import process_vision_info
|
| 493 |
+
|
| 494 |
+
messages = [
|
| 495 |
+
{"role": "user", "content": [
|
| 496 |
+
{"type": "video", "video": "clip.mp4", "fps": 2.0},
|
| 497 |
+
{"type": "text", "text": "Describe this video."},
|
| 498 |
+
]}
|
| 499 |
+
]
|
| 500 |
+
|
| 501 |
+
images, videos, video_kwargs = process_vision_info(messages)
|
| 502 |
+
# images = None
|
| 503 |
+
# videos = [[PIL.Image, PIL.Image, ...]] (one list of frames per video)
|
| 504 |
+
# video_kwargs = {"sample_fps_list": [2.0], "metadata_list": [...]}
|
| 505 |
+
"""
|
| 506 |
+
vision_infos = extract_vision_info(conversations)
|
| 507 |
+
|
| 508 |
+
image_inputs: List[Image.Image] = []
|
| 509 |
+
video_inputs: List[List[Image.Image]] = []
|
| 510 |
+
sample_fps_list: List[float] = []
|
| 511 |
+
metadata_list: List[dict] = []
|
| 512 |
+
|
| 513 |
+
for info in vision_infos:
|
| 514 |
+
if "image" in info or "image_url" in info:
|
| 515 |
+
image_inputs.append(fetch_image(info))
|
| 516 |
+
|
| 517 |
+
elif "video" in info:
|
| 518 |
+
frames, sample_fps, metadata = fetch_video(info)
|
| 519 |
+
video_inputs.append(frames)
|
| 520 |
+
sample_fps_list.append(sample_fps)
|
| 521 |
+
metadata_list.append(metadata)
|
| 522 |
+
|
| 523 |
+
else:
|
| 524 |
+
raise ValueError(
|
| 525 |
+
"Vision element must contain 'image', 'image_url', or 'video' key."
|
| 526 |
+
)
|
| 527 |
+
|
| 528 |
+
video_kwargs = {
|
| 529 |
+
"sample_fps_list": sample_fps_list,
|
| 530 |
+
"metadata_list": metadata_list,
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
return (
|
| 534 |
+
image_inputs if image_inputs else None,
|
| 535 |
+
video_inputs if video_inputs else None,
|
| 536 |
+
video_kwargs,
|
| 537 |
+
)
|
| 538 |
+
|
| 539 |
+
|
| 540 |
+
def build_text_from_messages(
|
| 541 |
+
messages: List[Dict[str, Any]],
|
| 542 |
+
image_token: str = "<|image_pad|>",
|
| 543 |
+
video_token: str = "<|video_pad|>",
|
| 544 |
+
) -> List[Dict[str, Any]]:
|
| 545 |
+
"""
|
| 546 |
+
Convert structured messages (with typed content lists) into plain-text
|
| 547 |
+
messages that ``apply_chat_template`` can handle.
|
| 548 |
+
|
| 549 |
+
Each ``{"type": "image", ...}`` is replaced with ``image_token``.
|
| 550 |
+
Each ``{"type": "video", ...}`` is replaced with ``video_token``.
|
| 551 |
+
Text elements are concatenated.
|
| 552 |
+
|
| 553 |
+
Returns:
|
| 554 |
+
New message list with plain string ``content`` fields.
|
| 555 |
+
"""
|
| 556 |
+
output = []
|
| 557 |
+
for msg in messages:
|
| 558 |
+
content = msg.get("content")
|
| 559 |
+
if isinstance(content, str):
|
| 560 |
+
output.append(msg)
|
| 561 |
+
continue
|
| 562 |
+
|
| 563 |
+
parts = []
|
| 564 |
+
for ele in content:
|
| 565 |
+
typ = ele.get("type", "text")
|
| 566 |
+
if typ == "text":
|
| 567 |
+
parts.append(ele.get("text", ""))
|
| 568 |
+
elif typ in ("image", "image_url"):
|
| 569 |
+
parts.append(image_token)
|
| 570 |
+
elif typ == "video":
|
| 571 |
+
parts.append(video_token)
|
| 572 |
+
output.append({**msg, "content": "".join(parts)})
|
| 573 |
+
return output
|
| 574 |
+
|
| 575 |
+
|
| 576 |
+
__all__ = [
|
| 577 |
+
"fetch_image",
|
| 578 |
+
"fetch_video",
|
| 579 |
+
"smart_nframes",
|
| 580 |
+
"extract_vision_info",
|
| 581 |
+
"process_vision_info",
|
| 582 |
+
"build_text_from_messages",
|
| 583 |
+
]
|