2026-07-17 11:26:35 +08:00
|
|
|
|
# Replica Data Parallelism for Video Generation
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|------|---------|
|
2026-07-21 20:28:31 +08:00
|
|
|
|
| `wan2_2_ti2v_dp.yaml` | Deploy config; `num_replicas` + `devices` drive the fan-out. |
|
2026-07-17 11:26:35 +08:00
|
|
|
|
| `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):
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 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:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 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: N` fans out `N` replicas; `runtime.devices` assigns their
|
|
|
|
|
|
GPUs. With `tensor_parallel_size = 1`, list one GPU per replica
|
|
|
|
|
|
(`num_replicas * tensor_parallel_size` entries, pool mode).
|
2026-07-21 20:28:31 +08:00
|
|
|
|
- Replica fan-out here comes from the deploy config, not a CLI flag. (The headless /
|
2026-07-17 11:26:35 +08:00
|
|
|
|
multi-runtime launch path uses the process-local `--omni-dp-size-local`, which
|
|
|
|
|
|
requires `--stage-id`.)
|
2026-07-21 20:28:31 +08:00
|
|
|
|
- This recipe serves via `--deploy-config`. Replica fan-out comes from the deploy
|
|
|
|
|
|
config's `num_replicas` / `devices`; stage topology comes from the registered
|
|
|
|
|
|
`WanPipeline`.
|