prometheusAIR commited on
Commit
e07ec8d
·
verified ·
1 Parent(s): 552b356

Upload folder using huggingface_hub

Browse files
Files changed (50) hide show
  1. .gitattributes +5 -0
  2. BIAS.md +11 -0
  3. EXPLAINABILITY.md +16 -0
  4. LICENSE +49 -0
  5. PRIVACY.md +6 -0
  6. README.md +187 -0
  7. SAFETY.md +11 -0
  8. assets/example_first_frame.png +3 -0
  9. assets/example_output.mp4 +3 -0
  10. assets/example_prompt.json +1 -0
  11. assets/original_prompt.txt +1 -0
  12. chat_template.json +3 -0
  13. checkpoint.json +5 -0
  14. config.json +252 -0
  15. generation_config.json +14 -0
  16. images/aa-i2v-all-models-2026-07-17.png +3 -0
  17. images/aa-i2v-open-models-2026-07-17.png +3 -0
  18. load_cosmos3_modelopt.py +256 -0
  19. merges.txt +0 -0
  20. model.safetensors.index.json +0 -0
  21. model_index.json +28 -0
  22. modular_model_index.json +64 -0
  23. preprocessor_config.json +21 -0
  24. quantize_cosmos3_i2v4step_streaming.py +383 -0
  25. repackage_for_hf_i2v4step.py +97 -0
  26. scheduler/scheduler_config.json +28 -0
  27. scripts/gen_video.py +76 -0
  28. scripts/upsample_prompt.py +168 -0
  29. serve_cosmos3_i2v4step_diffusers.py +449 -0
  30. text_tokenizer/added_tokens.json +28 -0
  31. text_tokenizer/chat_template.jinja +120 -0
  32. text_tokenizer/merges.txt +0 -0
  33. text_tokenizer/special_tokens_map.json +31 -0
  34. text_tokenizer/tokenizer.json +3 -0
  35. text_tokenizer/tokenizer_config.json +239 -0
  36. text_tokenizer/vocab.json +0 -0
  37. tokenizer.json +0 -0
  38. tokenizer_config.json +239 -0
  39. transformer/config.json +43 -0
  40. transformer/diffusion_pytorch_model-00001-of-00004.safetensors +3 -0
  41. transformer/diffusion_pytorch_model-00002-of-00004.safetensors +3 -0
  42. transformer/diffusion_pytorch_model-00003-of-00004.safetensors +3 -0
  43. transformer/diffusion_pytorch_model-00004-of-00004.safetensors +3 -0
  44. transformer/diffusion_pytorch_model.safetensors.index.json +0 -0
  45. transformer/modelopt_state.pth +3 -0
  46. vae/config.json +129 -0
  47. vae/diffusion_pytorch_model.safetensors +3 -0
  48. validate_cosmos3_i2v4step_fp8.py +77 -0
  49. video_preprocessor_config.json +21 -0
  50. vocab.json +0 -0
