Text-to-image, text-to-video, image-to-video, and video-to-video serving
- Vendor: NVIDIA
- Model:
nvidia/Cosmos3-Nano - Task: Text-to-image (T2I), text-to-video (T2V), image-to-video (I2V), and video-to-video (V2V) generation, with optional transfer controls, synchronized audio (video + sound), action policy
- Mode: Online serving with the OpenAI-compatible image/video APIs, plus offline generation via the
OmniAPI - Maintainer: Community
Use this recipe to deploy nvidia/Cosmos3-Nano for image and video generation.
A single pipeline class (Cosmos3OmniDiffusersPipeline) serves these modes; the
mode is selected per request:
-
T2I —
POST /v1/images/generations(or a prompt carryingmodalities=["image"]). -
T2V —
POST /v1/videos/syncwithnum_frames > 1and no reference image/video. -
I2V —
POST /v1/videos/syncwith a reference image (input_referencefile upload, orimage_referenceJSON). -
V2V —
POST /v1/videos/syncwith a reference video (input_referencevideo upload, orvideo_referenceJSON). Cosmos3 conditions on selected reference-video latent frames; useextra_params.condition_frame_indexes_visionandextra_params.condition_video_keepto choose which prefix/tail frames guide generation. -
Transfer V2V — pass one or more transfer hints in
extra_params(edge,blur,depth,seg,wsm) to guide generation with control frames. Transfer mode is video-only and cannot be combined with sound or action. -
T2VS / I2VS — add
generate_sound=true(and optionalsound_duration) to a T2V/I2V/v1/videos/syncrequest to also generate synchronized audio, muxed into the mp4 as AAC 48 kHz stereo. See the official model card's "Video + Audio" examples. -
Action — pass
extra_params={"action_mode": ...}to drive Physical-AI tasks:forward_dynamics— given a first frame or video and an action trajectory, roll out the resulting video. Synchronous:POST /v1/videos/sync.policy— given a first frame or video and a language instruction, predict the action trajectory (and a rollout video). Use the asyncPOST /v1/videosendpoint and read the predicted action from the top-levelactionfield.inverse_dynamics— given a video, recover the action trajectory. Use the asyncPOST /v1/videosendpoint and read the recovered action from the top-levelactionfield ({data, shape, dtype, raw_action_dim, domain_id}).
Action requests also take
domain_name(e.g.av,bridge_orig_lerobot,droid_lerobot,agibotworld, …; or a numericdomain_id),raw_action_dim, andaction_chunk_size(must equalnum_framesornum_frames - 1). Forforward_dynamicsalso pass theactionarray. The dedicated policy checkpointnvidia/Cosmos3-Nano-Policy-DROIDis served the same way (domain_name=droid_lerobot). -
DROID policy server — serve
nvidia/Cosmos3-Nano-Policy-DROIDand connect RoboLab or another OpenPI-compatible client to/v1/realtime/robot/openpi. This endpoint returns action chunks directly instead of an mp4.Action requests can use
input_referenceorvideo_referencefor video input.policyandforward_dynamicscan also use an image reference;inverse_dynamicsrequires a video reference.
- Model card (authoritative usage + example assets): https://huggingface.co/nvidia/Cosmos3-Nano
- Example inputs/outputs live in the repo's
assets/(example_t2v_prompt.json,example_i2v_prompt.json,example_i2v_input.jpg,negative_prompt.json; audio examples:example_t2vs_prompt.json,example_t2vs_output.mp4,example_i2vs_output.mp4). - Prompt upsampling (recommended for quality): the model expects JSON-upsampled
structured prompts; see NVIDIA's
cosmos-frameworkprompt-upsampling docs. - Pipeline:
vllm_omni/diffusion/models/cosmos3/pipeline_cosmos3.py - Smoke tests (canonical request formats):
tests/e2e/accuracy/test_cosmos3_similarity.py
- OS: Ubuntu 22.04+
- Python: 3.12+
- Driver / runtime: NVIDIA CUDA environment
- vLLM version: match the repository requirements from your current checkout
- vLLM-Omni version or commit: use the commit you are deploying from
Requires the vllm-omni package (or the vllm/vllm-omni:cosmos3 container),
which provides the vllm serve … --omni entrypoint used below.
Safety guardrails are on by default (NVIDIA Open Model License). They load
the gated nvidia/Cosmos-1.0-Guardrail model, so to keep them on you must:
pip install cosmos-guardrail- Accept the license at https://huggingface.co/nvidia/Cosmos-1.0-Guardrail
- Export a token with access:
export HF_TOKEN=hf_...
Then launch the recommended server:
vllm serve nvidia/Cosmos3-Nano \
--omni \
--host 0.0.0.0 --port 8000 \
--init-timeout 1800To run without guardrails (you are responsible for license compliance),
add --no-guardrails (no token/cosmos-guardrail needed). For extra GPUs use
--ulysses-degree N (context parallel) or --tensor-parallel-size N;
--enable-layerwise-offload reduces VRAM on smaller GPUs;
--quantization fp8 (online, no calibration) cuts peak VRAM for 720p video
generation from ~50 GB to ~36 GB with BF16-level quality (T2V composition can
shift at the same seed). The pipeline
auto-resolves from model_index.json; pass
--model-class-name Cosmos3OmniDiffusersPipeline to force it explicitly.
For a serialized ModelOpt FP8 or NVFP4 checkpoint, an experimental mixed-precision schedule can use native W8A8/W4A4 in middle denoising steps and dense W8A16/W4A16 in the first and last steps:
vllm serve /path/to/Cosmos3-Nano-modelopt \
--omni \
--additional-config \
'{"cosmos3_mixed_precision":{"first_steps":3,"last_steps":3,"reasoner":"a16"}}'The nested object's presence supplies an explicit runtime override; use an
empty object for these defaults. A compatible checkpoint can instead declare
the versioned runtime.diffusion_step_policy in its authoritative
transformer/config.json. The checkpoint policy is used only when no runtime
override is present. Use
--additional-config '{"cosmos3_mixed_precision":{"enabled":false}}' to
disable the checkpoint schedule without disabling checkpoint quantization.
This path currently requires tensor parallel size 1 and does not support HSDP
or block-scaled FP8. It keeps one live quantized weight representation:
scheduled FP8 requires serialized tensorwise scales and a canonical backend,
while scheduled NVFP4 requires a supported CUTLASS-compatible native or
FlashInfer layout. Its dequantization is a correctness baseline; no speedup is
implied. Quantized reasoner weights use A16 by default; set
"reasoner":"native" in the nested object to keep W8A8/W4A4.
The checkpoint's ModelOpt configuration selects FP8 or NVFP4; mixed FP8/NVFP4
checkpoints are not supported by this schedule. BF16 linears are left unchanged.
The schedule currently supports one active request per worker. Model-level and
layer-wise offload are designed to work with this live-weight path but still
require GPU validation. Distributed layer-wise offload and incompatible native
weight layouts fail during loading.
Best quality uses the JSON-upsampled prompts from assets/ (download with
hf download nvidia/Cosmos3-Nano assets/ --local-dir Cosmos3-Nano). Minimal
self-contained examples:
curl http://localhost:8000/v1/models
# Text-to-image -> /v1/images/generations (1024x1024, 50 steps; base64 PNG)
curl -sS -X POST http://localhost:8000/v1/images/generations \
-H "Content-Type: application/json" \
-d '{
"model": "nvidia/Cosmos3-Nano",
"prompt": "A photorealistic red sports car on a city street at golden hour, cinematic lighting.",
"negative_prompt": "blurry, distorted, low quality",
"size": "1024x1024", "n": 1, "response_format": "b64_json",
"num_inference_steps": 50, "guidance_scale": 7.0, "seed": 42
}' | python -c "import sys,json,base64; open('cosmos3_t2i.png','wb').write(base64.b64decode(json.load(sys.stdin)['data'][0]['b64_json']))"
# Text-to-video -> /v1/videos/sync (720p, 189 frames @ 24fps; official params)
curl -sS -X POST http://localhost:8000/v1/videos/sync \
-H "Accept: video/mp4" \
-F "model=nvidia/Cosmos3-Nano" \
-F "prompt=A robot arm is cleaning a plate in the kitchen" \
-F "negative_prompt=blurry, distorted, low quality, jittery, deformed" \
-F "size=1280x720" -F "num_frames=189" -F "fps=24" \
-F "num_inference_steps=35" -F "guidance_scale=6.0" \
-F "max_sequence_length=4096" -F "flow_shift=10.0" \
-F 'extra_params={"use_resolution_template":false,"use_duration_template":false,"guardrails":true}' \
-F "seed=123" \
-o cosmos3_t2v.mp4
# Image-to-video -> /v1/videos/sync with an uploaded reference image
curl -sS -X POST http://localhost:8000/v1/videos/sync \
-H "Accept: video/mp4" \
-F "model=nvidia/Cosmos3-Nano" \
-F "prompt=The scene comes to life with smooth, natural motion." \
-F "negative_prompt=blurry, distorted, low quality" \
-F "size=1280x720" -F "num_frames=189" -F "fps=24" \
-F "num_inference_steps=35" -F "guidance_scale=6.0" \
-F "max_sequence_length=4096" -F "flow_shift=10.0" \
-F 'extra_params={"use_resolution_template":false,"use_duration_template":false,"guardrails":true}' \
-F "seed=1111" \
-F "input_reference=@/path/to/reference.jpg;type=image/jpeg" \
-o cosmos3_i2v.mp4
# Video-to-video -> /v1/videos/sync with an uploaded reference video.
# By default Cosmos3 conditions on latent indexes [0, 1]. For the default
# temporal VAE stride this decodes only the first 5 input frames.
# The model works best when the prompt describes the actual situation happening in the video.
# Generic prompts may create sub-standard generations.
curl -sS -X POST http://localhost:8000/v1/videos/sync \
-H "Accept: video/mp4" \
-F "model=nvidia/Cosmos3-Nano" \
-F "prompt=Continue the same scene with smooth natural motion and consistent subjects." \
-F "negative_prompt=blurry, distorted, low quality, jittery, deformed" \
-F "size=1280x720" -F "num_frames=189" -F "fps=24" \
-F "num_inference_steps=35" -F "guidance_scale=6.0" \
-F "max_sequence_length=4096" -F "flow_shift=10.0" \
-F 'extra_params={"use_resolution_template":false,"use_duration_template":false,"guardrails":true,"condition_frame_indexes_vision":[0,1],"condition_video_keep":"first"}' \
-F "seed=2222" \
-F "input_reference=@/path/to/reference.mp4;type=video/mp4" \
-o cosmos3_v2v.mp4
# V2V can also use a JSON-safe URL/data-URL video reference. Do not combine
# video_reference with input_reference or image_reference.
curl -sS -X POST http://localhost:8000/v1/videos/sync \
-H "Accept: video/mp4" \
-F "model=nvidia/Cosmos3-Nano" \
-F "prompt=Continue the same scene with smooth natural motion and consistent subjects." \
-F "size=1280x720" -F "num_frames=189" -F "fps=24" \
-F "num_inference_steps=35" -F "guidance_scale=6.0" \
-F "max_sequence_length=4096" -F "flow_shift=10.0" \
-F 'extra_params={"condition_frame_indexes_vision":[0,1],"condition_video_keep":"last"}' \
-F 'video_reference={"video_url":"https://example.com/reference.mp4"}' \
-o cosmos3_v2v_from_url.mp4
# Transfer V2V with a precomputed depth control video. `control_path` can point
# to a local image/video; edge and blur can also be computed from `input_reference`
# by passing `"edge":true` or `"blur":true`. The reference negative prompt is
# optional; omit the `negative_prompt` form field to use an empty negative branch.
curl -sS -X POST http://localhost:8000/v1/videos/sync \
-H "Accept: video/mp4" \
-F "model=nvidia/Cosmos3-Nano" \
-F "prompt=Generate a realistic scene following the provided control video." \
--form-string "negative_prompt=$(jq -c . recipes/cosmos3/negative_prompt.json)" \
-F "size=1280x720" -F "num_frames=121" \
-F "num_inference_steps=50" -F "seed=125" \
-F 'extra_params={"depth":{"control_path":"/path/to/depth_control.mp4"},"max_frames":121,"resolution":"720","num_video_frames_per_chunk":121}' \
-o cosmos3_transfer_depth.mp4
# The same transfer control can be uploaded by a remote client instead of
# being placed on the server filesystem. Uploads are limited to 512 MiB.
curl -sS -X POST http://localhost:8000/v1/videos/sync \
-H "Accept: video/mp4" \
-F "model=nvidia/Cosmos3-Nano" \
-F "prompt=Generate a realistic scene following the provided world-state control." \
-F "input_reference=@/path/to/input.mp4;type=video/mp4" \
-F "control_reference=@/path/to/wsm.mp4;type=video/mp4" \
-F "control_type=wsm" \
-F 'extra_params={"wsm":{"control_weight":1.0},"max_frames":121,"resolution":"720","num_video_frames_per_chunk":121}' \
-o cosmos3_transfer_wsm.mp4
# Text-to-video-with-sound
curl -sS -X POST http://localhost:8000/v1/videos/sync \
-H "Accept: video/mp4" \
-F "model=nvidia/Cosmos3-Nano" \
-F "prompt=The video opens with a view of a well-lit indoor fruit display. A robotic arm picks up a pear, an orange, and a carambola one by one, placing each into a plastic bag in a shopping cart with red handles. The video is 7.875 seconds long, 24 FPS, and 1280x720. Audio description: soft servo whirs, gentle fruit thuds, plastic bag rustling, and a faint refrigeration hum." \
-F "negative_prompt=blurry, distorted, low quality" \
-F "size=1280x720" \
-F "num_frames=189" \
-F "fps=24" \
-F "num_inference_steps=35" \
-F "guidance_scale=6.0" \
-F "max_sequence_length=4096" \
-F "flow_shift=10.0" \
-F "seed=0" \
-F "generate_sound=true" \
-F "sound_duration=7.875" \
-F 'extra_params={"use_resolution_template":false,"use_duration_template":false,"guardrails":true}' \
-o cosmos3_t2v_with_sound.mp4
# Action — forward dynamics (first frame + action trajectory -> rollout video).
# Synchronous; `action` is a JSON array shaped [action_chunk_size, raw_action_dim].
curl -sS -X POST http://localhost:8000/v1/videos/sync \
-H "Accept: video/mp4" \
--form-string "model=nvidia/Cosmos3-Nano" \
--form-string "prompt=You are an autonomous vehicle. This video is captured from a first-person perspective." \
-F "input_reference=@first_frame.jpg;type=image/jpeg" \
-F "size=640x480" -F "num_frames=61" -F "fps=10" \
-F "num_inference_steps=30" -F "guidance_scale=1.0" -F "flow_shift=5.0" \
--form-string "extra_params={\"action_mode\":\"forward_dynamics\",\"domain_name\":\"av\",\"raw_action_dim\":9,\"action_chunk_size\":60,\"action\":$(cat action.json)}" \
-F "seed=0" \
-o cosmos3_forward_dynamics.mp4
# Action — policy (first frame + instruction -> predicted action trajectory + video).
# Asynchronous: POST returns a job id; poll, then read the predicted action from
# the top-level `action` field ({data, shape, dtype, raw_action_dim, domain_id}).
VIDEO_ID=$(curl -sS -X POST http://localhost:8000/v1/videos \
-H "Accept: application/json" \
--form-string "model=nvidia/Cosmos3-Nano" \
--form-string "prompt=Pick up the banana and place it in the bowl." \
-F "input_reference=@first_frame.jpg;type=image/jpeg" \
-F "size=640x480" -F "num_frames=17" -F "fps=5" \
-F "num_inference_steps=30" -F "guidance_scale=1.0" -F "flow_shift=5.0" \
--form-string 'extra_params={"action_mode":"policy","domain_name":"bridge_orig_lerobot","raw_action_dim":10,"action_chunk_size":16}' \
-F "seed=0" | jq -r '.id')
# poll until status == completed, then:
curl -sS "http://localhost:8000/v1/videos/$VIDEO_ID" | jq '.action | {shape, dtype, raw_action_dim, domain_id}'
curl -sS -L "http://localhost:8000/v1/videos/$VIDEO_ID/content" -o cosmos3_policy.mp4
# Action — inverse dynamics (video -> recovered action trajectory).
# Asynchronous: use the job metadata to read the recovered action.
VIDEO_ID=$(curl -sS -X POST http://localhost:8000/v1/videos \
-H "Accept: application/json" \
--form-string "model=nvidia/Cosmos3-Nano" \
--form-string "prompt=Recover the robot action trajectory from this clip." \
-F "input_reference=@motion_clip.mp4;type=video/mp4" \
-F "size=640x480" -F "num_frames=17" -F "fps=5" \
-F "num_inference_steps=30" -F "guidance_scale=1.0" -F "flow_shift=5.0" \
--form-string 'extra_params={"action_mode":"inverse_dynamics","domain_name":"bridge_orig_lerobot","raw_action_dim":10,"action_chunk_size":16}' \
-F "seed=0" | jq -r '.id')
# poll until status == completed, then:
curl -sS "http://localhost:8000/v1/videos/$VIDEO_ID" | jq '.action | {shape, dtype, raw_action_dim, domain_id}'
curl -sS -L "http://localhost:8000/v1/videos/$VIDEO_ID/content" -o cosmos3_inverse_dynamics.mp4
# DROID websocket policy server. Use the tested cosmos-framework revision
# directly from source; installing the package can introduce dependency conflicts.
export COSMOS_FRAMEWORK_ROOT=/path/to/cosmos-framework
git -C "$COSMOS_FRAMEWORK_ROOT" checkout c14617c2bc93dacbf69674fb964eec93182933d9
export PYTHONPATH="$COSMOS_FRAMEWORK_ROOT"
# Validate every cosmos-framework symbol used by the action-policy pipeline
# before allocating the model.
python - <<'PY'
from vllm_omni.diffusion.models.cosmos3.utils import (
get_robolab_domain_id,
preflight_cosmos3_action_framework_imports,
)
preflight_cosmos3_action_framework_imports()
print("cosmos-framework action imports OK; DROID domain:", get_robolab_domain_id("droid_lerobot"))
PY
# The bundled deploy config (vllm_omni/deploy/cosmos3_policy_droid.yaml)
# selects the registered cosmos3_policy pipeline and carries the DROID
# checkpoint's serving defaults: JSON prompt formatting (a property of this
# checkpoint's training recipe, not a generic server default), the
# model-specific OpenPI binary handshake metadata (policy_server_config), and
# guardrails off (policy serving emits robot actions; the guardrail stack is
# not part of it, so --no-guardrails is implied).
# Policy checkpoints cannot be auto-detected — they share their HF metadata
# with the T2I/video Cosmos3 checkpoints — so --deploy-config is required.
# Per-checkpoint model_config tweaks can be layered on top with
# --stage-overrides; dict overrides deep-merge with the deploy yaml.
export VLLM_OMNI_ROOT=/absolute/path/to/vllm-omni
vllm serve nvidia/Cosmos3-Nano-Policy-DROID \
--omni \
--host 0.0.0.0 --port 8000 \
--deploy-config "$VLLM_OMNI_ROOT/vllm_omni/deploy/cosmos3_policy_droid.yaml" \
--robot-openpi-idle-timeout 0
# From a RoboLab checkout:
python policies/cosmos3/run.py \
--remote-uri ws://localhost:8000/v1/realtime/robot/openpi \
--task BananaInBowlTask
# For a server started with "--api-key $POLICY_API_KEY", pass the same value as
# a Bearer token. --remote-token takes precedence over COSMOS3_API_TOKEN.
COSMOS3_API_TOKEN="$POLICY_API_KEY" python policies/cosmos3/run.py \
--remote-uri wss://policy.example/v1/realtime/robot/openpi \
--task BananaInBowlTaskThe endpoint sends policy_server_config as its initial binary MsgPack
message and returns the action array directly. RoboLab accepts that direct
array as well as proxy responses shaped as {"action": ...} or
{"actions": ...}, and turns structured server errors into client exceptions.
RoboLab supplies session_id=robolab-episode-<episode>-env-<env_id>, so
parallel environments have independent policy state even though they share
one WebSocket. The server tracks interleaved session IDs independently.
The default receive-idle timeout is 30 seconds; set
--robot-openpi-idle-timeout 0 when simulator steps between replans can take
longer, or set another non-negative timeout in seconds.
If vLLM-Omni is started with --api-key or VLLM_API_KEY, the standard
OpenPI route uses the normal API authentication middleware. RoboLab's
--remote-token and COSMOS3_API_TOKEN send the required
Authorization: Bearer ... header.
- Measured latency (1x B300, bf16, guardrails off):
- T2I 1024² — 10 / 25 / 50 steps → ~0.4 / 0.7 / 1.3 s
- T2V 1280×720 @ 35 steps — 25 / 49 / 93 / 189 frames → ~7 / 15 / 33 / ~93 s
- I2V 1280×720, 189 frames @ 35 steps → ~99 s
- Action 640×480 @ 30 steps — forward-dynamics 61f ~4 s, policy 17f ~1–3 s.
- Guardrails-on overhead: ~8% on T2I, negligible on video.
- Memory: transformer ~17 GiB (bf16); peak ~46 GiB for 720p video on 1 GPU; full repo (transformer + Wan VAE + Qwen3-VL vision encoder + audio tokenizer) ~33 GB on disk.
- Determinism: identical seed reproduces identical output on the same hardware; outputs are not bit-identical across different GPU types.
- Supported sizes (per model card): 256p / 480p / 720p at 16:9, 4:3, 1:1,
3:4, 9:16. Defaults: T2I 1024², 50 steps, guidance 7.0; T2V/I2V/V2V
1280×720, 189 frames, 35 steps, guidance 6.0,
flow_shift=10.0. - Key flags / params:
--no-guardrails(server) orextra_params={"guardrails":false}(per request) toggles safety. The per-request flag only takes effect when the server was launched with guardrails enabled (it cannot re-enable them on a--no-guardrailsserver). Outside transfer mode,use_resolution_template/use_duration_templateare off by default and only needed when not using upsampled prompts that already encode resolution/duration. For V2V,condition_frame_indexes_visionselects the clean conditioned latent frame indexes (default[0, 1]), andcondition_video_keepselects whether the API decodes the first or last needed reference frames ("first"by default). - Transfer controls:
extra_paramsmay includeedge,blur,depth,seg, orwsm. Each hint acceptstrue, a path string, or an object such as{"control_path": "/path/to/control.mp4"};edgealso acceptspreset_edge_thresholdandbluracceptspreset_blur_strength. Every hint accepts a non-negativecontrol_weight; weights are normalized across active controls and therefore only set their relative influence. A single positive weight always normalizes to1.0; usecontrol_guidanceto change the absolute strength of a single control. With two or more active controls, the per-control attention passes run replicated on every sequence-parallel (Ulysses) rank, so Ulysses does not reduce per-rank memory or latency for multi-control transfer requests. Transfer always uses Cosmos3's transfer-specific system prompt. By default it also appends a directive naming every active hint and asking the model to follow its shape, position, and motion precisely; set the request-levelemphasize_control_in_promptoption tofalsefor prompt ablations. Transfer does not add a negative prompt automatically. An optional reference prompt is provided innegative_prompt.json; compact the JSON withjq -cand pass it throughnegative_promptas shown in the transfer example. Transfer enables duration/FPS and resolution metadata on both CFG branches. Setuse_duration_templateoruse_resolution_templatetofalseto disable either template.negative_metadata_modeacceptssame(the transfer default),inverse, ornone. Transfer-level options includecontrol_guidance,control_guidance_interval,num_video_frames_per_chunk(default93,101for WSM),num_conditional_frames(default1),num_first_chunk_conditional_frames,max_frames,show_control_condition,show_input, andshare_vision_temporal_positions. Non-WSM transfer preserves the input video fps when available; WSM defaults to 10 fps unlessfpsis supplied. - DROID OpenPI observations: include a string
prompt, eitherobservation/imageor the three-view DROID camera keys (observation/wrist_image_left,observation/exterior_image_1_left,observation/exterior_image_2_left), plusobservation/gripper_positionandobservation/joint_position. Optional extra params includehistory_length,conditioning_fps,action_chunk_size,raw_action_dim,deterministic_seed, andsession_id. - Known limitations:
- Guardrails-on requires
cosmos-guardrailand access to the gatednvidia/Cosmos-1.0-Guardrailrepo (accept license +HF_TOKEN); otherwise the server fails at pipeline build with a gated-repo / safety-checker error. - A guardrail-blocked prompt currently returns HTTP 500
(
"Guardrail blocked prompt"). - Action
forward_dynamics,policy, andinverse_dynamicsare supported online. Use asyncPOST /v1/videoswhen you need the predicted/recovered action payload under the top-levelactionfield; sync/v1/videos/syncreturns raw MP4 bytes and does not expose action metadata in the response body.
- Guardrails-on requires
- OS: Ubuntu 22.04+
- Python: 3.12+
- Driver / runtime: NVIDIA CUDA environment
- vLLM-Omni version or commit: use the commit you are deploying from
Cosmos3 runs through the standard task examples; pass model-specific knobs via
--extra-body. Guardrails are on by default — pass "guardrails": false for a
quick local run (install cosmos-guardrail + accept the gated repo to enable them).
# Text-to-image -> examples/offline_inference/text_to_image
python examples/offline_inference/text_to_image/text_to_image.py \
--model nvidia/Cosmos3-Nano \
--prompt "A photorealistic red sports car at golden hour, cinematic lighting." \
--negative-prompt "blurry, distorted, low quality" \
--height 1024 --width 1024 --num-inference-steps 50 --guidance-scale 7.0 \
--extra-body '{"flow_shift": 3.0, "guardrails": false}' \
--output cosmos3_t2i.png
# Text-to-video -> examples/offline_inference/text_to_video
python examples/offline_inference/text_to_video/text_to_video.py \
--model nvidia/Cosmos3-Nano \
--prompt "A robot arm is cleaning a plate in the kitchen." \
--negative-prompt "blurry, distorted, low quality, jittery, deformed" \
--height 720 --width 1280 --num-frames 189 --fps 24 \
--num-inference-steps 35 --guidance-scale 6.0 \
--extra-body '{"flow_shift": 10.0, "max_sequence_length": 4096, "guardrails": false,
"use_resolution_template": false, "use_duration_template": false}' \
--output cosmos3_t2v.mp4
# Image-to-video -> examples/offline_inference/image_to_video
# (Cosmos3 bundles example frames under assets/; any RGB image works too.)
python examples/offline_inference/image_to_video/image_to_video.py \
--model nvidia/Cosmos3-Nano \
--image /path/to/Cosmos3-Nano/assets/example_i2v_input.jpg \
--prompt "The scene comes to life with smooth, natural motion." \
--height 720 --width 1280 --num-frames 189 --fps 24 \
--num-inference-steps 35 --guidance-scale 6.0 \
--extra-body '{"flow_shift": 10.0, "max_sequence_length": 4096, "guardrails": false}' \
--output cosmos3_i2v.mp4python -c "from PIL import Image; im=Image.open('cosmos3_t2i.png'); print('image', im.size, im.mode)"
ffprobe -v error -show_entries stream=codec_type,nb_frames,width,height cosmos3_t2v.mp4- A single
Cosmos3OmniDiffusersPipelineserves every mode; the standard examples select it automatically frommodel_index.json. T2I is chosen by thetext_to_imageprompt builder (which marksmodalities=["image"]);text_to_videodefaults to T2V;image_to_videoaddsmulti_modal_data={"image": ...}(I2V). V2V is served online (/v1/videos/sync). - Model-specific knobs (
flow_shift,max_sequence_length,condition_*,generate_sound/sound_duration,guardrails,action_*, ...) are declared once invllm_omni/model_extras/cosmos3.pyand forwarded through--extra-body; unknown keys for the model are dropped.
- OS: Ubuntu 22.04+
- Python: 3.12+
- Driver / runtime: ROCm, HIP 7.2, gfx942 or gfx950 (validated on gfx950 / MI350X, which exposes 252 GiB of HBM to PyTorch)
- PyTorch: 2.11.0 (ROCm build)
- vLLM version: match the repository requirements from your current checkout
- vLLM-Omni version or commit: use the commit you are deploying from
No ROCm-specific patch or flag is needed: Cosmos3 runs on the stock code path.
The NVIDIA command works unchanged. Guardrails need the gated
nvidia/Cosmos-1.0-Guardrail repo, so the quick path is to disable them (you are
then responsible for license compliance):
vllm serve nvidia/Cosmos3-Nano \
--omni \
--no-guardrails \
--host 0.0.0.0 --port 8000 \
--init-timeout 1800For 720p video, add --vae-use-tiling: it cuts peak VRAM by ~68% for ~13%
latency, which is the difference between needing a 120 GiB card and a 40 GiB one.
--quantization fp8 and --enable-layerwise-offload are also supported; see the
Notes for the measured cost of each. For extra GPUs use --ulysses-degree N or
--tensor-parallel-size N (not validated on ROCm yet).
Use the same curl requests as the CUDA section above. The ROCm images do not
ship ffprobe, so the CUDA section's ffprobe line does not work here. imageio
and pyav are already installed and report the same thing:
python -c "from PIL import Image; im=Image.open('cosmos3_t2i.png'); print(im.size, im.mode)"
python -c "import imageio.v3 as iio; print(iio.improps('cosmos3_t2v.mp4', plugin='pyav').shape)"Expect (1024, 1024) RGB and (189, 720, 1280, 3) for the requests above.
Re-running the same request with the same seed reproduces a byte-identical mp4,
so an md5 comparison across two runs also works as a smoke check.
-
Warm up once per output shape before timing anything. The first generation of a shape pays a one-time cost that is cached on disk and reused by later processes in the same container: a ~250 s aiter attention-kernel JIT build plus a ~390 s build of the VAE decode path for that shape, so warming 1024² images does nothing for 189-frame video. At 720p / 189 frames / 35 steps this is 540 s cold vs 161 s warm, with byte-identical output.
-
Measured on 1x MI350X (bf16, guardrails off, warm): T2I 1024² @ 50 steps ~2.7 s; T2V 1280×720 / 189 frames @ 35 steps ~161 s, of which ~92% is the DiT denoise loop and ~4% VAE decode, so optimization effort belongs in the denoise loop. The optional flags act on different terms of the memory bill and are therefore complementary rather than redundant:
Flag Latency Peak reserved Peak allocated Acts on (none) 161 s 120 GiB 95 GiB — --vae-use-tiling183 s (+13.5%) 38 GiB (−68%) 36 GiB (−62%) decode activations --enable-layerwise-offload162 s (+0.8%) 84 GiB (−30%) 69 GiB (−27%) weights --quantization fp8150 s (−6.6%) 107 GiB (−11%) 82 GiB (−14%) weights (online, no calibration) Reserved is the caching-allocator high water mark and runs ~2–25 GiB above allocated; allocated is the figure to compare against another platform.
-
--vae-use-tilingis by far the biggest lever for video. Of the 95 GiB allocated by default only ~35 GiB is weights and fixed overhead; the remaining 60 GiB is activations from decoding all 189 frames in one piece, which is why fp8 and offload cannot touch it and why tiling, which leaves under 5 GiB of them, wins so much.--vae-use-slicingis a no-op for a single video request: peak memory is bit-identical to the default. -
--enable-layerwise-offloadis close to free on this part: per-block DiT compute is long enough to hide the weight transfer, so on a card this size it buys headroom for concurrency or higher resolution rather than the speed-for-memory trade it is on small cards. -
Attention backend: the numbers above are aiter FlashAttention, not SDPA. ROCm picks aiter when it is installed and the encoded device capability satisfies
90 < major * 10 + minor < 100(gfx942 and gfx950); otherwise it falls back toTORCH_SDPAand says so only at debug level, which is easy to miss. If you are reporting numbers, assert the choice instead of trusting the default:RocmOmniPlatform.get_diffusion_attn_backend_cls(None, 128)returns the resolved path. -
Determinism is per-configuration: same seed and same flags reproduce a byte-identical mp4 across processes, but different configurations do not match each other — including offload, which nominally only relocates weights, so do not use it as a bit-exact regression baseline. Quality was not evaluated for any configuration.
Same as the online serving section above.
The standard task examples run unchanged:
# Text-to-image
python examples/offline_inference/text_to_image/text_to_image.py \
--model nvidia/Cosmos3-Nano \
--prompt "A photorealistic red sports car at golden hour, cinematic lighting." \
--negative-prompt "blurry, distorted, low quality" \
--height 1024 --width 1024 --num-inference-steps 50 --guidance-scale 7.0 \
--extra-body '{"flow_shift": 3.0, "guardrails": false}' \
--output cosmos3_t2i.png
# Text-to-video
python examples/offline_inference/text_to_video/text_to_video.py \
--model nvidia/Cosmos3-Nano \
--prompt "A robot arm is cleaning a plate in the kitchen." \
--negative-prompt "blurry, distorted, low quality" \
--height 720 --width 1280 --num-frames 189 --fps 24 \
--num-inference-steps 35 --guidance-scale 6.0 --flow-shift 10.0 \
--extra-body '{"max_sequence_length": 4096, "guardrails": false,
"use_resolution_template": false, "use_duration_template": false}' \
--output cosmos3_t2v.mp4Both scripts print Total generation time and Worker peak GPU memory (reserved), which is where the latency and reserved figures in the Notes above
come from. Add --vae-use-tiling, --quantization fp8 or
--enable-layerwise-offload to reproduce the other rows. The allocated column
needs VLLM_LOGGING_LEVEL=DEBUG, which enables a per-request line reporting
reserved, allocated and pool overhead together.
Same as the online serving section above.
- Run each command twice and read the second run; the first pays the one-time
compilation described above. If you run in a container, keep the container
alive between runs (
docker run --rmthrows the JIT cache away and you pay the ~250 s kernel build every time). - Latency and memory figures are identical to the online serving section — they were taken from this path, because a single process has no client/server timing ambiguity.
- OS: Linux (aarch64)
- Python: 3.12+
- Driver / runtime: CANN 8.5.1 + NNAL + Ascend 910B / 910C
- vLLM version: match the repository requirements from your current checkout
- vLLM-Ascend version: match the repository requirements from your current checkout
- vLLM-Omni version or commit: use the commit you are deploying from
Requires the vllm-omni package (or the quay.io/atlas-ci/vllm-ascend A2 / A3 container),
which provides the vllm serve … --omni entrypoint used below.
Safety guardrails are on by default (NVIDIA Open Model License). They load
the gated nvidia/Cosmos-1.0-Guardrail model, so to keep them on you must:
pip install cosmos-guardrail- Accept the license at https://huggingface.co/nvidia/Cosmos-1.0-Guardrail
- Export a token with access:
export HF_TOKEN=hf_...
Then launch the recommended server:
vllm serve nvidia/Cosmos3-Nano \
--omni \
--host 0.0.0.0 --port 8000 \
--init-timeout 1800To run without guardrails (you are responsible for license compliance),
add --no-guardrails (no token/cosmos-guardrail needed). For tensor parallel
add --tensor-parallel-size 8. --quantization fp8 and
--enable-layerwise-offload are not supported on NPU.
The pipeline auto-resolves from model_index.json; pass
--model-class-name Cosmos3OmniDiffusersPipeline to force it explicitly.
Best quality uses the JSON-upsampled prompts from assets/ (download with
hf download nvidia/Cosmos3-Nano assets/ --local-dir Cosmos3-Nano). Minimal
self-contained examples:
curl http://localhost:8000/v1/models
# Text-to-image -> /v1/images/generations (1024x1024, 10 steps; base64 PNG)
curl -sS -X POST http://localhost:8000/v1/images/generations \
-H "Content-Type: application/json" \
-d '{
"model": "nvidia/Cosmos3-Nano",
"prompt": "A photorealistic red sports car on a city street at golden hour, cinematic lighting.",
"negative_prompt": "blurry, distorted, low quality",
"size": "1024x1024", "n": 1, "response_format": "b64_json",
"num_inference_steps": 10, "guidance_scale": 7.0, "seed": 42
}' | python -c "import sys,json,base64; open('cosmos3_t2i.png','wb').write(base64.b64decode(json.load(sys.stdin)['data'][0]['b64_json']))"
# Text-to-video -> /v1/videos/sync (720p, 49 frames @ 24fps)
curl -sS -X POST http://localhost:8000/v1/videos/sync \
-H "Accept: video/mp4" \
-F "model=nvidia/Cosmos3-Nano" \
-F "prompt=A robot arm is cleaning a plate in the kitchen" \
-F "negative_prompt=blurry, distorted, low quality, jittery, deformed" \
-F "size=1280x720" -F "num_frames=49" -F "fps=24" \
-F "num_inference_steps=20" -F "guidance_scale=6.0" \
-F "max_sequence_length=4096" -F "flow_shift=10.0" \
-F "seed=123" \
-o cosmos3_t2v.mp4
# Image-to-video -> /v1/videos/sync with an uploaded reference image
curl -sS -X POST http://localhost:8000/v1/videos/sync \
-H "Accept: video/mp4" \
-F "model=nvidia/Cosmos3-Nano" \
-F "prompt=The scene comes to life with smooth, natural motion." \
-F "size=1280x720" -F "num_frames=25" -F "fps=8" \
-F "num_inference_steps=10" -F "guidance_scale=6.0" \
-F "seed=42" \
-F "input_reference=@reference.jpg;type=image/jpeg" \
-o cosmos3_i2v.mp4
# Video-to-video -> /v1/videos/sync with an uploaded reference video
curl -sS -X POST http://localhost:8000/v1/videos/sync \
-H "Accept: video/mp4" \
-F "model=nvidia/Cosmos3-Nano" \
-F "prompt=Continue the same scene with smooth natural motion and consistent subjects." \
-F "size=1280x720" -F "num_frames=17" -F "fps=5" \
-F "num_inference_steps=10" -F "guidance_scale=6.0" \
-F "seed=42" \
-F "input_reference=@reference.mp4;type=video/mp4" \
-o cosmos3_v2v.mp4- Measured latency (1x Ascend 910B / 910C, bf16, guardrails off):
- T2I 1024² — 10 steps → ~8 s
- T2V 1280×720 @ 20 steps — 49 frames → ~55 s
- I2V 1280×720 @ 10 steps — 25 frames → ~25 s
- V2V 480×320 @ 10 steps — 17 frames → ~12 s
- Memory: transformer ~17 GiB (bf16); peak ~46 GiB for 720p video on 1 NPU; full repo (transformer + Wan VAE + Qwen3-VL vision encoder + audio tokenizer) ~33 GB on disk.
- Determinism: identical seed reproduces identical output on the same hardware; outputs are not bit-identical across different GPU/NPU types.
- Supported sizes (per model card): 256p / 480p / 720p at 16:9, 4:3, 1:1,
3:4, 9:16. Defaults: T2I 1024², 50 steps, guidance 7.0; T2V/I2V/V2V
1280×720, 35 steps, guidance 6.0,
flow_shift=10.0. - Key flags / params:
--no-guardrails(optional, to disable guardrails),--init-timeout 1800(for model loading),--tensor-parallel-size 8for multi-NPU, and--model-class-name Cosmos3OmniDiffusersPipelineto force the pipeline class. - Known limitations:
- Transfer V2V with
extra_params(edge/blur/depth/seg/wsm) hits a resolution-parsing bug; basic V2V without transfer hints works. - FP8 online quantization and layerwise offload are not supported on NPU.
- Transfer V2V with
- OS: Linux (aarch64)
- Python: 3.12+
- Driver / runtime: CANN 8.5.1 + NNAL + Ascend 910B / 910C
- vLLM-Omni version or commit: use the commit you are deploying from
The same offline task examples run on NPU; pass model-specific knobs via
--extra-body. Guardrails are on by default — pass "guardrails": false for a
quick local run (install cosmos-guardrail + accept the gated repo to enable them).
# Text-to-image -> examples/offline_inference/text_to_image
python examples/offline_inference/text_to_image/text_to_image.py \
--model nvidia/Cosmos3-Nano \
--prompt "A photorealistic red sports car at golden hour, cinematic lighting." \
--negative-prompt "blurry, distorted, low quality" \
--height 1024 --width 1024 --num-inference-steps 50 --guidance-scale 7.0 \
--extra-body '{"flow_shift": 3.0, "guardrails": false}' \
--output cosmos3_t2i.png
# Text-to-video -> examples/offline_inference/text_to_video
python examples/offline_inference/text_to_video/text_to_video.py \
--model nvidia/Cosmos3-Nano \
--prompt "A robot arm is cleaning a plate in the kitchen." \
--negative-prompt "blurry, distorted, low quality, jittery, deformed" \
--height 720 --width 1280 --num-frames 189 --fps 24 \
--num-inference-steps 35 --guidance-scale 6.0 \
--extra-body '{"flow_shift": 10.0, "max_sequence_length": 4096, "guardrails": false,
"use_resolution_template": false, "use_duration_template": false}' \
--output cosmos3_t2v.mp4
# Image-to-video -> examples/offline_inference/image_to_video
# (Cosmos3 bundles example frames under assets/; any RGB image works too.)
python examples/offline_inference/image_to_video/image_to_video.py \
--model nvidia/Cosmos3-Nano \
--image /path/to/Cosmos3-Nano/assets/example_i2v_input.jpg \
--prompt "The scene comes to life with smooth, natural motion." \
--height 720 --width 1280 --num-frames 189 --fps 24 \
--num-inference-steps 35 --guidance-scale 6.0 \
--extra-body '{"flow_shift": 10.0, "max_sequence_length": 4096, "guardrails": false}' \
--output cosmos3_i2v.mp4python -c "from PIL import Image; im=Image.open('cosmos3_t2i.png'); print('image', im.size, im.mode)"
ffprobe -v error -show_entries stream=codec_type,nb_frames,width,height cosmos3_t2v.mp4- Guardrails are on by default on NPU with
cosmos-guardrailinstalled. Pass"guardrails": falsein--extra-bodyto disable them (there is no--no-guardrailsflag for the offline scripts). - Video at the 189-frame default takes ~15 min/clip on 1 NPU; reduce
--num-framesfor faster iteration.