Signed-off-by: Chendi Xue <chendi.xue@intel.com> Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
136 lines
6.0 KiB
Markdown
136 lines
6.0 KiB
Markdown
# Speech-To-Video
|
|
|
|
This example demonstrates how to generate talking-head videos from a reference image and an audio clip using the Wan2.2 Speech-to-Video (S2V) pipeline with vLLM-Omni's offline inference API.
|
|
|
|
The S2V pipeline generates multiple video clips autoregressively — the last frames of each clip become the motion context for the next — producing a seamless video that spans the full audio duration.
|
|
|
|
## Prerequisites
|
|
|
|
The S2V pipeline requires `librosa` for audio loading:
|
|
|
|
```bash
|
|
pip install librosa decord
|
|
```
|
|
|
|
## Local CLI Usage
|
|
|
|
### Singing Example (480p)
|
|
|
|
```bash
|
|
wget -O "Five Hundred Miles.png" "https://raw.githubusercontent.com/Wan-Video/Wan2.2/main/examples/Five%20Hundred%20Miles.png"
|
|
wget -O "Five Hundred Miles.MP3" "https://raw.githubusercontent.com/Wan-Video/Wan2.2/main/examples/Five%20Hundred%20Miles.MP3"
|
|
python speech_to_video.py \
|
|
--model Wan-AI/Wan2.2-S2V-14B \
|
|
--image "Five Hundred Miles.png" \
|
|
--audio "Five Hundred Miles.MP3" \
|
|
--prompt "A person singing" \
|
|
--height 448 --width 832 \
|
|
--num-inference-steps 5 \
|
|
--output s2v_singing_480p.mp4
|
|
```
|
|
|
|
## Key Arguments
|
|
|
|
| Parameter | Default | Description |
|
|
|-----------|---------|-------------|
|
|
| `--model` | *(required)* | Path to Wan2.2 S2V model (local path or HuggingFace ID) |
|
|
| `--image` | *(required)* | Path to reference image (face/portrait) |
|
|
| `--audio` | *(required)* | Path to audio file (wav/mp3) |
|
|
| `--prompt` | `"A person speaking naturally"` | Text prompt describing the scene |
|
|
| `--negative-prompt` | *(S2V default)* | Negative prompt (built-in Chinese quality filter if not set) |
|
|
| `--height` / `--width` | *auto* | Output resolution (auto-calculated from image aspect ratio if not set, must be divisible by 64) |
|
|
| `--num-frames` | `80` | Number of frames per clip (should be divisible by 4) |
|
|
| `--num-inference-steps` | `40` | Number of denoising steps |
|
|
| `--guidance-scale` | `4.5` | Classifier-free guidance scale |
|
|
| `--flow-shift` | `3.0` | Scheduler flow shift |
|
|
| `--seed` | `42` | Random seed for reproducibility |
|
|
| `--fps` | `16` | Frames per second for the saved MP4 |
|
|
| `--init-first-frame` | `False` | Use reference image as the first frame |
|
|
| `--output` | `s2v_output.mp4` | Output video file path |
|
|
| `--vae-use-slicing` | `False` | Enable VAE slicing for memory optimization |
|
|
| `--vae-use-tiling` | `False` | Enable VAE tiling for memory optimization |
|
|
| `--tensor-parallel-size` | `1` | Number of GPUs for tensor parallelism (TP) inside the DiT |
|
|
| `--cfg-parallel-size` | `1` | Number of GPUs for CFG parallelism (1 or 2) |
|
|
| `--vae-patch-parallel-size` | `1` | Number of GPUs for VAE patch parallelism |
|
|
| `--enable-cpu-offload` | `False` | Enable CPU offloading |
|
|
| `--enable-layerwise-offload` | `False` | Enable layerwise offloading on DiT |
|
|
|
|
> If you encounter OOM errors, try `--vae-use-slicing` and `--vae-use-tiling` to reduce memory usage, or `--enable-cpu-offload` for more aggressive memory saving.
|
|
|
|
## Performance Tips
|
|
|
|
The dominant cost in S2V is self-attention across the full token sequence (~80K at 720p), which scales quadratically with resolution. Strategies to speed up generation:
|
|
|
|
| Strategy | Speedup | How |
|
|
|---|---|---|
|
|
| **Lower resolution** (480p) | ~3.5x | `--height 448 --width 832` — reduces tokens from 80K to 33K |
|
|
| **Tensor parallelism** (2 GPUs) | ~1.4x | `--tensor-parallel-size 2` — splits attention/GEMM across GPUs |
|
|
| **Fewer steps** | Linear | `--num-inference-steps 5` — trades quality for speed |
|
|
| **Combine all above** | ~5x+ | 480p + TP=2 + 5 steps |
|
|
|
|
## Profiling
|
|
|
|
To profile the S2V pipeline and identify performance bottlenecks:
|
|
|
|
### Enable Built-in Profiler
|
|
|
|
Use `--enable-diffusion-pipeline-profiler` to display stage durations:
|
|
|
|
```bash
|
|
python speech_to_video.py \
|
|
--model Wan-AI/Wan2.2-S2V-14B \
|
|
--image "Five Hundred Miles.png" \
|
|
--audio "Five Hundred Miles.MP3" \
|
|
--prompt "A person singing" \
|
|
--height 448 --width 832 \
|
|
--num-inference-steps 5 \
|
|
--enable-diffusion-pipeline-profiler \
|
|
--output s2v_output.mp4
|
|
```
|
|
|
|
### Torch Profiler (Device-Level Profiling)
|
|
|
|
For detailed GPU/XPU kernel-level profiling with Chrome trace visualization:
|
|
|
|
```bash
|
|
python speech_to_video.py \
|
|
--model Wan-AI/Wan2.2-S2V-14B \
|
|
--image "Five Hundred Miles.png" \
|
|
--audio "Five Hundred Miles.MP3" \
|
|
--prompt "A person singing" \
|
|
--height 448 --width 832 \
|
|
--num-inference-steps 1 \
|
|
--profile-dir /tmp/s2v_profile \
|
|
--profile-record-shapes \
|
|
--profile-with-memory \
|
|
----profile-with-stack \
|
|
--output s2v_profiled.mp4
|
|
```
|
|
|
|
**Profiler Arguments:**
|
|
|
|
| Parameter | Description |
|
|
|-----------|-------------|
|
|
| `--profile-dir` | Enable torch profiler and save traces to this directory |
|
|
| `--profile-record-shapes` | Record tensor shapes (increases trace size) |
|
|
| `--profile-with-stack` | Record stack traces (increases overhead) |
|
|
| `--profile-with-memory` | Profile memory usage |
|
|
| `--profile-with-flops` | Estimate FLOPs for operations |
|
|
|
|
**Output Files:**
|
|
- `trace_rank*.json.gz` - Chrome trace (open in `chrome://tracing`)
|
|
- `ops_rank*.xlsx` - Excel workbook with operation statistics
|
|
|
|
> **Note:** Use `--num-inference-steps 1` for faster profiling. The trace captures one full denoising step with all transformer blocks and attention operations.
|
|
|
|
## How It Works
|
|
|
|
The S2V pipeline processes in the following stages:
|
|
|
|
1. **Pre-process**: The reference image is resized/cropped to fit the target resolution. The audio path is validated.
|
|
2. **Text encoding**: The prompt is encoded using the UMT5 text encoder.
|
|
3. **Audio encoding**: The audio file is loaded via `librosa`, processed through Wav2Vec2, and bucketed to align with video frame-rate. The audio length determines the number of clips (`num_repeat`).
|
|
4. **Reference image encoding**: The reference image is VAE-encoded into latent tokens.
|
|
5. **Multi-clip denoising**: For each clip, random noise is generated and denoised through the `WanModel_S2V` transformer with audio injection. The last frames of each decoded clip become the motion context for the next.
|
|
6. **Post-process**: All clips are concatenated and converted to pixel-space video frames.
|