.gitattributes CHANGED
@@ -33,3 +33,8 @@ 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
+ text_tokenizer/tokenizer.json filter=lfs diff=lfs merge=lfs -text
37
+ assets/example_first_frame.png filter=lfs diff=lfs merge=lfs -text
38
+ assets/example_output.mp4 filter=lfs diff=lfs merge=lfs -text
39
+ images/aa-i2v-all-models-2026-07-17.png filter=lfs diff=lfs merge=lfs -text
40
+ images/aa-i2v-open-models-2026-07-17.png filter=lfs diff=lfs merge=lfs -text
BIAS.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Bias
2
+
3
+ | Field | Response |
4
+ | :---- | :---- |
5
+ | Participation considerations from adversely impacted groups [protected classes](https://www.senate.ca.gov/content/protected-classes) in model design and testing | None. |
6
+ | Measures taken to mitigate against unwanted bias | Training, evaluation, and testing data are curated before release to filter restricted content, including content relating to protected classes. Model behavior is evaluated across Physical AI domains — robotics, autonomous vehicles, human-centric scenes, common scenes, industry, miscellaneous, and physics-oriented benchmarks — with attention to coverage across diverse demographic and contextual characteristics that affect protected-class outcomes. |
7
+ | Which characteristic (feature) show(s) the greatest difference in performance?: | Greatest performance differences are observed in tasks requiring long-horizon temporal consistency, fine-grained physical interactions, and embodiment-specific action generation. Performance is generally stronger on common visual reasoning and world-generation tasks than on complex multi-agent, robotics-control, or tightly synchronized multimodal generation scenarios. |
8
+ | Which feature(s) have the worst performance overall? | Performance is generally weakest in tasks requiring long-horizon temporal consistency, precise physical interactions, embodiment-specific action control, and strict audio-visual synchronization. |
9
+ | If using internal data, description of methods implemented in data acquisition or processing, if any, to address the prevalence of identifiable biases in the training, testing, and validation data: | Bias-specific methods applied during data processing include person-presence screening, demographic-taxonomy classification (age, gender, ethnicity), embedding-based diversity analysis, and dataset balancing across sources. Internal analysis surfaced: non-person scenes are more prevalent than person-centric content; demographic-taxonomy outputs on person-present samples are most frequently "uncertain" across age, gender, and ethnicity dimensions; and source-type variation, with people-centric image and video datasets showing higher demographic signal than document-, object-, robotics-, or scene-focused datasets. *(Quantitative details in the row below.)* Downstream deployments should add bias audits, fairness evaluation, red-teaming, demographically balanced fine-tuning, or counterfactual augmentation as mitigations. |
10
+ | Tools used to assess statistical imbalances and highlight patterns that may introduce bias into AI models: | Dataset analytics pipelines, metadata distribution analysis, heuristic quality checks, embedding-based clustering, model-assisted filtering systems, and benchmark evaluation suites are used to assess statistical imbalances and identify patterns that may introduce bias into model behavior. |
11
+ | Tools used to assess statistical imbalances and highlight patterns that may introduce bias into AI models: | These datasets, such as OpenImages-derived detection-to-NLP datasets, visual grounding and VQA datasets, document/image understanding datasets, video/action understanding datasets, and NVIDIA-created or curated visual datasets, do not collectively or exhaustively represent all demographic groups (and proportionally therein). For instance, automated person-presence screening did not identify a person in approximately 58% of visual samples analyzed across approximately 400 datasets, while person-present signals were identified in approximately 42% of analyzed samples. In the subset where person-present signals were identified, these datasets contain uneven representation splits across the measured visual taxonomies: age outputs were most frequently uncertain, followed by child and adult; gender outputs were most frequently uncertain, followed by male and female; and ethnicity outputs were most frequently uncertain, followed by Hispanic and White as the most frequent identified categories. Dataset-level results vary by source type, with people-centric image and video datasets containing higher person-present and demographic-taxonomy signals than document-, object-, robotics-, or scene-focused datasets. To mitigate these imbalances, we recommend considering evaluation techniques such as bias audits, task-specific fairness evaluation, and red-teaming, along with fine-tuning with demographically balanced datasets and counterfactual data augmentation to align with the desired model behavior. This evaluation used a baseline of 200 samples across all datasets, with larger subsets of up to 3,000 samples utilized for certain in-depth analyses, identified as optimal thresholds for maximizing embedder accuracy. |
EXPLAINABILITY.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Explainability
2
+
3
+ | Field | Response |
4
+ | :---- | :---- |
5
+ | Intended Application & Domain | World reasoning and generation for Physical AI. |
6
+ | Model Type | Mixture-of-Transformers architecture with two towers. One is an autoregressive model for Physical AI reasoning; the other is a diffusion model for Physical AI generation. |
7
+ | Intended Users | Physical AI developers, researchers, and practitioners building or evaluating autonomous vehicle, robotics, and world-generation workflows. |
8
+ | Output | Images, videos, audio, and action commands. |
9
+ | Tools used to evaluate datasets to identify synthetic data and ensure data authenticity. | Dataset provenance analysis, metadata validation, watermark and artifact detection, embedding-based clustering, heuristic quality checks, and model-assisted data validation pipelines are used to identify synthetic content patterns, assess dataset authenticity, and improve data quality during dataset curation. |
10
+ | Describe how the model works | Cosmos3 is an Omni world foundation model that generates texts, images, videos, audio, and action commands from combinations of text, images, videos, and action trajectory inputs. Input tokens from multiple modalities are packed into a shared sequence and processed by our mixture-of-transformer backbone with modality-specific output heads. |
11
+ | Name the adversely impacted groups this has been tested to deliver comparable outcomes regardless of: | None. |
12
+ | Technical Limitations | The model may not follow text, image, video, audio, or action trajectory inputs accurately in challenging cases, especially where the input contains complex scene composition, unusual camera motion, multiple interacting agents, low lighting, high motion blur, or fine-grained physical interactions. Generated outputs may contain temporal inconsistency, object morphing, inaccurate 3D structure, or implausible physical dynamics. Generated audio may not accurately render intelligible speech, or maintain strict temporal and semantic alignment with the visual context. |
13
+ | Verified to have met prescribed NVIDIA quality standards | Yes. |
14
+ | Performance Metrics | Video generation is measured using PAIBench-G, RBench, PhysicsIQ, and Artifical Analysis Image2Video benchmark. Image generation uses UniGenBench and Artifical Analysis Text2Image benchmark. For transfer evaluation, we use PAIBench-C and AVBench-C. Audio generation uses internal benchmarks. Action prediction uses metrics such as action MSE, Absolute Translation Error, Relative Translation Error, Relative Rotation Error, PSNR, and robotic task completion success rate. |
15
+ | Potential Known Risks | This model can generate synthetic media and may produce content that is offensive, unsafe, misleading, indecent, or unsuitable for a target deployment. Users should implement robust safety guardrails — including content filtering, abuse monitoring, and access controls — to reduce the risk of harmful outputs. Users are responsible for ensuring that their use of the model complies with all applicable laws and regulations, and for regularly reviewing and updating their guardrails as risks evolve. |
16
+ | Licensing | [OpenMDW1.1](https://openmdw.ai/) |
LICENSE ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ OpenMDW License Agreement, version 1.1 (OpenMDW-1.1)
2
+
3
+ By exercising rights granted to you under this agreement, you accept and agree
4
+ to its terms.
5
+
6
+ As used in this agreement, "Model Materials" means the materials provided to
7
+ you under this agreement, consisting of: (1) one or more machine learning
8
+ models (including architecture and parameters); and (2) all related artifacts
9
+ (including associated data, documentation and software) that are provided to
10
+ you hereunder.
11
+
12
+ Subject to your compliance with this agreement, permission is hereby granted,
13
+ free of charge, to deal in the Model Materials without restriction, including
14
+ under all copyright, patent, database, and trade secret rights included or
15
+ embodied therein.
16
+
17
+ If you distribute any portion of the Model Materials, you shall retain in your
18
+ distribution (1) a copy of this agreement, and (2) all copyright notices and
19
+ other notices of origin included in the Model Materials that are applicable to
20
+ your distribution.
21
+
22
+ If you file, maintain, or voluntarily participate in a lawsuit against any
23
+ person or entity asserting that the Model Materials directly or indirectly
24
+ infringe any patent or copyright, then all rights and grants made to you
25
+ hereunder are terminated, unless that lawsuit was in response to a
26
+ corresponding lawsuit first brought against you.
27
+
28
+ This agreement does not impose any restrictions or obligations with respect to
29
+ any use, modification, or sharing of any outputs generated by using the Model
30
+ Materials.
31
+
32
+ THE MODEL MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
33
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34
+ FITNESS FOR A PARTICULAR PURPOSE, TITLE, NONINFRINGEMENT, ACCURACY, OR THE
35
+ ABSENCE OF LATENT OR OTHER DEFECTS OR ERRORS, WHETHER OR NOT DISCOVERABLE, ALL
36
+ TO THE GREATEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW.
37
+
38
+ YOU ARE SOLELY RESPONSIBLE FOR (1) CLEARING RIGHTS OF OTHER PERSONS THAT MAY
39
+ APPLY TO THE MODEL MATERIALS OR ANY USE THEREOF, INCLUDING WITHOUT LIMITATION
40
+ ANY PERSON'S COPYRIGHTS OR OTHER RIGHTS INCLUDED OR EMBODIED IN THE MODEL
41
+ MATERIALS; (2) OBTAINING ANY NECESSARY CONSENTS, PERMISSIONS OR OTHER RIGHTS
42
+ REQUIRED FOR ANY USE OF THE MODEL MATERIALS; OR (3) PERFORMING ANY DUE
43
+ DILIGENCE OR UNDERTAKING ANY OTHER INVESTIGATIONS INTO THE MODEL MATERIALS OR
44
+ ANYTHING INCORPORATED OR EMBODIED THEREIN.
45
+
46
+ IN NO EVENT SHALL THE PROVIDERS OF THE MODEL MATERIALS BE LIABLE FOR ANY CLAIM,
47
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
48
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MODEL MATERIALS, THE
49
+ USE THEREOF OR OTHER DEALINGS THEREIN.
PRIVACY.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ ## Privacy
2
+ | Privacy Information |
3
+ |---|
4
+ | The model was trained on large-scale publicly available data that may contain images, audio-video, and text relating to people. NVIDIA collected and used this data in compliance with applicable data protection and privacy laws. This model was not designed to derive insights or otherwise learn from any personal data contained in the datasets. |
5
+ | NVIDIA uses a combination of filters, data minimization techniques, and other guardrails to help prevent personal data from being recited by our models. We employ automated tools and data processing techniques during pre-training or training to identify and filter certain categories of personal data. For example, for text-bearing source and document components, our automated tools identified potential personal data such as person names, locations, and possible business or public-facing contact information such as email addresses and phone numbers. We reviewed and removed any verified instances of personal data through a combination of automated filtering and human-in-the-loop validation. |
6
+ | Please review NVIDIA's [Privacy Policy](https://www.nvidia.com/en-us/about-nvidia/privacy-policy/) for more information. |
README.md ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: other
3
+ license_name: openmdw1.1-license
4
+ license_link: >-
5
+ https://openmdw.ai/license/1-1/
6
+ library_name: cosmos
7
+ tags:
8
+ - nvidia
9
+ - cosmos
10
+ - cosmos3
11
+ - image-to-video
12
+ - video-generation
13
+ - nvfp4
14
+ - quantized
15
+ - modelopt
16
+ ---
17
+
18
+ # Cosmos3-Super-Image2Video-4Step — NVFP4 (community quantization)
19
+
20
+ This is a community **NVFP4, weight-only** quantization of NVIDIA's
21
+ [`nvidia/Cosmos3-Super-Image2Video-4Step`](https://huggingface.co/nvidia/Cosmos3-Super-Image2Video-4Step) —
22
+ a 64B-parameter image-to-video model, DMD2-distilled for 4-step, CFG-free
23
+ generation — produced with [NVIDIA TensorRT Model Optimizer](https://github.com/NVIDIA/TensorRT-Model-Optimizer)
24
+ (`nvidia-modelopt`). A sibling of
25
+ [prometheusAIR/Cosmos3-Super-Image2Video-4Step-FP8](https://huggingface.co/prometheusAIR/Cosmos3-Super-Image2Video-4Step-FP8) —
26
+ this format trades a bit more quantization error for a much smaller footprint:
27
+ **~38GB resident vs FP8's ~66GB**, useful if you want headroom for longer clips,
28
+ higher resolutions, or running alongside other GPU workloads on the same card.
29
+
30
+ **Model Developer (original model): NVIDIA.** This is not an official NVIDIA
31
+ release. Everything about the model itself — architecture, training data,
32
+ benchmarks, full input/output specs, limitations, and ethical considerations —
33
+ is unchanged from NVIDIA's original and is documented on
34
+ [their model card](https://huggingface.co/nvidia/Cosmos3-Super-Image2Video-4Step);
35
+ it isn't reproduced here. This card only covers what we changed (the
36
+ quantization) and how to run *this* checkpoint.
37
+
38
+ ## License
39
+
40
+ Released under the [OpenMDW-1.1](https://openmdw.ai/license/1-1/) license, same
41
+ as the original model — see [`LICENSE`](LICENSE) in this repo.
42
+
43
+ ## Quantization Notes
44
+
45
+ **Recipe:** NVFP4 (E2M1 4-bit weights, block_size 16, FP8/E4M3 block scales +
46
+ an FP32 per-tensor scale) on the 64 transformer blocks' attention/MLP linears.
47
+ Activations, embeddings, norms, the bundled Qwen3 reasoner head,
48
+ `time_embedder`, and `proj_in`/`proj_out` are left in BF16. Weight-only, so no
49
+ calibration forward pass was needed — same recipe and same spared layers as
50
+ the FP8 sibling, just a smaller weight format. Per NVIDIA's own note, no
51
+ quantized precision is officially tested/supported for this model — treat
52
+ this as best-effort, and expect somewhat more quantization error than the
53
+ FP8 release given the lower bit-width.
54
+
55
+ **Loading gotchas — read before using with `diffusers`:** as of
56
+ `diffusers==0.39.0.dev0`, plain `Cosmos3OmniPipeline` usage has **two** bugs
57
+ against this checkpoint (identical to the FP8 release — same base checkpoint,
58
+ same diffusers version, unrelated to which quantization format you use). Both
59
+ are fixed automatically by the serving script below
60
+ (`serve_cosmos3_i2v4step_diffusers.py`); if you're writing your own loading
61
+ code, patch the scheduler yourself as shown.
62
+
63
+ 1. **Wrong step count / CFG on.** `Cosmos3OmniPipeline.__call__` does not read
64
+ this checkpoint's `scheduler/scheduler_config.json` →
65
+ `fixed_step_sampler_config.t_list` (the trained 4-step sde schedule). It
66
+ silently falls back to the pipeline's generic defaults
67
+ (`num_inference_steps=35`, `guidance_scale=6.0`), which is off-distribution
68
+ for a DMD2-distilled 4-step checkpoint. (`vLLM-Omni` parses this file
69
+ correctly; this gap is specific to the plain `diffusers` PyTorch path.)
70
+
71
+ 2. **Image conditioning gets destroyed into colorful static (critical).** This
72
+ checkpoint's scheduler ships `stochastic_sampling=True` (SDE sampling).
73
+ Cosmos3 anchors the conditioning frame by zeroing the model's predicted
74
+ velocity there — under a *deterministic* step that means "leave this frame
75
+ unchanged," but `FlowMatchEulerDiscreteScheduler`'s SDE branch computes
76
+ `x0 = sample - current_sigma * model_output` (= `sample`, since velocity is
77
+ 0) then `prev_sample = (1 - next_sigma) * x0 + next_sigma * randn_tensor(...)`
78
+ — it re-noises by `next_sigma` **regardless of velocity**. Across this
79
+ checkpoint's 4 steps that compounds to ~99.6% fresh noise in the
80
+ conditioned frame: your input image comes out as colorful static while the
81
+ genuinely-denoised motion frames still look like plausible video (this
82
+ combination — garbage first frame, coherent-but-drifted rest — is exactly
83
+ how it presents). Disabling `stochastic_sampling` restores the correct
84
+ zero-velocity-is-a-no-op behavior. Confirmed by direct A/B render, same
85
+ seed/image/prompt, only this flag changed.
86
+
87
+ ```python
88
+ def force_fixed_step_schedule(scheduler):
89
+ t_list = scheduler.config.fixed_step_sampler_config["t_list"]
90
+ orig = scheduler.set_timesteps
91
+ scheduler.set_timesteps = lambda num_inference_steps=None, device=None, **_: (
92
+ orig(sigmas=list(t_list), device=device)
93
+ )
94
+ if scheduler.config.stochastic_sampling:
95
+ scheduler.register_to_config(stochastic_sampling=False)
96
+
97
+ pipe = ... # Cosmos3OmniPipeline.from_pretrained(...)
98
+ force_fixed_step_schedule(pipe.scheduler)
99
+
100
+ result = pipe(prompt=..., image=..., guidance_scale=1.0, num_inference_steps=4, ...)
101
+ # guidance_scale=1.0 disables CFG; num_inference_steps is a no-op once patched
102
+ ```
103
+
104
+ Verified against this exact repo: the patch produces a 4-iteration denoising
105
+ loop (not 35) with CFG off and a correctly-preserved conditioning frame
106
+ (not colorful static), matching the checkpoint's trained regime. The
107
+ save/restore round trip (`transformer/modelopt_state.pth`) reloads correctly
108
+ with 896 quantized weight wrappers active.
109
+
110
+ ## Usage: Run Inference (single GPU, `diffusers`)
111
+
112
+ This repo is a `diffusers`-loadable repackage (`transformer/modelopt_state.pth`),
113
+ not NVIDIA's `vLLM-Omni` deployment export format. If you have a vLLM-Omni
114
+ cluster, use NVIDIA's original BF16 checkpoint and card instead. For everyone
115
+ else — anyone running this NVFP4 checkpoint on a single GPU — use the FastAPI
116
+ server included in this repo, which loads the checkpoint, applies the 4-step
117
+ scheduler fix above automatically, and exposes a plain HTTP endpoint.
118
+
119
+ ### 1. Install
120
+
121
+ Requires a `diffusers` build with Cosmos3 support — not yet in a PyPI release
122
+ as of this writing, so install from the exact commit this checkpoint was
123
+ produced and validated against:
124
+
125
+ ```bash
126
+ pip install "git+https://github.com/huggingface/diffusers.git@2c7efb95349296cf6bcce981ea036275a82a94df"
127
+ pip install nvidia-modelopt accelerate torch fastapi uvicorn python-multipart
128
+ ```
129
+
130
+ ### 2. Download this repo (weights + scripts together)
131
+
132
+ ```bash
133
+ hf download prometheusAIR/Cosmos3-Super-Image2Video-4Step-NVFP4 \
134
+ --local-dir Cosmos3-Super-Image2Video-4Step-NVFP4
135
+ cd Cosmos3-Super-Image2Video-4Step-NVFP4
136
+ ```
137
+
138
+ This pulls the whole ~39GB repo — NVFP4 weights, VAE, tokenizer, and the `.py`
139
+ scripts side by side, the same download either way.
140
+
141
+ ### 3. Serve it
142
+
143
+ ```bash
144
+ CUDA_VISIBLE_DEVICES=0 python serve_cosmos3_i2v4step_diffusers.py --repo .
145
+ ```
146
+
147
+ One GPU with roughly 45GB+ free memory is enough — noticeably less than the
148
+ FP8 release (~70GB+), so this fits single 48GB-class cards (RTX 6000 Ada,
149
+ A6000, L40S) in addition to the larger ones (RTX PRO 6000, H100/H200,
150
+ A100-80GB). No multi-GPU sharding required. The server listens on
151
+ `http://localhost:8000` once it's done loading.
152
+
153
+ ### 4. Use it
154
+
155
+ ```bash
156
+ curl -s -X POST http://localhost:8000/animate \
157
+ -F image=@your_first_frame.png \
158
+ -F 'prompt=The robotic arm slowly lowers its gripper toward the objects and holds. Static camera.' \
159
+ -F num_frames=49 -F fps=24 \
160
+ --output clip.mp4
161
+ ```
162
+
163
+ `num_frames` / `fps` / `height` / `width` are adjustable. `num_inference_steps`
164
+ and `guidance_scale` are intentionally not exposed — this checkpoint's 4-step,
165
+ CFG-free schedule is fixed and applied automatically by the server.
166
+
167
+ ### Other scripts in this repo
168
+
169
+ - `quantize_cosmos3_i2v4step_streaming.py` — reproduces this NVFP4 quantization
170
+ (`--format nvfp4`) from NVIDIA's BF16 source checkpoint; also supports
171
+ `--format fp8` for the sibling release.
172
+ - `repackage_for_hf_i2v4step.py` — rebuilds this diffusers-loadable repo format
173
+ from a quantized transformer.
174
+ - `load_cosmos3_modelopt.py` — the underlying loader `serve_cosmos3_i2v4step_diffusers.py`
175
+ uses; import `load_pipe(...)` directly if you want a `pipe` object instead of
176
+ an HTTP server.
177
+ - `validate_cosmos3_i2v4step_fp8.py` — a minimal standalone image→video smoke
178
+ test; despite the filename (kept for consistency with the FP8 repo) it
179
+ takes `--format nvfp4|fp8` and works against either checkpoint.
180
+
181
+ ## Responsible Use
182
+
183
+ See NVIDIA's [Bias](BIAS.md), [Explainability](EXPLAINABILITY.md),
184
+ [Safety & Security](SAFETY.md), and [Privacy](PRIVACY.md) subcards (included
185
+ in this repo), and the Limitations / Ethical Considerations sections of
186
+ [NVIDIA's original model card](https://huggingface.co/nvidia/Cosmos3-Super-Image2Video-4Step).
187
+ Report security vulnerabilities [here](https://www.nvidia.com/en-us/support/submit-security-vulnerability/).
SAFETY.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Safety & Security
2
+
3
+ | Field | Response |
4
+ | :---- | :---- |
5
+ | Model Application(s) | World reasoning and generation for Physical AI. |
6
+ | Describe the life critical impact: | This model is not a safety-certified component and must not be used as the sole basis for life-critical decisions or control without additional system-level validation, safety analysis, and safeguards. The model is not designed or tested by NVIDIA for use in any system or application where the use of or failure of such system or application developed with the model could result in injury, death, or catastrophic damage. NVIDIA is not liable to any party, in whole or in part, for any claims or damages arising from those uses. Any system or application developed with the model must include sufficient safety and redundancy features and comply with applicable legal and regulatory standards and requirements. |
7
+ | Description of methods implemented in data acquisition or processing, if any, to address other types of potentially harmful data in the training, testing, and validation data: | Training, evaluation, and validation datasets pass through multi-stage automated and manual filtering to reduce harmful, unsafe, restricted, or policy-violating content. Pipelines include source-licensing review, deduplication, metadata-based and classifier-based moderation, embedding-based anomaly detection, and human audits on selected datasets. For Physical AI data (robotics, autonomous driving, industrial scenes), filtering also targets invalid action trajectories, physically implausible interactions, and unsafe control sequences. Synthetic and simulation-generated data are evaluated through internal validation before inclusion. Benchmark and red-team testing surface remaining safety gaps across world generation, reasoning, audio, and action tasks. No data-filtering process can guarantee complete removal; developers are responsible for application-specific safeguards and validation before deployment. |
8
+ | Description of any methods implemented in data acquisition or processing, if any, to address illegal or harmful content in the training data, including, but not limited to, child sexual abuse material (CSAM) and non-consensual intimate imagery (NCII) | In addition to the general unsafe-content filtering described above, training data acquisition and preprocessing apply CSAM- and NCII-specific safeguards: hash-matching systems against known CSAM databases, classifier-based moderation models trained specifically for explicit content and NCII detection, and provenance and licensing review for sources containing human imagery. Identified content is removed at ingest, with human review and targeted audits supplementing automated filtering for selected datasets. Despite these safeguards, no large-scale data-filtering system can guarantee complete detection. Ongoing monitoring and dataset review continue post-release. |
9
+ | Use Case Restrictions | Use is governed by the [OpenMDW1.1](https://openmdw.ai/) |
10
+ | Model and dataset restrictions | The Principle of least privilege (PoLP) is applied limiting access for dataset generation and model development. Restrictions enforce dataset access during training, and dataset license constraints adhered to. |
11
+ | Responsible Data Handling | This AI model was developed based on our policies to ensure responsible data handling and risk mitigation. The datasets used for training have been scanned for harmful content and illegal content, consistent with our policies including scanning for Child Sexual Abuse Material (CSAM). Ongoing review and monitoring mechanisms are in place based on our policies and to maintain data integrity. |
assets/example_first_frame.png ADDED

Git LFS Details

  • SHA256: 677259954dfc05b6dd62fbc1d8c4064544e247f86d0df458214e6e8097341988
  • Pointer size: 132 Bytes
  • Size of remote file: 1.96 MB
assets/example_output.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:625d490237c02ed103797bc42b6c2aff9b219779b0de29226df7878c671ec907
3
+ size 8589231
assets/example_prompt.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"prompt": "{\"temporal_caption\": \"A fallen waffle cone lies on rough sunlit asphalt in an extreme low close-up, with a rounded scoop of vanilla and chocolate ice cream pressed against the road, a small melted puddle already spreading beneath it, and dry autumn leaves scattered around in warm late-afternoon light. The viewpoint stays near ground level and begins a slow, smooth arc around the cone from left to right, keeping the melting scoop dominant while the background street and leaves remain softly blurred. As the sun warms the ice cream, the glossy edges soften first, thin rivulets of vanilla and chocolate slide down the curved scoop, and the existing puddle widens into the cracks and pebbled texture of the asphalt. The waffle cone remains mostly rigid but grows slightly damp at the rim touching the ice cream, while the scoop loses its rounded shape, slumps lower, and exposes more of the cone’s open mouth. The moving viewpoint continues its gentle orbit, revealing the chocolate side thinning into streaks and the vanilla side collapsing into pale liquid that creeps outward under gravity. By the end, most of the ice cream has flattened into a shallow glossy stain that drains into small road fissures and spreads out of the immediate area, leaving the cone lying in place with only thin cream-colored and brown traces clinging to the asphalt in the warm light.\", \"duration\": \"7s\", \"fps\": 24.0, \"resolution\": {\"H\": 480, \"W\": 832}, \"aspect_ratio\": \"16,9\"}", "negative_prompt": "The video captures a series of frames showing macroblocking artifacts, chromatic aberration, high-frequency noise, and rolling shutter distortion. It includes static with no motion, motion blur, over-saturation, shaky footage, low resolution, grainy texture, pixelated images, poorly lit areas, underexposed and overexposed scenes, poor color balance, washed out colors, choppy sequences, jerky movements, low frame rate, bit-depth compression artifacts, color banding, unnatural transitions, outdated special effects, fake elements, unconvincing visuals, poorly edited content, jump cuts, hard cut, visual noise, and flickering. It features moiré patterns, edge halos, and temporal aliasing. Furthermore, the content defies common sense, generating illogical scenarios, nonsensical entities, absurd character behaviors, and conceptual paradoxes that violate basic human reasoning and everyday reality. The video looks like a surreal or glitchy hallucination. Overall, the video is of poor quality."}
assets/original_prompt.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ The ice cream melts and gradually disappears. The camera moves around.
chat_template.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "chat_template": "{%- if tools %}\n {{- '<|im_start|>system\\n' }}\n {%- if messages[0].role == 'system' %}\n {%- if messages[0].content is string %}\n {{- messages[0].content }}\n {%- else %}\n {%- for content in messages[0].content %}\n {%- if 'text' in content %}\n {{- content.text }}\n {%- endif %}\n {%- endfor %}\n {%- endif %}\n {{- '\\n\\n' }}\n {%- endif %}\n {{- \"# 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>\" }}\n {%- for tool in tools %}\n {{- \"\\n\" }}\n {{- tool | tojson }}\n {%- endfor %}\n {{- \"\\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\" }}\n{%- else %}\n {%- if messages[0].role == 'system' %}\n {{- '<|im_start|>system\\n' }}\n {%- if messages[0].content is string %}\n {{- messages[0].content }}\n {%- else %}\n {%- for content in messages[0].content %}\n {%- if 'text' in content %}\n {{- content.text }}\n {%- endif %}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n{%- endif %}\n{%- set image_count = namespace(value=0) %}\n{%- set video_count = namespace(value=0) %}\n{%- for message in messages %}\n {%- if message.role == \"user\" %}\n {{- '<|im_start|>' + message.role + '\\n' }}\n {%- if message.content is string %}\n {{- message.content }}\n {%- else %}\n {%- for content in message.content %}\n {%- if content.type == 'image' or 'image' in content or 'image_url' in content %}\n {%- set image_count.value = image_count.value + 1 %}\n {%- if add_vision_id %}Picture {{ image_count.value }}: {% endif -%}\n <|vision_start|><|image_pad|><|vision_end|>\n {%- elif content.type == 'video' or 'video' in content %}\n {%- set video_count.value = video_count.value + 1 %}\n {%- if add_vision_id %}Video {{ video_count.value }}: {% endif -%}\n <|vision_start|><|video_pad|><|vision_end|>\n {%- elif 'text' in content %}\n {{- content.text }}\n {%- endif %}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"assistant\" %}\n {{- '<|im_start|>' + message.role + '\\n' }}\n {%- if message.content is string %}\n {{- message.content }}\n {%- else %}\n {%- for content_item in message.content %}\n {%- if 'text' in content_item %}\n {{- content_item.text }}\n {%- endif %}\n {%- endfor %}\n {%- endif %}\n {%- if message.tool_calls %}\n {%- for tool_call in message.tool_calls %}\n {%- if (loop.first and message.content) or (not loop.first) %}\n {{- '\\n' }}\n {%- endif %}\n {%- if tool_call.function %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {{- '<tool_call>\\n{\"name\": \"' }}\n {{- tool_call.name }}\n {{- '\", \"arguments\": ' }}\n {%- if tool_call.arguments is string %}\n {{- tool_call.arguments }}\n {%- else %}\n {{- tool_call.arguments | tojson }}\n {%- endif %}\n {{- '}\\n</tool_call>' }}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if loop.first or (messages[loop.index0 - 1].role != \"tool\") %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n<tool_response>\\n' }}\n {%- if message.content is string %}\n {{- message.content }}\n {%- else %}\n {%- for content in message.content %}\n {%- if content.type == 'image' or 'image' in content or 'image_url' in content %}\n {%- set image_count.value = image_count.value + 1 %}\n {%- if add_vision_id %}Picture {{ image_count.value }}: {% endif -%}\n <|vision_start|><|image_pad|><|vision_end|>\n {%- elif content.type == 'video' or 'video' in content %}\n {%- set video_count.value = video_count.value + 1 %}\n {%- if add_vision_id %}Video {{ video_count.value }}: {% endif -%}\n <|vision_start|><|video_pad|><|vision_end|>\n {%- elif 'text' in content %}\n {{- content.text }}\n {%- endif %}\n {%- endfor %}\n {%- endif %}\n {{- '\\n</tool_response>' }}\n {%- if loop.last or (messages[loop.index0 + 1].role != \"tool\") %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n{%- endif %}\n"
3
+ }
checkpoint.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "checkpoint_type": "hf",
3
+ "source_weights": "ema",
4
+ "student_only": true
5
+ }
config.json ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "allow_patterns_overrides": [
3
+ "*/*.safetensors"
4
+ ],
5
+ "architectures": [
6
+ "Cosmos3ForConditionalGeneration"
7
+ ],
8
+ "image_token_id": 151655,
9
+ "model": {
10
+ "_recursive_": false,
11
+ "_target": "omni_mot_model",
12
+ "config": {
13
+ "_type": "omni_mot_model_config",
14
+ "action_gen": false,
15
+ "activation_checkpointing": {
16
+ "_type": "activation_checkpointing_config",
17
+ "determinism_check": "default",
18
+ "mode": "full",
19
+ "preserve_rng_state": true,
20
+ "save_ops_regex": [
21
+ "fmha"
22
+ ]
23
+ },
24
+ "causal_training_strategy": "none",
25
+ "compile": {
26
+ "_type": "compile_config",
27
+ "compile_dynamic": true,
28
+ "compiled_region": "language",
29
+ "coordinate_descent_tuning": false,
30
+ "enabled": false,
31
+ "max_autotune_pointwise": false,
32
+ "use_cuda_graphs": false
33
+ },
34
+ "diffusion_expert_config": {
35
+ "_type": "diffusion_expert_config",
36
+ "base_fps": 16,
37
+ "enable_fps_modulation": true,
38
+ "load_weights_from_pretrained": true,
39
+ "max_vae_latent_side_after_patchify": 20,
40
+ "patch_spatial": 2,
41
+ "sound_base_temporal_compression_factor": null,
42
+ "timestep_range": 1.0,
43
+ "unified_3d_mrope_reset_spatial_ids": true,
44
+ "unified_3d_mrope_temporal_modality_margin": 15000,
45
+ "vision_temporal_position_mode": "latent_index"
46
+ },
47
+ "ema": {
48
+ "_type": "ema_config",
49
+ "enabled": false,
50
+ "iteration_shift": 0,
51
+ "rate": 0.1
52
+ },
53
+ "enable_input_bias": true,
54
+ "exclude_reasoner_weights_from_checkpoint": false,
55
+ "fixed_step_sampler_config": {
56
+ "_type": "fixed_step_sampler_config",
57
+ "sample_type": "sde",
58
+ "t_list": [
59
+ 1.0,
60
+ 0.9375,
61
+ 0.8333333333333334,
62
+ 0.625
63
+ ]
64
+ },
65
+ "input_caption_key": "ai_caption",
66
+ "input_image_key": "images",
67
+ "input_video_key": "video",
68
+ "joint_attn_implementation": "two_way",
69
+ "latent_downsample_factor": 16,
70
+ "lbl": {
71
+ "_type": "lbl_config",
72
+ "coeff_gen": null,
73
+ "coeff_und": null,
74
+ "method": "local"
75
+ },
76
+ "log_enc_time_every_n": 100,
77
+ "lora_alpha": 32,
78
+ "lora_enabled": false,
79
+ "lora_rank": 16,
80
+ "lora_target_modules": "q_proj_moe_gen,k_proj_moe_gen,v_proj_moe_gen,o_proj_moe_gen",
81
+ "max_action_dim": 32,
82
+ "max_num_tokens_after_packing": 45056,
83
+ "natten_parameter_list": null,
84
+ "net": null,
85
+ "num_embodiment_domains": 32,
86
+ "parallelism": {
87
+ "_type": "parallelism_config",
88
+ "attention_io_layout": "sequence_sharded",
89
+ "cfg_parallel_shard_degree": 1,
90
+ "context_parallel_shard_degree": 1,
91
+ "data_parallel_replicate_degree": 1,
92
+ "data_parallel_shard_degree": 128,
93
+ "enable_inference_mode": false,
94
+ "fsdp_master_dtype": "float32"
95
+ },
96
+ "precision": "bfloat16",
97
+ "rectified_flow_inference_config": {
98
+ "_type": "rectified_flow_inference_config",
99
+ "num_train_timesteps": 1000,
100
+ "scheduler_type": "unipc",
101
+ "shift": 1,
102
+ "use_dynamic_shifting": false
103
+ },
104
+ "rectified_flow_training_config": {
105
+ "_type": "rectified_flow_training_config",
106
+ "action_loss_weight": 10.0,
107
+ "image_loss_scale": null,
108
+ "independent_action_schedule": false,
109
+ "independent_sound_schedule": false,
110
+ "loss_scale": 10.0,
111
+ "normalize_loss_by_active": false,
112
+ "shift": {
113
+ "256": 3,
114
+ "480": 5,
115
+ "720": 10
116
+ },
117
+ "shift_action": null,
118
+ "shift_sound": null,
119
+ "sound_loss_scale": null,
120
+ "train_time_action_distribution": "logitnormal",
121
+ "train_time_image_distribution": "logitnormal",
122
+ "train_time_sound_distribution": "logitnormal",
123
+ "train_time_video_distribution": "uniform",
124
+ "train_time_weight": "uniform",
125
+ "use_discrete_rf": false,
126
+ "use_dynamic_shift": false
127
+ },
128
+ "resolution": "480",
129
+ "sound_dim": null,
130
+ "sound_gen": false,
131
+ "sound_latent_fps": 25,
132
+ "sound_tokenizer": null,
133
+ "state_ch": 48,
134
+ "state_t": 300,
135
+ "tokenizer": {
136
+ "_target": "wan2pt2_vae_interface",
137
+ "bucket_name": "bucket",
138
+ "causal": true,
139
+ "chunk_duration": 93,
140
+ "encode_bucket_multiple": 1,
141
+ "encode_chunk_frames": {
142
+ "256": 68,
143
+ "480": 24,
144
+ "720": 12
145
+ },
146
+ "encode_exact_durations": [
147
+ 17,
148
+ 61,
149
+ 73
150
+ ],
151
+ "keep_decoder_cache": false,
152
+ "object_store_credential_path_pretrained": "",
153
+ "spatial_compression_factor": 16,
154
+ "temporal_compression_factor": 4,
155
+ "temporal_window": null,
156
+ "use_streaming_encode": false,
157
+ "vae_path": "pretrained/tokenizers/video/wan2pt2/Wan2.2_VAE.pth"
158
+ },
159
+ "video_temporal_causal": false,
160
+ "vision_gen": true,
161
+ "vlm_config": {
162
+ "_type": "vlm_config",
163
+ "layer_module": null,
164
+ "model_instance": {
165
+ "_target": "qwen3_vl_text_for_causal_lm",
166
+ "config": {
167
+ "_target": "create_vlm_config",
168
+ "base_config": {
169
+ "_target": "qwen3_vl_mot_config_from_json_file",
170
+ "json_file": "cosmos3://vfm/models/vlm/qwen3_vl/configs/Qwen3-VL-32B-Instruct.json"
171
+ },
172
+ "qk_norm_for_text": true
173
+ }
174
+ },
175
+ "model_name": "nvidia/Cosmos3-Super-Reasoner",
176
+ "pretrained_weights": {
177
+ "_type": "pretrained_weights_config",
178
+ "backbone_path": "",
179
+ "checkpoint_format": null,
180
+ "credentials_path": "",
181
+ "enable_gcs_patch_in_boto3": false,
182
+ "enabled": false
183
+ },
184
+ "qk_norm": false,
185
+ "safetensors_path": "",
186
+ "tie_word_embeddings": false,
187
+ "tokenizer": {
188
+ "_target": "create_qwen2_tokenizer_with_download",
189
+ "config_variant": "hf",
190
+ "pretrained_model_name": "Qwen/Qwen3-VL-32B-Instruct"
191
+ },
192
+ "use_system_prompt": false
193
+ }
194
+ }
195
+ },
196
+ "model_type": "cosmos3_omni",
197
+ "text_config": {
198
+ "attention_bias": false,
199
+ "attention_dropout": 0.0,
200
+ "bos_token_id": 151643,
201
+ "dtype": "bfloat16",
202
+ "eos_token_id": 151645,
203
+ "head_dim": 128,
204
+ "hidden_act": "silu",
205
+ "hidden_size": 5120,
206
+ "initializer_range": 0.02,
207
+ "intermediate_size": 25600,
208
+ "max_position_embeddings": 262144,
209
+ "model_type": "qwen3_vl_text",
210
+ "num_attention_heads": 64,
211
+ "num_hidden_layers": 64,
212
+ "num_key_value_heads": 8,
213
+ "rms_norm_eps": 1e-06,
214
+ "rope_scaling": {
215
+ "mrope_interleaved": true,
216
+ "mrope_section": [
217
+ 24,
218
+ 20,
219
+ 20
220
+ ],
221
+ "rope_type": "default"
222
+ },
223
+ "rope_theta": 5000000,
224
+ "use_cache": true,
225
+ "vocab_size": 151936
226
+ },
227
+ "tie_word_embeddings": false,
228
+ "transformers_version": "4.57.0.dev0",
229
+ "video_token_id": 151656,
230
+ "vision_config": {
231
+ "deepstack_visual_indexes": [
232
+ 8,
233
+ 16,
234
+ 24
235
+ ],
236
+ "depth": 27,
237
+ "hidden_act": "gelu_pytorch_tanh",
238
+ "hidden_size": 1152,
239
+ "in_channels": 3,
240
+ "initializer_range": 0.02,
241
+ "intermediate_size": 4304,
242
+ "model_type": "qwen3_vl",
243
+ "num_heads": 16,
244
+ "num_position_embeddings": 2304,
245
+ "out_hidden_size": 5120,
246
+ "patch_size": 16,
247
+ "spatial_merge_size": 2,
248
+ "temporal_patch_size": 2
249
+ },
250
+ "vision_end_token_id": 151653,
251
+ "vision_start_token_id": 151652
252
+ }
generation_config.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token_id": 151643,
3
+ "pad_token_id": 151643,
4
+ "do_sample": true,
5
+ "eos_token_id": [
6
+ 151645,
7
+ 151643
8
+ ],
9
+ "top_p": 0.8,
10
+ "top_k": 20,
11
+ "temperature": 0.7,
12
+ "repetition_penalty": 1.0,
13
+ "transformers_version": "4.56.0"
14
+ }
images/aa-i2v-all-models-2026-07-17.png ADDED

Git LFS Details

  • SHA256: 358f682335c074222233a0a101f8b091ead7a1bb9806df2e716a3fddb5cf945f
  • Pointer size: 131 Bytes
  • Size of remote file: 756 kB
images/aa-i2v-open-models-2026-07-17.png ADDED

Git LFS Details

  • SHA256: ede7eddb377cb74d02b36c228167b6aaeefdbc12975671edaa308c53cc236af8
  • Pointer size: 131 Bytes
  • Size of remote file: 430 kB
load_cosmos3_modelopt.py ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """
3
+ Drop-in loader for the weight-only NVFP4 / FP8 (NVIDIA ModelOpt) Cosmos3-Super checkpoint
4
+ saved in the ROUND-TRIPPABLE format (modelopt_state.pth present -- see repackage_for_hf.py).
5
+
6
+ Current diffusers + accelerate + modelopt treat this path as experimental; each shim below
7
+ works around a specific, source-verified version-skew gap. None modify the checkpoint:
8
+
9
+ 1. enable_huggingface_checkpointing()
10
+ Registers ModelOpt's HF handlers so `from_pretrained` restores the quantized module
11
+ structure from modelopt_state.pth before weights load.
12
+
13
+ 2. set_module_tensor_to_device patch (parameter materialization)
14
+ The modelopt_state restore runs inside diffusers' meta-device init, so each quantized
15
+ weight is a QTensorWrapper whose storage is a META tensor carrying dequant metadata.
16
+ `param.data = real` can't cross meta<->real, and accelerate's rebuild both rejects
17
+ requires_grad and discards metadata. We REPLACE the parameter with a fresh wrapper
18
+ around the loaded bytes + the existing metadata. Two extra duties here:
19
+ - payload dtype restore: diffusers casts floating params to torch_dtype during load
20
+ when no hf_quantizer is present (model_loading_utils.py -- their own TODO flags
21
+ float8). FP8 payloads are floating and arrive cast to bf16; we cast back to the
22
+ wrapper's payload dtype (exact: every e4m3fn value round-trips through bf16).
23
+ NVFP4's uint8 payload is never cast, so this is a no-op there.
24
+ - direct-to-GPU materialization: staging payloads on CPU would put the whole packed
25
+ model in system RAM (FP8: ~64 GB on a 32 GB box -> OOM-killed; NVFP4 only survived
26
+ because uncast tensors stay mmap-backed). Wrappers go straight to `materialize_device`.
27
+
28
+ 3. Post-restore quantizer re-disable
29
+ modelopt_state replays the QUANT CONFIG, not imperative `.disable()` calls made after
30
+ quantize. The NVFP4 build used NVFP4_DEFAULT_CFG (activation quantization ON in-config)
31
+ with activations disabled imperatively -- so the restored model comes back with ~1806
32
+ dynamic fake-quant activation quantizers active: ~10x slower, fatter, and quantizing
33
+ activations the validated regime never quantized. We re-apply weight-only + spare
34
+ disabling after load. (FP8's config had the disables baked in; this is then a no-op.)
35
+
36
+ 4. Full bf16 normalization (the validated serve regime)
37
+ Cosmos3OmniTransformer pins time_embedder to fp32 via _keep_in_fp32_modules
38
+ (transformer_cosmos3.py:297); the quantized model runs all-bf16. Cast floating buffers
39
+ and non-wrapper floating params to bf16, retarget wrapper dequant dtype to bf16, and
40
+ register bf16 input-cast pre-hooks on the time embedders.
41
+
42
+ 5. NVIDIAModelOptQuantizer.create_quantized_param patch
43
+ Only relevant if a checkpoint carries an embedded quantization_config (hf_quantizer
44
+ path): requires_grad only for float/complex tensors. Kept for robustness.
45
+
46
+ Usage (library):
47
+ from load_cosmos3_modelopt import load_pipe
48
+ pipe = load_pipe("YOUR_HF_USERNAME/Cosmos3-Super-nvfp4") # or a local dir
49
+ # NOTE: a bare pipe(prompt) call renders the pipeline DEFAULT: a 189-frame 720x1280
50
+ # video (~8 s at 24 fps) -- not a still. For a single-image smoke test, be explicit:
51
+ r = pipe("a red cube on a table", height=1024, width=1024, num_frames=1,
52
+ num_inference_steps=50, guidance_scale=4.0)
53
+ r.video[0].save("out.png") # .video is the list of PIL frames; [0] is the image
54
+
55
+ Usage (interactive -- lands in a REPL with `pipe` loaded):
56
+ CUDA_VISIBLE_DEVICES=0 python -i load_cosmos3_modelopt.py ./cosmos3-super-nvfp4-hf
57
+ """
58
+ import os
59
+
60
+ os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
61
+
62
+ import torch
63
+
64
+ SPARE_SUBSTRINGS = [
65
+ "time_embedder", "proj_in", "proj_out", "lm_head", "embed", "norm", "audio_proj",
66
+ ]
67
+
68
+
69
+ def _qtensor_wrapper_cls():
70
+ try:
71
+ from modelopt.torch.quantization.qtensor.base_qtensor import QTensorWrapper
72
+ return QTensorWrapper
73
+ except Exception:
74
+ return None
75
+
76
+
77
+ def _patch_modelopt_quantizer() -> None:
78
+ """diffusers pre-quantized hf_quantizer branch: only float/complex tensors may require grad."""
79
+ import diffusers.quantizers.modelopt.modelopt_quantizer as moq
80
+
81
+ if getattr(moq.NVIDIAModelOptQuantizer, "_cqp_patched", False):
82
+ return
83
+ _orig = moq.NVIDIAModelOptQuantizer.create_quantized_param
84
+
85
+ def _cqp(self, model, param_value, param_name, target_device, *args, **kwargs):
86
+ if self.pre_quantized:
87
+ module, tname = moq.get_module_from_name(model, param_name)
88
+ needs_grad = param_value.is_floating_point() or param_value.is_complex()
89
+ module._parameters[tname] = torch.nn.Parameter(
90
+ param_value.to(device=target_device), requires_grad=needs_grad
91
+ )
92
+ return
93
+ return _orig(self, model, param_value, param_name, target_device, *args, **kwargs)
94
+
95
+ moq.NVIDIAModelOptQuantizer.create_quantized_param = _cqp
96
+ moq.NVIDIAModelOptQuantizer._cqp_patched = True
97
+
98
+
99
+ def _patch_qtensor_loading() -> None:
100
+ """Materialize restored (meta) QTensorWrapper params: replace the parameter object with
101
+ a fresh wrapper around the loaded bytes, restoring the payload dtype (undoes diffusers'
102
+ float cast on FP8) and landing directly on the target device (keeps payloads out of RAM)."""
103
+ import diffusers.models.model_loading_utils as mlu
104
+
105
+ if getattr(mlu, "_qtw_inplace_patched", False):
106
+ return
107
+ QTensorWrapper = _qtensor_wrapper_cls()
108
+ if QTensorWrapper is None:
109
+ return # different modelopt layout; nothing to patch
110
+
111
+ _orig = mlu.set_module_tensor_to_device
112
+ stats = {"materialized": 0, "target_device": None}
113
+
114
+ def _patched(model, tensor_name, device, value=None, *args, **kwargs):
115
+ if value is not None:
116
+ module, leaf = model, tensor_name
117
+ if "." in tensor_name:
118
+ mod_path, leaf = tensor_name.rsplit(".", 1)
119
+ try:
120
+ module = model.get_submodule(mod_path)
121
+ except AttributeError:
122
+ module = None
123
+ if module is not None:
124
+ cur = getattr(module, "_parameters", {}).get(leaf)
125
+ if isinstance(cur, QTensorWrapper):
126
+ tgt = stats.get("target_device") or device
127
+ module._parameters[leaf] = QTensorWrapper(
128
+ value.to(device=tgt, dtype=cur.data.dtype), # exact cast-back for fp8
129
+ metadata=dict(cur.metadata),
130
+ )
131
+ stats["materialized"] += 1
132
+ return None
133
+ return _orig(model, tensor_name, device, value=value, *args, **kwargs)
134
+
135
+ mlu.set_module_tensor_to_device = _patched
136
+ mlu._qtw_inplace_patched = True
137
+ mlu._qtw_stats = stats
138
+
139
+
140
+ def _enforce_weight_only(transformer) -> None:
141
+ """Re-apply the validated weight-only + spare regime: the state replay re-enables any
142
+ quantizers that were disabled imperatively after quantize (NVFP4 default cfg has
143
+ activation quantization ON in-config)."""
144
+ n_act = n_spare = 0
145
+ for name, m in transformer.named_modules():
146
+ if not (name.endswith("_quantizer") and hasattr(m, "disable")):
147
+ continue
148
+ if name.endswith("weight_quantizer"):
149
+ if any(s in name for s in SPARE_SUBSTRINGS):
150
+ if getattr(m, "is_enabled", False):
151
+ n_spare += 1
152
+ m.disable()
153
+ else:
154
+ if getattr(m, "is_enabled", False):
155
+ n_act += 1
156
+ m.disable()
157
+ print(f"[load] re-disabled quantizers the state replay re-enabled: "
158
+ f"{n_act} activation, {n_spare} spare-weight")
159
+
160
+
161
+ def _apply_dtype_nudges(transformer) -> None:
162
+ """Reproduce the validated all-bf16 serve regime (all no-ops where already aligned)."""
163
+ QTensorWrapper = _qtensor_wrapper_cls() or ()
164
+
165
+ n_buf = n_par = n_meta = 0
166
+ for m in transformer.modules():
167
+ for bn, buf in list(m._buffers.items()):
168
+ if buf is not None and buf.is_floating_point() and buf.dtype != torch.bfloat16:
169
+ m._buffers[bn] = buf.to(torch.bfloat16)
170
+ n_buf += 1
171
+ for _, p in transformer.named_parameters():
172
+ if isinstance(p, QTensorWrapper):
173
+ d = p.metadata.get("dtype")
174
+ if isinstance(d, torch.dtype) and d.is_floating_point and d != torch.bfloat16:
175
+ p.metadata["dtype"] = torch.bfloat16 # dequant target only; payload untouched
176
+ n_meta += 1
177
+ continue # packed payloads: never cast
178
+ if p.is_floating_point() and p.dtype != torch.bfloat16:
179
+ p.data = p.data.to(torch.bfloat16)
180
+ n_par += 1
181
+ print(f"[load] normalized to bf16: {n_par} params, {n_buf} buffers; "
182
+ f"retargeted {n_meta} dequant dtypes")
183
+
184
+ def _cast_bf16(_m, args):
185
+ return tuple(
186
+ a.to(torch.bfloat16)
187
+ if torch.is_tensor(a) and a.is_floating_point() and a.dtype != torch.bfloat16
188
+ else a
189
+ for a in args
190
+ )
191
+
192
+ for name, m in transformer.named_modules():
193
+ if "time_embedder" in name and hasattr(m, "linear_1"):
194
+ m.register_forward_pre_hook(_cast_bf16)
195
+
196
+
197
+ def load_pipe(
198
+ model_id_or_path: str,
199
+ *,
200
+ torch_dtype=torch.bfloat16,
201
+ enable_safety_checker: bool = False,
202
+ device: str = "cuda",
203
+ materialize_device: str | None = "cuda", # packed weights stream straight here (RAM stays low)
204
+ **kwargs,
205
+ ):
206
+ """Load a ModelOpt-quantized Cosmos3-Super pipeline with all load-time fixes applied."""
207
+ from diffusers import Cosmos3OmniPipeline
208
+ from modelopt.torch.opt import enable_huggingface_checkpointing
209
+
210
+ enable_huggingface_checkpointing() # must run before from_pretrained
211
+ _patch_modelopt_quantizer()
212
+ _patch_qtensor_loading()
213
+
214
+ import diffusers.models.model_loading_utils as mlu
215
+ if hasattr(mlu, "_qtw_stats"):
216
+ mlu._qtw_stats["materialized"] = 0
217
+ mlu._qtw_stats["target_device"] = materialize_device
218
+
219
+ pipe = Cosmos3OmniPipeline.from_pretrained(
220
+ model_id_or_path,
221
+ torch_dtype=torch_dtype,
222
+ enable_safety_checker=enable_safety_checker,
223
+ **kwargs,
224
+ )
225
+
226
+ n_mat = getattr(mlu, "_qtw_stats", {}).get("materialized", 0)
227
+ print(f"[load] materialized {n_mat} packed quantized weight tensors")
228
+
229
+ transformer = getattr(pipe, "transformer", None)
230
+ if transformer is not None:
231
+ _enforce_weight_only(transformer)
232
+ _apply_dtype_nudges(transformer)
233
+
234
+ pipe = pipe.to(device)
235
+
236
+ QTensorWrapper = _qtensor_wrapper_cls()
237
+ if QTensorWrapper is not None and transformer is not None:
238
+ n_live = sum(1 for p in transformer.parameters() if isinstance(p, QTensorWrapper))
239
+ print(f"[load] {n_live} quantized weight wrappers active after move to {device}")
240
+ if n_mat and not n_live:
241
+ print("[load] WARNING: wrappers were lost during .to() -- do not render; report this")
242
+
243
+ return pipe
244
+
245
+
246
+ if __name__ == "__main__":
247
+ import sys
248
+
249
+ path = sys.argv[1] if len(sys.argv) > 1 else "./cosmos3-super-nvfp4-hf"
250
+ print(f"[load] loading {path} ...")
251
+ pipe = load_pipe(path)
252
+ print("[load] OK -- `pipe` is ready.")
253
+ print(" NOTE: bare pipe(prompt) renders a 189-frame 720x1280 video (pipeline default).")
254
+ print(" single-still smoke test:")
255
+ print(" r = pipe('a red cube on a table', height=1024, width=1024, num_frames=1,")
256
+ print(" num_inference_steps=50, guidance_scale=4.0); r.video[0].save('out.png')")
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
model.safetensors.index.json ADDED
The diff for this file is too large to render. See raw diff
 
model_index.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_class_name": "Cosmos3OmniPipeline",
3
+ "_diffusers_version": "0.39.0",
4
+ "safety_checker": [
5
+ null,
6
+ null
7
+ ],
8
+ "scheduler": [
9
+ "diffusers",
10
+ "FlowMatchEulerDiscreteScheduler"
11
+ ],
12
+ "sound_tokenizer": [
13
+ null,
14
+ null
15
+ ],
16
+ "text_tokenizer": [
17
+ "transformers",
18
+ "Qwen2TokenizerFast"
19
+ ],
20
+ "transformer": [
21
+ "diffusers",
22
+ "Cosmos3OmniTransformer"
23
+ ],
24
+ "vae": [
25
+ "diffusers",
26
+ "AutoencoderKLWan"
27
+ ]
28
+ }
modular_model_index.json ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_blocks_class_name": "Cosmos3DistilledBlocks",
3
+ "_class_name": "Cosmos3DistilledModularPipeline",
4
+ "_diffusers_version": "0.39.0",
5
+ "is_distilled": true,
6
+ "distilled_sigmas": [
7
+ 1.0,
8
+ 0.9375,
9
+ 0.8333333333333334,
10
+ 0.625
11
+ ],
12
+ "scheduler": [
13
+ "diffusers",
14
+ "FlowMatchEulerDiscreteScheduler",
15
+ {
16
+ "pretrained_model_name_or_path": "nvidia/Cosmos3-Super-Image2Video-4Step",
17
+ "subfolder": "scheduler",
18
+ "type_hint": [
19
+ "diffusers",
20
+ "FlowMatchEulerDiscreteScheduler"
21
+ ],
22
+ "variant": null
23
+ }
24
+ ],
25
+ "text_tokenizer": [
26
+ "transformers",
27
+ "Qwen2TokenizerFast",
28
+ {
29
+ "pretrained_model_name_or_path": "nvidia/Cosmos3-Super-Image2Video-4Step",
30
+ "subfolder": "text_tokenizer",
31
+ "type_hint": [
32
+ "transformers",
33
+ "Qwen2TokenizerFast"
34
+ ],
35
+ "variant": null
36
+ }
37
+ ],
38
+ "transformer": [
39
+ "diffusers",
40
+ "Cosmos3OmniTransformer",
41
+ {
42
+ "pretrained_model_name_or_path": "nvidia/Cosmos3-Super-Image2Video-4Step",
43
+ "subfolder": "transformer",
44
+ "type_hint": [
45
+ "diffusers",
46
+ "Cosmos3OmniTransformer"
47
+ ],
48
+ "variant": null
49
+ }
50
+ ],
51
+ "vae": [
52
+ "diffusers",
53
+ "AutoencoderKLWan",
54
+ {
55
+ "pretrained_model_name_or_path": "nvidia/Cosmos3-Super-Image2Video-4Step",
56
+ "subfolder": "vae",
57
+ "type_hint": [
58
+ "diffusers",
59
+ "AutoencoderKLWan"
60
+ ],
61
+ "variant": null
62
+ }
63
+ ]
64
+ }
preprocessor_config.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "size": {
3
+ "longest_edge": 16777216,
4
+ "shortest_edge": 65536
5
+ },
6
+ "patch_size": 16,
7
+ "temporal_patch_size": 2,
8
+ "merge_size": 2,
9
+ "image_mean": [
10
+ 0.5,
11
+ 0.5,
12
+ 0.5
13
+ ],
14
+ "image_std": [
15
+ 0.5,
16
+ 0.5,
17
+ 0.5
18
+ ],
19
+ "processor_class": "Qwen3VLProcessor",
20
+ "image_processor_type": "Qwen2VLImageProcessorFast"
21
+ }
quantize_cosmos3_i2v4step_streaming.py ADDED
@@ -0,0 +1,383 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """
3
+ Stream-quantize NVIDIA Cosmos3-Super-Image2Video-4Step's transformer to weight-only
4
+ FP8 or NVFP4, WITHOUT ever materializing the full ~128 GB BF16 model.
5
+
6
+ This is the same-architecture sibling of quantize_cosmos3_super_streaming.py (the
7
+ recipe validated against nvidia/Cosmos3-Super): identical Cosmos3OmniTransformer
8
+ class, identical dims (64 layers, hidden_size 5120), so the empty-on-meta ->
9
+ mtq.quantize -> mtq.compress -> stream-load recipe and the SPARE_SUBSTRINGS list
10
+ carry over unchanged. Three things do NOT carry over -- this checkpoint is a DMD2
11
+ 4-step distillation of Cosmos3-Super-Image2Video, and differs as follows:
12
+
13
+ 1. SCHEDULER IS FIXED, NOT SWAPPABLE. The base-model script (and
14
+ serve_cosmos3_diffusers.py) replace the shipped scheduler with
15
+ UniPCMultistepScheduler(flow_shift=...). This checkpoint ships
16
+ FlowMatchEulerDiscreteScheduler with a baked-in fixed_step_sampler_config
17
+ (sde sampling, t_list=[1.0, 0.9375, 0.8333, 0.625] -- literally 4 steps).
18
+ Do NOT override it -- use pipe.scheduler as loaded.
19
+ 2. num_inference_steps / guidance_scale are NOT meaningfully configurable per
20
+ NVIDIA's model card (CFG is distilled out; the checkpoint was trained for an
21
+ exact 4-step sde schedule). CONFIRMED BY RUNNING IT: Cosmos3OmniPipeline
22
+ (diffusers 0.39.0.dev0) does not know this checkpoint's scheduler carries a
23
+ fixed_step_sampler_config -- an unpatched call silently ran the pipeline's
24
+ 35-step/guidance=6.0 default instead. render_from_memory() below patches the
25
+ scheduler (_force_fixed_step_schedule) to force the correct 4-step t_list and
26
+ passes guidance_scale=1.0 explicitly. See that function's docstring.
27
+ 3. This checkpoint is Image2Video-specific (unlike the T2I/T2V/I2V-omni base
28
+ model), so the smoke render requires a conditioning IMAGE -- there is no
29
+ text-only still-image path to fall back on. sound_tokenizer is also null in
30
+ this repo (audio branch inactive), so the "audio_proj" spare substring is
31
+ believed inert here, but is kept for parity/safety.
32
+
33
+ USAGE
34
+ -----
35
+ python quantize_cosmos3_i2v4step_streaming.py --format fp8
36
+ python quantize_cosmos3_i2v4step_streaming.py --format fp8 --smoke --image out.png
37
+
38
+ Outputs go to ./cosmos3-i2v4step-<fmt>/ (override with --export-dir).
39
+ """
40
+
41
+ import argparse
42
+ import os
43
+
44
+ # Reduce allocator fragmentation on the big card (cheap, always-on).
45
+ os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
46
+
47
+ import torch
48
+ from accelerate import init_empty_weights, load_checkpoint_in_model
49
+ from accelerate.utils import get_max_memory, infer_auto_device_map
50
+ from accelerate.utils.dataclasses import CustomDtype
51
+ from huggingface_hub import snapshot_download
52
+
53
+ import modelopt.torch.quantization as mtq
54
+ from modelopt.torch.export import export_hf_checkpoint
55
+
56
+ # Cosmos3 classes require diffusers built from git main (already installed in the venv).
57
+ from diffusers import Cosmos3OmniTransformer
58
+
59
+ SRC_REPO = "nvidia/Cosmos3-Super-Image2Video-4Step"
60
+
61
+ # ---------------------------------------------------------------------------
62
+ # Layers to KEEP IN BF16 (never quantize). Matched as substrings of module names.
63
+ # Unchanged from the base-model recipe -- same transformer class + dims, so the
64
+ # same layers are quality-sensitive: embeddings, norms, the bundled Qwen3 reasoner
65
+ # head, time/modality adapters, and the in/out projections.
66
+ # ---------------------------------------------------------------------------
67
+ SPARE_SUBSTRINGS = [
68
+ "time_embedder",
69
+ "proj_in",
70
+ "proj_out",
71
+ "lm_head",
72
+ "embed", # token / position embeddings
73
+ "norm", # layernorms / rmsnorms
74
+ "audio_proj", # audio modality adapter (inert here: sound_tokenizer is null)
75
+ ]
76
+
77
+
78
+ def _is_spare(module_name: str) -> bool:
79
+ return any(s in module_name for s in SPARE_SUBSTRINGS)
80
+
81
+
82
+ def build_quant_cfg(fmt: str) -> dict:
83
+ """Return a WEIGHT-ONLY quant config for the chosen format. Same as the
84
+ base-model recipe: FP8 per-tensor E4M3, or NVFP4 4-bit block-scale."""
85
+ if fmt == "fp8":
86
+ return {
87
+ "quant_cfg": {
88
+ "*weight_quantizer": {"num_bits": (4, 3), "axis": None, "enable": True},
89
+ "*input_quantizer": {"enable": False},
90
+ "*output_quantizer": {"enable": False},
91
+ "*softmax_quantizer": {"enable": False},
92
+ },
93
+ "algorithm": "max",
94
+ }
95
+ elif fmt == "nvfp4":
96
+ import copy
97
+
98
+ base = getattr(mtq, "W4A16_NVFP4_CFG", None) or mtq.NVFP4_DEFAULT_CFG
99
+ return copy.deepcopy(base)
100
+ else:
101
+ raise ValueError(f"Unknown format: {fmt!r}")
102
+
103
+
104
+ def enforce_weight_only_and_spare(model) -> tuple[int, int]:
105
+ """Disable all activation quantizers, and weight quantizers on SPARE layers.
106
+ Config-form agnostic (works for both the FP8 dict and modelopt's NVFP4 preset)."""
107
+ n_spare = 0
108
+ n_act = 0
109
+ for name, module in model.named_modules():
110
+ if not (name.endswith("_quantizer") and hasattr(module, "disable")):
111
+ continue
112
+ if name.endswith("weight_quantizer"):
113
+ parent = name.rsplit(".", 1)[0]
114
+ if _is_spare(parent):
115
+ module.disable()
116
+ n_spare += 1
117
+ else:
118
+ module.disable()
119
+ n_act += 1
120
+ return n_spare, n_act
121
+
122
+
123
+ def compressed_device_map(model, gpu_mem_fraction: float = 0.85) -> dict:
124
+ """Build a device_map sized for the COMPRESSED weights (same as base-model recipe)."""
125
+ max_memory = {k: v * gpu_mem_fraction for k, v in get_max_memory().items()}
126
+
127
+ no_split = set()
128
+ for name, module in model.named_modules():
129
+ if name.endswith((".layers.0", ".blocks.0", ".transformer_blocks.0")):
130
+ no_split.add(module.__class__.__name__)
131
+
132
+ special_dtypes = {}
133
+ for name, module in model.named_modules():
134
+ if (
135
+ hasattr(module, "weight")
136
+ and hasattr(module, "weight_quantizer")
137
+ and getattr(module.weight_quantizer, "is_enabled", True)
138
+ and not getattr(module.weight_quantizer, "fake_quant", True)
139
+ ):
140
+ nb = module.weight_quantizer.num_bits
141
+ if isinstance(nb, tuple):
142
+ nb = nb[0] + nb[1] + 1
143
+ special_dtypes[name + ".weight"] = CustomDtype.FP8 if nb == 8 else CustomDtype.INT4
144
+
145
+ return infer_auto_device_map(
146
+ model,
147
+ max_memory=max_memory,
148
+ no_split_module_classes=list(no_split),
149
+ special_dtypes=special_dtypes,
150
+ )
151
+
152
+
153
+ def main():
154
+ ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
155
+ ap.add_argument("--format", choices=["fp8", "nvfp4"], required=True,
156
+ help="Weight-only quantization format to produce.")
157
+ ap.add_argument("--export-dir", default=None,
158
+ help="Output dir (default: ./cosmos3-i2v4step-<format>).")
159
+ ap.add_argument("--gpu-mem-fraction", type=float, default=0.85,
160
+ help="Fraction of each GPU's memory accelerate may use for placement.")
161
+ ap.add_argument("--smoke", action="store_true",
162
+ help="Validate by rendering a short clip from the in-memory model "
163
+ "(runs before export; output: cosmos3_i2v4step_<fmt>_validate.mp4).")
164
+ ap.add_argument("--image", default="out.png",
165
+ help="Conditioning image for the --smoke render (this checkpoint is "
166
+ "Image2Video-only -- there is no text-only still path).")
167
+ args = ap.parse_args()
168
+
169
+ export_dir = args.export_dir or f"./cosmos3-i2v4step-{args.format}"
170
+ os.makedirs(export_dir, exist_ok=True)
171
+
172
+ print(f"[1/6] Resolving local checkpoint for {SRC_REPO} (transformer only)...")
173
+ local_root = snapshot_download(SRC_REPO, allow_patterns=["transformer/*"])
174
+ transformer_dir = os.path.join(local_root, "transformer")
175
+ print(f" transformer dir: {transformer_dir}")
176
+
177
+ print("[2/6] Building EMPTY transformer on meta device (params on meta, buffers real)...")
178
+ config = Cosmos3OmniTransformer.load_config(transformer_dir)
179
+ with init_empty_weights(include_buffers=False):
180
+ model = Cosmos3OmniTransformer.from_config(config)
181
+
182
+ print(f"[3/6] Inserting quantizers ({args.format}) on the meta model...")
183
+ quant_cfg = build_quant_cfg(args.format)
184
+ mtq.quantize(model, quant_cfg) # no forward_loop: weight-only needs no calibration
185
+ n_spare, n_act = enforce_weight_only_and_spare(model)
186
+ print(f" weight-only: disabled {n_act} activation quantizers; "
187
+ f"kept {n_spare} projection layers in BF16 (plus embeddings/norms/head)")
188
+
189
+ print("[4/6] Setting up compressed parameter shapes (mtq.compress)...")
190
+ try:
191
+ mtq.compress(model, config=mtq.CompressConfig(quant_gemm=False))
192
+ except (AttributeError, TypeError):
193
+ mtq.compress(model)
194
+
195
+ print("[5/6] Streaming BF16 shards into compressed form (this is the long step)...")
196
+ device_map = compressed_device_map(model, args.gpu_mem_fraction)
197
+ load_checkpoint_in_model(
198
+ model,
199
+ checkpoint=transformer_dir,
200
+ device_map=device_map,
201
+ dtype=torch.bfloat16,
202
+ )
203
+
204
+ n_fixed = 0
205
+ for _, module in model.named_modules():
206
+ for bname, buf in list(module._buffers.items()):
207
+ if buf is not None and getattr(buf, "is_meta", False):
208
+ module._buffers[bname] = torch.zeros(buf.shape, dtype=buf.dtype, device="cuda")
209
+ n_fixed += 1
210
+ for pname, par in list(module._parameters.items()):
211
+ if par is not None and getattr(par, "is_meta", False):
212
+ module._parameters[pname] = torch.nn.Parameter(
213
+ torch.zeros(par.shape, dtype=par.dtype, device="cuda"), requires_grad=False
214
+ )
215
+ n_fixed += 1
216
+ if n_fixed:
217
+ print(f" materialized {n_fixed} residual meta tensors (disabled-quantizer scratch)")
218
+
219
+ n_bytes = sum(p.numel() * p.element_size() for p in model.parameters() if p.device.type != "meta")
220
+ n_bytes += sum(b.numel() * b.element_size() for b in model.buffers() if b.device.type != "meta")
221
+ print(f" live footprint: {n_bytes / 1e9:.1f} GB")
222
+
223
+ if args.smoke:
224
+ render_from_memory(model, args.format, args.image)
225
+
226
+ print(f"[6/6] Exporting unified HF checkpoint to {export_dir} ...")
227
+ with torch.inference_mode():
228
+ export_hf_checkpoint(model, export_dir=export_dir)
229
+ print(f"DONE. Quantized {args.format.upper()} checkpoint written to {export_dir}")
230
+
231
+
232
+ def _force_fixed_step_schedule(scheduler) -> bool:
233
+ """CONFIRMED (not speculative): Cosmos3OmniPipeline.__call__ always calls
234
+ scheduler.set_timesteps(num_inference_steps, device=device) with no sigmas
235
+ passthrough (pipeline_cosmos3_omni.py:1529 in diffusers 0.39.0.dev0), so this
236
+ checkpoint's scheduler_config.json fixed_step_sampler_config (t_list) is silently
237
+ dropped -- an unpatched call falls back to the pipeline's num_inference_steps=35
238
+ default (verified empirically: a real run produced a 35-step progress bar despite
239
+ this being a 4-step DMD2-distilled checkpoint). Running any schedule other than the
240
+ exact trained t_list is off-distribution for what the model was distilled to
241
+ denoise, so patch THIS scheduler instance's set_timesteps to always use it,
242
+ regardless of whatever num_inference_steps the pipeline passes in.
243
+
244
+ ALSO disables stochastic_sampling (forces the deterministic ODE branch) -- CONFIRMED
245
+ by direct A/B render, not speculative. This checkpoint ships stochastic_sampling=True
246
+ (SDE sampling). Cosmos3's image-conditioning anchors frame 0 by zeroing the model's
247
+ predicted velocity there (_mask_velocity_predictions), which only means "leave this
248
+ position unchanged" under the DETERMINISTIC step (prev_sample = sample + dt*0 =
249
+ sample). The SDE branch instead computes
250
+ x0 = sample - current_sigma * model_output # = sample when velocity is 0
251
+ prev_sample = (1 - next_sigma) * x0 + next_sigma * randn_tensor(...)
252
+ which re-noises the sample by next_sigma regardless of velocity -- there is no
253
+ zero-velocity no-op in the SDE formula. Across this checkpoint's 4 steps that
254
+ compounds to ~99.6% fresh noise by the final step: the conditioning image is
255
+ destroyed into colorful static while the (non-anchored, genuinely denoised) motion
256
+ frames still look like a plausible video. Disabling stochastic_sampling makes zero
257
+ velocity a true no-op again, which an A/B render (same seed/image/prompt) confirmed
258
+ fixes it outright. This is presumably NVIDIA's own reference runtime doing a masked
259
+ resample this diffusers pipeline port doesn't implement; revisit if that lands
260
+ upstream."""
261
+ cfg = getattr(scheduler.config, "fixed_step_sampler_config", None)
262
+ t_list = cfg.get("t_list") if isinstance(cfg, dict) else None
263
+ if not t_list:
264
+ print("[warn] no fixed_step_sampler_config.t_list on this scheduler; leaving set_timesteps unpatched")
265
+ return False
266
+ _orig = scheduler.set_timesteps
267
+
268
+ def _patched(num_inference_steps=None, device=None, sigmas=None, mu=None, timesteps=None):
269
+ return _orig(sigmas=list(t_list), device=device)
270
+
271
+ scheduler.set_timesteps = _patched
272
+ if getattr(scheduler.config, "stochastic_sampling", False):
273
+ scheduler.register_to_config(stochastic_sampling=False)
274
+ print("[patch] disabled stochastic_sampling (SDE re-noising corrupts the "
275
+ "image-conditioned frame -- see docstring)")
276
+ print(f"[patch] forced fixed {len(t_list)}-step sde schedule: {t_list}")
277
+ return True
278
+
279
+
280
+ def render_from_memory(model, fmt: str, image_path: str):
281
+ """Validate the quantization by rendering an image->video clip from the IN-MEMORY
282
+ model. Does NOT swap the scheduler object itself (keeps FlowMatchEulerDiscreteScheduler
283
+ with its stochastic_sampling config), but DOES patch its set_timesteps via
284
+ _force_fixed_step_schedule -- see that function for why this is required rather than
285
+ optional. guidance_scale=1.0 is passed explicitly: CFG is distilled out of this
286
+ checkpoint (do_classifier_free_guidance is guidance_scale != 1.0 in the pipeline
287
+ source), and the 6.0 pipeline default would silently re-enable it."""
288
+ import gc
289
+
290
+ print(f"\n[validate] Rendering an image->video clip from the in-memory {fmt.upper()} model "
291
+ f"(conditioning image: {image_path})...")
292
+ try:
293
+ from PIL import Image
294
+
295
+ from diffusers import Cosmos3OmniPipeline
296
+
297
+ if not os.path.isfile(image_path):
298
+ raise FileNotFoundError(
299
+ f"conditioning image {image_path!r} not found -- pass --image with a real "
300
+ "file; this checkpoint has no text-only still path to fall back on."
301
+ )
302
+ cond_image = Image.open(image_path).convert("RGB")
303
+
304
+ model.to("cuda")
305
+
306
+ # Dtype consistency at render time (same nudge as the base-model script): our
307
+ # model mixes FP8/NVFP4 (compressed) weights with BF16 spare weights, while
308
+ # diffusers computes the timestep sinusoidal fresh in FP32 each step.
309
+ for _module in model.modules():
310
+ for _bn, _buf in list(_module._buffers.items()):
311
+ if _buf is not None and _buf.dtype == torch.float32:
312
+ _module._buffers[_bn] = _buf.to(torch.bfloat16)
313
+
314
+ def _cast_inputs_bf16(_m, args):
315
+ return tuple(
316
+ a.to(torch.bfloat16)
317
+ if torch.is_tensor(a) and a.is_floating_point() and a.dtype != torch.bfloat16
318
+ else a
319
+ for a in args
320
+ )
321
+
322
+ n_hooks = 0
323
+ for _name, _module in model.named_modules():
324
+ if "time_embedder" in _name and hasattr(_module, "linear_1"):
325
+ _module.register_forward_pre_hook(_cast_inputs_bf16)
326
+ n_hooks += 1
327
+ print(f"[validate] dtype-safety: cast fp32 buffers to bf16, hooked {n_hooks} time-embedder(s)")
328
+
329
+ # Pass OUR quantized transformer in so the pipeline does NOT reload it from the hub.
330
+ # Deliberately do NOT touch pipe.scheduler -- the shipped FlowMatchEulerDiscreteScheduler
331
+ # carries the fixed 4-step sde schedule for this checkpoint.
332
+ pipe = Cosmos3OmniPipeline.from_pretrained(
333
+ SRC_REPO,
334
+ transformer=model,
335
+ torch_dtype=torch.bfloat16,
336
+ enable_safety_checker=False,
337
+ )
338
+ for name, comp in pipe.components.items():
339
+ if name != "transformer" and isinstance(comp, torch.nn.Module):
340
+ comp.to("cuda")
341
+
342
+ _force_fixed_step_schedule(pipe.scheduler)
343
+
344
+ prompt = (
345
+ "The camera holds static as the scene continues naturally, with subtle "
346
+ "motion and realistic physics."
347
+ )
348
+ with torch.inference_mode():
349
+ # num_inference_steps is a no-op once _force_fixed_step_schedule has patched
350
+ # set_timesteps (it always substitutes the checkpoint's own t_list), but is
351
+ # passed for clarity. guidance_scale=1.0 disables CFG -- see docstring above.
352
+ # 13 frames (4n+1) keeps the smoke test quick; bump for a real quality check.
353
+ result = pipe(
354
+ prompt=prompt,
355
+ negative_prompt="",
356
+ image=cond_image,
357
+ num_frames=13,
358
+ height=256,
359
+ width=256,
360
+ num_inference_steps=4,
361
+ guidance_scale=1.0,
362
+ generator=torch.Generator(device="cuda").manual_seed(1234),
363
+ )
364
+ out_path = f"cosmos3_i2v4step_{fmt}_validate.mp4"
365
+ from diffusers.utils import export_to_video
366
+ export_to_video(result.video, out_path, fps=24)
367
+ print(f"[validate] Wrote {out_path}. Eyeball it for coherence with the conditioning image.")
368
+
369
+ del pipe, result
370
+ gc.collect()
371
+ torch.cuda.empty_cache()
372
+ except Exception as e:
373
+ import traceback
374
+ print(f"[validate] Render failed ({type(e).__name__}: {e}).")
375
+ print("[validate] This does NOT affect the quantized weights; export still proceeds below.")
376
+ print("[validate] If this is a TypeError about an unexpected keyword argument, that's real "
377
+ "signal about this checkpoint's actual pipe() call shape -- adjust the call above "
378
+ "(e.g. drop/rename kwargs) rather than assuming the defaults here were correct.")
379
+ traceback.print_exc()
380
+
381
+
382
+ if __name__ == "__main__":
383
+ main()
repackage_for_hf_i2v4step.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """
3
+ Re-save the in-memory quantized Cosmos3-Super-Image2Video-4Step transformer in the
4
+ ROUND-TRIPPABLE ModelOpt HF format and assemble a complete drop-in diffusers repo
5
+ around it. Sibling of repackage_for_hf.py -- identical logic, just imports the
6
+ build helpers from serve_cosmos3_i2v4step_diffusers instead (which targets
7
+ nvidia/Cosmos3-Super-Image2Video-4Step and drops the scheduler swap this
8
+ checkpoint doesn't want -- see that file's docstring).
9
+
10
+ Run in the ModelOpt venv, from the directory containing serve_cosmos3_i2v4step_diffusers.py:
11
+ CUDA_VISIBLE_DEVICES=0 python repackage_for_hf_i2v4step.py --format fp8 \
12
+ --serve-dir ./cosmos3-i2v4step-fp8-serve \
13
+ --out-dir ./cosmos3-i2v4step-fp8-hf \
14
+ [--cache ./cosmos3-i2v4step-cache]
15
+
16
+ Then verify the result loads + renders:
17
+ python -i load_cosmos3_modelopt.py ./cosmos3-i2v4step-fp8-hf
18
+ """
19
+ import argparse
20
+ import json
21
+ import os
22
+ import pathlib
23
+ import shutil
24
+
25
+ os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
26
+
27
+ import torch # noqa: F401 (ensures CUDA init / dtype availability)
28
+ from modelopt.torch.opt import enable_huggingface_checkpointing
29
+
30
+ from serve_cosmos3_i2v4step_diffusers import build_quantized_transformer, try_restore_quantized
31
+
32
+ QUANT_TYPE = {"fp8": "FP8", "nvfp4": "NVFP4"}
33
+
34
+
35
+ def ensure_loadable_config(transformer_dir: str, fmt: str) -> None:
36
+ """If save_pretrained wrote a quantization_config, make sure diffusers can construct
37
+ it: NVIDIAModelOptConfig needs `quant_type`, and a truthy `modelopt_config` avoids the
38
+ buggy get_config_from_quant_type() builder. (Structure restore itself comes from
39
+ modelopt_state.pth; this just keeps config parsing from crashing on load.)"""
40
+ cfg_path = pathlib.Path(transformer_dir) / "config.json"
41
+ cfg = json.loads(cfg_path.read_text())
42
+ qc = cfg.get("quantization_config")
43
+ if isinstance(qc, dict):
44
+ qc["quant_type"] = QUANT_TYPE[fmt]
45
+ qc.setdefault("weight_only", True)
46
+ if not qc.get("modelopt_config"):
47
+ qc["modelopt_config"] = {"quant_cfg": {}, "algorithm": "max"}
48
+ cfg["quantization_config"] = qc
49
+ cfg_path.write_text(json.dumps(cfg, indent=2))
50
+ print(f"[patch] quantization_config made loadable (quant_type={qc['quant_type']})")
51
+ else:
52
+ print("[patch] no embedded quantization_config; relying on modelopt_state.pth for restore")
53
+
54
+
55
+ def main() -> None:
56
+ ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
57
+ ap.add_argument("--format", choices=["fp8", "nvfp4"], default="fp8")
58
+ ap.add_argument("--serve-dir", required=True,
59
+ help="existing assembled pipeline dir (source of VAE / tokenizers / model_index.json)")
60
+ ap.add_argument("--out-dir", required=True, help="new drop-in repo dir to create")
61
+ ap.add_argument("--cache", default=None, help="optional mto cache dir for a faster rebuild")
62
+ ap.add_argument("--gpu-mem-fraction", type=float, default=0.85)
63
+ args = ap.parse_args()
64
+
65
+ model = try_restore_quantized(args.format, args.cache) if args.cache else None
66
+ if model is None:
67
+ model = build_quantized_transformer(args.format, args.gpu_mem_fraction)
68
+
69
+ enable_huggingface_checkpointing()
70
+ tdir = os.path.join(args.out_dir, "transformer")
71
+ os.makedirs(tdir, exist_ok=True)
72
+ print(f"[save] writing round-trippable transformer (+ modelopt_state.pth) -> {tdir}")
73
+ model.save_pretrained(tdir)
74
+ state_file = os.path.join(tdir, "modelopt_state.pth")
75
+ assert os.path.isfile(state_file), (
76
+ f"expected {state_file} to exist -- enable_huggingface_checkpointing() must run "
77
+ "before save_pretrained(); without modelopt_state.pth the repo won't load in diffusers"
78
+ )
79
+ ensure_loadable_config(tdir, args.format)
80
+
81
+ print(f"[assemble] copying non-transformer components from {args.serve_dir}")
82
+ for name in os.listdir(args.serve_dir):
83
+ if name == "transformer":
84
+ continue
85
+ src = os.path.join(args.serve_dir, name)
86
+ dst = os.path.join(args.out_dir, name)
87
+ if os.path.isdir(src):
88
+ shutil.copytree(src, dst, dirs_exist_ok=True)
89
+ else:
90
+ shutil.copy2(src, dst)
91
+
92
+ print(f"[done] drop-in repo -> {args.out_dir}")
93
+ print(f" verify: python -i load_cosmos3_modelopt.py {args.out_dir}")
94
+
95
+
96
+ if __name__ == "__main__":
97
+ main()
scheduler/scheduler_config.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_class_name": "FlowMatchEulerDiscreteScheduler",
3
+ "_diffusers_version": "0.39.0",
4
+ "base_image_seq_len": 256,
5
+ "base_shift": 0.5,
6
+ "fixed_step_requires_explicit_sigmas": true,
7
+ "fixed_step_sampler_config": {
8
+ "sample_type": "sde",
9
+ "t_list": [
10
+ 1.0,
11
+ 0.9375,
12
+ 0.8333333333333334,
13
+ 0.625
14
+ ]
15
+ },
16
+ "invert_sigmas": false,
17
+ "max_image_seq_len": 4096,
18
+ "max_shift": 1.15,
19
+ "num_train_timesteps": 1000,
20
+ "shift": 1.0,
21
+ "shift_terminal": null,
22
+ "stochastic_sampling": true,
23
+ "time_shift_type": "exponential",
24
+ "use_beta_sigmas": false,
25
+ "use_dynamic_shifting": false,
26
+ "use_exponential_sigmas": false,
27
+ "use_karras_sigmas": false
28
+ }
scripts/gen_video.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Minimal image-to-video generation against a vLLM-Omni endpoint (sync mode).
2
+
3
+ Run from the Cosmos3-Super-Image2Video-4Step repo root:
4
+
5
+ python scripts/gen_video.py \
6
+ --prompt-file assets/example_prompt.json \
7
+ --image-path assets/example_first_frame.png \
8
+ --output-path scripts/output.mp4
9
+
10
+ Use --endpoint http://<server-host>:8000 if the vLLM-Omni server is not local.
11
+ """
12
+
13
+ import argparse
14
+ import json
15
+ from pathlib import Path
16
+
17
+ import requests
18
+
19
+ # Fixed generation settings: 16:9 480p, 189 frames @ 24 fps.
20
+ ASPECT_RATIO = "16,9"
21
+ WIDTH = 832
22
+ HEIGHT = 480
23
+ NUM_FRAMES = 189
24
+ FPS = 24
25
+
26
+
27
+ def main() -> None:
28
+ parser = argparse.ArgumentParser(description="Generate one I2V sample (sync mode).")
29
+ parser.add_argument("--endpoint", default="http://localhost:8000", help="vLLM-Omni endpoint base URL.")
30
+ parser.add_argument("--prompt-file", type=Path, default=Path("assets/example_prompt.json"))
31
+ parser.add_argument("--image-path", type=Path, default=Path("assets/example_first_frame.png"))
32
+ parser.add_argument("--output-path", type=Path, default=Path("scripts/output.mp4"))
33
+ args = parser.parse_args()
34
+
35
+ spec = json.loads(args.prompt_file.read_text(encoding="utf-8"))
36
+ prompt = json.loads(spec["prompt"])
37
+ prompt["duration"] = f"{int(NUM_FRAMES / FPS)}s"
38
+ prompt["fps"] = float(round(FPS))
39
+ prompt["resolution"] = {"H": HEIGHT, "W": WIDTH}
40
+ prompt["aspect_ratio"] = ASPECT_RATIO
41
+
42
+ request_body = {
43
+ "prompt": json.dumps(prompt, ensure_ascii=False),
44
+ "negative_prompt": spec["negative_prompt"],
45
+ "size": f"{WIDTH}x{HEIGHT}",
46
+ "num_frames": NUM_FRAMES,
47
+ "fps": FPS,
48
+ "guidance_scale": 1.0,
49
+ "extra_params": json.dumps(
50
+ {
51
+ "guardrails": True,
52
+ "use_resolution_template": False,
53
+ "use_duration_template": False,
54
+ }
55
+ ),
56
+ }
57
+ files = {"input_reference": ("input.png", args.image_path.read_bytes(), "image/png")}
58
+ headers = {"Accept": "video/mp4", "User-Agent": "curl/8.5.0"}
59
+
60
+ endpoint = args.endpoint.rstrip("/")
61
+ response = requests.post(
62
+ f"{endpoint}/v1/videos/sync",
63
+ data=request_body,
64
+ files=files,
65
+ headers=headers,
66
+ timeout=(10, 600),
67
+ )
68
+ response.raise_for_status()
69
+
70
+ args.output_path.parent.mkdir(parents=True, exist_ok=True)
71
+ args.output_path.write_bytes(response.content)
72
+ print(f"Saved video to {args.output_path} ({len(response.content) / (1024 * 1024):.1f} MB)")
73
+
74
+
75
+ if __name__ == "__main__":
76
+ main()
scripts/upsample_prompt.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Minimal image-to-video prompt upsampler.
2
+
3
+ Run from the Cosmos3-Super-Image2Video-4Step repo root:
4
+
5
+ export PROMPT_UPSAMPLER_API_KEY="..."
6
+ python scripts/upsample_prompt.py \
7
+ --model-name <model> \
8
+ --base-url <VLM-endpoint-url> \
9
+ --image-path assets/example_first_frame.png \
10
+ --user-prompt "The dog flies into the outer space" \
11
+ --output-path scripts/upsampled.json
12
+ """
13
+
14
+ import argparse
15
+ import base64
16
+ import json
17
+ import mimetypes
18
+ import os
19
+ import re
20
+ from pathlib import Path
21
+
22
+ import requests
23
+
24
+ # Fixed generation settings: 16:9 480p, 189 frames @ 24 fps.
25
+ ASPECT_RATIO = "16,9"
26
+ WIDTH = 832
27
+ HEIGHT = 480
28
+ NUM_FRAMES = 189
29
+ FPS = 24
30
+
31
+ MAX_TOKENS = 8192
32
+
33
+ PROMPT_TEMPLATE = """You are an expert prompt engineer for an image-to-video generative model. You are given a STARTING FRAME image (the first frame of the video) and a USER INSTRUCTION describing the desired motion or changes to animate. Your task is to produce a dense, cinematic video description that the model will use to generate the full video, together with a customized negative prompt.
34
+
35
+ Complete this task in two phases.
36
+
37
+ ---
38
+ ### PHASE 1: VIDEO DESCRIPTION
39
+ Write a dense, narrative temporal_caption inside `<final_prompt>` XML tags, formatted as a JSON object using this exact template:
40
+
41
+ {
42
+ "temporal_caption": "...",
43
+ "duration": "placeholder",
44
+ "fps": "placeholder",
45
+ "resolution": {
46
+ "H": "placeholder",
47
+ "W": "placeholder"
48
+ },
49
+ "aspect_ratio": "placeholder"
50
+ }
51
+
52
+ Rules for the temporal_caption:
53
+ - The provided image is the exact starting frame - all described motion must be consistent with the starting frame.
54
+ - Opening: Establish the scene — subjects, environment, lighting — describing what is directly visible in the starting frame accurately and faithfully, noting essential elements that the motion will directly involve, the subject's orientation (e.g., "facing away", "in three-quarter profile"), and any implied ongoing motion (e.g., a cyclist leaning into a curve, water already splashing) so the video continues smoothly. Phrase it naturally as a scene description (do not say "in the starting frame", "initially shown", or similar meta-references).
55
+ - Motion: Describe the changes and actions in chronological order. Flow naturally from one action to the next. Advance time using natural conjunctions (e.g., "while," "as," "and").
56
+ - Physical Accuracy: All motion must obey gravity and reflect realistic material behavior (e.g., cloth ripples, water splashes, rigid objects resist deformation).
57
+ - Cause-and-effect: Always describe causes before their effects. Reflections, shadows, and secondary effects cannot appear on their own — the source object must first enter the frame or move into the relevant position before any reflection or shadow is described. E.g., a person must walk to the water's edge before their reflection appears on the surface; an object must strike the water before a splash erupts.
58
+ - Object Permanence: Every subject must persist throughout or have a clear reason for entering or exiting. When a new subject not present in the starting frame is introduced (e.g., an opposing team, an arriving vehicle), briefly describe their appearance (e.g., uniform color, vehicle type and color) so the generator can render them consistently, and describe a logical way for them to come into the frame (e.g., entering from a specific side of the frame, walking in through a door, or emerging from behind an existing object) rather than having them appear out of nowhere.
59
+ - Taboo Phrases: NEVER refer to the video medium itself. Avoid "the video shows...", "the scene...", "the clip...", "the frame...", "the camera shows...", "we see...".
60
+ - Perspective: Describe human body sides from the subject's own perspective (e.g., "her right hand" = the subject's right hand) to avoid ambiguity. This applies whenever a body part enters or moves in the frame: always specify whether it is the left or right (e.g., "his right hand reaches in from the lower edge"), never a bare "a hand enters the frame".
61
+ - Pronouns: Use singular pronouns ("he", "she", "him", "her", "it") or a singular noun phrase ("the person", "the rider", "the child") for single subjects. Never use "they"/"them"/"their" to refer to one person, as this can cause the model to render multiple subjects.
62
+ - Spatial Phrasing: Use spatial relationships for motion (e.g., "enters from the left", "rises above the horizon") rather than camera-centric descriptions.
63
+ - Camera: Include camera motion only if specified in the instruction; otherwise describe from a static viewpoint. Keep any described camera movement subtle and gradual — do not exaggerate altitude loss, tilt angle, or speed beyond what is minimally implied by the instruction. Do not use the word "transition" when describing camera motion.
64
+ - Cinematography Terms: When the instruction references a lens, camera, or filming technique (e.g., "probe lens", "macro lens", "fisheye", "drone shot", "GoPro"), treat it as a cinematographic style describing how the footage is captured — never as a physical object visible in the scene. Mention the style (e.g., for a probe lens: extreme close shot; for a fisheye lens: extreme wide angle fisheye view) rather than mentioning the lens or camera apparatus itself.
65
+ - Timelapse: If the instruction implies timelapse, explicitly use the word "timelapse" in the caption and avoid exaggerating its effects.
66
+ - Cuts & Montages: Always describe a single continuous shot with no hard cuts unless the user instruction explicitly used words like "cut", "hard cut", "jump cut", "shot change", or "montage". When multiple shots are requested without specifying an exact number, describe at most 3 shots, and dedicate the majority of the description to the opening action before any cut. Never use phrases like "the first shot", "the opening shot", or number shots as "first", "second", etc. — simply describe the action directly.
67
+ - Tone: Neutral, objective, descriptive. No opinions, value judgments, or inferred emotions unless physically observable.
68
+ - Length & Format: Write exactly ONE coherent paragraph of 5-8 sentences. No bullet points or lists.
69
+
70
+ USER INSTRUCTION:
71
+ "{nl_description}"
72
+
73
+ ---
74
+ ### PHASE 2: NEGATIVE PROMPT
75
+ Using your final video description from Phase 1, create a customized negative prompt.
76
+
77
+ HOW IT WORKS:
78
+ A negative prompt describes exactly what a bad video looks like. Use declarative statements (e.g., "blurry faces"). Never use negative instructions like "avoid" or "do not".
79
+
80
+ ---
81
+ DEFAULT NEGATIVE PROMPT:
82
+ The video captures a series of frames showing macroblocking artifacts, chromatic aberration, high-frequency noise, and rolling shutter distortion. It includes static with no motion, motion blur, over-saturation, shaky footage, low resolution, grainy texture, pixelated images, poorly lit areas, underexposed and overexposed scenes, poor color balance, washed out colors, choppy sequences, jerky movements, low frame rate, bit-depth compression artifacts, color banding, unnatural transitions, outdated special effects, fake elements, unconvincing visuals, poorly edited content, jump cuts, hard cut, visual noise, and flickering. It features moiré patterns, edge halos, and temporal aliasing. Furthermore, the content defies common sense, generating illogical scenarios, nonsensical entities, absurd character behaviors, and conceptual paradoxes that violate basic human reasoning and everyday reality. The video looks like a surreal or glitchy hallucination. Overall, the video is of poor quality.
83
+ ---
84
+
85
+ INSTRUCTIONS:
86
+ Delete any words from the default negative prompt that contradict your intended video. Keep most of the original wording and structure intact, and do not add new items. Examples:
87
+ * If you want scene cuts/montages -> REMOVE "jump cuts" and "hard cut".
88
+ * If you want a motionless/static scene -> REMOVE "static with no motion".
89
+ * If you want fantasy, sci-fi, or surrealism -> REMOVE "defies common sense", "illogical scenarios", "nonsensical entities", "surreal", and related logic-violation terms.
90
+ * If the scene has flickering light -> REMOVE "flickering".
91
+ * If it is a night-time timelapse -> REMOVE "motion blur".
92
+
93
+ Output only the final negative prompt as a single paragraph, wrapped in <negative_prompt> tags. Do not output any explanation or preamble."""
94
+
95
+
96
+ def image_to_data_url(path: Path) -> str:
97
+ """Encode a local image as a base64 data URL."""
98
+ mime = mimetypes.guess_type(path.name)[0] or "image/png"
99
+ encoded = base64.b64encode(path.read_bytes()).decode("ascii")
100
+ return f"data:{mime};base64,{encoded}"
101
+
102
+
103
+ def extract_tag(text: str, tag: str) -> str | None:
104
+ """Return the stripped inner text of the first <tag>...</tag> block, if present."""
105
+ match = re.search(rf"<{tag}>(.*?)</{tag}>", text, flags=re.DOTALL)
106
+ return match.group(1).strip() if match else None
107
+
108
+
109
+ def parse_args() -> argparse.Namespace:
110
+ parser = argparse.ArgumentParser(description="Upsample an image-to-video prompt with a VLM.")
111
+ parser.add_argument("--image-path", type=Path, default=Path("assets/example_first_frame.png"))
112
+ parser.add_argument("--user-prompt", default="The dog flies into the outer space")
113
+ parser.add_argument("--output-path", type=Path, default=Path("scripts/upsampled.json"))
114
+ parser.add_argument("--model-name", required=True)
115
+ parser.add_argument("--base-url", required=True, metavar="<VLM-endpoint-url>")
116
+ return parser.parse_args()
117
+
118
+
119
+ def invoke_vlm(image_path: Path, user_prompt: str, model_name: str, base_url: str) -> str:
120
+ """Call an OpenAI-compatible chat completions endpoint and return the assistant text."""
121
+ payload = {
122
+ "model": model_name,
123
+ "max_tokens": MAX_TOKENS,
124
+ "messages": [
125
+ {
126
+ "role": "user",
127
+ "content": [
128
+ {"type": "image_url", "image_url": {"url": image_to_data_url(image_path)}},
129
+ {"type": "text", "text": PROMPT_TEMPLATE.replace("{nl_description}", user_prompt.strip())},
130
+ ],
131
+ }
132
+ ],
133
+ }
134
+ headers = {"Authorization": f"Bearer {os.environ['PROMPT_UPSAMPLER_API_KEY']}"}
135
+ response = requests.post(f"{base_url.rstrip('/')}/chat/completions", json=payload, headers=headers)
136
+ response.raise_for_status()
137
+ return response.json()["choices"][0]["message"]["content"]
138
+
139
+
140
+ def main() -> None:
141
+ args = parse_args()
142
+ content = invoke_vlm(args.image_path, args.user_prompt, args.model_name, args.base_url)
143
+
144
+ final_prompt = extract_tag(content, "final_prompt")
145
+ if final_prompt is None:
146
+ raise RuntimeError(f"Response missing <final_prompt> block:\n{content}")
147
+
148
+ # Pin the output parameters post-hoc (the template leaves them as placeholders).
149
+ data = json.loads(final_prompt)
150
+ data["duration"] = f"{int(NUM_FRAMES / FPS)}s"
151
+ data["fps"] = float(round(FPS))
152
+ data["resolution"] = {"H": HEIGHT, "W": WIDTH}
153
+ data["aspect_ratio"] = ASPECT_RATIO
154
+
155
+ record: dict = {"prompt": json.dumps(data, ensure_ascii=False)}
156
+ negative = extract_tag(content, "negative_prompt")
157
+ if negative:
158
+ record["negative_prompt"] = negative
159
+
160
+ args.output_path.parent.mkdir(parents=True, exist_ok=True)
161
+ args.output_path.write_text(json.dumps(record, ensure_ascii=False), encoding="utf-8")
162
+ print(f"PROMPT:\n{record['prompt']}")
163
+ print(f"\nNEGATIVE PROMPT:\n{record.get('negative_prompt', '')}")
164
+ print(f"\nWrote {args.output_path}")
165
+
166
+
167
+ if __name__ == "__main__":
168
+ main()
serve_cosmos3_i2v4step_diffusers.py ADDED
@@ -0,0 +1,449 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """
3
+ Local generation server for your quantized Cosmos3-Super-Image2Video-4Step, built on
4
+ the *validated* diffusers path (NOT vLLM-Omni). Sibling of serve_cosmos3_diffusers.py
5
+ (the nvidia/Cosmos3-Super base-model server) -- same build recipe, adapted for three
6
+ real differences in this checkpoint:
7
+
8
+ 1. NO /generate (text -> still) ENDPOINT. This checkpoint is Image2Video-specific
9
+ (unlike the T2I/T2V/I2V-omni base model); NVIDIA's docs never demonstrate a
10
+ text-only call for it, and there's no local way to verify one works without
11
+ the checkpoint in hand. Rather than ship a silently-untested endpoint, this
12
+ server exposes /animate only. If a text-only path turns out to work when you
13
+ test it, port /generate over from serve_cosmos3_diffusers.py at that point.
14
+ 2. NO SCHEDULER OBJECT SWAP, BUT A PATCHED set_timesteps. serve_cosmos3_diffusers.py
15
+ replaces the shipped scheduler with UniPCMultistepScheduler(flow_shift=...); this
16
+ checkpoint instead keeps FlowMatchEulerDiscreteScheduler as shipped (do not swap
17
+ it) but needs one targeted patch: Cosmos3OmniPipeline.__call__ always calls
18
+ scheduler.set_timesteps(num_inference_steps, device=device) with no passthrough
19
+ for this checkpoint's scheduler_config.json fixed_step_sampler_config (verified by
20
+ running it -- an unpatched call silently executed the pipeline's 35-step default
21
+ instead of the checkpoint's trained 4-step sde schedule). make_pipeline() below
22
+ applies _force_fixed_step_schedule() to fix this.
23
+ 3. NO num_inference_steps IN THE REQUEST; guidance_scale IS FIXED AT 1.0. Per
24
+ NVIDIA's model card these are fixed by the distilled checkpoint -- CFG is
25
+ distilled out (do_classifier_free_guidance is guidance_scale != 1.0 in the
26
+ pipeline source, so the 6.0 pipeline default would silently re-enable it) and
27
+ the step count comes from the scheduler patch above, not from the caller.
28
+
29
+ ENDPOINTS
30
+ ---------
31
+ GET /health -> readiness + which format is loaded
32
+ POST /animate -> image -> video (multipart upload; returns MP4, or GIF if no
33
+ mp4 encoder is installed)
34
+
35
+ USAGE
36
+ -----
37
+ CUDA_VISIBLE_DEVICES=0 python serve_cosmos3_i2v4step_diffusers.py --repo prometheusAIR/Cosmos3-I2V4Step-fp8
38
+ CUDA_VISIBLE_DEVICES=0 python serve_cosmos3_i2v4step_diffusers.py --repo ./cosmos3-i2v4step-fp8-hf
39
+
40
+ # or rebuild from the bf16 source (the original streaming path):
41
+ CUDA_VISIBLE_DEVICES=0 python serve_cosmos3_i2v4step_diffusers.py --format fp8
42
+ CUDA_VISIBLE_DEVICES=0 python serve_cosmos3_i2v4step_diffusers.py --format fp8 --cache ./cosmos3-i2v4step-cache
43
+
44
+ Image -> video:
45
+ curl -s -X POST http://localhost:8000/animate \
46
+ -F image=@out.png \
47
+ -F 'prompt=The robotic arm slowly lowers its gripper toward the objects and holds. Static camera.' \
48
+ -F num_frames=49 -F fps=24 \
49
+ --output clip.mp4
50
+
51
+ Health:
52
+ curl -s http://localhost:8000/health
53
+ """
54
+
55
+ import argparse
56
+ import asyncio
57
+ import contextlib
58
+ import gc
59
+ import io
60
+ import os
61
+ import tempfile
62
+
63
+ os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
64
+
65
+ import torch
66
+ from accelerate import init_empty_weights, load_checkpoint_in_model
67
+ from accelerate.utils import get_max_memory, infer_auto_device_map
68
+ from accelerate.utils.dataclasses import CustomDtype
69
+ from fastapi import FastAPI, File, Form, UploadFile
70
+ from fastapi.responses import Response
71
+ from huggingface_hub import snapshot_download
72
+ from PIL import Image
73
+ from pydantic import BaseModel
74
+
75
+ import modelopt.torch.quantization as mtq
76
+ from diffusers import Cosmos3OmniTransformer
77
+ from diffusers.utils import export_to_gif, export_to_video
78
+
79
+ SRC_REPO = "nvidia/Cosmos3-Super-Image2Video-4Step"
80
+
81
+ SPARE_SUBSTRINGS = [
82
+ "time_embedder", "proj_in", "proj_out", "lm_head", "embed", "norm", "audio_proj",
83
+ ]
84
+
85
+
86
+ def _is_spare(name: str) -> bool:
87
+ return any(s in name for s in SPARE_SUBSTRINGS)
88
+
89
+
90
+ def build_quant_cfg(fmt: str) -> dict:
91
+ if fmt == "fp8":
92
+ return {
93
+ "quant_cfg": {
94
+ "*weight_quantizer": {"num_bits": (4, 3), "axis": None, "enable": True},
95
+ "*input_quantizer": {"enable": False},
96
+ "*output_quantizer": {"enable": False},
97
+ "*softmax_quantizer": {"enable": False},
98
+ },
99
+ "algorithm": "max",
100
+ }
101
+ if fmt == "nvfp4":
102
+ import copy
103
+ # Return the base preset UNMODIFIED -- on this installed modelopt version,
104
+ # W4A16_NVFP4_CFG's quant_cfg is a LIST (newer format), not the dict this
105
+ # function used to assume (confirmed empirically: "TypeError: list indices
106
+ # must be integers or slices, not str" trying dict-style key assignment
107
+ # here). enforce_weight_only_and_spare() below disables activations/spares
108
+ # on the model's actual inserted quantizer modules AFTER mtq.quantize(),
109
+ # which is config-form agnostic -- no need to pre-bake into the config dict.
110
+ # load_cosmos3_modelopt.py's loader re-applies the same disabling on every
111
+ # restore anyway (modelopt_state replays the config, not our imperative
112
+ # .disable() calls), so skipping the pre-bake here loses nothing.
113
+ base = getattr(mtq, "W4A16_NVFP4_CFG", None) or mtq.NVFP4_DEFAULT_CFG
114
+ return copy.deepcopy(base)
115
+ raise ValueError(f"Unknown format: {fmt!r}")
116
+
117
+
118
+ def enforce_weight_only_and_spare(model) -> tuple[int, int]:
119
+ n_spare = n_act = 0
120
+ for name, module in model.named_modules():
121
+ if not (name.endswith("_quantizer") and hasattr(module, "disable")):
122
+ continue
123
+ if name.endswith("weight_quantizer"):
124
+ if _is_spare(name.rsplit(".", 1)[0]):
125
+ module.disable()
126
+ n_spare += 1
127
+ else:
128
+ module.disable()
129
+ n_act += 1
130
+ return n_spare, n_act
131
+
132
+
133
+ def compressed_device_map(model, gpu_mem_fraction: float = 0.85) -> dict:
134
+ max_memory = {k: v * gpu_mem_fraction for k, v in get_max_memory().items()}
135
+ no_split = set()
136
+ for name, module in model.named_modules():
137
+ if name.endswith((".layers.0", ".blocks.0", ".transformer_blocks.0")):
138
+ no_split.add(module.__class__.__name__)
139
+ special_dtypes = {}
140
+ for name, module in model.named_modules():
141
+ if (
142
+ hasattr(module, "weight")
143
+ and hasattr(module, "weight_quantizer")
144
+ and getattr(module.weight_quantizer, "is_enabled", True)
145
+ and not getattr(module.weight_quantizer, "fake_quant", True)
146
+ ):
147
+ nb = module.weight_quantizer.num_bits
148
+ if isinstance(nb, tuple):
149
+ nb = nb[0] + nb[1] + 1
150
+ special_dtypes[name + ".weight"] = CustomDtype.FP8 if nb == 8 else CustomDtype.INT4
151
+ return infer_auto_device_map(
152
+ model, max_memory=max_memory,
153
+ no_split_module_classes=list(no_split), special_dtypes=special_dtypes,
154
+ )
155
+
156
+
157
+ def _materialize_residual_meta(model) -> int:
158
+ n = 0
159
+ for _, module in model.named_modules():
160
+ for bn, buf in list(module._buffers.items()):
161
+ if buf is not None and getattr(buf, "is_meta", False):
162
+ module._buffers[bn] = torch.zeros(buf.shape, dtype=buf.dtype, device="cuda")
163
+ n += 1
164
+ for pn, par in list(module._parameters.items()):
165
+ if par is not None and getattr(par, "is_meta", False):
166
+ module._parameters[pn] = torch.nn.Parameter(
167
+ torch.zeros(par.shape, dtype=par.dtype, device="cuda"), requires_grad=False
168
+ )
169
+ n += 1
170
+ return n
171
+
172
+
173
+ def _transformer_dir() -> str:
174
+ local_root = snapshot_download(SRC_REPO, allow_patterns=["transformer/*"])
175
+ return os.path.join(local_root, "transformer")
176
+
177
+
178
+ def build_quantized_transformer(fmt: str, gpu_mem_fraction: float = 0.85):
179
+ """The proven path: empty-on-meta -> quantize -> compress -> stream shards in."""
180
+ transformer_dir = _transformer_dir()
181
+ print(f"[build] empty transformer on meta from {transformer_dir}")
182
+ config = Cosmos3OmniTransformer.load_config(transformer_dir)
183
+ with init_empty_weights(include_buffers=False):
184
+ model = Cosmos3OmniTransformer.from_config(config)
185
+
186
+ print(f"[build] inserting weight-only {fmt} quantizers")
187
+ mtq.quantize(model, build_quant_cfg(fmt))
188
+ n_spare, n_act = enforce_weight_only_and_spare(model)
189
+ print(f"[build] weight-only: disabled {n_act} activation quantizers; {n_spare} spare weight layers")
190
+
191
+ print("[build] setting up compressed parameter shapes")
192
+ try:
193
+ mtq.compress(model, config=mtq.CompressConfig(quant_gemm=False))
194
+ except (AttributeError, TypeError):
195
+ mtq.compress(model)
196
+
197
+ print("[build] streaming BF16 shards into compressed form (slow step)")
198
+ load_checkpoint_in_model(
199
+ model, checkpoint=transformer_dir,
200
+ device_map=compressed_device_map(model, gpu_mem_fraction), dtype=torch.bfloat16,
201
+ )
202
+ fixed = _materialize_residual_meta(model)
203
+ if fixed:
204
+ print(f"[build] materialized {fixed} residual meta tensors")
205
+ return model
206
+
207
+
208
+ # --- optional fast-restart cache (modelopt_state + weights, per ModelOpt docs) ----------
209
+ def _cache_paths(cache_dir: str, fmt: str):
210
+ return (os.path.join(cache_dir, f"modelopt_state_{fmt}.pt"),
211
+ os.path.join(cache_dir, f"weights_{fmt}.pt"))
212
+
213
+
214
+ def save_quantized(model, fmt: str, cache_dir: str) -> None:
215
+ try:
216
+ from modelopt.torch.opt import modelopt_state
217
+ except ImportError:
218
+ from modelopt.torch.opt.conversion import modelopt_state
219
+ os.makedirs(cache_dir, exist_ok=True)
220
+ state_path, weights_path = _cache_paths(cache_dir, fmt)
221
+ print(f"[cache] writing {state_path} + {weights_path} (large; one time)")
222
+ torch.save(modelopt_state(model), state_path)
223
+ torch.save(model.state_dict(), weights_path)
224
+
225
+
226
+ def try_restore_quantized(fmt: str, cache_dir: str):
227
+ state_path, weights_path = _cache_paths(cache_dir, fmt)
228
+ if not (os.path.isfile(state_path) and os.path.isfile(weights_path)):
229
+ return None
230
+ try:
231
+ try:
232
+ from modelopt.torch.opt import restore_from_modelopt_state
233
+ except ImportError:
234
+ from modelopt.torch.opt.conversion import restore_from_modelopt_state
235
+ print(f"[cache] restoring from {state_path}")
236
+ config = Cosmos3OmniTransformer.load_config(_transformer_dir())
237
+ with init_empty_weights(include_buffers=False):
238
+ model = Cosmos3OmniTransformer.from_config(config)
239
+ state = torch.load(state_path, map_location="cpu", weights_only=False)
240
+ restore_from_modelopt_state(model, state)
241
+ weights = torch.load(weights_path, map_location="cpu", weights_only=False)
242
+ model.load_state_dict(weights, strict=False, assign=True)
243
+ _materialize_residual_meta(model)
244
+ print("[cache] restore OK")
245
+ return model
246
+ except Exception as e:
247
+ import traceback
248
+ print(f"[cache] restore failed ({type(e).__name__}: {e}); falling back to full rebuild")
249
+ traceback.print_exc()
250
+ return None
251
+
252
+
253
+ def _force_fixed_step_schedule(scheduler) -> bool:
254
+ """See module docstring point 2. Patches THIS scheduler instance's set_timesteps
255
+ to always use the checkpoint's own fixed_step_sampler_config.t_list, regardless of
256
+ whatever num_inference_steps Cosmos3OmniPipeline.__call__ passes in internally.
257
+
258
+ ALSO disables stochastic_sampling (forces the deterministic ODE branch) -- CONFIRMED
259
+ by direct A/B render (same seed/image/prompt), not speculative. This checkpoint's
260
+ scheduler ships stochastic_sampling=True (SDE). Cosmos3's image-conditioning anchors
261
+ frame 0 by zeroing the model's predicted velocity there; that only means "leave this
262
+ position unchanged" under the deterministic step (prev_sample = sample + dt*0). The
263
+ SDE branch instead computes x0 = sample - current_sigma*model_output (= sample when
264
+ velocity is 0), then prev_sample = (1-next_sigma)*x0 + next_sigma*randn_tensor(...) --
265
+ it re-noises by next_sigma regardless of velocity, with no zero-velocity no-op. Over
266
+ this checkpoint's 4 steps that compounds to ~99.6% fresh noise in the conditioned
267
+ frame by the end: the input image comes out as colorful static while the genuinely
268
+ denoised motion frames still look like a plausible video. Disabling stochastic_
269
+ sampling restores the correct zero-velocity-is-a-no-op behavior."""
270
+ cfg = getattr(scheduler.config, "fixed_step_sampler_config", None)
271
+ t_list = cfg.get("t_list") if isinstance(cfg, dict) else None
272
+ if not t_list:
273
+ print("[warn] no fixed_step_sampler_config.t_list on this scheduler; leaving set_timesteps unpatched")
274
+ return False
275
+ _orig = scheduler.set_timesteps
276
+
277
+ def _patched(num_inference_steps=None, device=None, sigmas=None, mu=None, timesteps=None):
278
+ return _orig(sigmas=list(t_list), device=device)
279
+
280
+ scheduler.set_timesteps = _patched
281
+ if getattr(scheduler.config, "stochastic_sampling", False):
282
+ scheduler.register_to_config(stochastic_sampling=False)
283
+ print("[build] disabled stochastic_sampling (SDE re-noising corrupts the "
284
+ "image-conditioned frame -- see docstring)")
285
+ print(f"[build] forced fixed {len(t_list)}-step sde schedule: {t_list}")
286
+ return True
287
+
288
+
289
+ # --- pipeline assembly --------------------------------------------------------------
290
+ def make_pipeline(model):
291
+ from diffusers import Cosmos3OmniPipeline
292
+
293
+ model.to("cuda")
294
+ for m in model.modules():
295
+ for bn, buf in list(m._buffers.items()):
296
+ if buf is not None and buf.dtype == torch.float32:
297
+ m._buffers[bn] = buf.to(torch.bfloat16)
298
+
299
+ def _cast_bf16(_m, args):
300
+ return tuple(
301
+ a.to(torch.bfloat16)
302
+ if torch.is_tensor(a) and a.is_floating_point() and a.dtype != torch.bfloat16 else a
303
+ for a in args
304
+ )
305
+
306
+ for name, m in model.named_modules():
307
+ if "time_embedder" in name and hasattr(m, "linear_1"):
308
+ m.register_forward_pre_hook(_cast_bf16)
309
+
310
+ pipe = Cosmos3OmniPipeline.from_pretrained(
311
+ SRC_REPO, transformer=model, torch_dtype=torch.bfloat16,
312
+ enable_safety_checker=False, # local single-user server; revisit if exposing it
313
+ )
314
+ # Keep the shipped FlowMatchEulerDiscreteScheduler object, but patch its
315
+ # set_timesteps to actually honor the checkpoint's fixed 4-step sde schedule.
316
+ _force_fixed_step_schedule(pipe.scheduler)
317
+ for name, comp in pipe.components.items():
318
+ if name != "transformer" and isinstance(comp, torch.nn.Module):
319
+ comp.to("cuda")
320
+ return pipe
321
+
322
+
323
+ # --- HTTP server ------------------------------------------------------------------------
324
+ STATE: dict = {}
325
+ _gen_lock = asyncio.Lock() # one generation at a time on a single GPU
326
+
327
+
328
+ def _run_i2v(pil_image, prompt, negative_prompt, num_frames, fps, height, width, seed) -> tuple[bytes, str]:
329
+ pipe = STATE["pipe"]
330
+ image = pil_image.convert("RGB") # the pipeline resizes this to (height, width)
331
+ gen = torch.Generator(device="cuda").manual_seed(int(seed)) if seed >= 0 else None
332
+ with torch.inference_mode():
333
+ # num_inference_steps is a no-op once _force_fixed_step_schedule has patched
334
+ # the scheduler (it always substitutes the checkpoint's own t_list).
335
+ # guidance_scale=1.0 disables CFG -- see module docstring point 3.
336
+ result = pipe(
337
+ prompt=prompt, negative_prompt=negative_prompt,
338
+ image=image, num_frames=num_frames, fps=fps,
339
+ height=height, width=width,
340
+ num_inference_steps=4, guidance_scale=1.0,
341
+ generator=gen, output_type="pil",
342
+ )
343
+ frames = result.video
344
+ try:
345
+ with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tf:
346
+ path = tf.name
347
+ export_to_video(frames, path, fps=int(round(fps)))
348
+ media = "video/mp4"
349
+ except Exception: # no mp4 backend installed -> GIF (PIL-only, always works)
350
+ with tempfile.NamedTemporaryFile(suffix=".gif", delete=False) as tf:
351
+ path = tf.name
352
+ export_to_gif(frames, path)
353
+ media = "image/gif"
354
+ data = open(path, "rb").read()
355
+ os.remove(path)
356
+ del result
357
+ gc.collect()
358
+ torch.cuda.empty_cache()
359
+ return data, media
360
+
361
+
362
+ @contextlib.asynccontextmanager
363
+ async def lifespan(app: FastAPI):
364
+ fmt = STATE["fmt"]
365
+ repo = STATE.get("repo")
366
+ if repo:
367
+ from load_cosmos3_modelopt import load_pipe
368
+
369
+ path = repo
370
+ if not os.path.isdir(path):
371
+ from huggingface_hub import snapshot_download as _snap
372
+ print(f"[serve] fetching full snapshot of {repo} from the Hub ...")
373
+ path = _snap(repo)
374
+ print(f"[serve] loading drop-in checkpoint: {path}")
375
+ pipe = load_pipe(path)
376
+ # load_cosmos3_modelopt.load_pipe() is shared with the base model and doesn't
377
+ # know about this checkpoint's fixed-step schedule -- patch it here instead.
378
+ _force_fixed_step_schedule(pipe.scheduler)
379
+ STATE["pipe"] = pipe
380
+ print(f"[serve] ready (drop-in: {repo}, {fmt.upper()} assumed from repo contents)")
381
+ yield
382
+ STATE.clear()
383
+ return
384
+ cache_dir = STATE.get("cache_dir")
385
+ model = None
386
+ if cache_dir:
387
+ model = try_restore_quantized(fmt, cache_dir)
388
+ if model is None:
389
+ model = build_quantized_transformer(fmt, STATE["gpu_mem_fraction"])
390
+ if cache_dir:
391
+ try:
392
+ save_quantized(model, fmt, cache_dir)
393
+ except Exception as e:
394
+ print(f"[cache] save failed ({type(e).__name__}: {e}); continuing without cache")
395
+ STATE["pipe"] = make_pipeline(model)
396
+ print(f"[ready] serving {fmt.upper()} Cosmos3-Super-Image2Video-4Step on diffusers")
397
+ yield
398
+ STATE.clear()
399
+
400
+
401
+ app = FastAPI(lifespan=lifespan)
402
+
403
+
404
+ @app.get("/health")
405
+ async def health():
406
+ return {"status": "ok" if "pipe" in STATE else "loading", "format": STATE.get("fmt")}
407
+
408
+
409
+ @app.post("/animate")
410
+ async def animate(
411
+ image: UploadFile = File(...),
412
+ prompt: str = Form(...),
413
+ negative_prompt: str = Form(""),
414
+ num_frames: int = Form(49), # ~2.04s @ 24fps; 4n+1 maps cleanly to the VAE's 4x temporal compression
415
+ fps: float = Form(24.0),
416
+ height: int = Form(1024),
417
+ width: int = Form(1024),
418
+ seed: int = Form(1234), # pass -1 for a random clip each call
419
+ ):
420
+ pil = Image.open(io.BytesIO(await image.read()))
421
+ async with _gen_lock:
422
+ loop = asyncio.get_running_loop()
423
+ data, media = await loop.run_in_executor(
424
+ None, _run_i2v, pil, prompt, negative_prompt, num_frames, fps, height, width, seed,
425
+ )
426
+ return Response(content=data, media_type=media)
427
+
428
+
429
+ if __name__ == "__main__":
430
+ ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
431
+ ap.add_argument("--format", choices=["fp8", "nvfp4"], default="fp8")
432
+ ap.add_argument("--repo", default=None,
433
+ help="Serve a published drop-in checkpoint: an HF repo id or a local "
434
+ "repackaged dir. Skips the bf16 rebuild entirely; requires "
435
+ "load_cosmos3_modelopt.py next to this file.")
436
+ ap.add_argument("--host", default="0.0.0.0")
437
+ ap.add_argument("--port", type=int, default=8000)
438
+ ap.add_argument("--gpu-mem-fraction", type=float, default=0.85)
439
+ ap.add_argument("--cache", default=None,
440
+ help="Dir for a fast-restart cache. First boot rebuilds + writes it; "
441
+ "later boots restore from it. Any restore error -> full rebuild.")
442
+ args = ap.parse_args()
443
+
444
+ STATE.update(
445
+ fmt=args.format, gpu_mem_fraction=args.gpu_mem_fraction, cache_dir=args.cache, repo=args.repo,
446
+ )
447
+
448
+ import uvicorn
449
+ uvicorn.run(app, host=args.host, port=args.port)
text_tokenizer/added_tokens.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "</think>": 151668,
3
+ "</tool_call>": 151658,
4
+ "</tool_response>": 151666,
5
+ "<think>": 151667,
6
+ "<tool_call>": 151657,
7
+ "<tool_response>": 151665,
8
+ "<|box_end|>": 151649,
9
+ "<|box_start|>": 151648,
10
+ "<|endoftext|>": 151643,
11
+ "<|file_sep|>": 151664,
12
+ "<|fim_middle|>": 151660,
13
+ "<|fim_pad|>": 151662,
14
+ "<|fim_prefix|>": 151659,
15
+ "<|fim_suffix|>": 151661,
16
+ "<|im_end|>": 151645,
17
+ "<|im_start|>": 151644,
18
+ "<|image_pad|>": 151655,
19
+ "<|object_ref_end|>": 151647,
20
+ "<|object_ref_start|>": 151646,
21
+ "<|quad_end|>": 151651,
22
+ "<|quad_start|>": 151650,
23
+ "<|repo_name|>": 151663,
24
+ "<|video_pad|>": 151656,
25
+ "<|vision_end|>": 151653,
26
+ "<|vision_pad|>": 151654,
27
+ "<|vision_start|>": 151652
28
+ }
text_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 %}
text_tokenizer/merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
text_tokenizer/special_tokens_map.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<|im_start|>",
4
+ "<|im_end|>",
5
+ "<|object_ref_start|>",
6
+ "<|object_ref_end|>",
7
+ "<|box_start|>",
8
+ "<|box_end|>",
9
+ "<|quad_start|>",
10
+ "<|quad_end|>",
11
+ "<|vision_start|>",
12
+ "<|vision_end|>",
13
+ "<|vision_pad|>",
14
+ "<|image_pad|>",
15
+ "<|video_pad|>"
16
+ ],
17
+ "eos_token": {
18
+ "content": "<|im_end|>",
19
+ "lstrip": false,
20
+ "normalized": false,
21
+ "rstrip": false,
22
+ "single_word": false
23
+ },
24
+ "pad_token": {
25
+ "content": "<|endoftext|>",
26
+ "lstrip": false,
27
+ "normalized": false,
28
+ "rstrip": false,
29
+ "single_word": false
30
+ }
31
+ }
text_tokenizer/tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:aeb13307a71acd8fe81861d94ad54ab689df773318809eed3cbe794b4492dae4
3
+ size 11422654
text_tokenizer/tokenizer_config.json ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_bos_token": false,
3
+ "add_prefix_space": false,
4
+ "added_tokens_decoder": {
5
+ "151643": {
6
+ "content": "<|endoftext|>",
7
+ "lstrip": false,
8
+ "normalized": false,
9
+ "rstrip": false,
10
+ "single_word": false,
11
+ "special": true
12
+ },
13
+ "151644": {
14
+ "content": "<|im_start|>",
15
+ "lstrip": false,
16
+ "normalized": false,
17
+ "rstrip": false,
18
+ "single_word": false,
19
+ "special": true
20
+ },
21
+ "151645": {
22
+ "content": "<|im_end|>",
23
+ "lstrip": false,
24
+ "normalized": false,
25
+ "rstrip": false,
26
+ "single_word": false,
27
+ "special": true
28
+ },
29
+ "151646": {
30
+ "content": "<|object_ref_start|>",
31
+ "lstrip": false,
32
+ "normalized": false,
33
+ "rstrip": false,
34
+ "single_word": false,
35
+ "special": true
36
+ },
37
+ "151647": {
38
+ "content": "<|object_ref_end|>",
39
+ "lstrip": false,
40
+ "normalized": false,
41
+ "rstrip": false,
42
+ "single_word": false,
43
+ "special": true
44
+ },
45
+ "151648": {
46
+ "content": "<|box_start|>",
47
+ "lstrip": false,
48
+ "normalized": false,
49
+ "rstrip": false,
50
+ "single_word": false,
51
+ "special": true
52
+ },
53
+ "151649": {
54
+ "content": "<|box_end|>",
55
+ "lstrip": false,
56
+ "normalized": false,
57
+ "rstrip": false,
58
+ "single_word": false,
59
+ "special": true
60
+ },
61
+ "151650": {
62
+ "content": "<|quad_start|>",
63
+ "lstrip": false,
64
+ "normalized": false,
65
+ "rstrip": false,
66
+ "single_word": false,
67
+ "special": true
68
+ },
69
+ "151651": {
70
+ "content": "<|quad_end|>",
71
+ "lstrip": false,
72
+ "normalized": false,
73
+ "rstrip": false,
74
+ "single_word": false,
75
+ "special": true
76
+ },
77
+ "151652": {
78
+ "content": "<|vision_start|>",
79
+ "lstrip": false,
80
+ "normalized": false,
81
+ "rstrip": false,
82
+ "single_word": false,
83
+ "special": true
84
+ },
85
+ "151653": {
86
+ "content": "<|vision_end|>",
87
+ "lstrip": false,
88
+ "normalized": false,
89
+ "rstrip": false,
90
+ "single_word": false,
91
+ "special": true
92
+ },
93
+ "151654": {
94
+ "content": "<|vision_pad|>",
95
+ "lstrip": false,
96
+ "normalized": false,
97
+ "rstrip": false,
98
+ "single_word": false,
99
+ "special": true
100
+ },
101
+ "151655": {
102
+ "content": "<|image_pad|>",
103
+ "lstrip": false,
104
+ "normalized": false,
105
+ "rstrip": false,
106
+ "single_word": false,
107
+ "special": true
108
+ },
109
+ "151656": {
110
+ "content": "<|video_pad|>",
111
+ "lstrip": false,
112
+ "normalized": false,
113
+ "rstrip": false,
114
+ "single_word": false,
115
+ "special": true
116
+ },
117
+ "151657": {
118
+ "content": "<tool_call>",
119
+ "lstrip": false,
120
+ "normalized": false,
121
+ "rstrip": false,
122
+ "single_word": false,
123
+ "special": false
124
+ },
125
+ "151658": {
126
+ "content": "</tool_call>",
127
+ "lstrip": false,
128
+ "normalized": false,
129
+ "rstrip": false,
130
+ "single_word": false,
131
+ "special": false
132
+ },
133
+ "151659": {
134
+ "content": "<|fim_prefix|>",
135
+ "lstrip": false,
136
+ "normalized": false,
137
+ "rstrip": false,
138
+ "single_word": false,
139
+ "special": false
140
+ },
141
+ "151660": {
142
+ "content": "<|fim_middle|>",
143
+ "lstrip": false,
144
+ "normalized": false,
145
+ "rstrip": false,
146
+ "single_word": false,
147
+ "special": false
148
+ },
149
+ "151661": {
150
+ "content": "<|fim_suffix|>",
151
+ "lstrip": false,
152
+ "normalized": false,
153
+ "rstrip": false,
154
+ "single_word": false,
155
+ "special": false
156
+ },
157
+ "151662": {
158
+ "content": "<|fim_pad|>",
159
+ "lstrip": false,
160
+ "normalized": false,
161
+ "rstrip": false,
162
+ "single_word": false,
163
+ "special": false
164
+ },
165
+ "151663": {
166
+ "content": "<|repo_name|>",
167
+ "lstrip": false,
168
+ "normalized": false,
169
+ "rstrip": false,
170
+ "single_word": false,
171
+ "special": false
172
+ },
173
+ "151664": {
174
+ "content": "<|file_sep|>",
175
+ "lstrip": false,
176
+ "normalized": false,
177
+ "rstrip": false,
178
+ "single_word": false,
179
+ "special": false
180
+ },
181
+ "151665": {
182
+ "content": "<tool_response>",
183
+ "lstrip": false,
184
+ "normalized": false,
185
+ "rstrip": false,
186
+ "single_word": false,
187
+ "special": false
188
+ },
189
+ "151666": {
190
+ "content": "</tool_response>",
191
+ "lstrip": false,
192
+ "normalized": false,
193
+ "rstrip": false,
194
+ "single_word": false,
195
+ "special": false
196
+ },
197
+ "151667": {
198
+ "content": "<think>",
199
+ "lstrip": false,
200
+ "normalized": false,
201
+ "rstrip": false,
202
+ "single_word": false,
203
+ "special": false
204
+ },
205
+ "151668": {
206
+ "content": "</think>",
207
+ "lstrip": false,
208
+ "normalized": false,
209
+ "rstrip": false,
210
+ "single_word": false,
211
+ "special": false
212
+ }
213
+ },
214
+ "additional_special_tokens": [
215
+ "<|im_start|>",
216
+ "<|im_end|>",
217
+ "<|object_ref_start|>",
218
+ "<|object_ref_end|>",
219
+ "<|box_start|>",
220
+ "<|box_end|>",
221
+ "<|quad_start|>",
222
+ "<|quad_end|>",
223
+ "<|vision_start|>",
224
+ "<|vision_end|>",
225
+ "<|vision_pad|>",
226
+ "<|image_pad|>",
227
+ "<|video_pad|>"
228
+ ],
229
+ "bos_token": null,
230
+ "clean_up_tokenization_spaces": false,
231
+ "eos_token": "<|im_end|>",
232
+ "errors": "replace",
233
+ "extra_special_tokens": {},
234
+ "model_max_length": 262144,
235
+ "pad_token": "<|endoftext|>",
236
+ "split_special_tokens": false,
237
+ "tokenizer_class": "Qwen2Tokenizer",
238
+ "unk_token": null
239
+ }
text_tokenizer/vocab.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_bos_token": false,
3
+ "add_prefix_space": false,
4
+ "added_tokens_decoder": {
5
+ "151643": {
6
+ "content": "<|endoftext|>",
7
+ "lstrip": false,
8
+ "normalized": false,
9
+ "rstrip": false,
10
+ "single_word": false,
11
+ "special": true
12
+ },
13
+ "151644": {
14
+ "content": "<|im_start|>",
15
+ "lstrip": false,
16
+ "normalized": false,
17
+ "rstrip": false,
18
+ "single_word": false,
19
+ "special": true
20
+ },
21
+ "151645": {
22
+ "content": "<|im_end|>",
23
+ "lstrip": false,
24
+ "normalized": false,
25
+ "rstrip": false,
26
+ "single_word": false,
27
+ "special": true
28
+ },
29
+ "151646": {
30
+ "content": "<|object_ref_start|>",
31
+ "lstrip": false,
32
+ "normalized": false,
33
+ "rstrip": false,
34
+ "single_word": false,
35
+ "special": true
36
+ },
37
+ "151647": {
38
+ "content": "<|object_ref_end|>",
39
+ "lstrip": false,
40
+ "normalized": false,
41
+ "rstrip": false,
42
+ "single_word": false,
43
+ "special": true
44
+ },
45
+ "151648": {
46
+ "content": "<|box_start|>",
47
+ "lstrip": false,
48
+ "normalized": false,
49
+ "rstrip": false,
50
+ "single_word": false,
51
+ "special": true
52
+ },
53
+ "151649": {
54
+ "content": "<|box_end|>",
55
+ "lstrip": false,
56
+ "normalized": false,
57
+ "rstrip": false,
58
+ "single_word": false,
59
+ "special": true
60
+ },
61
+ "151650": {
62
+ "content": "<|quad_start|>",
63
+ "lstrip": false,
64
+ "normalized": false,
65
+ "rstrip": false,
66
+ "single_word": false,
67
+ "special": true
68
+ },
69
+ "151651": {
70
+ "content": "<|quad_end|>",
71
+ "lstrip": false,
72
+ "normalized": false,
73
+ "rstrip": false,
74
+ "single_word": false,
75
+ "special": true
76
+ },
77
+ "151652": {
78
+ "content": "<|vision_start|>",
79
+ "lstrip": false,
80
+ "normalized": false,
81
+ "rstrip": false,
82
+ "single_word": false,
83
+ "special": true
84
+ },
85
+ "151653": {
86
+ "content": "<|vision_end|>",
87
+ "lstrip": false,
88
+ "normalized": false,
89
+ "rstrip": false,
90
+ "single_word": false,
91
+ "special": true
92
+ },
93
+ "151654": {
94
+ "content": "<|vision_pad|>",
95
+ "lstrip": false,
96
+ "normalized": false,
97
+ "rstrip": false,
98
+ "single_word": false,
99
+ "special": true
100
+ },
101
+ "151655": {
102
+ "content": "<|image_pad|>",
103
+ "lstrip": false,
104
+ "normalized": false,
105
+ "rstrip": false,
106
+ "single_word": false,
107
+ "special": true
108
+ },
109
+ "151656": {
110
+ "content": "<|video_pad|>",
111
+ "lstrip": false,
112
+ "normalized": false,
113
+ "rstrip": false,
114
+ "single_word": false,
115
+ "special": true
116
+ },
117
+ "151657": {
118
+ "content": "<tool_call>",
119
+ "lstrip": false,
120
+ "normalized": false,
121
+ "rstrip": false,
122
+ "single_word": false,
123
+ "special": false
124
+ },
125
+ "151658": {
126
+ "content": "</tool_call>",
127
+ "lstrip": false,
128
+ "normalized": false,
129
+ "rstrip": false,
130
+ "single_word": false,
131
+ "special": false
132
+ },
133
+ "151659": {
134
+ "content": "<|fim_prefix|>",
135
+ "lstrip": false,
136
+ "normalized": false,
137
+ "rstrip": false,
138
+ "single_word": false,
139
+ "special": false
140
+ },
141
+ "151660": {
142
+ "content": "<|fim_middle|>",
143
+ "lstrip": false,
144
+ "normalized": false,
145
+ "rstrip": false,
146
+ "single_word": false,
147
+ "special": false
148
+ },
149
+ "151661": {
150
+ "content": "<|fim_suffix|>",
151
+ "lstrip": false,
152
+ "normalized": false,
153
+ "rstrip": false,
154
+ "single_word": false,
155
+ "special": false
156
+ },
157
+ "151662": {
158
+ "content": "<|fim_pad|>",
159
+ "lstrip": false,
160
+ "normalized": false,
161
+ "rstrip": false,
162
+ "single_word": false,
163
+ "special": false
164
+ },
165
+ "151663": {
166
+ "content": "<|repo_name|>",
167
+ "lstrip": false,
168
+ "normalized": false,
169
+ "rstrip": false,
170
+ "single_word": false,
171
+ "special": false
172
+ },
173
+ "151664": {
174
+ "content": "<|file_sep|>",
175
+ "lstrip": false,
176
+ "normalized": false,
177
+ "rstrip": false,
178
+ "single_word": false,
179
+ "special": false
180
+ },
181
+ "151665": {
182
+ "content": "<tool_response>",
183
+ "lstrip": false,
184
+ "normalized": false,
185
+ "rstrip": false,
186
+ "single_word": false,
187
+ "special": false
188
+ },
189
+ "151666": {
190
+ "content": "</tool_response>",
191
+ "lstrip": false,
192
+ "normalized": false,
193
+ "rstrip": false,
194
+ "single_word": false,
195
+ "special": false
196
+ },
197
+ "151667": {
198
+ "content": "<think>",
199
+ "lstrip": false,
200
+ "normalized": false,
201
+ "rstrip": false,
202
+ "single_word": false,
203
+ "special": false
204
+ },
205
+ "151668": {
206
+ "content": "</think>",
207
+ "lstrip": false,
208
+ "normalized": false,
209
+ "rstrip": false,
210
+ "single_word": false,
211
+ "special": false
212
+ }
213
+ },
214
+ "additional_special_tokens": [
215
+ "<|im_start|>",
216
+ "<|im_end|>",
217
+ "<|object_ref_start|>",
218
+ "<|object_ref_end|>",
219
+ "<|box_start|>",
220
+ "<|box_end|>",
221
+ "<|quad_start|>",
222
+ "<|quad_end|>",
223
+ "<|vision_start|>",
224
+ "<|vision_end|>",
225
+ "<|vision_pad|>",
226
+ "<|image_pad|>",
227
+ "<|video_pad|>"
228
+ ],
229
+ "bos_token": null,
230
+ "chat_template": "{%- if tools %}\n {{- '<|im_start|>system\\n' }}\n {%- if messages[0].role == 'system' %}\n {%- if messages[0].content is string %}\n {{- messages[0].content }}\n {%- else %}\n {%- for content in messages[0].content %}\n {%- if 'text' in content %}\n {{- content.text }}\n {%- endif %}\n {%- endfor %}\n {%- endif %}\n {{- '\\n\\n' }}\n {%- endif %}\n {{- \"# 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>\" }}\n {%- for tool in tools %}\n {{- \"\\n\" }}\n {{- tool | tojson }}\n {%- endfor %}\n {{- \"\\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\" }}\n{%- else %}\n {%- if messages[0].role == 'system' %}\n {{- '<|im_start|>system\\n' }}\n {%- if messages[0].content is string %}\n {{- messages[0].content }}\n {%- else %}\n {%- for content in messages[0].content %}\n {%- if 'text' in content %}\n {{- content.text }}\n {%- endif %}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n{%- endif %}\n{%- set image_count = namespace(value=0) %}\n{%- set video_count = namespace(value=0) %}\n{%- for message in messages %}\n {%- if message.role == \"user\" %}\n {{- '<|im_start|>' + message.role + '\\n' }}\n {%- if message.content is string %}\n {{- message.content }}\n {%- else %}\n {%- for content in message.content %}\n {%- if content.type == 'image' or 'image' in content or 'image_url' in content %}\n {%- set image_count.value = image_count.value + 1 %}\n {%- if add_vision_id %}Picture {{ image_count.value }}: {% endif -%}\n <|vision_start|><|image_pad|><|vision_end|>\n {%- elif content.type == 'video' or 'video' in content %}\n {%- set video_count.value = video_count.value + 1 %}\n {%- if add_vision_id %}Video {{ video_count.value }}: {% endif -%}\n <|vision_start|><|video_pad|><|vision_end|>\n {%- elif 'text' in content %}\n {{- content.text }}\n {%- endif %}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"assistant\" %}\n {{- '<|im_start|>' + message.role + '\\n' }}\n {%- if message.content is string %}\n {{- message.content }}\n {%- else %}\n {%- for content_item in message.content %}\n {%- if 'text' in content_item %}\n {{- content_item.text }}\n {%- endif %}\n {%- endfor %}\n {%- endif %}\n {%- if message.tool_calls %}\n {%- for tool_call in message.tool_calls %}\n {%- if (loop.first and message.content) or (not loop.first) %}\n {{- '\\n' }}\n {%- endif %}\n {%- if tool_call.function %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {{- '<tool_call>\\n{\"name\": \"' }}\n {{- tool_call.name }}\n {{- '\", \"arguments\": ' }}\n {%- if tool_call.arguments is string %}\n {{- tool_call.arguments }}\n {%- else %}\n {{- tool_call.arguments | tojson }}\n {%- endif %}\n {{- '}\\n</tool_call>' }}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if loop.first or (messages[loop.index0 - 1].role != \"tool\") %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n<tool_response>\\n' }}\n {%- if message.content is string %}\n {{- message.content }}\n {%- else %}\n {%- for content in message.content %}\n {%- if content.type == 'image' or 'image' in content or 'image_url' in content %}\n {%- set image_count.value = image_count.value + 1 %}\n {%- if add_vision_id %}Picture {{ image_count.value }}: {% endif -%}\n <|vision_start|><|image_pad|><|vision_end|>\n {%- elif content.type == 'video' or 'video' in content %}\n {%- set video_count.value = video_count.value + 1 %}\n {%- if add_vision_id %}Video {{ video_count.value }}: {% endif -%}\n <|vision_start|><|video_pad|><|vision_end|>\n {%- elif 'text' in content %}\n {{- content.text }}\n {%- endif %}\n {%- endfor %}\n {%- endif %}\n {{- '\\n</tool_response>' }}\n {%- if loop.last or (messages[loop.index0 + 1].role != \"tool\") %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n{%- endif %}\n",
231
+ "clean_up_tokenization_spaces": false,
232
+ "eos_token": "<|im_end|>",
233
+ "errors": "replace",
234
+ "model_max_length": 262144,
235
+ "pad_token": "<|endoftext|>",
236
+ "split_special_tokens": false,
237
+ "tokenizer_class": "Qwen2Tokenizer",
238
+ "unk_token": null
239
+ }
transformer/config.json ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_class_name": "Cosmos3OmniTransformer",
3
+ "_diffusers_version": "0.39.0.dev0",
4
+ "action_dim": 32,
5
+ "action_gen": false,
6
+ "attention_bias": false,
7
+ "attention_dropout": 0.0,
8
+ "base_fps": 16,
9
+ "enable_fps_modulation": true,
10
+ "head_dim": 128,
11
+ "hidden_size": 5120,
12
+ "intermediate_size": 25600,
13
+ "latent_channel": 48,
14
+ "latent_patch_size": 2,
15
+ "num_attention_heads": 64,
16
+ "num_embodiment_domains": 32,
17
+ "num_hidden_layers": 64,
18
+ "num_key_value_heads": 8,
19
+ "patch_latent_dim": 192,
20
+ "rms_norm_eps": 1e-06,
21
+ "rope_axes_dim": [
22
+ 24,
23
+ 20,
24
+ 20
25
+ ],
26
+ "rope_scaling": {
27
+ "mrope_interleaved": true,
28
+ "mrope_section": [
29
+ 24,
30
+ 20,
31
+ 20
32
+ ],
33
+ "rope_type": "default"
34
+ },
35
+ "rope_theta": 5000000,
36
+ "sound_dim": null,
37
+ "sound_gen": false,
38
+ "sound_latent_fps": 25,
39
+ "timestep_scale": 0.001,
40
+ "unified_3d_mrope_reset_spatial_ids": true,
41
+ "unified_3d_mrope_temporal_modality_margin": 15000,
42
+ "vocab_size": 151936
43
+ }
transformer/diffusion_pytorch_model-00001-of-00004.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7e2aa2e718722509028b354db2f24616f8e10a9f7c2782db7e2f3eecc9bce490
3
+ size 9964515442
transformer/diffusion_pytorch_model-00002-of-00004.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:98d10b08cd826c462d0c6de64a3640648ea03841af48abdac24b10405ed7caf5
3
+ size 9948271838
transformer/diffusion_pytorch_model-00003-of-00004.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9a417ced6bebae39de4df3eaa58f744630d46e7715e9773d34ec00787dae2eca
3
+ size 9948271838
transformer/diffusion_pytorch_model-00004-of-00004.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a9416e9e32370e3e34ff2281ea90d965a3d54cc3e5956eb2abd0e0210cab8eb2
3
+ size 8419116030
transformer/diffusion_pytorch_model.safetensors.index.json ADDED
The diff for this file is too large to render. See raw diff
 
