Replica Data Parallelism for Video Generation¶
Source https://github.com/vllm-project/vllm-omni/tree/main/examples/online_serving/replica_data_parallel.
A runnable recipe + benchmark for replica data parallelism (replica-DP) on a video DiT. Replica-DP runs N independent diffusion engine replicas, one per GPU, and routes each request to a single replica. It scales request throughput near-linearly; it does not change single-request latency (for that, use an intra-request axis such as tensor/sequence/CFG parallelism).
This example uses Wan-AI/Wan2.2-TI2V-5B-Diffusers with one GPU per replica.
Files¶
| File | Purpose |
|---|---|
wan2_2_ti2v_dp.yaml | Deploy config; num_replicas + devices drive the fan-out. |
run_server.sh | Substitutes NUM_REPLICAS / DEVICES into the config and serves. |
bench_replica_dp.py | Replica-agnostic load driver; reports throughput, latency, and a per-input isolation check. |
Run¶
Start the server with the replica count you want (one GPU per replica):
# baseline
NUM_REPLICAS=1 DEVICES=0 ./run_server.sh
# 2 replicas
NUM_REPLICAS=2 DEVICES=0,1 ./run_server.sh
# 4 replicas
NUM_REPLICAS=4 DEVICES=0,1,2,3 ./run_server.sh
In another shell, drive a fixed workload and read the throughput:
python bench_replica_dp.py --url http://127.0.0.1:8098 \
--num-requests 28 --concurrency 8 --label "replicas=4"
Re-run the server at NUM_REPLICAS=1,2,4 (same client workload each time) and compare videos/min. Pass --baseline-tpm <N=1 value> to print a scaling factor.
Isolation check¶
Identical outputs under a shared prompt+seed prove nothing -- every request would be identical regardless of isolation. Instead each request gets a distinct input (a prompt from the pool + a unique seed base_seed+i), and we check that a request's output is unchanged whether it runs alone or concurrently amid other distinct requests. Capture a per-input baseline on N=1, then verify it under N>=2 concurrency:
# 1) against NUM_REPLICAS=1 (serial), record each input's output hash
python bench_replica_dp.py --num-requests 8 --concurrency 1 \
--write-baseline baseline.json
# 2) against NUM_REPLICAS>=2, replay the SAME inputs concurrently and verify
python bench_replica_dp.py --num-requests 8 --concurrency 8 \
--check-baseline baseline.json
Step 2 exits non-zero if any request's output differs from its own baseline (a mismatch means cross-request state bleed or misrouting). Keep --num-requests, --base-seed, and the prompt source identical between the two runs so the input sets match.
Measured scaling¶
Wan2.2-TI2V-5B (832×480, 33 frames, 30 steps), 4× A800-80GB (NVLink), one GPU per replica:
| Replicas | Throughput (videos/min) | Scaling | Efficiency |
|---|---|---|---|
| 1 | 4.71 | 1.00× | — |
| 2 | 9.20 | 1.95× | 98% |
| 4 | 18.02 | 3.83× | 96% |
Per-request latency stayed flat (~13–14 s) across all replica counts. Isolation is checked per-input via the baseline/verify protocol above: each request's output under N>=2 concurrency must match its own single-replica baseline.
Notes on the config surface¶
runtime.num_replicas: Nfans outNreplicas;runtime.devicesassigns their GPUs. Withtensor_parallel_size = 1, list one GPU per replica (num_replicas * tensor_parallel_sizeentries, pool mode).- Replica fan-out here comes from the deploy config, not a CLI flag. (The headless / multi-runtime launch path uses the process-local
--omni-dp-size-local, which requires--stage-id.) - This recipe serves via
--deploy-config. Replica fan-out comes from the deploy config'snum_replicas/devices; stage topology comes from the registeredWanPipeline.
Example materials¶
bench_replica_dp.py
Large file omitted from the rendered docs. View it on GitHub: https://github.com/vllm-project/vllm-omni/blob/main/examples/online_serving/replica_data_parallel/bench_replica_dp.py.
run_server.sh
#!/usr/bin/env bash
# Serve N independent Wan2.2 TI2V-5B replicas (replica data parallelism).
#
# Usage:
# NUM_REPLICAS=1 DEVICES=0 ./run_server.sh # baseline
# NUM_REPLICAS=2 DEVICES=0,1 ./run_server.sh
# NUM_REPLICAS=4 DEVICES=0,1,2,3 ./run_server.sh
#
# Then drive load with bench_replica_dp.py (see README.md) and compare
# throughput across replica counts.
set -euo pipefail
MODEL="${MODEL:-Wan-AI/Wan2.2-TI2V-5B-Diffusers}"
HOST="${HOST:-127.0.0.1}"
PORT="${PORT:-8098}"
NUM_REPLICAS="${NUM_REPLICAS:-1}"
DEVICES="${DEVICES:-0}" # one GPU per replica for tensor_parallel_size=1
HERE="$(cd "$(dirname "$0")" && pwd)"
TEMPLATE="$HERE/wan2_2_ti2v_dp.yaml"
CFG="$(mktemp --suffix=_wan2_2_dp.yaml)"
trap 'rm -f "$CFG"' EXIT
sed -e "s/__NUM_REPLICAS__/${NUM_REPLICAS}/" \
-e "s/__DEVICES__/${DEVICES}/" \
"$TEMPLATE" > "$CFG"
echo "Serving ${MODEL}: num_replicas=${NUM_REPLICAS} devices=${DEVICES} (config ${CFG})"
vllm serve "$MODEL" --omni \
--host "$HOST" \
--port "$PORT" \
--deploy-config "$CFG"
wan2_2_ti2v_dp.yaml
# Replica data-parallel recipe for Wan2.2 TI2V-5B (video DiT).
#
# Fans out `num_replicas` independent DiffusionEngine replicas, one per GPU,
# and lets the serving layer route each request to a single replica. This
# scales request throughput near-linearly; it does not change single-request
# latency. See ./README.md for measured numbers and the `run_server.sh` driver.
#
# run_server.sh substitutes __NUM_REPLICAS__ / __DEVICES__ from env before serving.
# For tensor_parallel_size = 1, `devices` lists one GPU per replica (pool mode):
# num_replicas=4 -> devices "0,1,2,3".
#
# Stage topology (diffusion DiT, video output) comes from the registered
# WanPipeline, which auto-detects TI2V-5B mode from model_index.json; this file
# carries deployment knobs only.
trust_remote_code: true
distributed_executor_backend: mp
stages:
- stage_id: 0
num_replicas: __NUM_REPLICAS__
devices: "__DEVICES__"
max_num_seqs: 1
tensor_parallel_size: 1
enforce_eager: true
vae_use_tiling: true
default_sampling_params:
seed: 42