Image-To-Video¶
Source https://github.com/vllm-project/vllm-omni/tree/main/examples/offline_inference/image_to_video.
This shared example generates videos from images with VACE, Wan2.2, LTX-2/LTX-2.3, HunyuanVideo-1.5, Cosmos3, and other compatible pipelines.
image_to_video.py: command-line script for single video generation with advanced options.
Table of Contents¶
Overview¶
This folder provides a unified CLI script for image-to-video generation using vLLM-Omni diffusion/video pipelines. The script selects practical defaults for supported model families while still exposing common sampling, memory, and parallelism options.
Supported Models¶
| Model | Default Resolution | Default Frames | Default Steps | Guidance | VRAM Notes |
|---|---|---|---|---|---|
Wan-AI/Wan2.2-I2V-A14B-Diffusers | 480 x 832 | 81 | 50 | 5.0 | Around 60 GiB BF16 for basic single-card usage |
Wan-AI/Wan2.2-TI2V-5B-Diffusers | 480 x 832 | 81 | 50 | 4.0 | Around 20–25 GiB BF16, smallest I2V model |
hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-480p_i2v | 480 x 832 | 121 | 50 | 6.0 | Around 100 GiB at default settings; the example enables --enable-cpu-offload + VAE tiling/slicing to fit an 80 GiB card |
LTX2 (local path + --model-class-name LTX2ImageToVideoPipeline) | 512 x 768 | 121 | 40 | 4.0 | Memory use depends on frame count and tensor parallelism |
Info
Peak VRAM: based on basic single-card usage, batch size = 1, without any acceleration/optimization features. Some model weights cannot fit into one card with 80 GiB VRAM, which may need to use CPU offloading.
Default model: Wan-AI/Wan2.2-I2V-A14B-Diffusers.
Prerequisites¶
Download the example image used in the snippets below:
curl -L -o cherry_blossom.jpg https://vllm-public-assets.s3.us-west-2.amazonaws.com/vision_model_images/cherry_blossom.jpg
Quick Start¶
Python API¶
Single-prompt generation using TI2V-5B (lightweight):
import PIL.Image
import torch
from vllm_omni.entrypoints.omni import Omni
from vllm_omni.inputs.data import OmniDiffusionSamplingParams
if __name__ == "__main__":
image = PIL.Image.open("cherry_blossom.jpg").convert("RGB")
image = image.resize((576, 320))
omni = Omni(
model="Wan-AI/Wan2.2-TI2V-5B-Diffusers",
flow_shift=12.0,
)
outputs = omni.generate(
{
"prompt": "Cherry blossoms swaying gently in the breeze, petals falling",
"multi_modal_data": {"image": image},
},
OmniDiffusionSamplingParams(
height=320,
width=576,
num_frames=17,
num_inference_steps=20,
guidance_scale=4.0,
generator=torch.Generator(device="cuda").manual_seed(42),
),
)
from diffusers.utils import export_to_video
frames = outputs[0].request_output.images
export_to_video(frames, "quick_test_i2v.mp4", fps=16)
Local CLI Usage¶
Quick test using TI2V-5B with a small resolution and few frames:
python image_to_video.py \
--model Wan-AI/Wan2.2-TI2V-5B-Diffusers \
--image cherry_blossom.jpg \
--prompt "Cherry blossoms swaying gently in the breeze, petals falling, smooth motion" \
--height 320 \
--width 576 \
--num-frames 17 \
--guidance-scale 4.0 \
--num-inference-steps 20 \
--flow-shift 12.0 \
--fps 16 \
--output quick_test_i2v.mp4
Key Arguments¶
| Argument | Type | Default | Description |
|---|---|---|---|
--model | str | Wan-AI/Wan2.2-I2V-A14B-Diffusers | Diffusers I2V model ID or local path |
--model-class-name | str | None | Override model class name (e.g., LTX2ImageToVideoPipeline) |
--image | str | (required) | Path to input image |
--prompt | str | "" | Text description of desired motion/animation |
--negative-prompt | str | "" | Optional list of artifacts to suppress |
--seed | int | 42 | Random seed for deterministic sampling |
--guidance-scale | float | 5.0 | CFG scale |
--guidance-scale-high | float | None | Separate CFG for high-noise stage (MoE only) |
--height | int | auto | Video height (auto-calculated from image if not set). Multiples of 16 |
--width | int | auto | Video width (auto-calculated from image if not set). Multiples of 16 |
--num-frames | int | 81 | Number of frames |
--num-inference-steps | int | 50 | Number of denoising steps |
--boundary-ratio | float | 0.875 | Boundary split ratio for two-stage MoE models |
--flow-shift | float | 5.0 | Scheduler flow shift (5.0 for 720p, 12.0 for 480p) |
--sample-solver | str | unipc | Wan2.2 sampling solver (unipc or euler for Lightning/Distill) |
--fps | int | None | Frames per second for the saved MP4 |
--frame-rate | float | None | Generation frame rate for pipelines that require it (e.g., LTX2) |
--output | str | i2v_output.mp4 | Path to save the generated video |
--vae-use-slicing | flag | off | Enable VAE slicing for memory optimization |
--vae-use-tiling | flag | off | Enable VAE tiling for memory optimization |
--enable-cpu-offload | flag | off | Enable CPU offloading for diffusion models |
--enable-layerwise-offload | flag | off | Enable layerwise offloading on DiT modules |
--cfg-parallel-size | int | 1 | Set to 2 to enable CFG Parallel |
--tensor-parallel-size | int | 1 | Tensor parallel size (effective for models that support TP, e.g. LTX2) |
--ulysses-degree | int | 1 | Ulysses sequence parallel degree |
--ring-degree | int | 1 | Ring sequence parallel degree |
--cache-backend | str | None | Cache backend: cache_dit or tea_cache |
--use-hsdp | flag | off | Enable Hybrid Sharded Data Parallel |
--hsdp-shard-size | int | -1 | GPUs per shard group (-1 auto-calculates) |
--hsdp-replicate-size | int | 1 | Number of replica groups for HSDP |
More CLI Examples¶
Wan2.2-I2V-A14B-Diffusers (MoE)¶
python image_to_video.py \
--model Wan-AI/Wan2.2-I2V-A14B-Diffusers \
--image cherry_blossom.jpg \
--prompt "Cherry blossoms swaying gently in the breeze, petals falling, smooth motion" \
--negative-prompt "low quality, blurry" \
--height 480 \
--width 832 \
--num-frames 48 \
--guidance-scale 5.0 \
--guidance-scale-high 6.0 \
--num-inference-steps 40 \
--boundary-ratio 0.875 \
--flow-shift 12.0 \
--fps 16 \
--output i2v_wan_moe.mp4
Wan2.2-TI2V-5B-Diffusers (Unified)¶
python image_to_video.py \
--model Wan-AI/Wan2.2-TI2V-5B-Diffusers \
--image cherry_blossom.jpg \
--prompt "Cherry blossoms swaying gently in the breeze, petals falling, smooth motion" \
--negative-prompt "low quality, blurry" \
--height 480 \
--width 832 \
--num-frames 48 \
--guidance-scale 4.0 \
--num-inference-steps 40 \
--flow-shift 12.0 \
--fps 16 \
--output i2v_wan_ti2v.mp4
HunyuanVideo-1.5 I2V (480p)¶
python image_to_video.py \
--model hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-480p_i2v \
--image cherry_blossom.jpg \
--prompt "Cherry blossoms swaying gently in the breeze, petals falling, smooth motion" \
--height 480 \
--width 832 \
--num-frames 121 \
--guidance-scale 6.0 \
--flow-shift 5.0 \
--num-inference-steps 50 \
--fps 24 \
--enable-cpu-offload \
--vae-use-tiling \
--vae-use-slicing \
--output hunyuan_i2v.mp4
LTX2 Image-to-Video¶
python image_to_video.py \
--model /path/to/LTX-2 \
--model-class-name LTX2ImageToVideoPipeline \
--image cherry_blossom.jpg \
--prompt "A cinematic dolly shot of cherry blossoms" \
--height 512 \
--width 768 \
--num-frames 121 \
--num-inference-steps 40 \
--guidance-scale 4.0 \
--frame-rate 24 \
--fps 24 \
--output ltx2_i2v.mp4
Advanced Features¶
CFG Parallel¶
Set --cfg-parallel-size 2 to enable CFG Parallel for faster inference on multi-GPU setups. See more examples in the cfg_parallel user guide.
Cache Acceleration¶
Use --cache-backend cache_dit for Cache-DiT acceleration or --cache-backend tea_cache for Timestep Embedding Aware Cache:
python image_to_video.py \
--model Wan-AI/Wan2.2-I2V-A14B-Diffusers \
--image cherry_blossom.jpg \
--prompt "Cherry blossoms swaying gently in the breeze" \
--cache-backend cache_dit \
--output i2v_cached.mp4
LTX-2.3¶
python image_to_video.py \
--model diffusers/LTX-2.3-Diffusers \
--model-class-name LTX23ImageToVideoPipeline \
--image cherry_blossom.jpg \
--prompt "Cherry blossoms swaying gently in the breeze with synchronized ambient sound" \
--negative-prompt "worst quality, inconsistent motion, blurry, jittery, distorted" \
--height 384 \
--width 512 \
--num-frames 25 \
--guidance-scale 4.0 \
--num-inference-steps 20 \
--frame-rate 24 \
--fps 24 \
--output ltx23_i2v_output.mp4
Use the Diffusers-format checkpoint diffusers/LTX-2.3-Diffusers; the upstream Lightricks/LTX-2.3 raw safetensors repo is not directly loadable by this pipeline. Pass --model-class-name LTX23ImageToVideoPipeline to select the LTX-2.3 image-to-video pipeline.
Cosmos3¶
# Cosmos3 bundles example frames under assets/ (any RGB image works too):
python 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." \
--negative-prompt "blurry, distorted, low quality" \
--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.mp4
Key arguments:
--model: Model ID (I2V-A14B for MoE, TI2V-5B for unified T2V+I2V, LTX-2/LTX-2.3, Cosmos3, or VACE).--image: Path to the first-frame or source image.--last-image: Optional last-frame condition for models such as VACE.--mask-image: Optional inpainting mask. White pixels are regenerated and black pixels are preserved.--reference-image: Optional reference image; repeat it to provide multiple references.--extra-body: JSON object of model-specific generation params, filtered against the model's declaredextra_body_params(seevllm_omni/model_extras). Used by Cosmos3.--prompt: Text description of desired motion/animation.--height/--width: Output resolution (auto-calculated from image if not set). Wan dimensions should be multiples of 16; LTX dimensions should be multiples of 32.--num-frames: Number of frames (model-specific default; LTX-style models work best with8k + 1; Cosmos3 defaults to 189).--guidance-scaleand--guidance-scale-high: CFG scale (applied to low/high-noise stages for MoE).--negative-prompt: Optional list of artifacts to suppress.--boundary-ratio: Boundary split ratio for two-stage MoE models.--flow-shift: Scheduler flow shift (default: model-specific — Wan/LTX2 5.0, Cosmos3 10.0).--sample-solver: Wan2.2 sampling solver. Useunipcfor the default multistep solver, oreulerfor Lightning/Distill checkpoints.--num-inference-steps: Number of denoising steps (default: model-specific — Wan 50, LTX2 40, Cosmos3 35).--fps: Frames per second for the saved MP4 (requiresdiffusersexport_to_video).--audio-sample-rate: fallback audio sample rate for embedded audio.--output: Path to save the generated video.--vae-use-slicing: Enable VAE slicing for memory optimization.--vae-use-tiling: Enable VAE tiling for memory optimization.--cfg-parallel-size: set it to 2 to enable CFG Parallel. See more examples inuser_guide.--tensor-parallel-size: tensor parallel size (effective for models that support TP, e.g. LTX2).--enable-cpu-offload: enable CPU offloading for diffusion models.--use-hsdp: Enable Hybrid Sharded Data Parallel to shard model weights across GPUs.--hsdp-shard-size: Number of GPUs to shard model weights across within each replica group. -1 (default) auto-calculates as world_size / replicate_size.--hsdp-replicate-size: Number of replica groups for HSDP. Each replica holds a full sharded copy. Default 1 means pure sharding (no replication).
ℹ️ If you encounter OOM errors, try using
--vae-use-slicingand--vae-use-tilingto reduce memory usage.
Wan2.1 VACE Conditional Tasks¶
The shared script selects the VACE conditioning structure from the media inputs. No explicit mode parameter is required: the script constructs the source video, mask, or reference images consumed by the VACE pipeline. Download the same Hugging Face assets used by the original VACE example:
wget -O astronaut.jpg https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/astronaut.jpg
wget -O vace_first_frame.png https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/flf2v_input_first_frame.png
wget -O vace_last_frame.png https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/flf2v_input_last_frame.png
Image-to-Video (I2V)¶
python image_to_video.py \
--model Wan-AI/Wan2.1-VACE-1.3B-diffusers \
--image astronaut.jpg \
--prompt "An astronaut emerging from a cracked, otherworldly egg on the surface of the moon" \
--seed 42 --height 480 --width 832 --num-frames 81 \
--num-inference-steps 30 --guidance-scale 5.0 --flow-shift 5.0 \
--vae-use-tiling --output vace_i2v_output.mp4
Video-to-Last-Frame (V2LF)¶
python image_to_video.py \
--model Wan-AI/Wan2.1-VACE-1.3B-diffusers \
--last-image astronaut.jpg \
--prompt "An astronaut emerging from a cracked, otherworldly egg on the surface of the moon" \
--seed 42 --height 480 --width 832 --num-frames 81 \
--num-inference-steps 30 --guidance-scale 5.0 --flow-shift 5.0 \
--vae-use-tiling --output vace_v2lf_output.mp4
First-Last-Frame-to-Video (FLF2V)¶
python image_to_video.py \
--model Wan-AI/Wan2.1-VACE-1.3B-diffusers \
--image vace_first_frame.png \
--last-image vace_last_frame.png \
--prompt "CG animation style, a small blue bird takes off from a branch and lands on another branch" \
--seed 42 --height 512 --width 512 --num-frames 81 \
--num-inference-steps 30 --guidance-scale 5.0 --flow-shift 5.0 \
--vae-use-tiling --output vace_flf2v_output.mp4
Inpainting¶
Create a mask matching the original VACE example: a 160-pixel-wide white vertical stripe marks the region to regenerate.
python - <<'PY'
from PIL import Image
mask = Image.new("L", (832, 480), 0)
mask.paste(255, (336, 0, 496, 480))
mask.save("vace_center_mask.png")
PY
python image_to_video.py \
--model Wan-AI/Wan2.1-VACE-1.3B-diffusers \
--image astronaut.jpg \
--mask-image vace_center_mask.png \
--prompt "Shrek, the ogre, walks out of a building in a happy mood" \
--seed 42 --height 480 --width 832 --num-frames 81 \
--num-inference-steps 30 --guidance-scale 5.0 --flow-shift 5.0 \
--vae-use-tiling --output vace_inpaint_output.mp4
Reference-to-Video (R2V)¶
Repeat --reference-image to provide more than one reference image.
python image_to_video.py \
--model Wan-AI/Wan2.1-VACE-1.3B-diffusers \
--reference-image astronaut.jpg \
--prompt "Camera slowly zooms out from the character walking in a garden" \
--seed 42 --height 480 --width 832 --num-frames 81 \
--num-inference-steps 30 --guidance-scale 5.0 --flow-shift 5.0 \
--vae-use-tiling --output vace_r2v_output.mp4
The VACE T2V command is documented in the shared text_to_video.py example.
For Wan2.2 LightX2V-converted local Diffusers directories and related LoRA assets, see the LoRA guide.
FAQ¶
OOM errors: Try using --vae-use-slicing and --vae-use-tiling to reduce memory usage. For very large models, add --enable-cpu-offload or --enable-layerwise-offload.
Auto-calculated resolution: If --height and --width are not provided, the script calculates output dimensions from the input image while maintaining aspect ratio and targeting 480 x 832 area (or 512 x 768 for LTX2).
Wan2.2 MoE vs unified: I2V-A14B is a larger Mixture-of-Experts model with separate low/high-noise DiT stages (use --guidance-scale-high and --boundary-ratio). TI2V-5B is a smaller unified T2V+I2V model that does not need these extra arguments.
Example materials¶
image_to_video.py
Large file omitted from the rendered docs. View it on GitHub: https://github.com/vllm-project/vllm-omni/blob/main/examples/offline_inference/image_to_video/image_to_video.py.