transformer/modelopt_state.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d622a0d180c70ff7396db6e5abafd855072d8080fc9e66bdea2eb6489d0e1560
3
+ size 1295319
vae/config.json ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_class_name": "AutoencoderKLWan",
3
+ "_diffusers_version": "0.39.0",
4
+ "_name_or_path": "Wan-AI/Wan2.2-TI2V-5B-Diffusers",
5
+ "attn_scales": [],
6
+ "base_dim": 160,
7
+ "clip_output": false,
8
+ "decoder_base_dim": 256,
9
+ "dim_mult": [
10
+ 1,
11
+ 2,
12
+ 4,
13
+ 4
14
+ ],
15
+ "dropout": 0.0,
16
+ "in_channels": 12,
17
+ "is_residual": true,
18
+ "latents_mean": [
19
+ -0.2289,
20
+ -0.0052,
21
+ -0.1323,
22
+ -0.2339,
23
+ -0.2799,
24
+ 0.0174,
25
+ 0.1838,
26
+ 0.1557,
27
+ -0.1382,
28
+ 0.0542,
29
+ 0.2813,
30
+ 0.0891,
31
+ 0.157,
32
+ -0.0098,
33
+ 0.0375,
34
+ -0.1825,
35
+ -0.2246,
36
+ -0.1207,
37
+ -0.0698,
38
+ 0.5109,
39
+ 0.2665,
40
+ -0.2108,
41
+ -0.2158,
42
+ 0.2502,
43
+ -0.2055,
44
+ -0.0322,
45
+ 0.1109,
46
+ 0.1567,
47
+ -0.0729,
48
+ 0.0899,
49
+ -0.2799,
50
+ -0.123,
51
+ -0.0313,
52
+ -0.1649,
53
+ 0.0117,
54
+ 0.0723,
55
+ -0.2839,
56
+ -0.2083,
57
+ -0.052,
58
+ 0.3748,
59
+ 0.0152,
60
+ 0.1957,
61
+ 0.1433,
62
+ -0.2944,
63
+ 0.3573,
64
+ -0.0548,
65
+ -0.1681,
66
+ -0.0667
67
+ ],
68
+ "latents_std": [
69
+ 0.4765,
70
+ 1.0364,
71
+ 0.4514,
72
+ 1.1677,
73
+ 0.5313,
74
+ 0.499,
75
+ 0.4818,
76
+ 0.5013,
77
+ 0.8158,
78
+ 1.0344,
79
+ 0.5894,
80
+ 1.0901,
81
+ 0.6885,
82
+ 0.6165,
83
+ 0.8454,
84
+ 0.4978,
85
+ 0.5759,
86
+ 0.3523,
87
+ 0.7135,
88
+ 0.6804,
89
+ 0.5833,
90
+ 1.4146,
91
+ 0.8986,
92
+ 0.5659,
93
+ 0.7069,
94
+ 0.5338,
95
+ 0.4889,
96
+ 0.4917,
97
+ 0.4069,
98
+ 0.4999,
99
+ 0.6866,
100
+ 0.4093,
101
+ 0.5709,
102
+ 0.6065,
103
+ 0.6415,
104
+ 0.4944,
105
+ 0.5726,
106
+ 1.2042,
107
+ 0.5458,
108
+ 1.6887,
109
+ 0.3971,
110
+ 1.06,
111
+ 0.3943,
112
+ 0.5537,
113
+ 0.5444,
114
+ 0.4089,
115
+ 0.7468,
116
+ 0.7744
117
+ ],
118
+ "num_res_blocks": 2,
119
+ "out_channels": 12,
120
+ "patch_size": 2,
121
+ "scale_factor_spatial": 16,
122
+ "scale_factor_temporal": 4,
123
+ "temperal_downsample": [
124
+ false,
125
+ true,
126
+ true
127
+ ],
128
+ "z_dim": 48
129
+ }
vae/diffusion_pytorch_model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:230496cb59ff85bc9c040487737c4062480cb61c71e697b197b4c30142f2a0da
3
+ size 1409400600
validate_cosmos3_i2v4step_fp8.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """
3
+ Standalone re-validation of the Cosmos3-Super-Image2Video-4Step FP8 quantization
4
+ (quantize_cosmos3_i2v4step_streaming.py). Exists because the first --smoke run's
5
+ render was invalid: it used the pipeline's default 35-step/guidance=6.0 schedule
6
+ instead of this checkpoint's trained 4-step sde schedule (a diffusers version gap --
7
+ Cosmos3OmniPipeline doesn't pass the scheduler_config.json's fixed_step_sampler_config
8
+ through to scheduler.set_timesteps; see _force_fixed_step_schedule in
9
+ serve_cosmos3_i2v4step_diffusers.py for the full rationale).
10
+
11
+ NOTE: export_hf_checkpoint() (what the quantize script wrote to ./cosmos3-i2v4step-fp8)
12
+ is NVIDIA's *deployment* format for vLLM/TRT-LLM -- it has no modelopt_state.pth, so
13
+ diffusers' from_pretrained / load_cosmos3_modelopt.py can't load it directly (same gap
14
+ repackage_for_hf.py exists to solve for the base model). Rather than write a second
15
+ ~65GB copy to disk just to validate, this rebuilds the quantized transformer in memory
16
+ via the same build_quantized_transformer() used during quantization (re-streams the
17
+ 121GB source once) and renders straight from that -- no extra disk footprint beyond the
18
+ output clip. If you want a real servable drop-in repo afterward, run
19
+ repackage_for_hf_i2v4step.py (that DOES need the disk headroom).
20
+
21
+ USAGE
22
+ python validate_cosmos3_i2v4step_fp8.py --format fp8 --image out.png
23
+ """
24
+ import argparse
25
+ import os
26
+
27
+ os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
28
+
29
+ import torch
30
+ from PIL import Image
31
+
32
+ from serve_cosmos3_i2v4step_diffusers import build_quantized_transformer, make_pipeline
33
+
34
+
35
+ def main():
36
+ ap = argparse.ArgumentParser()
37
+ ap.add_argument("--format", choices=["fp8", "nvfp4"], default="fp8")
38
+ ap.add_argument("--gpu-mem-fraction", type=float, default=0.85)
39
+ ap.add_argument("--image", default="out.png")
40
+ ap.add_argument("--num-frames", type=int, default=49)
41
+ ap.add_argument("--height", type=int, default=512)
42
+ ap.add_argument("--width", type=int, default=512)
43
+ ap.add_argument("--seed", type=int, default=1234)
44
+ ap.add_argument("--out", default="cosmos3_i2v4step_fp8_validate.mp4")
45
+ ap.add_argument(
46
+ "--prompt",
47
+ default="The camera holds static as the scene continues naturally, with subtle motion and realistic physics.",
48
+ )
49
+ args = ap.parse_args()
50
+
51
+ print(f"[build] rebuilding quantized ({args.format}) transformer in memory ...")
52
+ model = build_quantized_transformer(args.format, args.gpu_mem_fraction)
53
+ pipe = make_pipeline(model) # includes _force_fixed_step_schedule on pipe.scheduler
54
+
55
+ cond_image = Image.open(args.image).convert("RGB")
56
+
57
+ print(f"[render] {args.num_frames} frames @ {args.height}x{args.width}, seed={args.seed}")
58
+ with torch.inference_mode():
59
+ result = pipe(
60
+ prompt=args.prompt,
61
+ negative_prompt="",
62
+ image=cond_image,
63
+ num_frames=args.num_frames,
64
+ height=args.height,
65
+ width=args.width,
66
+ num_inference_steps=4, # no-op once patched; kept for clarity
67
+ guidance_scale=1.0, # CFG is distilled out of this checkpoint
68
+ generator=torch.Generator(device="cuda").manual_seed(args.seed),
69
+ )
70
+
71
+ from diffusers.utils import export_to_video
72
+ export_to_video(result.video, args.out, fps=24)
73
+ print(f"[done] wrote {args.out}")
74
+
75
+
76
+ if __name__ == "__main__":
77
+ main()
video_preprocessor_config.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "size": {
3
+ "longest_edge": 25165824,
4
+ "shortest_edge": 4096
5
+ },
6
+ "patch_size": 16,
7
+ "temporal_patch_size": 2,
8
+ "merge_size": 2,
9
+ "image_mean": [
10
+ 0.5,
11
+ 0.5,
12
+ 0.5
13
+ ],
14
+ "image_std": [
15
+ 0.5,
16
+ 0.5,
17
+ 0.5
18
+ ],
19
+ "processor_class": "Qwen3VLProcessor",
20
+ "video_processor_type": "Qwen3VLVideoProcessor"
21
+ }
vocab.json ADDED
The diff for this file is too large to render. See raw diff