mlboydaisuke commited on
Commit
c3bd985
·
verified ·
1 Parent(s): fa09f29

RGBA-Image-2.1-Turbo Core AI port: bf16 + int8 DiT, text encoder, VAE x3 (debug locations stripped), host/, tokenizer/, card

Browse files
.gitattributes CHANGED
@@ -33,3 +33,16 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ host/rope_axis0_cos.f32 filter=lfs diff=lfs merge=lfs -text
37
+ host/rope_axis0_sin.f32 filter=lfs diff=lfs merge=lfs -text
38
+ host/rope_axis1_cos.f32 filter=lfs diff=lfs merge=lfs -text
39
+ host/rope_axis1_sin.f32 filter=lfs diff=lfs merge=lfs -text
40
+ host/rope_axis2_cos.f32 filter=lfs diff=lfs merge=lfs -text
41
+ host/rope_axis2_sin.f32 filter=lfs diff=lfs merge=lfs -text
42
+ qi21_encoder_dynL_w16a32_ids_iofp32.aimodel/main.mlirb filter=lfs diff=lfs merge=lfs -text
43
+ qi21_vae_1024_fp32.aimodel/main.mlirb filter=lfs diff=lfs merge=lfs -text
44
+ qi21_vae_256_fp32.aimodel/main.mlirb filter=lfs diff=lfs merge=lfs -text
45
+ qi21_vae_512_fp32.aimodel/main.mlirb filter=lfs diff=lfs merge=lfs -text
46
+ qi21t_dit_full_bf16_dyn_iofp32.aimodel/main.mlirb filter=lfs diff=lfs merge=lfs -text
47
+ qi21t_dit_full_int8lin_dyn_iofp32.aimodel/main.mlirb filter=lfs diff=lfs merge=lfs -text
48
+ tokenizer/tokenizer.json filter=lfs diff=lfs merge=lfs -text
LICENSE ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Qwen RESEARCH LICENSE AGREEMENT
2
+
3
+ Qwen RESEARCH LICENSE AGREEMENT Release Date: September 20, 2026
4
+
5
+ By clicking to agree or by using or distributing any portion or element of the Qwen Materials, you will be deemed to have recognized and accepted the content of this Agreement, which is effective immediately.
6
+
7
+ 1. Definitions
8
+ a. This Qwen RESEARCH LICENSE AGREEMENT (this "Agreement") shall mean the terms and conditions for use, reproduction, distribution and modification of the Materials as defined by this Agreement.
9
+ b. "We" (or "Us") shall mean Hangzhou Tongyi Laboratory Technology Co., Ltd.
10
+ c. "You" (or "Your") shall mean a natural person or legal entity exercising the rights granted by this Agreement and/or using the Materials for any purpose and in any field of use.
11
+ d. "Third Parties" shall mean individuals or legal entities that are not under common control with us or you.
12
+ e. "Qwen" shall mean the large language models, diffusion models, and software and algorithms, consisting of trained model weights, parameters (including optimizer states), machine-learning model code, inference-enabling code, training-enabling code, fine-tuning enabling code and other elements of the foregoing distributed by us.
13
+ f. "Materials" shall mean, collectively, our proprietary Qwen and Documentation (and any portion thereof) made available under this Agreement.
14
+ g. "Source" form shall mean the preferred form for making modifications, including but not limited to model source code, documentation source, and configuration files.
15
+ h. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
16
+ i. "Non-Commercial" shall mean for research or evaluation purposes only.
17
+
18
+ 2. Grant of Rights
19
+ a. You are granted a non-exclusive, worldwide, non-transferable and royalty-free limited license under our intellectual property or other rights owned by us embodied in the Materials to use, reproduce, distribute, copy, create derivative works of, and make modifications to the Materials FOR NON-COMMERCIAL PURPOSES ONLY.
20
+ b. You shall not use the Materials for any commercial purpose without obtaining a separate commercial license from us. If you wish to use the Materials commercially, you shall request a license from us at model-business@notice.qwencloud.com.
21
+
22
+ 3. Redistribution
23
+ Subject to Section 2 (Grant of Rights), you may distribute copies or make the Materials, or derivative works thereof, available as part of a product or service that contains any of them, with or without modifications, and in Source or Object form, provided that you meet the following conditions:
24
+ a. You shall give any other recipients of the Materials or derivative works a copy of this Agreement;
25
+ b. You shall cause any modified files to carry prominent notices stating that you changed the files;
26
+ c. You shall retain in all copies of the Materials that you distribute the following attribution notices within a "Notice" text file distributed as a part of such copies: "Qwen is licensed under the Qwen RESEARCH LICENSE AGREEMENT, Copyright (c) 2026 Hangzhou Tongyi Laboratory Technology Co., Ltd. All Rights Reserved."; and
27
+ d. You may add your own copyright statement to your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of your modifications, or for any such derivative works as a whole, provided your use, reproduction, and distribution of the work otherwise complies with the terms and conditions of this Agreement.
28
+
29
+ 4. Rules of use
30
+ a. The Materials may be subject to export controls or restrictions in China, the United States or other countries or regions. You shall comply with applicable laws and regulations in your use of the Materials.
31
+ b. If you use the Materials or any outputs or results therefrom to create, train, fine-tune, or improve an AI model that is distributed or made available, you shall prominently display “Built with Qwen” or “Improved using Qwen” in the related product documentation.
32
+ c. You shall not use "Qwen" as the primary name or identifier of any derivative works or products; reasonable descriptive use (e.g., "fine-tuned from Qwen Image") is permitted.
33
+
34
+ 5. Intellectual Property
35
+ a. We retain ownership of all intellectual property rights in and to the Materials and derivatives made by or for us. Conditioned upon compliance with the terms and conditions of this Agreement, with respect to any derivative works and modifications of the Materials that are made by you, you are and will be the owner of such derivative works and modifications.
36
+ b. No trademark license is granted to use the trade names, trademarks, service marks, or product names of us, except as required to fulfill notice requirements under this Agreement or as required for reasonable and customary use in describing and redistributing the Materials.
37
+ c. If you commence a lawsuit or other proceedings (including a cross-claim or counterclaim in a lawsuit) against us or any entity alleging that the Materials or any output therefrom, or any part of the foregoing, infringe any intellectual property or other right owned or licensable by you, then all licenses granted to you under this Agreement shall terminate as of the date such lawsuit or other proceeding is commenced or brought.
38
+
39
+ 6. Disclaimer of Warranty and Limitation of Liability
40
+ a. We are not obligated to support, update, provide training for, or develop any further version of the Qwen Materials or to grant any license thereto.
41
+ b. THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE. WE MAKE NO WARRANTY AND ASSUME NO RESPONSIBILITY FOR THE SAFETY OR STABILITY OF THE MATERIALS AND ANY OUTPUT THEREFROM.
42
+ c. IN NO EVENT SHALL WE BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE MATERIALS OR ANY OUTPUT OF IT, NO MATTER HOW IT’S CAUSED.
43
+ d. You will defend, indemnify and hold harmless us from and against any claim by any third party arising out of or related to your use or distribution of the Materials.
44
+
45
+ 7. Survival and Termination.
46
+ a. The term of this Agreement shall commence upon your acceptance of this Agreement or access to the Materials and will continue in full force and effect until terminated in accordance with the terms and conditions herein.
47
+ b. We may terminate this Agreement if you breach any of the terms or conditions of this Agreement. Upon termination of this Agreement, you must delete and cease use of the Materials. Sections 6 and 8 shall survive the termination of this Agreement.
48
+
49
+ 8. Governing Law and Jurisdiction.
50
+ a. This Agreement and any dispute arising out of or relating to it will be governed by the laws of China, without regard to conflict of law principles, and the UN Convention on Contracts for the International Sale of Goods does not apply to this Agreement.
51
+ b. The People's Courts in Hangzhou City shall have exclusive jurisdiction over any dispute arising out of this Agreement.
52
+
53
+ 9. Other Terms and Conditions.
54
+ a. Any arrangements, understandings, or agreements regarding the Material not stated herein are separate from and independent of the terms and conditions of this Agreement. You shall request a separate license from us, if you use the Materials in ways not expressly agreed to in this Agreement.
55
+ b. We shall not be bound by any additional or different terms or conditions communicated by you unless expressly agreed.
NOTICE ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Qwen is licensed under the Qwen RESEARCH LICENSE AGREEMENT, Copyright (c) 2026 Hangzhou Tongyi Laboratory Technology Co., Ltd. All Rights Reserved.
2
+
3
+ The model files in this repository were converted and re-authored into Apple Core AI .aimodel graphs
4
+ from the Qwen-Image-2.1-Turbo weights (Qwen/Qwen-Image-2.1-Turbo, revision
5
+ d65dbc9a7e8f6b5479e33dee6030eaab2a906509) and the Qwen-Image-2.1 weights (Qwen/Qwen-Image-2.1,
6
+ revision 790c92633540aa0cb11d9abf19eb46d861714758). They were changed as follows.
7
+
8
+ qi21t_dit_full_bf16_dyn_iofp32.aimodel — the diffusion transformer (from Qwen-Image-2.1-Turbo transformer/)
9
+ - Re-authored in plain PyTorch with the checkpoint's parameter names, then exported as one graph.
10
+ - Block-causal attention is computed as two scaled-dot-product-attention calls per block
11
+ (text tokens attend causally to text; image tokens attend to every token).
12
+ - Rotary position embeddings are applied as real-valued cos/sin pairs that the host supplies.
13
+ - The prefix key/value cache is removed: the text prefix is recomputed at every step.
14
+ - Weights and computation are bfloat16; every graph input and output is float32.
15
+ - Both sequence axes are dynamic (text 8-512 tokens, image 64-4096 tokens). Text-to-image only:
16
+ the graph has no condition-image input.
17
+ - The export-time debug locations (the conversion machine's source file paths) are stripped from
18
+ the graph file; the operations and the weights are untouched.
19
+
20
+ qi21t_dit_full_int8lin_dyn_iofp32.aimodel — the same diffusion transformer, with int8 Linear weights
21
+ - The same graph as above, from the same weights.
22
+ - The 232 Linear weight matrices are stored as int8 (symmetric, -127..127, one bfloat16 scale per
23
+ block of 32 input features) and dequantized to bfloat16 inside the graph. The normalization
24
+ weights and all computation stay bfloat16.
25
+ - The export-time debug locations (the conversion machine's source file paths) are stripped from
26
+ the graph file; the operations and the weights are untouched.
27
+
28
+ qi21_encoder_dynL_w16a32_ids_iofp32.aimodel — the text encoder (from Qwen-Image-2.1 text_encoder/)
29
+ - The text encoder of Qwen-Image-2.1-Turbo is byte-identical to that of Qwen-Image-2.1 (750 of 750
30
+ tensors). The graph is the one published in mlboydaisuke/RGBA-Image-2.1-CoreAI (revision
31
+ a9b5c9493571a8c4087dde0f4a191803feb0fd69), with its export-time debug locations (the conversion
32
+ machine's source file paths) stripped; the operations and the weights are untouched.
33
+ - Only the text path of the Qwen3-VL-8B encoder is kept. The vision tower, the language-model head
34
+ and the final RMSNorm are removed; the output is the residual stream after the last layer.
35
+ - Re-authored in plain PyTorch; the token embedding is inside the graph (int32 token ids in).
36
+ - Weights are stored in bfloat16 and all computation is float32; the output is float32.
37
+ - The sequence axis is dynamic (16-512 tokens).
38
+
39
+ qi21_vae_256_fp32.aimodel, qi21_vae_512_fp32.aimodel, qi21_vae_1024_fp32.aimodel — the VAE (from Qwen-Image-2.1 vae/)
40
+ - The float32 VAE weights of Qwen-Image-2.1. The vae/ of Qwen-Image-2.1-Turbo holds the same
41
+ weights rounded to bfloat16. The graphs are the ones published in
42
+ mlboydaisuke/RGBA-Image-2.1-CoreAI (revision a9b5c9493571a8c4087dde0f4a191803feb0fd69), with
43
+ their export-time debug locations (the conversion machine's source file paths) stripped; the
44
+ operations and the weights are untouched.
45
+ - Decoder only, one frame; the VAE encoder is not included.
46
+ - The latent un-normalisation (latents * std + mean) and the token-to-grid unpacking are inside
47
+ the graph.
48
+ - One graph per output size (256x256, 512x512, 1024x1024), float32.
49
+
50
+ Copied without changes from Qwen-Image-2.1-Turbo: LICENSE; config.json (= transformer/config.json);
51
+ tokenizer/ (= processor/ tokenizer.json, tokenizer_config.json, processor_config.json,
52
+ chat_template.jinja).
53
+
54
+ Added by the conversion: host/ (rotary tables and the sampler constants, computed from the model
55
+ definition and the checkpoint's sample_sigmas, and host_contract.md) and README.md.
README.md ADDED
@@ -0,0 +1,325 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: other
3
+ license_name: qwen-research
4
+ license_link: LICENSE
5
+ base_model: Qwen/Qwen-Image-2.1-Turbo
6
+ pipeline_tag: text-to-image
7
+ library_name: coreai
8
+ tags:
9
+ - coreai
10
+ - rgba
11
+ - text-to-image
12
+ - apple-silicon
13
+ ---
14
+
15
+ # RGBA-Image-2.1-Turbo — Core AI port of Qwen-Image-2.1-Turbo
16
+
17
+ - **Built with Qwen.**
18
+ - **Non-commercial use only** — Qwen Research License (research or evaluation purposes).
19
+ - **macOS 27 on Apple silicon only.** Six Core AI bundles, 39.97 GB (37.22 GiB) in total; a run loads
20
+ five of them, 32.41 GB with the bf16 DiT or 25.73 GB with the int8 DiT.
21
+
22
+ RGBA-Image-2.1-Turbo is [`Qwen/Qwen-Image-2.1-Turbo`](https://huggingface.co/Qwen/Qwen-Image-2.1-Turbo)
23
+ (revision `d65dbc9`) converted to Core AI `.aimodel` graphs with coreai-torch 0.4.1 and coreai-core
24
+ 1.0.0b2. On an Apple M4 Max (macOS 27.0 26A428, measured 2026-10-11) the 7B DiT runs a 1024² step in
25
+ 4.72 s, so an 8-step image takes about 38 s of DiT time.
26
+
27
+ A Qwen3-VL-8B text encoder (text path only) conditions a 7B single-stream DiT (32 blocks,
28
+ block-causal attention). A 64-channel VAE decodes to four channels, RGBA. The sampler is the
29
+ checkpoint's own: 8 FlowMatch Euler steps on a fixed sigma grid, no CFG. Ask for a transparent
30
+ background in the prompt and the fourth channel is a real alpha.
31
+
32
+ Sizes: 256², 512² and 1024², square. The DiT and the text encoder have dynamic axes (see Graph
33
+ contracts); the VAE has one graph per size. The upstream 1:1 preset of 2048² needs 16,384 image
34
+ tokens, outside this DiT's 64–4096-token axis.
35
+
36
+ ## What changed from RGBA-Image-2.1
37
+
38
+ The graph code and the host code are those of
39
+ [RGBA-Image-2.1](https://huggingface.co/mlboydaisuke/RGBA-Image-2.1-CoreAI). The differences, and why
40
+ the rest is the same:
41
+
42
+ - **Sampler.** 8 steps on the grid the checkpoint carries (`sample_sigmas` in its `model_index.json`:
43
+ 1.0 … 0.414568), shift 1.0, no `μ`, no CFG. RGBA-Image-2.1 runs 40 steps on a shifted linspace.
44
+ - **DiT.** Re-exported from the Turbo weights with the same exporter: 297 bf16 tensors with the
45
+ base checkpoint's names, shapes and dtypes. An int8 variant ships beside it.
46
+ - **Text encoder.** The Turbo text encoder is byte-identical to the base one (750 of 750 tensors).
47
+ This repo carries RGBA-Image-2.1's encoder graph. Its export-time debug locations are stripped, so
48
+ the file differs from RGBA-Image-2.1's by that alone.
49
+ - **VAE.** The Turbo `vae/` is the base fp32 VAE rounded to bf16 (238 of 238 tensors). This repo
50
+ carries RGBA-Image-2.1's fp32 VAE graphs. Their export-time debug locations are stripped, so the
51
+ files differ from RGBA-Image-2.1's by that alone. Their decode differs from the Turbo pipeline's by
52
+ the rounding band in Measured.
53
+
54
+ The Turbo DiT is a distilled checkpoint. On the same noise and prompt, the fp32 Turbo pipeline's
55
+ 8-step image and the fp32 base pipeline's 40-step image are 21.75 dB (256²) and 23.35 dB (512²)
56
+ apart (white-composited RGB PSNR).
57
+
58
+ ## Bundle
59
+
60
+ [🤗 mlboydaisuke/RGBA-Image-2.1-Turbo-CoreAI](https://huggingface.co/mlboydaisuke/RGBA-Image-2.1-Turbo-CoreAI)
61
+
62
+ | file | what it is | size |
63
+ | --- | --- | --- |
64
+ | `qi21t_dit_full_bf16_dyn_iofp32.aimodel` | the DiT: bf16 weights and compute, fp32 inputs and outputs | 14.23 GB (13.25 GiB) |
65
+ | `qi21t_dit_full_int8lin_dyn_iofp32.aimodel` | the same DiT with int8 Linear weights (one bf16 scale per 32 inputs), bf16 compute | 7.56 GB (7.04 GiB) |
66
+ | `qi21_encoder_dynL_w16a32_ids_iofp32.aimodel` | the text encoder: bf16 weights, fp32 compute; token ids in, `embed_tokens` inside | 15.14 GB (14.10 GiB) |
67
+ | `qi21_vae_{256,512,1024}_fp32.aimodel` | the VAE decoder, fp32, one per size | 1.01 GB (0.94 GiB) each |
68
+ | `host/` | per-axis RoPE tables, `scheduler.json` (the 8-step grid), [`host_contract.md`](https://huggingface.co/mlboydaisuke/RGBA-Image-2.1-Turbo-CoreAI/blob/main/host/host_contract.md) | |
69
+ | `tokenizer/` | the source's `processor/` files, unchanged | |
70
+ | `config.json` | the source's `transformer/config.json`, unchanged | |
71
+ | `LICENSE`, `NOTICE` | the Qwen Research License and the change notice | |
72
+
73
+ The two DiT bundles have one interface; a run uses one of them. On every gate below the int8 DiT
74
+ stays inside the bar, at the bf16 DiT's speed (within 0.1 %). Compiled, the bf16 DiT is 26.52 GiB
75
+ and the int8 DiT 20.30 GiB.
76
+
77
+ **Compile before you run.** On macOS 27.0 (26A428) the Python runtime crashes on this DiT unless it
78
+ is compiled ahead of time with `--expect-frequent-reshapes` (step 2 below). A plain ahead-of-time
79
+ compile fails at the initial call (`ANERegion.mm:414 … Code=-19`); so did a just-in-time compile of
80
+ the same graph with the base weights on 2026-09-25. The compiled copies need their own disk:
81
+ 26.52 GiB for the bf16 DiT or 20.30 GiB for the int8, and 14.10 GiB for the encoder.
82
+
83
+ ## Use it
84
+
85
+ There is no Swift app for this model yet. The Python engine
86
+ [`conversion/qwenimage21/pipeline_engine.py`](https://github.com/john-rocky/coreai-model-zoo/blob/main/conversion/qwenimage21/pipeline_engine.py)
87
+ runs the whole loop on the three bundles: tokenize, encode, 8 DiT steps, decode, write a PNG.
88
+ `--turbo` selects the 8-step grid.
89
+
90
+ ```
91
+ # 1. the bundles (the tokenizer is in tokenizer/)
92
+ hf download mlboydaisuke/RGBA-Image-2.1-Turbo-CoreAI --local-dir RGBA-Image-2.1-Turbo-CoreAI
93
+
94
+ # 2. compile for the Mac GPU (once per bundle; the gates used --architecture h16c on an M4 Max)
95
+ cd RGBA-Image-2.1-Turbo-CoreAI
96
+ for m in qi21_encoder_dynL_w16a32_ids_iofp32 qi21t_dit_full_bf16_dyn_iofp32 qi21_vae_256_fp32 qi21_vae_1024_fp32; do
97
+ xcrun coreai-build compile $m.aimodel --output aot/$m --platform macOS --architecture h16c \
98
+ --preferred-compute gpu --expect-frequent-reshapes
99
+ done
100
+ R=$PWD; A=$PWD/aot
101
+
102
+ # 3. generate, from a checkout of the zoo
103
+ # (Python with coreai-core 1.0.0b2, torch, numpy, tokenizers, pillow)
104
+ cd /path/to/coreai-model-zoo/conversion/qwenimage21
105
+ python pipeline_engine.py --turbo \
106
+ --prompt "This is an RGBA image with transparency. A cute cartoon dragon sticker. The image has alpha channel and the background is transparent." \
107
+ --size 1024 --seed 42 --tag dragon \
108
+ --tokenizer-json $R/tokenizer/tokenizer.json \
109
+ --encoder $A/qi21_encoder_dynL_w16a32_ids_iofp32/qi21_encoder_dynL_w16a32_ids_iofp32.h16c.aimodelc \
110
+ --dit $A/qi21t_dit_full_bf16_dyn_iofp32/qi21t_dit_full_bf16_dyn_iofp32.h16c.aimodelc \
111
+ --vae $A/qi21_vae_1024_fp32/qi21_vae_1024_fp32.h16c.aimodelc
112
+ # -> _work/samples/dragon.png (RGBA) and dragon_rgb.png (composited on white)
113
+ ```
114
+
115
+ For the int8 DiT, compile `qi21t_dit_full_int8lin_dyn_iofp32` the same way and pass its
116
+ `.aimodelc` as `--dit`. The prompt above is the upstream card's recommended form for transparent
117
+ images: "This is an RGBA image with transparency. {subject}. The image has alpha channel and the
118
+ background is transparent." The noise is `torch.randn` on a CPU generator seeded with `--seed`, the
119
+ same draw the reference pipeline makes with a CPU generator and that seed.
120
+
121
+ To check the port against the fp32 reference, record the reference once and run the engine in
122
+ oracle mode. `capture_oracle.py` runs the diffusers-main pipeline in fp32 on the CPU, 17 s of
123
+ generation at 256² on the M4 Max. It needs the full `Qwen/Qwen-Image-2.1-Turbo` snapshot and a venv
124
+ with diffusers main 85c9fa4 and transformers 5.17.
125
+
126
+ ```
127
+ python capture_oracle.py --snapshot <Qwen-Image-2.1-Turbo snapshot dir> --model-id Qwen/Qwen-Image-2.1-Turbo \
128
+ --size 256 --steps 8 --tag turbo256 # -> oracle/turbo256/
129
+ python pipeline_engine.py --turbo --oracle oracle/turbo256 \
130
+ --tokenizer-json $R/tokenizer/tokenizer.json \
131
+ --encoder $A/qi21_encoder_dynL_w16a32_ids_iofp32/qi21_encoder_dynL_w16a32_ids_iofp32.h16c.aimodelc \
132
+ --dit $A/qi21t_dit_full_bf16_dyn_iofp32/qi21t_dit_full_bf16_dyn_iofp32.h16c.aimodelc \
133
+ --vae $A/qi21_vae_256_fp32/qi21_vae_256_fp32.h16c.aimodelc
134
+ # prints the latent corr vs the reference after every step, then the RGBA and white-composited PSNR
135
+ ```
136
+
137
+ ## Which image model should I use?
138
+
139
+ The zoo's Mac text-to-image models are not ranked; pick by trade-off. The two RGBA-Image models write
140
+ RGBA natively, so they fit images that need an alpha channel.
141
+
142
+ | | params | sampler | time @1024 | precision |
143
+ | --- | --- | --- | --- | --- |
144
+ | **FLUX.2 klein** | 4B | 4 steps, guidance-distilled (no CFG) | ~11 s | fp16 or int8 |
145
+ | **Z-Image-Turbo** | 6B | 8 steps + CFG (16 forwards) | ~70 s | bf16, near-lossless |
146
+ | **GLM-Image** | 16B (9B AR + 7B DiT) | AR prior + 20-step DiT | ~208 s | int8 |
147
+ | **RGBA-Image-2.1** | 7B | 40 steps, no CFG | ~190 s | bf16 |
148
+ | **RGBA-Image-2.1-Turbo** | 7B | 8 steps, distilled, no CFG | ~38 s | bf16 or int8 |
149
+
150
+ Times are the ones each card reports, on an M4 Max. For the two RGBA-Image models they are the DiT
151
+ steps at the warm median per forward: 40 × 4.757 s and 8 × 4.721 s. They leave out the encoder, the
152
+ VAE and loading.
153
+
154
+ ## Graph contracts
155
+
156
+ Every graph has one function, `main`, and fp32 inputs and outputs except `input_ids`. Both DiT
157
+ bundles have the DiT row's contract.
158
+
159
+ | graph | inputs | output |
160
+ | --- | --- | --- |
161
+ | encoder | `input_ids [1,Lfull]` int32, `Lfull` 16..512 | `hidden [1,Lfull,4096]`: the last layer's residual stream, before the final norm |
162
+ | DiT | `img_tokens [1,N,64]`, `txt_feats [1,L,4096]`, `timestep [1]`, `txt_cos`/`txt_sin [1,L,64]`, `img_cos`/`img_sin [1,N,64]`; `L` 8..512, `N` 64..4096 | `vel [1,N,64]` |
163
+ | VAE | `latents_packed [1,N,64]`, the sampler's latent unchanged | `image [1,4,S,S]`, RGBA in [-1, 1] |
164
+
165
+ - **Prompt.** One tokenization of the text-to-image chat template around the prompt, no padding.
166
+ The DiT reads `hidden[:, drop_idx:]`. `drop_idx` is the token count of the template's system
167
+ part: 14 with this tokenizer. Compute it; do not hard-code it.
168
+ - **Sequence.** `[text L | image N]`, image tokens in raster order, one token per 16×16 px tile
169
+ (256² → 256 tokens, 512² → 1024, 1024² → 4096). There is no 2×2 latent packing.
170
+ - **RoPE.** Text token `i` sits at `(i, i, i)`. Image token `(y, x)` sits at `(L, y − (h − h//2),
171
+ x − (w − w//2))`. `host/` has the per-axis tables for positions −1024..8191.
172
+ - **Sampler.** The 8 sigmas in `host/scheduler.json`, then `0`. Shift 1.0 leaves them unchanged,
173
+ and there is no `μ` and no terminal stretch, so the grid is the same at every size. The DiT's
174
+ `timestep` input is `timesteps[i] / 1000` in fp32 (σᵢ bit for bit on this grid), and each step is
175
+ `x += (σᵢ₊₁ − σᵢ)·v`.
176
+ - **VAE.** The graph unpacks the tokens and applies `latents·std + mean` itself. Feed it the raw
177
+ sampler latent.
178
+
179
+ The full contract, with the formulas a Swift host needs:
180
+ [`host/host_contract.md`](https://huggingface.co/mlboydaisuke/RGBA-Image-2.1-Turbo-CoreAI/blob/main/host/host_contract.md).
181
+
182
+ ## Measured
183
+
184
+ M4 Max (128 GiB), macOS 27.0 (26A428), coreai-core 1.0.0b2, 2026-10-11. Bundles compiled ahead of
185
+ time with `--expect-frequent-reshapes` (`--architecture h16c`), run with
186
+ `SpecializationOptions.default()`. Speed runs held the Mac's measurement window, which holds back
187
+ other sessions' heavy jobs. The same form timed in different windows moved by up to 1.6 %. The
188
+ timings were taken on the bundles before their debug locations were stripped; the published files
189
+ compute the same outputs bit for bit (Gates).
190
+
191
+ **DiT speed** (`bench_dit.py`, text L = 40, bf16 DiT):
192
+
193
+ | size | image tokens | initial call | s/forward (warm median of 5) | 8 steps |
194
+ | --- | --- | --- | --- | --- |
195
+ | 256² | 256 | 2.27 s | 0.341 s | 2.7 s |
196
+ | 512² | 1024 | 1.10 s | 1.097 s | 8.8 s |
197
+ | 1024² | 4096 | 4.72 s | 4.721 s | 37.8 s |
198
+
199
+ The int8 DiT against the bf16 one in the same process (`ab_dit.py`, L = 40, 8 alternating pairs per
200
+ size): 0.3409 / 1.0923 / 4.7808 s per forward against 0.3410 / 1.0926 / 4.7850 s.
201
+
202
+ **One image end to end** (`pipeline_engine.py --turbo`, bf16 DiT, inside the measurement window,
203
+ compile cache already warm):
204
+
205
+ | prompt, size | encoder load / call | DiT load / initial step / 8 steps | VAE load / call | total |
206
+ | --- | --- | --- | --- | --- |
207
+ | dragon sticker, 512² | 17.0 / 0.40 s | 2.0 / 3.20 / 10.9 s | 1.2 / 0.38 s | 32.0 s |
208
+ | dragon sticker, 1024² | 3.4 / 0.37 s | 2.0 / 6.63 / 39.6 s | 0.5 / 1.45 s | 47.3 s |
209
+ | apple, 1024² | 3.5 / 0.36 s | 1.9 / 6.64 / 39.3 s | 0.3 / 1.46 s | 47.0 s |
210
+
211
+ Load times vary between processes on this shared Mac: 1.9–43.3 s for the DiT and 2.5–55.8 s for
212
+ the encoder across the gate runs. The cold load of a new `.aimodelc` adds a compile-cache entry the
213
+ size of the compiled bundle (26 GB for the bf16 DiT, 20 GB for the int8).
214
+
215
+ **Memory.** Peak memory footprint 4.80 GB at 512² and 17.77–18.16 GB at 1024²
216
+ (`/usr/bin/time -l`). Its "maximum resident set size", 58.3 GB with the bf16 DiT and 51.6 GB with
217
+ the int8, counts the mapped weight pages of the encoder and the DiT.
218
+
219
+ **Fidelity** against the fp32 diffusers Turbo pipeline (prompt "a red apple on a wooden table,
220
+ studio lighting", seed 1234, the same noise, 8 steps):
221
+
222
+ | size | bf16 DiT: white-composited RGB PSNR / final latent corr | int8 DiT: the same | alpha max\|Δ\| |
223
+ | --- | --- | --- | --- |
224
+ | 256² | 43.79 dB / 0.999961 | 41.76 dB / 0.999944 | 1/255 |
225
+ | 512² | 42.45 dB / 0.999800 | 49.28 dB / 0.999976 | 1/255 |
226
+ | 1024² | 42.50 dB / 0.999926 | 39.32 dB / 0.999873 | 1/255 |
227
+
228
+ The reference decodes with the Turbo bf16 VAE file and the bundles carry the fp32 weights; the band
229
+ between the two (below) is inside these numbers. With the reference's prompt embeddings in place of
230
+ the encoder bundle, 256² scores 46.57 dB (bf16 DiT) and 42.56 dB (int8 DiT).
231
+
232
+ **The VAE band.** The same final latent decoded with the fp32 weights (these bundles) and with the
233
+ Turbo pipeline's bf16 copy:
234
+
235
+ | size | max\|Δ\| on [-1, 1] | uint8 PSNR | max levels, RGB / alpha | bundle vs a fp32 decode of its own weights |
236
+ | --- | --- | --- | --- | --- |
237
+ | 256² | 0.074 | 56.95 dB | 10 / 1 | max\|Δ\| 3.0e-5 |
238
+ | 512² | 0.106 | 58.95 dB | 14 / 1 | max\|Δ\| 3.2e-5 |
239
+ | 1024² | 0.105 | 58.15 dB | 13 / 1 | max\|Δ\| 4.2e-5 |
240
+
241
+ **Gates:**
242
+
243
+ - DiT re-authored in plain PyTorch, fp32, with the Turbo weights, teacher-forced on all 8 steps:
244
+ min corr 0.999999999982 at 256² and 0.999999999997 at 512²; 9 of 9 broken variants fail the bar
245
+ (256²).
246
+ - DiT bundles (GPU), teacher-forced against the fp32 reference, 8/8 steps, NaN 0: min corr 0.999971 /
247
+ 0.999940 / 0.999977 at 256² / 512² / 1024² (bf16) and 0.999960 / 0.999883 / 0.999965 (int8).
248
+ - Text encoder bundle on the Turbo reference: min per-token corr 0.999999998629, NaN 0. The host
249
+ tokenizer gives the Turbo processor's ids, `drop_idx` 14.
250
+ - VAE bundles against a fp32 decode of their own weights: max|Δ| 3.0e-5 / 3.2e-5 / 4.2e-5, every
251
+ channel corr ≥ 0.99999995.
252
+ - Sampler: sigmas, timesteps and all 8 Euler steps bit-exact at 256², 512² and 1024². RoPE tables
253
+ bit-exact against diffusers main.
254
+ - Transparency: the dragon prompt above, seed 42: alpha min 0 and all four corner pixels 0 at 512²
255
+ (alpha mean 102) and 1024² (alpha mean 82).
256
+ - Stripped bundles reproduce the unstripped outputs bit for bit. The published files have their
257
+ export-time debug locations stripped; against the bundles they were made from, both DiTs (8
258
+ teacher-forced steps at 256²), the encoder, the three VAEs and a 256² image end to end with each DiT
259
+ give identical outputs.
260
+
261
+ **Other forms tried** (s/forward against the shipped bf16 DiT in the same window):
262
+
263
+ | form | result |
264
+ | --- | --- |
265
+ | int8 Linear weights, AOT with `--expect-frequent-reshapes` | compiles in 301 s, passes every gate, −0.02 / −0.02 / −0.09 % at 256² / 512² / 1024²: ships as the second DiT |
266
+ | image axis fixed at N = 4096 | −0.50 % at L = 40, +0.58 % at L = 18: the dynamic graph ships |
267
+ | `--preferred-compute neural-engine` | 0 Neural Engine regions; runs on the GPU, outputs equal bit for bit, +0.01 / 0.00 / +0.72 % |
268
+ | plain AOT, no `--expect-frequent-reshapes` | crashes at the initial call (`ANERegion.mm:414 … Code=-19`), dynamic and fixed image axis alike |
269
+ | text K/V computed once per image | the 32 text tokens between L = 8 and L = 40 cost 1.59 % of a forward at 512² and 0.51 % at 1024² |
270
+
271
+ ## Lessons
272
+
273
+ 1. **A probe's compile result does not carry to the full graph, either way.** The 2-layer int8 probe
274
+ with random weights fails the `--expect-frequent-reshapes` compile (`Pass failed:
275
+ MPSMemrefAllocFusion`), on 2026-09-25 and again on 2026-10-11. The full 32-layer int8 DiT with the
276
+ Turbo weights compiles in 301 s and passes every gate. On 2026-09-25 it went the other way: the
277
+ probe ran where the full bf16 DiT crashed. Judge compilation on the full graph.
278
+ 2. **A sibling checkpoint can carry a bf16 copy of a component.** The Turbo `vae/` is the base fp32
279
+ VAE rounded to bf16, so the fp32 bundles sit 0.074–0.106 from the Turbo pipeline's decode, 7–10×
280
+ the 1e-2 bar. Gate a bundle against a fp32 decode of the weights it holds, and report the rounding
281
+ band beside it. Alpha is near-constant on an opaque image (0.976–1.000), so its correlation drops
282
+ to 0.966–0.991 under that band: report alpha in levels, not correlation.
283
+ 3. **Read a dB gap between two DiT forms next to a nudge control.** The 8-step sampler turns a
284
+ 1.25e-5 relative change of the prompt embeddings into 29.03 dB (512²) and 32.08 dB (1024²)
285
+ between dragon stickers. The int8 and bf16 stickers are 34.42 and 28.99 dB apart, the same order.
286
+ 78–88 % of the pixels whose alpha moves by more than 2 levels lie within 3 px of the silhouette:
287
+ alpha max|Δ| on a sticker (227–255) measures the edge.
288
+ 4. **`--preferred-compute neural-engine` can compile to 0 regions without an error.** This DiT
289
+ compiled that way has no Neural Engine region and runs on the GPU, equal bit for bit to the gpu
290
+ compile. Count the `*ANE_region*` entries before timing an ANE form.
291
+ 5. **An exported `.aimodel` carries the export machine's paths.** coreai-torch writes every op's
292
+ source location into `main.mlirb`, and `grep -I` skips that binary. coreai-torch's
293
+ `strip_debug_info` removes them without touching the ops or the weights
294
+ ([`strip_bundle.py`](https://github.com/john-rocky/coreai-model-zoo/blob/main/conversion/qwenimage21/strip_bundle.py));
295
+ the result is a new asset, so gate it again.
296
+
297
+ The lessons of the base port (the Neural Engine region, the encoder's fp32 compute, the bf16 band):
298
+ [RGBA-Image-2.1](https://github.com/john-rocky/coreai-model-zoo/blob/main/models/rgba-image-2.1/README.md#lessons).
299
+ Port notes, every gate and the dead ends:
300
+ [`knowledge/qwenimage21-port.md`](https://github.com/john-rocky/coreai-model-zoo/blob/main/knowledge/qwenimage21-port.md).
301
+ Scripts: [`conversion/qwenimage21/`](https://github.com/john-rocky/coreai-model-zoo/tree/main/conversion/qwenimage21).
302
+
303
+ ## Licence
304
+
305
+ The weights are Qwen Materials under the **Qwen RESEARCH LICENSE AGREEMENT** (release date
306
+ 2026-09-20), included unchanged as
307
+ [`LICENSE`](https://huggingface.co/mlboydaisuke/RGBA-Image-2.1-Turbo-CoreAI/blob/main/LICENSE). A
308
+ summary follows; the Agreement is what binds.
309
+
310
+ - **§2, non-commercial only.** You may use, copy, modify and redistribute the Materials for
311
+ research or evaluation purposes only. Commercial use needs a separate licence from Hangzhou
312
+ Tongyi Laboratory Technology Co., Ltd.; §2(b) gives the contact.
313
+ - **§3, redistribution,** under three conditions: every recipient gets a copy of the Agreement
314
+ (`LICENSE`); modified files carry a notice that they were changed (`NOTICE` lists every change);
315
+ and copies keep the attribution text below in a "Notice" file (`NOTICE`, line 1).
316
+ - **§4(b).** An AI model created from the Materials and made available displays "Built with Qwen"
317
+ prominently in its documentation. This card does, at the top.
318
+ - **§4(c).** "Qwen" is not the primary name of a derivative. This port is named
319
+ RGBA-Image-2.1-Turbo; "Core AI port of Qwen-Image-2.1-Turbo" is the descriptive use the Agreement
320
+ permits.
321
+
322
+ [`NOTICE`](https://huggingface.co/mlboydaisuke/RGBA-Image-2.1-Turbo-CoreAI/blob/main/NOTICE) begins
323
+ with the attribution text §3(c) requires:
324
+
325
+ > Qwen is licensed under the Qwen RESEARCH LICENSE AGREEMENT, Copyright (c) 2026 Hangzhou Tongyi Laboratory Technology Co., Ltd. All Rights Reserved.
config.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_class_name": "QwenImage21Transformer2DModel",
3
+ "_diffusers_version": "0.41.0.dev0",
4
+ "attention_head_dim": 128,
5
+ "axes_dims_rope": [
6
+ 16,
7
+ 56,
8
+ 56
9
+ ],
10
+ "causal_condition": true,
11
+ "context_in_dim": 4096,
12
+ "eps": 1e-06,
13
+ "in_channels": 64,
14
+ "mlp_ratio": 3,
15
+ "num_attention_heads": 32,
16
+ "num_layers": 32,
17
+ "out_channels": 64,
18
+ "patch_size": 1
19
+ }
host/host_contract.md ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Host contract — RGBA-Image-2.1-Turbo (Core AI port of Qwen-Image-2.1-Turbo)
2
+
3
+ Everything a host computes around the three graphs, for text-to-image, batch 1, no CFG.
4
+ The Python reference of every step below is in the zoo's
5
+ [`conversion/qwenimage21/`](https://github.com/john-rocky/coreai-model-zoo/tree/main/conversion/qwenimage21):
6
+ `qi21_tokenize.py` (tokenizer), `qi21_host.py` (RoPE, pack/unpack), `qi21_sched.py` (sampler,
7
+ `schedule_fixed`), `pipeline_engine.py --turbo` (the whole loop on the three bundles). The first three
8
+ match the diffusers-main pipeline (diffusers 85c9fa4, `Qwen/Qwen-Image-2.1-Turbo` @ `d65dbc9`) exactly:
9
+ the same token ids, bit-identical RoPE tables, bit-identical sigmas and Euler steps.
10
+ `pipeline_engine.py` is scored against the pipeline's fp32 images.
11
+
12
+ This port shares its graph code and its text-encoder and VAE graphs with RGBA-Image-2.1 (the files here
13
+ have their export-time debug locations stripped). Only the DiT weights and the sampler differ. Section 6
14
+ is the part that changed.
15
+
16
+ ## 1. The graphs
17
+
18
+ Every graph has one function, `main`. All tensors crossing a graph boundary are fp32, except
19
+ `input_ids` (int32).
20
+
21
+ | bundle | inputs | output | axes |
22
+ | --- | --- | --- | --- |
23
+ | `qi21_encoder_dynL_w16a32_ids_iofp32.aimodel` | `input_ids [1,Lfull]` int32 | `hidden [1,Lfull,4096]` | `Lfull` 16..512 |
24
+ | `qi21t_dit_full_bf16_dyn_iofp32.aimodel` | `img_tokens [1,N,64]`, `txt_feats [1,L,4096]`, `timestep [1]`, `txt_cos [1,L,64]`, `txt_sin [1,L,64]`, `img_cos [1,N,64]`, `img_sin [1,N,64]` | `vel [1,N,64]` | `L` 8..512, `N` 64..4096 |
25
+ | `qi21t_dit_full_int8lin_dyn_iofp32.aimodel` | the same as the bf16 DiT | the same | the same |
26
+ | `qi21_vae_{256,512,1024}_fp32.aimodel` | `latents_packed [1,N,64]` | `image [1,4,S,S]` | fixed: `N = (S/16)²` |
27
+
28
+ - Encoder: the Qwen3-VL-8B text stack (36 layers). bf16 weights, fp32 compute. `embed_tokens` is
29
+ inside the graph. The output is the residual stream after the last layer, **before** the final
30
+ RMSNorm. Do not apply a norm on the host.
31
+ - DiT: 32 blocks, fp32 boundary. Two bundles with one interface; use either. `bf16`: bf16 weights
32
+ and compute. `int8lin`: the 232 Linear weights in int8 (symmetric, one bf16 scale per block of
33
+ 32), dequantized inside the graph; norms, scales and compute in bf16.
34
+ - VAE: decoder only, fp32. The graph unpacks the tokens and applies `latents * std + mean` itself.
35
+
36
+ ## 2. Tokenize
37
+
38
+ Tokenizer: `tokenizer/tokenizer.json` (Qwen2 BPE, byte-level), the Turbo checkpoint's
39
+ `processor/tokenizer.json`. No BOS token. An empty prompt is replaced by a single space `" "`.
40
+
41
+ Template (text-to-image):
42
+
43
+ ```
44
+ <|im_start|>system\nComprehend and analyze the provided prompt.<|im_end|>\n<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant\n
45
+ ```
46
+
47
+ `\n` is a newline character. Encode the whole string once, with no padding and no truncation, to get
48
+ `ids` (length `Lfull`).
49
+
50
+ **`drop_idx`** is the number of tokens of the system part alone,
51
+ `<|im_start|>system\nComprehend and analyze the provided prompt.<|im_end|>\n`. Compute it by encoding
52
+ that string. With this tokenizer it is 14:
53
+ `[151644, 8948, 198, 1092, 30782, 408, 323, 23643, 279, 3897, 9934, 13, 151645, 198]`.
54
+ Check that `ids[:drop_idx]` equals those tokens.
55
+
56
+ `Lfull` must be 16..512 (the encoder's axis), and the DiT needs `L = Lfull − drop_idx` in 8..512.
57
+ The template around the empty-prompt substitute `" "` is 23 tokens (`L` = 9).
58
+
59
+ The Turbo `tokenizer.json` differs from the base checkpoint's only in its offset and decoder
60
+ settings (`trim_offsets`, `add_prefix_space`, `use_regex`). Vocabulary, merges and added tokens are
61
+ the same, and both files give the processor's ids on every prompt the port was gated on.
62
+
63
+ ## 3. Encode
64
+
65
+ ```
66
+ hidden = encoder(input_ids = ids as int32 [1, Lfull]) # [1, Lfull, 4096]
67
+ prompt_embeds = hidden[:, drop_idx : Lfull] # [1, L, 4096], L = Lfull - drop_idx
68
+ ```
69
+
70
+ Pass exactly `Lfull` tokens; the axis is dynamic, so no padding is needed. (Attention is causal, so
71
+ pad tokens never reach the first `Lfull` outputs, but a longer input moves the GPU result by about
72
+ 4e-6 relative.) Run the encoder once per image.
73
+
74
+ ## 4. Sequence layout and RoPE
75
+
76
+ The DiT's sequence is `[text L | image N]`: the `L` prompt tokens, then the image tokens in raster
77
+ order. One image token covers one 16×16 px tile of the output: for an `S×S` image,
78
+ `h = w = S/16` and `N = h·w` (256² → 256 tokens, 512² → 1024, 1024² → 4096). There is no 2×2 packing.
79
+
80
+ Each token has a 3-axis position `(frame, height, width)`:
81
+
82
+ - text token `i` (0-based) → `(i, i, i)`;
83
+ - image token at row `y`, column `x` (0-based, token index `y·w + x`) →
84
+ `(L, y − (h − h//2), x − (w − w//2))`. The grid is centred on zero. For `h = 16`, rows go −8..7.
85
+
86
+ `host/rope_axis{a}_{cos,sin}.f32` hold one row per position −1024..8191: fp32, little-endian,
87
+ row-major `[9216, P_a]` with `P = (8, 28, 28)`. The row for position `p` is `p + 1024`. A token's
88
+ 64 values are the three rows concatenated in axis order:
89
+
90
+ ```
91
+ cos[token] = axis0_cos[f + 1024] ++ axis1_cos[hpos + 1024] ++ axis2_cos[wpos + 1024] # 8 + 28 + 28
92
+ sin[token] = the same with the _sin tables
93
+ txt_cos, txt_sin = rows of the L text tokens # [1, L, 64]
94
+ img_cos, img_sin = rows of the N image tokens # [1, N, 64]
95
+ ```
96
+
97
+ The tables are `torch.polar(1, outer(pos, 1 / 10000^(arange(0, d, 2)/d)))` for axis widths
98
+ `d = 16, 56, 56`, the same numbers as `QwenImage21Rope.freqs` of diffusers main (bit-exact). Axes 1
99
+ and 2 have the same width, so their files are byte-identical. The six files are byte-identical to
100
+ RGBA-Image-2.1's `host/`. The four tensors depend only on `L`, `h` and `w`: build them once per
101
+ image, not per step.
102
+
103
+ ## 5. Noise and pack
104
+
105
+ The initial latent is standard normal noise: 64 channels × `h` rows × `w` columns, channel-major.
106
+ The reference pipeline draws it as `randn((1, 1, 64, h, w))` and packs it into DiT tokens:
107
+
108
+ ```
109
+ x[0, y·w + x_, c] = z[c, y, x_] # = z.view(1, 64, h·w).transpose(1, 2)
110
+ ```
111
+
112
+ Any N(0, 1) noise generates an image. Matching the Python engine for a given seed needs its exact
113
+ draw: `torch.randn((1, 1, 64, h, w), generator=torch.Generator("cpu").manual_seed(seed))`.
114
+
115
+ ## 6. Sampler (FlowMatch Euler, a fixed 8-step grid, no CFG)
116
+
117
+ The checkpoint carries its own sigmas: `sample_sigmas` in its `model_index.json`, copied to
118
+ `host/scheduler.json`. The pipeline passes them to the scheduler in place of a linspace and ignores
119
+ `num_inference_steps`. `use_dynamic_shifting` is false, so there is no `mu` and the grid is the same
120
+ at every image size. All arrays are fp32.
121
+
122
+ ```
123
+ sigmas = fp32(sample_sigmas) # 1.0, 0.978453, 0.95418, 0.926626, 0.89508, 0.845148, 0.704534, 0.414568
124
+ sigmas = shift·sigmas / (1 + (shift − 1)·sigmas) # shift 1.0: unchanged, bit for bit
125
+ # shift_terminal null: no terminal stretch
126
+ timesteps = sigmas · num_train_timesteps # fp32
127
+ sigmas = sigmas ++ [0] # 9 values
128
+ for i in 0 ..< 8:
129
+ t = timesteps[i] / 1000 # fp32; this is the DiT `timestep` input
130
+ vel = dit(img_tokens = x, txt_feats = prompt_embeds, timestep = [t], txt_cos, txt_sin, img_cos, img_sin)
131
+ x = x + (sigmas[i+1] − sigmas[i]) · vel # fp32
132
+ ```
133
+
134
+ On this grid `t` equals `sigmas[i]` bit for bit at all 8 steps; keep `timesteps[i] / 1000` anyway,
135
+ the form the pipeline uses. `qi21_sched.schedule_fixed` reproduces the reference sigmas, timesteps
136
+ and all 8 Euler steps bit-exactly at 256², 512² and 1024².
137
+
138
+ RGBA-Image-2.1 runs 40 steps on a shifted linspace instead (its `host/host_contract.md`, §6). The
139
+ Turbo DiT is a distilled checkpoint, not the base DiT run for fewer steps: on the same noise and
140
+ prompt, the fp32 Turbo pipeline's 8-step image and the fp32 base pipeline's 40-step image are
141
+ 21.75 dB (256²) and 23.35 dB (512²) apart (white-composited RGB PSNR).
142
+
143
+ ## 7. Decode
144
+
145
+ ```
146
+ image = vae_S(latents_packed = x) # x after the last step, [1, N, 64], exactly as the sampler holds it
147
+ rgba8 = round(clip(image · 0.5 + 0.5, 0, 1) · 255) # [1, 4, S, S] -> channels R, G, B, A
148
+ ```
149
+
150
+ Feed the sampler's latent unchanged: no unpacking and no `* std + mean` on the host (the graph does
151
+ both). The four channels are what the reference pipeline saves as an RGBA PNG.
152
+
153
+ The VAE bundles hold the base checkpoint's fp32 VAE weights. The Turbo checkpoint's `vae/` is a bf16
154
+ copy of those weights (all 238 tensors are the round-to-nearest-even of the fp32 ones). Decoding the
155
+ same latent, the two sets of weights differ by up to 0.074–0.106 on the [-1, 1] scale: uint8 PSNR
156
+ 56.95 / 58.95 / 58.15 dB at 256² / 512² / 1024², at most 10–14 levels on one channel, 1 level on
157
+ alpha. A host that compares against the diffusers Turbo pipeline sees that band; the bundles match a
158
+ fp32 decode with their own weights to max|Δ| 3.0e-5 – 4.2e-5.
159
+
160
+ ## 8. Compile before running on the GPU
161
+
162
+ On macOS 27.0 (26A428) the Python runtime crashes on the 32-block DiT when the `.aimodel` is
163
+ compiled just-in-time: the MPSGraph delegate forms a Neural Engine region inside the graph and the
164
+ ANE inference fails (`ANERegion.mm:414 failed assertion … Code=-19`). A plain ahead-of-time compile
165
+ fails the same way, with a dynamic or a static image axis. What runs is an ahead-of-time compile with
166
+ `--expect-frequent-reshapes`, loaded with `SpecializationOptions.default()`:
167
+
168
+ ```
169
+ xcrun coreai-build compile qi21t_dit_full_bf16_dyn_iofp32.aimodel \
170
+ --output aot/qi21t_dit_full_bf16_dyn_iofp32 \
171
+ --platform macOS --architecture h16c --preferred-compute gpu --expect-frequent-reshapes
172
+ # -> aot/qi21t_dit_full_bf16_dyn_iofp32/qi21t_dit_full_bf16_dyn_iofp32.h16c.aimodelc
173
+ ```
174
+
175
+ Do the same for the encoder and the VAE bundle you use; every gate of this port ran all three this
176
+ way, on an M4 Max with `--architecture h16c` (without `--architecture`, `coreai-build` compiles for
177
+ every supported architecture). On that Mac the bf16 DiT compiles in 107.6 s to 26.52 GiB, the int8 DiT
178
+ in 301 s to 20.30 GiB; the encoder's compiled copy is 14.10 GiB. With
179
+ `--preferred-compute neural-engine` the DiT compiles to 0 Neural Engine regions and runs on the GPU.
180
+ Whether a Swift host using `GraphModel(computeUnits: .gpu)` hits the same Neural Engine region has
181
+ not been tested.
host/rope_axis0_cos.f32 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2a67b7ed9fea4c3f775dea442cf921f6cfa25be5d7da2671a87a01b154af3b5b
3
+ size 294912
host/rope_axis0_sin.f32 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a6da418893c5551a329985da7efbeb20858736f3fb21077239405f9ffb5f578f
3
+ size 294912
host/rope_axis1_cos.f32 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8152a557c6febd21a2baeded29590c6b5bf18c439da5ddbe110c1273379c6ee3
3
+ size 1032192
host/rope_axis1_sin.f32 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a9e468de85274824afd0a30ecf8ca8bb53005ed0d606b656a65703e51c1b21cc
3
+ size 1032192
host/rope_axis2_cos.f32 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8152a557c6febd21a2baeded29590c6b5bf18c439da5ddbe110c1273379c6ee3
3
+ size 1032192
host/rope_axis2_sin.f32 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a9e468de85274824afd0a30ecf8ca8bb53005ed0d606b656a65703e51c1b21cc
3
+ size 1032192
host/scheduler.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "sample_sigmas": [
3
+ 1.0,
4
+ 0.978453,
5
+ 0.95418,
6
+ 0.926626,
7
+ 0.89508,
8
+ 0.845148,
9
+ 0.704534,
10
+ 0.414568
11
+ ],
12
+ "shift": 1.0,
13
+ "use_dynamic_shifting": false,
14
+ "shift_terminal": null,
15
+ "num_train_timesteps": 1000,
16
+ "steps": 8
17
+ }
qi21_encoder_dynL_w16a32_ids_iofp32.aimodel/main.hash ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ �KͫRrC�l��´�
2
+ xY��X��zp3�����c
qi21_encoder_dynL_w16a32_ids_iofp32.aimodel/main.mlirb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:17a14bcdab527243b56cc1ecc2b4b40a7859cec45892f97a7033f88fb38ba763
3
+ size 15137683256
qi21_encoder_dynL_w16a32_ids_iofp32.aimodel/metadata.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "creationDate" : "20260925T065421Z",
3
+ "assetVersion" : "2.0",
4
+ "description" : "Qwen-Image-2.1 text encoder (Qwen3-VL-8B text stack, all 36 layers), bf16 weights, fp32 compute, int32 input_ids -> fp32 hidden (last layer, before the final norm), dynamic L 16..512. Source: Qwen\/Qwen-Image-2.1@790c926.",
5
+ "license" : "qwen-research",
6
+ "producer" : "coreai-core 1.0.0b2",
7
+ "creatorDefinedMetadata" : {
8
+ "strip" : {
9
+ "what" : "the .aimodel re-saved after coreai-torch's strip_debug_info: every op's source location (file, line, call stack) replaced by an unknown location; the ops and the weights are not touched",
10
+ "from_main_mlirb" : {
11
+ "bytes" : 15138226830,
12
+ "sha256" : "d37b8e64763648cb6a32b23a2199b42d0ee93fac2c3899835d8e64d534563243"
13
+ },
14
+ "main_mlirb" : {
15
+ "bytes" : 15137683256,
16
+ "sha256" : "17a14bcdab527243b56cc1ecc2b4b40a7859cec45892f97a7033f88fb38ba763"
17
+ },
18
+ "tool" : "conversion\/qwenimage21\/strip_bundle.py",
19
+ "versions" : {
20
+ "coreai-torch" : "0.4.1",
21
+ "coreai-core" : "1.0.0b2"
22
+ }
23
+ }
24
+ }
25
+ }
qi21_vae_1024_fp32.aimodel/main.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ �á�����d��̡$����a9� X��4לP
qi21_vae_1024_fp32.aimodel/main.mlirb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b4c3a184f7ee16f3f764ade7cca124a9a9b0ad613915ea8a0b58ffdf34d79c50
3
+ size 1012370701
qi21_vae_1024_fp32.aimodel/metadata.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "description" : "Qwen-Image-2.1 VAE decoder, 1024x1024, fp32: latents_packed [1,4096,64] (sampler output, normalised) -> image [1,4,1024,1024] RGBA in [-1,1]; unpack and latents*std+mean inside the graph. Source: Qwen\/Qwen-Image-2.1@790c926.",
3
+ "assetVersion" : "2.0",
4
+ "license" : "qwen-research",
5
+ "creationDate" : "20260925T071221Z",
6
+ "producer" : "coreai-core 1.0.0b2",
7
+ "creatorDefinedMetadata" : {
8
+ "strip" : {
9
+ "what" : "the .aimodel re-saved after coreai-torch's strip_debug_info: every op's source location (file, line, call stack) replaced by an unknown location; the ops and the weights are not touched",
10
+ "from_main_mlirb" : {
11
+ "bytes" : 1012440351,
12
+ "sha256" : "d82fc436a51e36dea17272c64e8dd667df7dcd0c1d485bf225319303ed823944"
13
+ },
14
+ "main_mlirb" : {
15
+ "bytes" : 1012370701,
16
+ "sha256" : "b4c3a184f7ee16f3f764ade7cca124a9a9b0ad613915ea8a0b58ffdf34d79c50"
17
+ },
18
+ "tool" : "conversion\/qwenimage21\/strip_bundle.py",
19
+ "versions" : {
20
+ "coreai-torch" : "0.4.1",
21
+ "coreai-core" : "1.0.0b2"
22
+ }
23
+ }
24
+ }
25
+ }
qi21_vae_256_fp32.aimodel/main.hash ADDED
@@ -0,0 +1 @@
 
 
1
+
qi21_vae_256_fp32.aimodel/main.mlirb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0dfd5cd6b8402850f5fa6d7a91b624e8c76188ceaecaab40d49681bed465633f
3
+ size 1012364804
qi21_vae_256_fp32.aimodel/metadata.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "creationDate" : "20260925T071101Z",
3
+ "producer" : "coreai-core 1.0.0b2",
4
+ "assetVersion" : "2.0",
5
+ "license" : "qwen-research",
6
+ "description" : "Qwen-Image-2.1 VAE decoder, 256x256, fp32: latents_packed [1,256,64] (sampler output, normalised) -> image [1,4,256,256] RGBA in [-1,1]; unpack and latents*std+mean inside the graph. Source: Qwen\/Qwen-Image-2.1@790c926.",
7
+ "creatorDefinedMetadata" : {
8
+ "strip" : {
9
+ "what" : "the .aimodel re-saved after coreai-torch's strip_debug_info: every op's source location (file, line, call stack) replaced by an unknown location; the ops and the weights are not touched",
10
+ "from_main_mlirb" : {
11
+ "bytes" : 1012434454,
12
+ "sha256" : "82396266f39abd444e11fd6b17b20347eeb7c3b8d5262b5522f877b13f527762"
13
+ },
14
+ "main_mlirb" : {
15
+ "bytes" : 1012364804,
16
+ "sha256" : "0dfd5cd6b8402850f5fa6d7a91b624e8c76188ceaecaab40d49681bed465633f"
17
+ },
18
+ "tool" : "conversion\/qwenimage21\/strip_bundle.py",
19
+ "versions" : {
20
+ "coreai-torch" : "0.4.1",
21
+ "coreai-core" : "1.0.0b2"
22
+ }
23
+ }
24
+ }
25
+ }
qi21_vae_512_fp32.aimodel/main.hash ADDED
Binary file (32 Bytes). View file
 
qi21_vae_512_fp32.aimodel/main.mlirb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d578ba43cf8a5f62134e3cd46885006f385153d8c1b1f83f9f7ce0a35215626f
3
+ size 1012366781
qi21_vae_512_fp32.aimodel/metadata.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "description" : "Qwen-Image-2.1 VAE decoder, 512x512, fp32: latents_packed [1,1024,64] (sampler output, normalised) -> image [1,4,512,512] RGBA in [-1,1]; unpack and latents*std+mean inside the graph. Source: Qwen\/Qwen-Image-2.1@790c926.",
3
+ "assetVersion" : "2.0",
4
+ "license" : "qwen-research",
5
+ "creationDate" : "20260925T071145Z",
6
+ "producer" : "coreai-core 1.0.0b2",
7
+ "creatorDefinedMetadata" : {
8
+ "strip" : {
9
+ "what" : "the .aimodel re-saved after coreai-torch's strip_debug_info: every op's source location (file, line, call stack) replaced by an unknown location; the ops and the weights are not touched",
10
+ "from_main_mlirb" : {
11
+ "bytes" : 1012436431,
12
+ "sha256" : "cf8b1b14704963bc912866b81482a2ac24b1367796c6f60eeed17e95e9282e56"
13
+ },
14
+ "main_mlirb" : {
15
+ "bytes" : 1012366781,
16
+ "sha256" : "d578ba43cf8a5f62134e3cd46885006f385153d8c1b1f83f9f7ce0a35215626f"
17
+ },
18
+ "tool" : "conversion\/qwenimage21\/strip_bundle.py",
19
+ "versions" : {
20
+ "coreai-torch" : "0.4.1",
21
+ "coreai-core" : "1.0.0b2"
22
+ }
23
+ }
24
+ }
25
+ }
qi21t_dit_full_bf16_dyn_iofp32.aimodel/main.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ �i�7H'�Q�� ��ˋ)�����l�mG����
qi21t_dit_full_bf16_dyn_iofp32.aimodel/main.mlirb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9c69d137481c271ffd51fa99098187cb8b298d82fb88c56c15e66d47afc1caf8
3
+ size 14230567115
qi21t_dit_full_bf16_dyn_iofp32.aimodel/metadata.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "license" : "qwen-research",
3
+ "producer" : "coreai-core 1.0.0b2",
4
+ "creationDate" : "20261011T062903Z",
5
+ "description" : "Qwen-Image-2.1 DiT (full), bf16 weights+compute, fp32 I\/O, dynamic text\/image axes. Source: Qwen\/Qwen-Image-2.1-Turbo@d65dbc9.",
6
+ "assetVersion" : "2.0",
7
+ "creatorDefinedMetadata" : {
8
+ "strip" : {
9
+ "what" : "the .aimodel re-saved after coreai-torch's strip_debug_info: every op's source location (file, line, call stack) replaced by an unknown location; the ops and the weights are not touched",
10
+ "from_main_mlirb" : {
11
+ "bytes" : 14231004528,
12
+ "sha256" : "94804e70b71730201413aa962dda9092b8a2b158adeef191fa6322f4336aa9f9"
13
+ },
14
+ "main_mlirb" : {
15
+ "bytes" : 14230567115,
16
+ "sha256" : "9c69d137481c271ffd51fa99098187cb8b298d82fb88c56c15e66d47afc1caf8"
17
+ },
18
+ "tool" : "conversion\/qwenimage21\/strip_bundle.py",
19
+ "versions" : {
20
+ "coreai-torch" : "0.4.1",
21
+ "coreai-core" : "1.0.0b2"
22
+ }
23
+ }
24
+ }
25
+ }
qi21t_dit_full_int8lin_dyn_iofp32.aimodel/main.hash ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ Q.p>�<X��ڧ
2
+ f��H&2�p��:݌ܺ-�
qi21t_dit_full_int8lin_dyn_iofp32.aimodel/main.mlirb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:511d2e703e04b33c1358a9fddaa70a66e5cd482632c070b5c33add8cdcba2dc7
3
+ size 7560188326
qi21t_dit_full_int8lin_dyn_iofp32.aimodel/metadata.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "assetVersion" : "2.0",
3
+ "producer" : "coreai-core 1.0.0b2",
4
+ "creationDate" : "20261011T065052Z",
5
+ "license" : "qwen-research",
6
+ "description" : "Qwen-Image-2.1 DiT (full), int8 per-block-32 Linear weights (symmetric), bf16 compute, fp32 I\/O, dynamic text\/image axes. Source: Qwen\/Qwen-Image-2.1-Turbo@d65dbc9.",
7
+ "creatorDefinedMetadata" : {
8
+ "strip" : {
9
+ "what" : "the .aimodel re-saved after coreai-torch's strip_debug_info: every op's source location (file, line, call stack) replaced by an unknown location; the ops and the weights are not touched",
10
+ "from_main_mlirb" : {
11
+ "bytes" : 7560697655,
12
+ "sha256" : "3190edb18e6167499ae015b1660532846a1f4aa1d6de5cdbcf1dae5e6d2c752e"
13
+ },
14
+ "main_mlirb" : {
15
+ "bytes" : 7560188326,
16
+ "sha256" : "511d2e703e04b33c1358a9fddaa70a66e5cd482632c070b5c33add8cdcba2dc7"
17
+ },
18
+ "tool" : "conversion\/qwenimage21\/strip_bundle.py",
19
+ "versions" : {
20
+ "coreai-torch" : "0.4.1",
21
+ "coreai-core" : "1.0.0b2"
22
+ }
23
+ }
24
+ }
25
+ }
tokenizer/chat_template.jinja ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- if tools %}
2
+ {{- '<|im_start|>system\n' }}
3
+ {%- if messages[0].role == 'system' %}
4
+ {%- if messages[0].content is string %}
5
+ {{- messages[0].content }}
6
+ {%- else %}
7
+ {%- for content in messages[0].content %}
8
+ {%- if 'text' in content %}
9
+ {{- content.text }}
10
+ {%- endif %}
11
+ {%- endfor %}
12
+ {%- endif %}
13
+ {{- '\n\n' }}
14
+ {%- endif %}
15
+ {{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
16
+ {%- for tool in tools %}
17
+ {{- "\n" }}
18
+ {{- tool | tojson }}
19
+ {%- endfor %}
20
+ {{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
21
+ {%- else %}
22
+ {%- if messages[0].role == 'system' %}
23
+ {{- '<|im_start|>system\n' }}
24
+ {%- if messages[0].content is string %}
25
+ {{- messages[0].content }}
26
+ {%- else %}
27
+ {%- for content in messages[0].content %}
28
+ {%- if 'text' in content %}
29
+ {{- content.text }}
30
+ {%- endif %}
31
+ {%- endfor %}
32
+ {%- endif %}
33
+ {{- '<|im_end|>\n' }}
34
+ {%- endif %}
35
+ {%- endif %}
36
+ {%- set image_count = namespace(value=0) %}
37
+ {%- set video_count = namespace(value=0) %}
38
+ {%- for message in messages %}
39
+ {%- if message.role == "user" %}
40
+ {{- '<|im_start|>' + message.role + '\n' }}
41
+ {%- if message.content is string %}
42
+ {{- message.content }}
43
+ {%- else %}
44
+ {%- for content in message.content %}
45
+ {%- if content.type == 'image' or 'image' in content or 'image_url' in content %}
46
+ {%- set image_count.value = image_count.value + 1 %}
47
+ {%- if add_vision_id %}Picture {{ image_count.value }}: {% endif -%}
48
+ <|vision_start|><|image_pad|><|vision_end|>
49
+ {%- elif content.type == 'video' or 'video' in content %}
50
+ {%- set video_count.value = video_count.value + 1 %}
51
+ {%- if add_vision_id %}Video {{ video_count.value }}: {% endif -%}
52
+ <|vision_start|><|video_pad|><|vision_end|>
53
+ {%- elif 'text' in content %}
54
+ {{- content.text }}
55
+ {%- endif %}
56
+ {%- endfor %}
57
+ {%- endif %}
58
+ {{- '<|im_end|>\n' }}
59
+ {%- elif message.role == "assistant" %}
60
+ {{- '<|im_start|>' + message.role + '\n' }}
61
+ {%- if message.content is string %}
62
+ {{- message.content }}
63
+ {%- else %}
64
+ {%- for content_item in message.content %}
65
+ {%- if 'text' in content_item %}
66
+ {{- content_item.text }}
67
+ {%- endif %}
68
+ {%- endfor %}
69
+ {%- endif %}
70
+ {%- if message.tool_calls %}
71
+ {%- for tool_call in message.tool_calls %}
72
+ {%- if (loop.first and message.content) or (not loop.first) %}
73
+ {{- '\n' }}
74
+ {%- endif %}
75
+ {%- if tool_call.function %}
76
+ {%- set tool_call = tool_call.function %}
77
+ {%- endif %}
78
+ {{- '<tool_call>\n{"name": "' }}
79
+ {{- tool_call.name }}
80
+ {{- '", "arguments": ' }}
81
+ {%- if tool_call.arguments is string %}
82
+ {{- tool_call.arguments }}
83
+ {%- else %}
84
+ {{- tool_call.arguments | tojson }}
85
+ {%- endif %}
86
+ {{- '}\n</tool_call>' }}
87
+ {%- endfor %}
88
+ {%- endif %}
89
+ {{- '<|im_end|>\n' }}
90
+ {%- elif message.role == "tool" %}
91
+ {%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
92
+ {{- '<|im_start|>user' }}
93
+ {%- endif %}
94
+ {{- '\n<tool_response>\n' }}
95
+ {%- if message.content is string %}
96
+ {{- message.content }}
97
+ {%- else %}
98
+ {%- for content in message.content %}
99
+ {%- if content.type == 'image' or 'image' in content or 'image_url' in content %}
100
+ {%- set image_count.value = image_count.value + 1 %}
101
+ {%- if add_vision_id %}Picture {{ image_count.value }}: {% endif -%}
102
+ <|vision_start|><|image_pad|><|vision_end|>
103
+ {%- elif content.type == 'video' or 'video' in content %}
104
+ {%- set video_count.value = video_count.value + 1 %}
105
+ {%- if add_vision_id %}Video {{ video_count.value }}: {% endif -%}
106
+ <|vision_start|><|video_pad|><|vision_end|>
107
+ {%- elif 'text' in content %}
108
+ {{- content.text }}
109
+ {%- endif %}
110
+ {%- endfor %}
111
+ {%- endif %}
112
+ {{- '\n</tool_response>' }}
113
+ {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
114
+ {{- '<|im_end|>\n' }}
115
+ {%- endif %}
116
+ {%- endif %}
117
+ {%- endfor %}
118
+ {%- if add_generation_prompt %}
119
+ {{- '<|im_start|>assistant\n' }}
120
+ {%- endif %}
tokenizer/processor_config.json ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "image_processor": {
3
+ "data_format": "channels_first",
4
+ "do_convert_rgb": true,
5
+ "do_normalize": true,
6
+ "do_rescale": true,
7
+ "do_resize": true,
8
+ "image_mean": [
9
+ 0.5,
10
+ 0.5,
11
+ 0.5
12
+ ],
13
+ "image_processor_type": "Qwen2VLImageProcessorFast",
14
+ "image_std": [
15
+ 0.5,
16
+ 0.5,
17
+ 0.5
18
+ ],
19
+ "merge_size": 2,
20
+ "patch_size": 16,
21
+ "resample": 3,
22
+ "rescale_factor": 0.00392156862745098,
23
+ "size": {
24
+ "longest_edge": 16777216,
25
+ "shortest_edge": 65536
26
+ },
27
+ "temporal_patch_size": 2
28
+ },
29
+ "processor_class": "Qwen3VLProcessor",
30
+ "video_processor": {
31
+ "data_format": "channels_first",
32
+ "default_to_square": true,
33
+ "do_convert_rgb": true,
34
+ "do_normalize": true,
35
+ "do_rescale": true,
36
+ "do_resize": true,
37
+ "do_sample_frames": true,
38
+ "fps": 2,
39
+ "image_mean": [
40
+ 0.5,
41
+ 0.5,
42
+ 0.5
43
+ ],
44
+ "image_std": [
45
+ 0.5,
46
+ 0.5,
47
+ 0.5
48
+ ],
49
+ "max_frames": 768,
50
+ "merge_size": 2,
51
+ "min_frames": 4,
52
+ "patch_size": 16,
53
+ "resample": 3,
54
+ "rescale_factor": 0.00392156862745098,
55
+ "return_metadata": false,
56
+ "size": {
57
+ "longest_edge": 25165824,
58
+ "shortest_edge": 4096
59
+ },
60
+ "temporal_patch_size": 2,
61
+ "video_processor_type": "Qwen3VLVideoProcessor"
62
+ }
63
+ }
tokenizer/tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be75606093db2094d7cd20f3c2f385c212750648bd6ea4fb2bf507a6a4c55506
3
+ size 11422650
tokenizer/tokenizer_config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "backend": "tokenizers",
4
+ "bos_token": null,
5
+ "clean_up_tokenization_spaces": false,
6
+ "eos_token": "<|im_end|>",
7
+ "errors": "replace",
8
+ "extra_special_tokens": [
9
+ "<|im_start|>",
10
+ "<|im_end|>",
11
+ "<|object_ref_start|>",
12
+ "<|object_ref_end|>",
13
+ "<|box_start|>",
14
+ "<|box_end|>",
15
+ "<|quad_start|>",
16
+ "<|quad_end|>",
17
+ "<|vision_start|>",
18
+ "<|vision_end|>",
19
+ "<|vision_pad|>",
20
+ "<|image_pad|>",
21
+ "<|video_pad|>"
22
+ ],
23
+ "is_local": true,
24
+ "model_max_length": 262144,
25
+ "pad_token": "<|endoftext|>",
26
+ "processor_class": "Qwen3VLProcessor",
27
+ "split_special_tokens": false,
28
+ "tokenizer_class": "Qwen2Tokenizer",
29
+ "unk_token": null
30
+ }