Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b188874539 |
No files matched your search
@@ -14,8 +14,6 @@ set -euo pipefail
|
|||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source .buildkite/common/scripts/resolve_skip_ci.sh
|
source .buildkite/common/scripts/resolve_skip_ci.sh
|
||||||
|
|
||||||
AMD_SUITE_SELECTOR=".buildkite/amd/scripts/select_test_suites.py"
|
|
||||||
|
|
||||||
if [[ -z "${RUN_ALL:-}" ]]; then
|
if [[ -z "${RUN_ALL:-}" ]]; then
|
||||||
RUN_ALL=0
|
RUN_ALL=0
|
||||||
fi
|
fi
|
||||||
@@ -32,20 +30,31 @@ if [[ -z "${AMD_MIRROR_HW:-}" ]]; then
|
|||||||
AMD_MIRROR_HW="amdproduction"
|
AMD_MIRROR_HW="amdproduction"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PR_LABELS=""
|
|
||||||
# Explicit debug suites do not depend on PR labels.
|
|
||||||
if [[ "${BUILDKITE_PULL_REQUEST:-false}" != "false" && -z "${DEBUG_TEST_YAML:-}" ]]; then
|
|
||||||
if ! PR_LABELS=$(curl -fsSL \
|
|
||||||
"https://api.github.com/repos/vllm-project/vllm-omni/pulls/$BUILDKITE_PULL_REQUEST" \
|
|
||||||
| jq -r '.labels[].name'); then
|
|
||||||
echo "ERROR: Could not read PR labels; refusing to select an incorrect AMD test tier." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
fail_fast() {
|
fail_fast() {
|
||||||
if [[ "${BUILDKITE_PULL_REQUEST:-false}" != "false" ]]; then
|
DISABLE_LABEL="ci-no-fail-fast"
|
||||||
|
# If BUILDKITE_PULL_REQUEST != "false", then we check the PR labels using curl and jq
|
||||||
|
if [ "$BUILDKITE_PULL_REQUEST" != "false" ]; then
|
||||||
|
PR_LABELS=$(curl -s "https://api.github.com/repos/vllm-project/vllm-omni/pulls/$BUILDKITE_PULL_REQUEST" | jq -r '.labels[].name')
|
||||||
|
if [[ $PR_LABELS == *"$DISABLE_LABEL"* ]]; then
|
||||||
|
echo false
|
||||||
|
else
|
||||||
echo true
|
echo true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo false # not a PR or BUILDKITE_PULL_REQUEST not set
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_run_all_label() {
|
||||||
|
RUN_ALL_LABEL="ready-run-all-tests"
|
||||||
|
# If BUILDKITE_PULL_REQUEST != "false", then we check the PR labels using curl and jq
|
||||||
|
if [ "$BUILDKITE_PULL_REQUEST" != "false" ]; then
|
||||||
|
PR_LABELS=$(curl -s "https://api.github.com/repos/vllm-project/vllm-omni/pulls/$BUILDKITE_PULL_REQUEST" | jq -r '.labels[].name')
|
||||||
|
if [[ $PR_LABELS == *"$RUN_ALL_LABEL"* ]]; then
|
||||||
|
echo true
|
||||||
|
else
|
||||||
|
echo false
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo false # not a PR or BUILDKITE_PULL_REQUEST not set
|
echo false # not a PR or BUILDKITE_PULL_REQUEST not set
|
||||||
fi
|
fi
|
||||||
@@ -55,57 +64,6 @@ if [[ -z "${COV_ENABLED:-}" ]]; then
|
|||||||
COV_ENABLED=0
|
COV_ENABLED=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
resolve_test_specs() {
|
|
||||||
local selected_specs
|
|
||||||
if ! selected_specs=$(python3 "$AMD_SUITE_SELECTOR" \
|
|
||||||
--branch "$BUILDKITE_BRANCH" \
|
|
||||||
--labels "$PR_LABELS" \
|
|
||||||
--debug-test-yaml "${DEBUG_TEST_YAML:-}"); then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
TEST_SPECS=()
|
|
||||||
while IFS= read -r suite_spec; do
|
|
||||||
[[ -z "$suite_spec" ]] && continue
|
|
||||||
TEST_SPECS+=("$suite_spec")
|
|
||||||
done <<< "$selected_specs"
|
|
||||||
}
|
|
||||||
|
|
||||||
filter_test_specs_by_skip_ci() {
|
|
||||||
local suite_spec level decision
|
|
||||||
local skip_all=0
|
|
||||||
local -a runnable_specs=()
|
|
||||||
|
|
||||||
for suite_spec in "${TEST_SPECS[@]}"; do
|
|
||||||
case "$suite_spec" in
|
|
||||||
READY_TESTS:*) level="l2" ;;
|
|
||||||
MERGE_TESTS:*) level="l3" ;;
|
|
||||||
*)
|
|
||||||
echo "ERROR: unknown AMD test suite spec '$suite_spec'" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if decision=$(python3 "$SKIP_CI_PY" gate amd "$level"); then
|
|
||||||
echo "Skipping AMD $level suite due to $decision decision."
|
|
||||||
[[ "$decision" == "skip-all" ]] && skip_all=1
|
|
||||||
else
|
|
||||||
runnable_specs+=("$suite_spec")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
TEST_SPECS=("${runnable_specs[@]}")
|
|
||||||
if [[ ${#TEST_SPECS[@]} -eq 0 ]]; then
|
|
||||||
if [[ $skip_all -eq 1 ]]; then
|
|
||||||
buildkite-agent annotate \
|
|
||||||
":memo: CI skipped — docs or pytest skip-mark changes only" \
|
|
||||||
--style "info" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
echo "No AMD L2/L3 suites remain after skip-ci filtering."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
upload_pipeline() {
|
upload_pipeline() {
|
||||||
echo "Uploading pipeline..."
|
echo "Uploading pipeline..."
|
||||||
# Install minijinja
|
# Install minijinja
|
||||||
@@ -126,7 +84,7 @@ upload_pipeline() {
|
|||||||
# (WIP) Use pipeline generator instead of jinja template
|
# (WIP) Use pipeline generator instead of jinja template
|
||||||
if [ -e ".buildkite/amd/pipeline_generator/pipeline_generator.py" ]; then
|
if [ -e ".buildkite/amd/pipeline_generator/pipeline_generator.py" ]; then
|
||||||
python -m pip install click pydantic
|
python -m pip install click pydantic
|
||||||
python .buildkite/amd/pipeline_generator/pipeline_generator.py --run_all="$RUN_ALL" --list_file_diff="$LIST_FILE_DIFF" --nightly="$NIGHTLY" --mirror_hw="$AMD_MIRROR_HW"
|
python .buildkite/amd/pipeline_generator/pipeline_generator.py --run_all=$RUN_ALL --list_file_diff="$LIST_FILE_DIFF" --nightly="$NIGHTLY" --mirror_hw="$AMD_MIRROR_HW"
|
||||||
buildkite-agent pipeline upload .buildkite/amd/pipeline.yaml
|
buildkite-agent pipeline upload .buildkite/amd/pipeline.yaml
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@@ -139,12 +97,49 @@ upload_pipeline() {
|
|||||||
|
|
||||||
cd .buildkite/amd
|
cd .buildkite/amd
|
||||||
|
|
||||||
# Multiple label-selected or debug-selected suites share one image build.
|
# Select test definition file: merge suite for main, ready suite for PRs.
|
||||||
if [[ ${#TEST_SPECS[@]} -eq 1 ]]; then
|
# For debugging, DEBUG_TEST_YAML accepts a comma-separated list containing
|
||||||
TEST_YAML="${TEST_SPECS[0]#*:}"
|
# "merge" and/or "ready" (case-insensitive). Multiple suites are combined
|
||||||
|
# before rendering so they share one amd-build step.
|
||||||
|
if [[ -n "${DEBUG_TEST_YAML:-}" ]]; then
|
||||||
|
declare -a DEBUG_TEST_SPECS=()
|
||||||
|
declare -A SEEN_DEBUG_TESTS=()
|
||||||
|
IFS=',' read -ra REQUESTED_DEBUG_TESTS <<< "${DEBUG_TEST_YAML,,}"
|
||||||
|
|
||||||
|
for requested_test in "${REQUESTED_DEBUG_TESTS[@]}"; do
|
||||||
|
# Permit readable values such as "ready, merge," and ignore the
|
||||||
|
# empty item produced by a trailing comma.
|
||||||
|
requested_test="${requested_test//[[:space:]]/}"
|
||||||
|
[[ -z "$requested_test" ]] && continue
|
||||||
|
|
||||||
|
if [[ -n "${SEEN_DEBUG_TESTS[$requested_test]:-}" ]]; then
|
||||||
|
echo "ERROR: duplicate DEBUG_TEST_YAML suite '$requested_test'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
SEEN_DEBUG_TESTS[$requested_test]=1
|
||||||
|
|
||||||
|
case "$requested_test" in
|
||||||
|
ready)
|
||||||
|
DEBUG_TEST_SPECS+=("READY_TESTS:test-amd-ready.yml")
|
||||||
|
;;
|
||||||
|
merge)
|
||||||
|
DEBUG_TEST_SPECS+=("MERGE_TESTS:test-amd-merge.yml")
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "ERROR: DEBUG_TEST_YAML entries must be 'merge' or 'ready', got '$requested_test'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#DEBUG_TEST_SPECS[@]} -eq 0 ]]; then
|
||||||
|
echo "ERROR: DEBUG_TEST_YAML did not contain a test suite" >&2
|
||||||
|
exit 1
|
||||||
|
elif [[ ${#DEBUG_TEST_SPECS[@]} -eq 1 ]]; then
|
||||||
|
TEST_YAML="${DEBUG_TEST_SPECS[0]#*:}"
|
||||||
else
|
else
|
||||||
TEST_YAML=$(mktemp "${TMPDIR:-/tmp}/amd-selected-tests.XXXXXX.yml")
|
TEST_YAML=$(mktemp "${TMPDIR:-/tmp}/amd-debug-tests.XXXXXX.yml")
|
||||||
python - "$TEST_YAML" "${TEST_SPECS[@]}" <<'PY'
|
python - "$TEST_YAML" "${DEBUG_TEST_SPECS[@]}" <<'PY'
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
@@ -178,7 +173,12 @@ with open(output_path, "w", encoding="utf-8") as output_file:
|
|||||||
yaml.safe_dump(combined, output_file, sort_keys=False)
|
yaml.safe_dump(combined, output_file, sort_keys=False)
|
||||||
PY
|
PY
|
||||||
fi
|
fi
|
||||||
echo "AMD test suites: ${TEST_SPECS[*]}"
|
echo "DEBUG_TEST_YAML override: using ${DEBUG_TEST_SPECS[*]}"
|
||||||
|
elif [[ $BUILDKITE_BRANCH == "main" ]]; then
|
||||||
|
TEST_YAML="test-amd-merge.yml"
|
||||||
|
else
|
||||||
|
TEST_YAML="test-amd-ready.yml"
|
||||||
|
fi
|
||||||
|
|
||||||
(
|
(
|
||||||
set -x
|
set -x
|
||||||
@@ -198,7 +198,7 @@ PY
|
|||||||
> pipeline.yaml
|
> pipeline.yaml
|
||||||
)
|
)
|
||||||
cat pipeline.yaml
|
cat pipeline.yaml
|
||||||
if [[ "$TEST_YAML" == "${TMPDIR:-/tmp}/amd-selected-tests."*.yml ]]; then
|
if [[ "$TEST_YAML" == "${TMPDIR:-/tmp}/amd-debug-tests."*.yml ]]; then
|
||||||
rm -f -- "$TEST_YAML"
|
rm -f -- "$TEST_YAML"
|
||||||
fi
|
fi
|
||||||
buildkite-agent artifact upload pipeline.yaml
|
buildkite-agent artifact upload pipeline.yaml
|
||||||
@@ -219,10 +219,12 @@ if [[ $BUILDKITE_BRANCH == "main" ]]; then
|
|||||||
file_diff=$(get_diff_main)
|
file_diff=$(get_diff_main)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Resolve PR tier labels before skip-ci so ready and merge suites can be
|
# Early exit: unified skip-ci (docs / skip marks) and CI-yaml-only level targeting.
|
||||||
# filtered independently for CI-YAML-only changes.
|
if [[ $BUILDKITE_BRANCH == "main" ]]; then
|
||||||
resolve_test_specs
|
gate_bootstrap_ci amd l3
|
||||||
filter_test_specs_by_skip_ci
|
else
|
||||||
|
gate_bootstrap_ci amd l2
|
||||||
|
fi
|
||||||
|
|
||||||
patterns=(
|
patterns=(
|
||||||
"docker/Dockerfile"
|
"docker/Dockerfile"
|
||||||
@@ -272,6 +274,14 @@ for file in $file_diff; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Check for ready-run-all-tests label
|
||||||
|
LABEL_RUN_ALL=$(check_run_all_label)
|
||||||
|
if [[ $LABEL_RUN_ALL == true ]]; then
|
||||||
|
RUN_ALL=1
|
||||||
|
NIGHTLY=1
|
||||||
|
echo "Found 'ready-run-all-tests' label. Running all tests including optional tests."
|
||||||
|
fi
|
||||||
|
|
||||||
# Decide whether to use precompiled wheels
|
# Decide whether to use precompiled wheels
|
||||||
# Relies on existing patterns array as a basis.
|
# Relies on existing patterns array as a basis.
|
||||||
if [[ -n "${VLLM_USE_PRECOMPILED:-}" ]]; then
|
if [[ -n "${VLLM_USE_PRECOMPILED:-}" ]]; then
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
|
||||||
"""Select AMD L2/L3 suites after Buildkite has created an AMD build.
|
|
||||||
|
|
||||||
This repository-side selector does not decide which GitHub label events start
|
|
||||||
the external ``vllm-omni-amd-ci`` pipeline. Its Buildkite PR build condition
|
|
||||||
must admit the relevant label event before this code can inspect the labels.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import sys
|
|
||||||
from collections.abc import Iterable
|
|
||||||
|
|
||||||
SUITE_SPECS = {
|
|
||||||
"ready": "READY_TESTS:test-amd-ready.yml",
|
|
||||||
"merge": "MERGE_TESTS:test-amd-merge.yml",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_debug_suites(value: str) -> tuple[str, ...]:
|
|
||||||
suites = tuple(item.strip().lower() for item in value.split(",") if item.strip())
|
|
||||||
if not suites:
|
|
||||||
raise ValueError("DEBUG_TEST_YAML did not contain a test suite")
|
|
||||||
|
|
||||||
seen: set[str] = set()
|
|
||||||
for suite in suites:
|
|
||||||
if suite not in SUITE_SPECS:
|
|
||||||
raise ValueError(f"DEBUG_TEST_YAML entries must be 'merge' or 'ready', got {suite!r}")
|
|
||||||
if suite in seen:
|
|
||||||
raise ValueError(f"duplicate DEBUG_TEST_YAML suite {suite!r}")
|
|
||||||
seen.add(suite)
|
|
||||||
return suites
|
|
||||||
|
|
||||||
|
|
||||||
def select_amd_test_suites(
|
|
||||||
*,
|
|
||||||
branch: str,
|
|
||||||
labels: Iterable[str],
|
|
||||||
debug_test_yaml: str = "",
|
|
||||||
) -> tuple[str, ...]:
|
|
||||||
"""Return ordered suite names while preserving legacy unlabeled PRs."""
|
|
||||||
|
|
||||||
if debug_test_yaml:
|
|
||||||
return _parse_debug_suites(debug_test_yaml)
|
|
||||||
if branch == "main":
|
|
||||||
return ("merge",)
|
|
||||||
|
|
||||||
label_set = {label.strip() for label in labels if label.strip()}
|
|
||||||
selected = tuple(suite for label, suite in (("ready", "ready"), ("merge-test", "merge")) if label in label_set)
|
|
||||||
# AMD historically uploaded L2 for every PR build. Keep that behavior for
|
|
||||||
# triggers such as amd-test while adding tier selection for ready/merge-test.
|
|
||||||
return selected or ("ready",)
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--branch", required=True)
|
|
||||||
parser.add_argument("--labels", default="")
|
|
||||||
parser.add_argument("--debug-test-yaml", default="")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
labels = tuple(args.labels.splitlines())
|
|
||||||
try:
|
|
||||||
suites = select_amd_test_suites(
|
|
||||||
branch=args.branch,
|
|
||||||
labels=labels,
|
|
||||||
debug_test_yaml=args.debug_test_yaml,
|
|
||||||
)
|
|
||||||
except ValueError as exc:
|
|
||||||
parser.error(str(exc))
|
|
||||||
|
|
||||||
label_set = {label.strip() for label in labels if label.strip()}
|
|
||||||
if not args.debug_test_yaml and args.branch != "main" and not ({"ready", "merge-test"} & label_set):
|
|
||||||
print(
|
|
||||||
"No AMD L2/L3 tier label found; preserving the legacy ready-suite fallback.",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
if "nightly-test" in label_set:
|
|
||||||
print(
|
|
||||||
"AMD nightly-test has no suite yet and does not affect L2/L3 selection.",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
|
|
||||||
for suite in suites:
|
|
||||||
print(SUITE_SPECS[suite])
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
raise SystemExit(main())
|
|
||||||
@@ -107,11 +107,6 @@ steps:
|
|||||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||||
- timeout 20m pytest -s -v tests/diffusion/distributed/test_sequence_parallel.py -m core_model
|
- timeout 20m pytest -s -v tests/diffusion/distributed/test_sequence_parallel.py -m core_model
|
||||||
- >-
|
|
||||||
timeout 20m pytest -s -v
|
|
||||||
tests/diffusion/models/ltx2/test_ltx2_transformer_ulysses.py
|
|
||||||
-m 'core_model and rocm and cards_2'
|
|
||||||
--run-level "core_model"
|
|
||||||
|
|
||||||
- label: "Diffusion GPU Worker Test"
|
- label: "Diffusion GPU Worker Test"
|
||||||
agent_pool: mi300_2
|
agent_pool: mi300_2
|
||||||
@@ -127,13 +122,7 @@ steps:
|
|||||||
mirror_hardwares: [amdproduction]
|
mirror_hardwares: [amdproduction]
|
||||||
grade: Blocking
|
grade: Blocking
|
||||||
commands:
|
commands:
|
||||||
# Preserve legacy one-GPU tests without cards_1 while excluding every
|
- timeout 15m pytest -sv tests/diffusion/models/ -m 'core_model and cuda' --run-level "core_model"
|
||||||
# registered multi-GPU marker from this one-GPU job.
|
|
||||||
- >-
|
|
||||||
timeout 15m pytest -sv tests/diffusion/models/
|
|
||||||
-m 'core_model and cuda and not
|
|
||||||
(cards_2 or cards_3 or cards_4 or cards_5 or cards_6 or cards_7 or cards_8)'
|
|
||||||
--run-level "core_model"
|
|
||||||
|
|
||||||
- label: "Diffusion · Wan22 Test"
|
- label: "Diffusion · Wan22 Test"
|
||||||
agent_pool: mi300_1
|
agent_pool: mi300_1
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
# a2b3_npu_1 — ascend-a2b3, resource_class npu-1 (A2/B3 CI image)
|
# a2b3_npu_1 — ascend-a2b3, resource_class npu-1 (A2/B3 CI image)
|
||||||
# a2b3_npu_4 — ascend-a2b3, resource_class npu-4
|
# a2b3_npu_4 — ascend-a2b3, resource_class npu-4
|
||||||
# a3_npu_2 — ascend-a3, resource_class npu-2 (A3 CI image tag …:$BUILDKITE_COMMIT-a3)
|
# a3_npu_2 — ascend-a3, resource_class npu-2 (A3 CI image tag …:$BUILDKITE_COMMIT-a3)
|
||||||
# a5_npu_2 — ascend-a5, resource_class npu-2
|
|
||||||
# 310p_npu_1 — ascend-310p, resource_class npu-1
|
|
||||||
#
|
#
|
||||||
# B200 (b200-k8s): matches vLLM device ``b200-k8s`` from ci-infra
|
# B200 (b200-k8s): matches vLLM device ``b200-k8s`` from ci-infra
|
||||||
# (AgentQueue.B200_K8S + b200_plugin_template). Queue routes the K8s pool;
|
# (AgentQueue.B200_K8S + b200_plugin_template). Queue routes the K8s pool;
|
||||||
@@ -28,9 +26,6 @@
|
|||||||
# packed onto g6.12xlarge L4 nodes (``vllm.ci/gpu-pool=l4x4``). GPU / CPU /
|
# packed onto g6.12xlarge L4 nodes (``vllm.ci/gpu-pool=l4x4``). GPU / CPU /
|
||||||
# memory / shm requests scale with card count (1 GPU = 10 CPU / 40Gi / 24Gi shm).
|
# memory / shm requests scale with card count (1 GPU = 10 CPU / 40Gi / 24Gi shm).
|
||||||
# Retry covers lost agents / killed pods, not pytest or OOM (exit 1 / 137).
|
# Retry covers lost agents / killed pods, not pytest or OOM (exit 1 / 137).
|
||||||
# The Kubernetes HF secret deliberately uses VLLM_CI_HF_TOKEN. Scheduled
|
|
||||||
# build-level HF_TOKEN values can override pod env entries with the same name;
|
|
||||||
# upload_pipeline.py restores the secret-backed value inside the job shell.
|
|
||||||
|
|
||||||
x-npu-k8s-plugins: &npu_k8s_plugins
|
x-npu-k8s-plugins: &npu_k8s_plugins
|
||||||
- kubernetes:
|
- kubernetes:
|
||||||
@@ -89,7 +84,7 @@ mirror_hardwares:
|
|||||||
env:
|
env:
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /fsx/hf_cache
|
value: /fsx/hf_cache
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -140,7 +135,7 @@ mirror_hardwares:
|
|||||||
env:
|
env:
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /fsx/hf_cache
|
value: /fsx/hf_cache
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -191,7 +186,7 @@ mirror_hardwares:
|
|||||||
env:
|
env:
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /fsx/hf_cache
|
value: /fsx/hf_cache
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -242,7 +237,7 @@ mirror_hardwares:
|
|||||||
env:
|
env:
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /fsx/hf_cache
|
value: /fsx/hf_cache
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -276,7 +271,7 @@ mirror_hardwares:
|
|||||||
env:
|
env:
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /root/.cache/huggingface
|
value: /root/.cache/huggingface
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -311,7 +306,7 @@ mirror_hardwares:
|
|||||||
env:
|
env:
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /root/.cache/huggingface
|
value: /root/.cache/huggingface
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -346,7 +341,7 @@ mirror_hardwares:
|
|||||||
env:
|
env:
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /root/.cache/huggingface
|
value: /root/.cache/huggingface
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -381,7 +376,7 @@ mirror_hardwares:
|
|||||||
env:
|
env:
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /root/.cache/huggingface
|
value: /root/.cache/huggingface
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -431,7 +426,7 @@ mirror_hardwares:
|
|||||||
value: "0"
|
value: "0"
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /raid/hf_cache
|
value: /raid/hf_cache
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -482,7 +477,7 @@ mirror_hardwares:
|
|||||||
value: "0"
|
value: "0"
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /raid/hf_cache
|
value: /raid/hf_cache
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -533,7 +528,7 @@ mirror_hardwares:
|
|||||||
value: "0"
|
value: "0"
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /raid/hf_cache
|
value: /raid/hf_cache
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -584,7 +579,7 @@ mirror_hardwares:
|
|||||||
value: "0"
|
value: "0"
|
||||||
- name: HF_HOME
|
- name: HF_HOME
|
||||||
value: /raid/hf_cache
|
value: /raid/hf_cache
|
||||||
- name: VLLM_CI_HF_TOKEN
|
- name: HF_TOKEN
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: hf-token-secret
|
name: hf-token-secret
|
||||||
@@ -651,52 +646,3 @@ mirror_hardwares:
|
|||||||
resource_class: "npu-16"
|
resource_class: "npu-16"
|
||||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a3"
|
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a3"
|
||||||
plugins: *npu_k8s_plugins
|
plugins: *npu_k8s_plugins
|
||||||
|
|
||||||
a5_npu_2:
|
|
||||||
agents:
|
|
||||||
queue: "ascend-a5"
|
|
||||||
resource_class: "npu-2"
|
|
||||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a5"
|
|
||||||
plugins: *npu_k8s_plugins
|
|
||||||
|
|
||||||
a5_npu_4:
|
|
||||||
agents:
|
|
||||||
queue: "ascend-a5"
|
|
||||||
resource_class: "npu-4"
|
|
||||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a5"
|
|
||||||
plugins: *npu_k8s_plugins
|
|
||||||
|
|
||||||
a5_npu_8:
|
|
||||||
agents:
|
|
||||||
queue: "ascend-a5"
|
|
||||||
resource_class: "npu-8"
|
|
||||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a5"
|
|
||||||
plugins: *npu_k8s_plugins
|
|
||||||
|
|
||||||
a5_npu_16:
|
|
||||||
agents:
|
|
||||||
queue: "ascend-a5"
|
|
||||||
resource_class: "npu-16"
|
|
||||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a5"
|
|
||||||
plugins: *npu_k8s_plugins
|
|
||||||
|
|
||||||
310p_npu_1:
|
|
||||||
agents:
|
|
||||||
queue: "ascend-310p"
|
|
||||||
resource_class: "npu-1"
|
|
||||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-310p"
|
|
||||||
plugins: *npu_k8s_plugins
|
|
||||||
|
|
||||||
310p_npu_2:
|
|
||||||
agents:
|
|
||||||
queue: "ascend-310p"
|
|
||||||
resource_class: "npu-2"
|
|
||||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-310p"
|
|
||||||
plugins: *npu_k8s_plugins
|
|
||||||
|
|
||||||
310p_npu_4:
|
|
||||||
agents:
|
|
||||||
queue: "ascend-310p"
|
|
||||||
resource_class: "npu-4"
|
|
||||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-310p"
|
|
||||||
plugins: *npu_k8s_plugins
|
|
||||||
@@ -70,15 +70,7 @@ from tests.helpers.mark import ( # noqa: E402
|
|||||||
|
|
||||||
LOG = "upload_pipeline"
|
LOG = "upload_pipeline"
|
||||||
BOOTSTRAP_STEPS_FILENAME = "bootstrap-upload-steps.yml"
|
BOOTSTRAP_STEPS_FILENAME = "bootstrap-upload-steps.yml"
|
||||||
BOOTSTRAP_IMAGE_BUILD_KEYS = frozenset(
|
BOOTSTRAP_IMAGE_BUILD_KEYS = frozenset({"image-build", "image-build-a2", "image-build-a3"})
|
||||||
{
|
|
||||||
"image-build",
|
|
||||||
"image-build-a2",
|
|
||||||
"image-build-a3",
|
|
||||||
"image-build-a5",
|
|
||||||
"image-build-310p",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
BOOTSTRAP_UPLOAD_IF_KEYS = {
|
BOOTSTRAP_UPLOAD_IF_KEYS = {
|
||||||
"upload-ready-pipeline": "ready",
|
"upload-ready-pipeline": "ready",
|
||||||
"upload-merge-pipeline": "merge",
|
"upload-merge-pipeline": "merge",
|
||||||
@@ -87,8 +79,6 @@ BOOTSTRAP_UPLOAD_IF_KEYS = {
|
|||||||
}
|
}
|
||||||
E2E_GROUP_MARKER = "E2E Test"
|
E2E_GROUP_MARKER = "E2E Test"
|
||||||
CI_MIRROR_HARDWARES_PATH = ROOT / ".buildkite/common/ci_mirror_hardwares.yml"
|
CI_MIRROR_HARDWARES_PATH = ROOT / ".buildkite/common/ci_mirror_hardwares.yml"
|
||||||
CUDA_HF_TOKEN_ENV = "VLLM_CI_HF_TOKEN"
|
|
||||||
CUDA_HF_TOKEN_EXPORT = f'if [ -n "$${{{CUDA_HF_TOKEN_ENV}:-}}" ]; then export HF_TOKEN="$${{{CUDA_HF_TOKEN_ENV}}}"; fi'
|
|
||||||
|
|
||||||
# Bootstrap Buildkite ``if`` expressions.
|
# Bootstrap Buildkite ``if`` expressions.
|
||||||
# ``*_MAIN_IF``: main + env schedule. ``*_LABEL_IF``: PR label (and/or composed with MAIN).
|
# ``*_MAIN_IF``: main + env schedule. ``*_LABEL_IF``: PR label (and/or composed with MAIN).
|
||||||
@@ -511,17 +501,6 @@ def _expand_mirror_hardwares(step: dict[str, Any]) -> dict[str, Any] | None:
|
|||||||
|
|
||||||
expanded = copy.deepcopy(preset)
|
expanded = copy.deepcopy(preset)
|
||||||
merged = {key: value for key, value in step.items() if key != "mirror_hardwares"} | expanded
|
merged = {key: value for key, value in step.items() if key != "mirror_hardwares"} | expanded
|
||||||
# A scheduled build's HF_TOKEN may override a pod env entry with the same
|
|
||||||
# name. The preset injects the Kubernetes secret under a collision-proof
|
|
||||||
# alias; restore the conventional name after Buildkite has merged env.
|
|
||||||
if any(preset_name == chip or preset_name.startswith(f"{chip}_") for chip in _cuda_mirror_chips()):
|
|
||||||
commands = merged.get("commands")
|
|
||||||
if isinstance(commands, list):
|
|
||||||
merged["commands"] = [CUDA_HF_TOKEN_EXPORT, *commands]
|
|
||||||
elif commands is None:
|
|
||||||
merged["commands"] = [CUDA_HF_TOKEN_EXPORT]
|
|
||||||
else:
|
|
||||||
merged["commands"] = [CUDA_HF_TOKEN_EXPORT, commands]
|
|
||||||
# Preset retry (K8S_RETRY on l4_*) must not clobber a step that opted out.
|
# Preset retry (K8S_RETRY on l4_*) must not clobber a step that opted out.
|
||||||
if "retry" in step:
|
if "retry" in step:
|
||||||
merged["retry"] = step["retry"]
|
merged["retry"] = step["retry"]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||||
|
VLLM_USE_FLASHINFER_MOE_FP16: 0
|
||||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||||
HF_HUB_ETAG_TIMEOUT: 60
|
HF_HUB_ETAG_TIMEOUT: 60
|
||||||
|
|
||||||
@@ -79,9 +80,6 @@ steps:
|
|||||||
steps:
|
steps:
|
||||||
- label: "TTS · Qwen3-TTS CustomVoice Test"
|
- label: "TTS · Qwen3-TTS CustomVoice Test"
|
||||||
source_file_dependencies:
|
source_file_dependencies:
|
||||||
- tests/e2e/features/prefill_phase/
|
|
||||||
- vllm_omni/worker/gpu_model_runner.py
|
|
||||||
- tests/helpers/media.py
|
|
||||||
- tests/e2e/online_serving/test_qwen3_tts_customvoice.py
|
- tests/e2e/online_serving/test_qwen3_tts_customvoice.py
|
||||||
- tests/e2e/offline_inference/test_qwen3_tts_customvoice.py
|
- tests/e2e/offline_inference/test_qwen3_tts_customvoice.py
|
||||||
- vllm_omni/model_executor/models/qwen3_tts/
|
- vllm_omni/model_executor/models/qwen3_tts/
|
||||||
@@ -98,13 +96,12 @@ steps:
|
|||||||
timeout 40m bash -c "
|
timeout 40m bash -c "
|
||||||
export VLLM_LOGGING_LEVEL=DEBUG
|
export VLLM_LOGGING_LEVEL=DEBUG
|
||||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
||||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py tests/e2e/offline_inference/test_qwen3_tts_customvoice.py tests/e2e/features/prefill_phase/test_chunked_prefill_tail.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py tests/e2e/offline_inference/test_qwen3_tts_customvoice.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||||
"
|
"
|
||||||
mirror_hardwares: l4_1
|
mirror_hardwares: l4_1
|
||||||
|
|
||||||
- label: "TTS · Qwen3-TTS Base Test"
|
- label: "TTS · Qwen3-TTS Base Test"
|
||||||
source_file_dependencies:
|
source_file_dependencies:
|
||||||
- tests/helpers/media.py
|
|
||||||
- tests/e2e/online_serving/test_qwen3_tts_base.py
|
- tests/e2e/online_serving/test_qwen3_tts_base.py
|
||||||
- tests/e2e/offline_inference/test_qwen3_tts_base.py
|
- tests/e2e/offline_inference/test_qwen3_tts_base.py
|
||||||
- vllm_omni/model_executor/models/qwen3_tts/
|
- vllm_omni/model_executor/models/qwen3_tts/
|
||||||
@@ -155,7 +152,6 @@ steps:
|
|||||||
source_file_dependencies:
|
source_file_dependencies:
|
||||||
- tests/e2e/offline_inference/test_minicpmo_4_5.py
|
- tests/e2e/offline_inference/test_minicpmo_4_5.py
|
||||||
- tests/e2e/online_serving/test_minicpmo_4_5.py
|
- tests/e2e/online_serving/test_minicpmo_4_5.py
|
||||||
- vllm_omni/transformers_utils/chat_templates/minicpmo45_native.jinja
|
|
||||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||||
- vllm_omni/model_executor/models/step_audio2/
|
- vllm_omni/model_executor/models/step_audio2/
|
||||||
- vllm_omni/model_executor/models/cosyvoice3/code2wav_core/
|
- vllm_omni/model_executor/models/cosyvoice3/code2wav_core/
|
||||||
@@ -166,11 +162,10 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
- pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||||
# h100_2, not h100_1: advanced_model asserts transcribe every audio
|
# h100_2, not h100_1: advanced_model asserts transcribe every audio
|
||||||
# response with Whisper, and tests/helpers/media.py requires at least
|
# response with Whisper, and tests/helpers/media.py only uses an
|
||||||
# 16 GiB free VRAM on a device to run Whisper on GPU. When the model
|
# accelerator for Whisper when a spare GPU exists. On a single card it
|
||||||
# server leaves insufficient memory, Whisper falls back to CPU:
|
# grades on CPU: ~8-10 min per clip vs ~30 s, which alone overruns the
|
||||||
# ~8-10 min per clip vs ~30 s, which overruns the 50-minute job timeout
|
# 50-minute job timeout (build 2956).
|
||||||
# (build 2956). h100_2 guarantees a second GPU with ample free VRAM.
|
|
||||||
mirror_hardwares: h100_2
|
mirror_hardwares: h100_2
|
||||||
|
|
||||||
- label: "Omni · MiniCPM-o 4.5 Duplex Test"
|
- label: "Omni · MiniCPM-o 4.5 Duplex Test"
|
||||||
@@ -186,21 +181,6 @@ steps:
|
|||||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_soft_interrupt.py
|
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_soft_interrupt.py
|
||||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||||
- tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py
|
- tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py
|
||||||
- vllm_omni/engine/duplex/
|
|
||||||
- vllm_omni/entrypoints/duplex/
|
|
||||||
# Public duplex client library + its unit suites: client-side
|
|
||||||
# changes must re-run the duplex e2e group. The live client probe
|
|
||||||
# (test_duplex_client_live.py, single GPU, core tier) runs in the
|
|
||||||
# ready pipeline's duplex group.
|
|
||||||
- vllm_omni/clients/
|
|
||||||
- tests/clients/
|
|
||||||
- vllm_omni/entrypoints/duplex_request_client.py
|
|
||||||
- vllm_omni/outputs/duplex.py
|
|
||||||
- vllm_omni/model_executor/duplex_sampling.py
|
|
||||||
- tests/engine/duplex/
|
|
||||||
- tests/entrypoints/duplex/
|
|
||||||
- tests/model_executor/models/minicpmo_4_5/duplex/
|
|
||||||
# Legacy Realtime probe client + video stacking used by the e2e drivers.
|
|
||||||
- vllm_omni/experimental/fullduplex/
|
- vllm_omni/experimental/fullduplex/
|
||||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||||
- vllm_omni/model_executor/models/step_audio2/
|
- vllm_omni/model_executor/models/step_audio2/
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||||
|
VLLM_USE_FLASHINFER_MOE_FP16: 0
|
||||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||||
HF_HUB_ETAG_TIMEOUT: 60
|
HF_HUB_ETAG_TIMEOUT: 60
|
||||||
|
|
||||||
@@ -343,12 +344,6 @@ steps:
|
|||||||
- pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m "full_model and cuda" --run-level "full_model"
|
- pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m "full_model and cuda" --run-level "full_model"
|
||||||
mirror_hardwares: h100_2
|
mirror_hardwares: h100_2
|
||||||
|
|
||||||
- label: ":full_moon: Diffusion X2V · MAGI-2 Preview Serving Smoke"
|
|
||||||
timeout_in_minutes: 180
|
|
||||||
commands:
|
|
||||||
- pytest -s -v tests/e2e/online_serving/test_magi2.py -m "advanced_model and diffusion and cuda and H100 and cards_4" --run-level "advanced_model"
|
|
||||||
mirror_hardwares: h100_4
|
|
||||||
|
|
||||||
- label: ":full_moon: Diffusion X2V · Doc Test"
|
- label: ":full_moon: Diffusion X2V · Doc Test"
|
||||||
timeout_in_minutes: 60
|
timeout_in_minutes: 60
|
||||||
commands:
|
commands:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||||
|
VLLM_USE_FLASHINFER_MOE_FP16: 0
|
||||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||||
HF_HUB_ETAG_TIMEOUT: 60
|
HF_HUB_ETAG_TIMEOUT: 60
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ steps:
|
|||||||
|
|
||||||
- label: "Diffusion · Other Test"
|
- label: "Diffusion · Other Test"
|
||||||
commands:
|
commands:
|
||||||
- timeout 15m pytest -sv tests/diffusion/*.py tests/diffusion/ar_diffusion -m 'core_model and cuda' --run-level "core_model"
|
- timeout 15m pytest -sv tests/diffusion/*.py -m 'core_model and cuda' --run-level "core_model"
|
||||||
mirror_hardwares: l4_1
|
mirror_hardwares: l4_1
|
||||||
|
|
||||||
- group: ":card_index_dividers: Tiny Model Tests [Single GPU]"
|
- group: ":card_index_dividers: Tiny Model Tests [Single GPU]"
|
||||||
@@ -93,7 +94,7 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- |
|
- |
|
||||||
timeout 15m bash -c "
|
timeout 15m bash -c "
|
||||||
pytest -sv tests/engine/ tests/model_executor/ tests/worker/test_batched_omni_output.py -m 'core_model and cuda' --run-level 'core_model'
|
pytest -sv tests/engine/ tests/model_executor/ -m 'core_model and cuda' --run-level 'core_model'
|
||||||
"
|
"
|
||||||
mirror_hardwares: l4_1
|
mirror_hardwares: l4_1
|
||||||
|
|
||||||
@@ -188,7 +189,6 @@ steps:
|
|||||||
- label: "Omni · MiniCPM-o 4.5 Online Test"
|
- label: "Omni · MiniCPM-o 4.5 Online Test"
|
||||||
source_file_dependencies:
|
source_file_dependencies:
|
||||||
- tests/e2e/online_serving/test_minicpmo_4_5.py
|
- tests/e2e/online_serving/test_minicpmo_4_5.py
|
||||||
- vllm_omni/transformers_utils/chat_templates/minicpmo45_native.jinja
|
|
||||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||||
- vllm_omni/model_executor/models/step_audio2/
|
- vllm_omni/model_executor/models/step_audio2/
|
||||||
- vllm_omni/model_executor/models/cosyvoice3/code2wav_core/
|
- vllm_omni/model_executor/models/cosyvoice3/code2wav_core/
|
||||||
@@ -215,21 +215,6 @@ steps:
|
|||||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_soft_interrupt.py
|
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_soft_interrupt.py
|
||||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||||
- tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py
|
- tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py
|
||||||
- vllm_omni/engine/duplex/
|
|
||||||
- vllm_omni/entrypoints/duplex/
|
|
||||||
# Public duplex client library + its unit suites: client-side
|
|
||||||
# changes must re-run the duplex e2e group, which includes the
|
|
||||||
# live client probe (test_duplex_client_live.py, single GPU).
|
|
||||||
- vllm_omni/clients/
|
|
||||||
- tests/clients/
|
|
||||||
- tests/e2e/online_serving/test_duplex_client_live.py
|
|
||||||
- vllm_omni/entrypoints/duplex_request_client.py
|
|
||||||
- vllm_omni/outputs/duplex.py
|
|
||||||
- vllm_omni/model_executor/duplex_sampling.py
|
|
||||||
- tests/engine/duplex/
|
|
||||||
- tests/entrypoints/duplex/
|
|
||||||
- tests/model_executor/models/minicpmo_4_5/duplex/
|
|
||||||
# Legacy Realtime probe client + video stacking used by the e2e drivers.
|
|
||||||
- vllm_omni/experimental/fullduplex/
|
- vllm_omni/experimental/fullduplex/
|
||||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||||
- vllm_omni/model_executor/models/step_audio2/
|
- vllm_omni/model_executor/models/step_audio2/
|
||||||
@@ -247,8 +232,8 @@ steps:
|
|||||||
- vllm_omni/config/stage_config.py
|
- vllm_omni/config/stage_config.py
|
||||||
commands:
|
commands:
|
||||||
- |
|
- |
|
||||||
timeout 35m bash -c "
|
timeout 20m bash -c "
|
||||||
pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex.py tests/e2e/online_serving/test_duplex_client_live.py -m 'core_model and cuda' --run-level 'core_model'
|
pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex.py -m 'core_model and cuda' --run-level 'core_model'
|
||||||
"
|
"
|
||||||
mirror_hardwares: h100_1
|
mirror_hardwares: h100_1
|
||||||
|
|
||||||
@@ -266,7 +251,6 @@ steps:
|
|||||||
|
|
||||||
- label: "TTS · Qwen3-TTS CustomVoice Test"
|
- label: "TTS · Qwen3-TTS CustomVoice Test"
|
||||||
source_file_dependencies:
|
source_file_dependencies:
|
||||||
- tests/helpers/media.py
|
|
||||||
- tests/e2e/online_serving/test_qwen3_tts_customvoice.py
|
- tests/e2e/online_serving/test_qwen3_tts_customvoice.py
|
||||||
- vllm_omni/model_executor/models/qwen3_tts/
|
- vllm_omni/model_executor/models/qwen3_tts/
|
||||||
- vllm_omni/model_executor/models/common/qwen3_code_predictor.py
|
- vllm_omni/model_executor/models/common/qwen3_code_predictor.py
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||||
|
VLLM_USE_FLASHINFER_MOE_FP16: 0
|
||||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||||
HF_HUB_ETAG_TIMEOUT: 60
|
HF_HUB_ETAG_TIMEOUT: 60
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
steps:
|
steps:
|
||||||
- label: ":buildkit: Build and Push NPU Test Image - A2"
|
- label: ":buildkit: Build and Push NPU Test Image - A2"
|
||||||
key: image-build-a2
|
key: image-build-a2
|
||||||
agents: &npu-image-build-agents
|
agents:
|
||||||
queue: "ascend-a2b3"
|
queue: "ascend-a2b3"
|
||||||
resource_class: "npu-1"
|
resource_class: "npu-1"
|
||||||
plugins: &npu-image-build-plugins
|
plugins:
|
||||||
- kubernetes:
|
- kubernetes:
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
@@ -46,47 +46,123 @@ steps:
|
|||||||
IMAGE_NAME: "vllm-omni-ci-npu"
|
IMAGE_NAME: "vllm-omni-ci-npu"
|
||||||
IMAGE_REGISTRY: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry"
|
IMAGE_REGISTRY: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry"
|
||||||
BUILDKITD_ADDR: "tcp://buildkitd-service.buildkitd:1234"
|
BUILDKITD_ADDR: "tcp://buildkitd-service.buildkitd:1234"
|
||||||
command: bash .buildkite/npu/scripts/build-npu-image.sh Dockerfile.npu.ci "$${VLLM_IMAGE_TAG}"
|
command: |
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
echo "--- Building and pushing NPU Test Image"
|
||||||
|
echo "Image: $${IMAGE_REGISTRY}/$${IMAGE_NAME}:$${VLLM_IMAGE_TAG}"
|
||||||
|
echo "buildkitd address: $${BUILDKITD_ADDR}"
|
||||||
|
|
||||||
|
if ! command -v buildctl &> /dev/null; then
|
||||||
|
echo "Installing buildctl..."
|
||||||
|
mkdir -p /tmp/buildkit
|
||||||
|
BUILDKIT_VERSION="v0.29.0"
|
||||||
|
wget -q "https://github.com/moby/buildkit/releases/download/$${BUILDKIT_VERSION}/buildkit-$${BUILDKIT_VERSION}.linux-arm64.tar.gz" -O /tmp/buildkit.tar.gz
|
||||||
|
tar -xzf /tmp/buildkit.tar.gz -C /tmp/buildkit
|
||||||
|
cp /tmp/buildkit/bin/buildctl /usr/local/bin/
|
||||||
|
fi
|
||||||
|
|
||||||
|
export DOCKER_CONFIG=/home/user/.docker
|
||||||
|
buildctl \
|
||||||
|
--addr="$${BUILDKITD_ADDR}" \
|
||||||
|
--tlscacert=/home/user/.docker/ca.pem \
|
||||||
|
--tlscert=/home/user/.docker/cert.pem \
|
||||||
|
--tlskey=/home/user/.docker/key.pem \
|
||||||
|
build \
|
||||||
|
--frontend dockerfile.v0 \
|
||||||
|
--local context=. \
|
||||||
|
--local dockerfile=./docker \
|
||||||
|
--opt filename=Dockerfile.npu.ci \
|
||||||
|
--secret id=dockerconfig,src=/home/user/.docker/config.json \
|
||||||
|
--output type=image,name=$${IMAGE_REGISTRY}/$${IMAGE_NAME}:$${VLLM_IMAGE_TAG},push=true \
|
||||||
|
--progress=plain
|
||||||
|
|
||||||
|
echo "--- Image pushed successfully"
|
||||||
|
echo "$${IMAGE_REGISTRY}/$${IMAGE_NAME}:$${VLLM_IMAGE_TAG}"
|
||||||
|
|
||||||
- label: ":buildkit: Build and Push NPU Test Image - A3"
|
- label: ":buildkit: Build and Push NPU Test Image - A3"
|
||||||
key: image-build-a3
|
key: image-build-a3
|
||||||
agents: *npu-image-build-agents
|
agents:
|
||||||
plugins: *npu-image-build-plugins
|
queue: "ascend-a2b3"
|
||||||
|
resource_class: "npu-1"
|
||||||
|
plugins:
|
||||||
|
- kubernetes:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
vault.hashicorp.com/agent-init-first: "true"
|
||||||
|
vault.hashicorp.com/agent-inject: "true"
|
||||||
|
vault.hashicorp.com/agent-inject-perms-ca.pem: "0400"
|
||||||
|
vault.hashicorp.com/agent-inject-perms-cert.pem: "0400"
|
||||||
|
vault.hashicorp.com/agent-inject-perms-config.json: "0400"
|
||||||
|
vault.hashicorp.com/agent-inject-perms-key.pem: "0400"
|
||||||
|
vault.hashicorp.com/agent-inject-secret-ca.pem: internal/data/ascend/buildkitd
|
||||||
|
vault.hashicorp.com/agent-inject-secret-cert.pem: internal/data/ascend/buildkitd
|
||||||
|
vault.hashicorp.com/agent-inject-secret-config.json: internal/data/ascend/buildkitd
|
||||||
|
vault.hashicorp.com/agent-inject-secret-key.pem: internal/data/ascend/buildkitd
|
||||||
|
vault.hashicorp.com/agent-inject-template-ca.pem: "{{- with secret \"internal/data/ascend/buildkitd\" -}}\n{{ .Data.data.RootCA }}\n{{- end }}"
|
||||||
|
vault.hashicorp.com/agent-inject-template-cert.pem: "{{- with secret \"internal/data/ascend/buildkitd\" -}}\n{{ .Data.data.ClientCaCert }}\n{{- end }}"
|
||||||
|
vault.hashicorp.com/agent-inject-template-config.json: "{{- with secret \"internal/data/ascend/buildkitd\" -}}\n{{ .Data.data.dockerConfig }}\n{{- end }}"
|
||||||
|
vault.hashicorp.com/agent-inject-template-key.pem: "{{- with secret \"internal/data/ascend/buildkitd\" -}}\n{{ .Data.data.ClientCaKey }}\n{{- end }}"
|
||||||
|
vault.hashicorp.com/agent-pre-populate-only: "true"
|
||||||
|
vault.hashicorp.com/agent-run-as-group: "1000"
|
||||||
|
vault.hashicorp.com/agent-run-as-user: "1000"
|
||||||
|
vault.hashicorp.com/agent-service-account-token-volume-name: token-vol
|
||||||
|
vault.hashicorp.com/role: ascend-gha-runners
|
||||||
|
vault.hashicorp.com/secret-volume-path: /home/user/.docker/
|
||||||
|
vault.hashicorp.com/tls-skip-verify: "true"
|
||||||
|
podSpecPatch:
|
||||||
|
volumes:
|
||||||
|
- name: token-vol
|
||||||
|
projected:
|
||||||
|
defaultMode: 420
|
||||||
|
sources:
|
||||||
|
- serviceAccountToken:
|
||||||
|
audience: api
|
||||||
|
expirationSeconds: 600
|
||||||
|
path: token
|
||||||
env:
|
env:
|
||||||
VLLM_IMAGE_TAG: "${BUILDKITE_COMMIT}-a3"
|
VLLM_IMAGE_TAG: "${BUILDKITE_COMMIT}-a3"
|
||||||
IMAGE_NAME: "vllm-omni-ci-npu"
|
IMAGE_NAME: "vllm-omni-ci-npu"
|
||||||
IMAGE_REGISTRY: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry"
|
IMAGE_REGISTRY: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry"
|
||||||
BUILDKITD_ADDR: "tcp://buildkitd-service.buildkitd:1234"
|
BUILDKITD_ADDR: "tcp://buildkitd-service.buildkitd:1234"
|
||||||
command: bash .buildkite/npu/scripts/build-npu-image.sh Dockerfile.npu.ci "$${VLLM_IMAGE_TAG}" -a3
|
command: |
|
||||||
|
set -ex
|
||||||
|
|
||||||
- label: ":buildkit: Build and Push NPU Test Image - A5"
|
echo "--- Building and pushing NPU Test Image"
|
||||||
key: image-build-a5
|
echo "Image: $${IMAGE_REGISTRY}/$${IMAGE_NAME}:$${VLLM_IMAGE_TAG}"
|
||||||
agents: *npu-image-build-agents
|
echo "buildkitd address: $${BUILDKITD_ADDR}"
|
||||||
plugins: *npu-image-build-plugins
|
|
||||||
env:
|
|
||||||
VLLM_IMAGE_TAG: "${BUILDKITE_COMMIT}-a5"
|
|
||||||
IMAGE_NAME: "vllm-omni-ci-npu"
|
|
||||||
IMAGE_REGISTRY: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry"
|
|
||||||
BUILDKITD_ADDR: "tcp://buildkitd-service.buildkitd:1234"
|
|
||||||
command: bash .buildkite/npu/scripts/build-npu-image.sh Dockerfile.npu.ci "$${VLLM_IMAGE_TAG}" -a5
|
|
||||||
|
|
||||||
- label: ":buildkit: Build and Push NPU Test Image - 310P"
|
if ! command -v buildctl &> /dev/null; then
|
||||||
key: image-build-310p
|
echo "Installing buildctl..."
|
||||||
agents: *npu-image-build-agents
|
mkdir -p /tmp/buildkit
|
||||||
plugins: *npu-image-build-plugins
|
BUILDKIT_VERSION="v0.29.0"
|
||||||
env:
|
wget -q "https://github.com/moby/buildkit/releases/download/$${BUILDKIT_VERSION}/buildkit-$${BUILDKIT_VERSION}.linux-arm64.tar.gz" -O /tmp/buildkit.tar.gz
|
||||||
VLLM_IMAGE_TAG: "${BUILDKITE_COMMIT}-310p"
|
tar -xzf /tmp/buildkit.tar.gz -C /tmp/buildkit
|
||||||
IMAGE_NAME: "vllm-omni-ci-npu"
|
cp /tmp/buildkit/bin/buildctl /usr/local/bin/
|
||||||
IMAGE_REGISTRY: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry"
|
fi
|
||||||
BUILDKITD_ADDR: "tcp://buildkitd-service.buildkitd:1234"
|
|
||||||
command: bash .buildkite/npu/scripts/build-npu-image.sh Dockerfile.npu.ci "$${VLLM_IMAGE_TAG}" -310p
|
export DOCKER_CONFIG=/home/user/.docker
|
||||||
|
buildctl \
|
||||||
|
--addr="$${BUILDKITD_ADDR}" \
|
||||||
|
--tlscacert=/home/user/.docker/ca.pem \
|
||||||
|
--tlscert=/home/user/.docker/cert.pem \
|
||||||
|
--tlskey=/home/user/.docker/key.pem \
|
||||||
|
build \
|
||||||
|
--frontend dockerfile.v0 \
|
||||||
|
--local context=. \
|
||||||
|
--local dockerfile=./docker \
|
||||||
|
--opt filename=Dockerfile.npu.ci.a3 \
|
||||||
|
--secret id=dockerconfig,src=/home/user/.docker/config.json \
|
||||||
|
--output type=image,name=$${IMAGE_REGISTRY}/$${IMAGE_NAME}:$${VLLM_IMAGE_TAG},push=true \
|
||||||
|
--progress=plain
|
||||||
|
|
||||||
|
echo "--- Image pushed successfully"
|
||||||
|
echo "$${IMAGE_REGISTRY}/$${IMAGE_NAME}:$${VLLM_IMAGE_TAG}"
|
||||||
|
|
||||||
- label: "Upload Ready Pipeline"
|
- label: "Upload Ready Pipeline"
|
||||||
depends_on:
|
depends_on:
|
||||||
- image-build-a2
|
- image-build-a2
|
||||||
- image-build-a3
|
- image-build-a3
|
||||||
- image-build-a5
|
|
||||||
- image-build-310p
|
|
||||||
key: upload-ready-pipeline
|
key: upload-ready-pipeline
|
||||||
agents:
|
agents:
|
||||||
queue: "cpu_queue_premerge"
|
queue: "cpu_queue_premerge"
|
||||||
@@ -98,8 +174,6 @@ steps:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- image-build-a2
|
- image-build-a2
|
||||||
- image-build-a3
|
- image-build-a3
|
||||||
- image-build-a5
|
|
||||||
- image-build-310p
|
|
||||||
key: upload-nightly-pipeline
|
key: upload-nightly-pipeline
|
||||||
commands:
|
commands:
|
||||||
- python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/npu/test-npu-nightly.yml
|
- python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/npu/test-npu-nightly.yml
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
dockerfile=${1:?Dockerfile is required}
|
|
||||||
image_tag=${2:?Image tag is required}
|
|
||||||
device_suffix=${3:-}
|
|
||||||
|
|
||||||
image_name=${IMAGE_NAME:-vllm-omni-ci-npu}
|
|
||||||
image_registry=${IMAGE_REGISTRY:-swr.cn-southwest-2.myhuaweicloud.com/modelfoundry}
|
|
||||||
buildkitd_addr=${BUILDKITD_ADDR:-tcp://buildkitd-service.buildkitd:1234}
|
|
||||||
|
|
||||||
echo "--- Building and pushing NPU Test Image"
|
|
||||||
echo "Image: ${image_registry}/${image_name}:${image_tag}"
|
|
||||||
echo "Dockerfile: ${dockerfile}"
|
|
||||||
|
|
||||||
if ! command -v buildctl &> /dev/null; then
|
|
||||||
mkdir -p /tmp/buildkit
|
|
||||||
buildkit_version=v0.29.0
|
|
||||||
wget -q \
|
|
||||||
"https://github.com/moby/buildkit/releases/download/${buildkit_version}/buildkit-${buildkit_version}.linux-arm64.tar.gz" \
|
|
||||||
-O /tmp/buildkit.tar.gz
|
|
||||||
tar -xzf /tmp/buildkit.tar.gz -C /tmp/buildkit
|
|
||||||
cp /tmp/buildkit/bin/buildctl /usr/local/bin/
|
|
||||||
fi
|
|
||||||
|
|
||||||
build_args=()
|
|
||||||
if [[ -n "${device_suffix}" ]]; then
|
|
||||||
build_args+=(--opt "build-arg:VLLM_ASCEND_DEVICE_SUFFIX=${device_suffix}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
export DOCKER_CONFIG=/home/user/.docker
|
|
||||||
buildctl \
|
|
||||||
--addr="${buildkitd_addr}" \
|
|
||||||
--tlscacert=/home/user/.docker/ca.pem \
|
|
||||||
--tlscert=/home/user/.docker/cert.pem \
|
|
||||||
--tlskey=/home/user/.docker/key.pem \
|
|
||||||
build \
|
|
||||||
--frontend dockerfile.v0 \
|
|
||||||
--local context=. \
|
|
||||||
--local dockerfile=./docker \
|
|
||||||
--opt "filename=${dockerfile}" \
|
|
||||||
"${build_args[@]}" \
|
|
||||||
--secret id=dockerconfig,src=/home/user/.docker/config.json \
|
|
||||||
--output "type=image,name=${image_registry}/${image_name}:${image_tag},push=true" \
|
|
||||||
--progress=plain
|
|
||||||
|
|
||||||
echo "--- Image pushed successfully"
|
|
||||||
echo "${image_registry}/${image_name}:${image_tag}"
|
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
steps:
|
steps:
|
||||||
- group: ":card_index_dividers: Simple Test"
|
|
||||||
depends_on: upload-ready-pipeline
|
|
||||||
steps:
|
|
||||||
- label: "Platforms Test"
|
- label: "Platforms Test"
|
||||||
key: ready-platforms-test
|
key: ready-platforms-test
|
||||||
|
depends_on: upload-ready-pipeline
|
||||||
mirror_hardwares: a3_npu_2
|
mirror_hardwares: a3_npu_2
|
||||||
commands:
|
commands:
|
||||||
- >-
|
- >-
|
||||||
@@ -12,49 +10,18 @@ steps:
|
|||||||
-m 'core_model and npu and A3 and omni'
|
-m 'core_model and npu and A3 and omni'
|
||||||
--run-level 'core_model'
|
--run-level 'core_model'
|
||||||
|
|
||||||
- label: "Diffusion NPU layer tests - A2"
|
- label: "Diffusion NPU layer tests"
|
||||||
key: ready-diffusion-npu-layer-tests-a2
|
|
||||||
mirror_hardwares: a2b3_npu_1
|
|
||||||
commands:
|
|
||||||
- >-
|
|
||||||
pytest -s -v
|
|
||||||
tests/diffusion/layers/test_activation.py
|
|
||||||
-m 'core_model and npu and A2'
|
|
||||||
--run-level 'core_model'
|
|
||||||
|
|
||||||
- label: "Diffusion NPU layer tests - A3"
|
|
||||||
key: ready-diffusion-npu-layer-tests
|
key: ready-diffusion-npu-layer-tests
|
||||||
|
depends_on: upload-ready-pipeline
|
||||||
mirror_hardwares: a3_npu_2
|
mirror_hardwares: a3_npu_2
|
||||||
commands:
|
commands:
|
||||||
- >-
|
- >-
|
||||||
pytest -s -v
|
pytest -s -v
|
||||||
tests/diffusion/layers/test_activation.py
|
tests/diffusion/layers/test_activation.py
|
||||||
tests/diffusion/layers/test_fused_qk_norm_rope_npu.py
|
tests/diffusion/layers/test_fused_qk_norm_rope_npu.py
|
||||||
tests/diffusion/models/minimax_h3/test_minimax_h3_qwen3vl_swiglu.py
|
|
||||||
tests/diffusion/models/minimax_h3/test_minimax_h3_modulation.py
|
|
||||||
-m 'core_model and npu and A3'
|
-m 'core_model and npu and A3'
|
||||||
--run-level 'core_model'
|
--run-level 'core_model'
|
||||||
|
|
||||||
- label: "Diffusion NPU layer tests - A5"
|
|
||||||
key: ready-diffusion-npu-layer-tests-a5
|
|
||||||
mirror_hardwares: a5_npu_2
|
|
||||||
commands:
|
|
||||||
- >-
|
|
||||||
pytest -s -v
|
|
||||||
tests/diffusion/layers/test_activation.py
|
|
||||||
-m 'core_model and npu and A5'
|
|
||||||
--run-level 'core_model'
|
|
||||||
|
|
||||||
- label: "Diffusion NPU layer tests - 310P"
|
|
||||||
key: ready-diffusion-npu-layer-tests-310p
|
|
||||||
mirror_hardwares: 310p_npu_1
|
|
||||||
commands:
|
|
||||||
- >-
|
|
||||||
pytest -s -v
|
|
||||||
tests/diffusion/layers/test_activation.py
|
|
||||||
-m 'core_model and npu and 310P'
|
|
||||||
--run-level 'core_model'
|
|
||||||
|
|
||||||
- group: ":card_index_dividers: Omni Model Test"
|
- group: ":card_index_dividers: Omni Model Test"
|
||||||
key: ready-omni-group
|
key: ready-omni-group
|
||||||
depends_on: upload-ready-pipeline
|
depends_on: upload-ready-pipeline
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: add-diffusion-model
|
name: add-diffusion-model
|
||||||
description: Add a new diffusion model (text-to-image, text-to-video, image-to-video, text-to-audio, image editing) to vLLM-Omni, including native non-Diffusers ports, reference-parity validation, Cache-DiT, offload, and parallelism support (TP, SP/USP, CFG-Parallel, HSDP). Use when integrating or reviewing a new diffusion model, porting a Diffusers pipeline or custom model repository, creating a DiT adapter, reusing shared examples, or qualifying multi-GPU and memory optimizations.
|
description: Add a new diffusion model (text-to-image, text-to-video, image-to-video, text-to-audio, image editing) to vLLM-Omni, including Cache-DiT acceleration and parallelism support (TP, SP/USP, CFG-Parallel, HSDP). Use when integrating a new diffusion model, porting a diffusers pipeline or a custom model repo to vllm-omni, creating a new DiT transformer adapter, adding diffusion model support, or enabling multi-GPU parallelism and cache acceleration for an existing model.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Adding a Diffusion Model to vLLM-Omni
|
# Adding a Diffusion Model to vLLM-Omni
|
||||||
@@ -26,16 +26,9 @@ Check the model's HF repo for `model_index.json`. This determines your path:
|
|||||||
|----------|----------------|----------------|
|
|----------|----------------|----------------|
|
||||||
| **Already supported** | `_class_name` in `model_index.json` matches a key in `_DIFFUSION_MODELS` in `registry.py` | Skip implementation, then validate model-specific examples, tests, and docs as needed |
|
| **Already supported** | `_class_name` in `model_index.json` matches a key in `_DIFFUSION_MODELS` in `registry.py` | Skip implementation, then validate model-specific examples, tests, and docs as needed |
|
||||||
| **Diffusers-based** | Has standard `model_index.json` with `_diffusers_version`, subfolders for `transformer/`, `vae/`, etc. | Follow **Path A** below |
|
| **Diffusers-based** | Has standard `model_index.json` with `_diffusers_version`, subfolders for `transformer/`, `vae/`, etc. | Follow **Path A** below |
|
||||||
| **Native non-Diffusers model** | No Diffusers index, non-standard checkpoint hierarchy, or custom architecture in a separate repo | Follow **Path B** below; port the runtime natively unless an external adapter was explicitly requested |
|
| **Custom/private repo** | No diffusers `model_index.json`, weights in non-standard format, custom model code in a separate git repo | Follow **Path B** below |
|
||||||
| **Hybrid** | Has some diffusers components (VAE) but custom transformer/fusion | Mix of Path A and Path B |
|
| **Hybrid** | Has some diffusers components (VAE) but custom transformer/fusion | Mix of Path A and Path B |
|
||||||
|
|
||||||
Before coding, write a short integration contract covering runtime ownership,
|
|
||||||
checkpoint discovery, reference revision, I/O geometry, attention semantics,
|
|
||||||
CFG behavior, auxiliary components, target hardware, and the default deployment.
|
|
||||||
For Path B, hybrid models, or any optimization work, read
|
|
||||||
[references/native-model-integration-checklist.md](references/native-model-integration-checklist.md)
|
|
||||||
and use its phase gates.
|
|
||||||
|
|
||||||
## Path A: Diffusers-Based Model
|
## Path A: Diffusers-Based Model
|
||||||
|
|
||||||
For models with a standard diffusers layout. See [references/transformer-adaptation.md](references/transformer-adaptation.md) for detailed code patterns.
|
For models with a standard diffusers layout. See [references/transformer-adaptation.md](references/transformer-adaptation.md) for detailed code patterns.
|
||||||
@@ -110,15 +103,9 @@ For custom loop structures, follow `vllm_omni/diffusion/models/progress_bar.py`
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Path B: Native / Non-Diffusers Model
|
## Path B: Custom/Private Repo Model
|
||||||
|
|
||||||
For models without a Diffusers pipeline—weights in custom formats and model
|
For models without a diffusers pipeline — weights in custom format, model code in a private repo. Real examples: BAGEL, HunyuanImage3. See [references/custom-model-patterns.md](references/custom-model-patterns.md) for concrete custom-model integration patterns.
|
||||||
code in another public or private repository. Treat that repository as a pinned
|
|
||||||
correctness oracle. A request for native support means the vLLM-Omni runtime
|
|
||||||
must not import the reference implementation; an external adapter is appropriate
|
|
||||||
only when the requested scope explicitly permits that dependency. See
|
|
||||||
[references/custom-model-patterns.md](references/custom-model-patterns.md) for
|
|
||||||
concrete integration patterns.
|
|
||||||
|
|
||||||
### B1. Understand the reference repo
|
### B1. Understand the reference repo
|
||||||
|
|
||||||
@@ -139,25 +126,16 @@ This is the key design decision for custom models. Follow these placement rules:
|
|||||||
| **Pipeline orchestration** (init, forward, denoise loop) | `vllm_omni/diffusion/models/<name>/pipeline_<name>.py` | Always required |
|
| **Pipeline orchestration** (init, forward, denoise loop) | `vllm_omni/diffusion/models/<name>/pipeline_<name>.py` | Always required |
|
||||||
| **Custom transformer/backbone** (ported and adapted to vllm-omni) | `vllm_omni/diffusion/models/<name>/<name>_transformer.py` or similar | `wan2_2.py`, `fusion.py`, `bagel_transformer.py` |
|
| **Custom transformer/backbone** (ported and adapted to vllm-omni) | `vllm_omni/diffusion/models/<name>/<name>_transformer.py` or similar | `wan2_2.py`, `fusion.py`, `bagel_transformer.py` |
|
||||||
| **Custom sub-models** (VAE, fusion, autoencoder) | `vllm_omni/diffusion/models/<name>/` as separate files | `autoencoder.py`, `fusion.py` |
|
| **Custom sub-models** (VAE, fusion, autoencoder) | `vllm_omni/diffusion/models/<name>/` as separate files | `autoencoder.py`, `fusion.py` |
|
||||||
| **Reference-only code** | Keep outside the runtime; use a pinned revision for golden outputs and architecture analysis | Reference inference script |
|
| **External dependency code** (original repo utilities) | **External repo**, installed via download script or pip | original-repo package via git clone |
|
||||||
| **Explicit external adapter dependency** | External package, only when the requested scope and maintainer direction allow it | Compatibility adapter, not native support |
|
|
||||||
| **Hardcoded model configs** | Module-level dicts in pipeline file | `VIDEO_CONFIG`, `AUDIO_CONFIG` dicts |
|
| **Hardcoded model configs** | Module-level dicts in pipeline file | `VIDEO_CONFIG`, `AUDIO_CONFIG` dicts |
|
||||||
| **Download/setup script** | `examples/offline_inference/<name>/download_<name>.py` | `download_<name>.py` |
|
| **Download/setup script** | `examples/offline_inference/<name>/download_<name>.py` | `download_<name>.py` |
|
||||||
| **Custom `model_index.json`** | Generated by download script, placed at model root | Minimal: `{"_class_name": "YourPipeline", ...}` |
|
| **Custom `model_index.json`** | Generated by download script, placed at model root | Minimal: `{"_class_name": "YourPipeline", ...}` |
|
||||||
|
|
||||||
### B3. Handle external dependencies
|
### B3. Handle external dependencies
|
||||||
|
|
||||||
If the model's code lives in a separate git repo, first decide whether the
|
If the model's code lives in a separate git repo:
|
||||||
requested deliverable is native support or an external adapter. Do not silently
|
|
||||||
choose the adapter path.
|
|
||||||
|
|
||||||
**Option 1: Port the code directly** (default for native support)
|
**Option 1: Import with graceful fallback** (recommended for models with external utils)
|
||||||
|
|
||||||
Copy the essential model files into `vllm_omni/diffusion/models/<name>/` and
|
|
||||||
adapt them to shared vLLM-Omni contracts. Keep checkpoint loading strict and
|
|
||||||
use the pinned reference only to generate parity evidence.
|
|
||||||
|
|
||||||
**Option 2: Import with graceful fallback** (adapter scope only)
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
try:
|
try:
|
||||||
@@ -169,9 +147,11 @@ except ImportError:
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Use an external runtime dependency only when the user explicitly requested an
|
**Option 2: Port the code directly** (preferred when feasible)
|
||||||
adapter or a maintainer approved the exception. Document the dependency,
|
|
||||||
pinned revision, installation path, and unsupported native features.
|
Copy the essential model files into `vllm_omni/diffusion/models/<name>/` and adapt them. This avoids external dependencies. BAGEL does this — `autoencoder.py` and `bagel_transformer.py` are ported directly.
|
||||||
|
|
||||||
|
**Decision criteria**: Port if the code is self-contained and won't diverge. Use external deps if the model repo is actively maintained and the code is complex.
|
||||||
|
|
||||||
### B4. Handle custom weight loading
|
### B4. Handle custom weight loading
|
||||||
|
|
||||||
@@ -241,8 +221,7 @@ class CustomPipeline(nn.Module):
|
|||||||
|
|
||||||
### B5. Create the `model_index.json`
|
### B5. Create the `model_index.json`
|
||||||
|
|
||||||
Prefer a `model_index.json` at the model root when vLLM-Omni owns an assembled
|
Custom models need a `model_index.json` at the model root for vllm-omni to discover them. For custom models, this is minimal:
|
||||||
checkpoint directory. For custom models, this is minimal:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -251,14 +230,7 @@ checkpoint directory. For custom models, this is minimal:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `_class_name` must match a key in `_DIFFUSION_MODELS` in `registry.py`.
|
The `_class_name` must match a key in `_DIFFUSION_MODELS` in `registry.py`. Additional keys are model-specific (accessed via `od_config.model_config`).
|
||||||
Additional keys are model-specific (accessed via `od_config.model_config`).
|
|
||||||
|
|
||||||
If the released repository is immutable and has neither a root `config.json`
|
|
||||||
nor a Diffusers index, add it to a generic native-checkpoint signature resolver:
|
|
||||||
match the exact Hub ID or a distinctive set of local files and return the
|
|
||||||
pipeline class. Do not use model-name substrings or add parallel one-off
|
|
||||||
predicates in CLI, config, and serving consumers.
|
|
||||||
|
|
||||||
If the model's weights come from multiple HF repos, write a **download script** that:
|
If the model's weights come from multiple HF repos, write a **download script** that:
|
||||||
1. Downloads from each repo
|
1. Downloads from each repo
|
||||||
@@ -320,9 +292,7 @@ Use the appropriate existing example script:
|
|||||||
| Image-to-Image | `examples/offline_inference/image_to_image/image_edit.py` |
|
| Image-to-Image | `examples/offline_inference/image_to_image/image_edit.py` |
|
||||||
| Text-to-Audio | `examples/offline_inference/text_to_audio/text_to_audio.py` |
|
| Text-to-Audio | `examples/offline_inference/text_to_audio/text_to_audio.py` |
|
||||||
|
|
||||||
Reuse these shared scripts even for custom models when their request and output
|
For custom/Omni models that don't fit these categories, create a dedicated example script.
|
||||||
contracts fit. Create a dedicated model script only when the shared category
|
|
||||||
cannot represent the protocol, and document that gap in the PR.
|
|
||||||
|
|
||||||
**Validation**: No errors, output is meaningful, quality matches reference implementation.
|
**Validation**: No errors, output is meaningful, quality matches reference implementation.
|
||||||
|
|
||||||
@@ -330,17 +300,13 @@ See [references/troubleshooting.md](references/troubleshooting.md) for common er
|
|||||||
|
|
||||||
### Step 6: Add Example Scripts
|
### Step 6: Add Example Scripts
|
||||||
|
|
||||||
Only when the shared category scripts cannot represent the model, create:
|
For Omni or custom models, create:
|
||||||
- `examples/offline_inference/your_model_name/` — offline script + README
|
- `examples/offline_inference/your_model_name/` — offline script + README
|
||||||
- `examples/online_serving/your_model_name/` — server script + client
|
- `examples/online_serving/your_model_name/` — server script + client
|
||||||
- Download script if weights require assembly from multiple sources
|
- Download script if weights require assembly from multiple sources
|
||||||
|
|
||||||
### Step 7: Update Documentation
|
### Step 7: Update Documentation
|
||||||
|
|
||||||
Follow the [`add-recipe` skill](../add-recipe/SKILL.md) to add or update the
|
|
||||||
model-family recipe and its `recipes/README.md` row with verified specifications,
|
|
||||||
hardware, commands, feature links, and qualification evidence.
|
|
||||||
|
|
||||||
Required updates:
|
Required updates:
|
||||||
1. `docs/user_guide/diffusion/parallelism/overview.md` — parallelism support overview/table
|
1. `docs/user_guide/diffusion/parallelism/overview.md` — parallelism support overview/table
|
||||||
2. `docs/user_guide/diffusion/cpu_offload.md` — if CPU offload supported (add to supported models table)
|
2. `docs/user_guide/diffusion/cpu_offload.md` — if CPU offload supported (add to supported models table)
|
||||||
@@ -380,20 +346,107 @@ Classify the model's **CI priority** first:
|
|||||||
|
|
||||||
**Keep model-specific code inside test modules — not `tests/helpers/{slug}.py`:** deploy constants, prompts, sampling dicts, and inline `request_config` / `form_data` belong in each `test_{slug}.py` and `test_{slug}_expansion.py`. Do not add per-model files under `tests/helpers/`; reuse only repo-wide harness (`mark`, `media`, `runtime`, `stage_config`, `assertions`). **L2+ online/offline e2e:** reuse or add `send_*_request` in `tests/helpers/runtime.py` — tests call the handler, not raw `omni.generate` / HTTP. See [vllm-omni-test skill](../vllm-omni-test/SKILL.md) § **Runtime send helpers**.
|
**Keep model-specific code inside test modules — not `tests/helpers/{slug}.py`:** deploy constants, prompts, sampling dicts, and inline `request_config` / `form_data` belong in each `test_{slug}.py` and `test_{slug}_expansion.py`. Do not add per-model files under `tests/helpers/`; reuse only repo-wide harness (`mark`, `media`, `runtime`, `stage_config`, `assertions`). **L2+ online/offline e2e:** reuse or add `send_*_request` in `tests/helpers/runtime.py` — tests call the handler, not raw `omni.generate` / HTTP. See [vllm-omni-test skill](../vllm-omni-test/SKILL.md) § **Runtime send helpers**.
|
||||||
|
|
||||||
Keep the model suite proportional using the six distinct failure owners in the
|
|
||||||
native integration checklist. Combine supported features into a few
|
|
||||||
parametrized E2E rows instead of creating one test per optimization.
|
|
||||||
|
|
||||||
### Step 9: Add Cache-DiT Acceleration
|
### Step 9: Add Cache-DiT Acceleration
|
||||||
|
|
||||||
Add caching only after uncached single-device correctness. Read
|
Cache-DiT accelerates inference by caching intermediate computation results across denoising steps. After your model is working correctly on a single GPU, add cache-dit support.
|
||||||
[references/cache-dit-patterns.md](references/cache-dit-patterns.md), use the
|
|
||||||
automatic single-block-list path when possible, and add a registered
|
|
||||||
`BlockAdapter` only for genuinely custom block topology.
|
|
||||||
|
|
||||||
Verify a real cache hit and compare quality with the uncached baseline. Make a
|
See [references/cache-dit-patterns.md](references/cache-dit-patterns.md) for detailed code patterns.
|
||||||
speed claim only at a realistic step count where warmup permits hits; an
|
|
||||||
all-warmup smoke proves integration, not acceleration.
|
#### 9a. Determine your model type
|
||||||
|
|
||||||
|
| Model Type | Description | Action |
|
||||||
|
|------------|-------------|--------|
|
||||||
|
| **Standard single-transformer** | One transformer with one `ModuleList` of blocks | No code needed — `CacheDiTBackend` auto-detects via `enable_cache_for_dit()` |
|
||||||
|
| **Multi-block-list** | One transformer with multiple block lists (e.g., `transformer_blocks` + `single_transformer_blocks`) | Write custom enabler with `BlockAdapter` |
|
||||||
|
| **Dual-transformer** | Two transformers (e.g., high-noise + low-noise) | Write custom enabler with `BlockAdapter` wrapping both |
|
||||||
|
|
||||||
|
#### 9b. Standard models — verify automatic support
|
||||||
|
|
||||||
|
For standard single-transformer models, test directly:
|
||||||
|
|
||||||
|
```python
|
||||||
|
omni = Omni(
|
||||||
|
model="your-model-name",
|
||||||
|
cache_backend="cache_dit",
|
||||||
|
cache_config={
|
||||||
|
"Fn_compute_blocks": 1,
|
||||||
|
"Bn_compute_blocks": 0,
|
||||||
|
"max_warmup_steps": 4,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Check logs for "Cache-dit enabled successfully on xxx". If it works, skip to Step 9e.
|
||||||
|
|
||||||
|
#### 9c. Custom architectures — write a custom enabler
|
||||||
|
|
||||||
|
For multi-block-list or dual-transformer models, write a custom enabler function:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from cache_dit import BlockAdapter, ForwardPattern, ParamsModifier, DBCacheConfig
|
||||||
|
|
||||||
|
def enable_cache_for_your_model(pipeline, cache_config):
|
||||||
|
db_cache_config = DBCacheConfig(
|
||||||
|
num_inference_steps=None,
|
||||||
|
Fn_compute_blocks=cache_config.Fn_compute_blocks,
|
||||||
|
Bn_compute_blocks=cache_config.Bn_compute_blocks,
|
||||||
|
max_warmup_steps=cache_config.max_warmup_steps,
|
||||||
|
max_cached_steps=cache_config.max_cached_steps,
|
||||||
|
max_continuous_cached_steps=cache_config.max_continuous_cached_steps,
|
||||||
|
residual_diff_threshold=cache_config.residual_diff_threshold,
|
||||||
|
)
|
||||||
|
|
||||||
|
cache_dit.enable_cache(
|
||||||
|
BlockAdapter(
|
||||||
|
transformer=pipeline.transformer,
|
||||||
|
blocks=[
|
||||||
|
pipeline.transformer.transformer_blocks,
|
||||||
|
pipeline.transformer.single_transformer_blocks,
|
||||||
|
],
|
||||||
|
forward_pattern=[ForwardPattern.Pattern_1, ForwardPattern.Pattern_1],
|
||||||
|
params_modifiers=[ParamsModifier(...)],
|
||||||
|
),
|
||||||
|
cache_config=db_cache_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
def refresh_cache_context(pipeline, num_inference_steps, verbose=True):
|
||||||
|
cache_dit.refresh_context(
|
||||||
|
pipeline.transformer, num_inference_steps=num_inference_steps, verbose=verbose
|
||||||
|
)
|
||||||
|
return refresh_cache_context
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 9d. Register the custom enabler
|
||||||
|
|
||||||
|
Add your enabler to `CUSTOM_DIT_ENABLERS` in
|
||||||
|
`vllm_omni/diffusion/cache/cachedit/model_specific.py`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
CUSTOM_DIT_ENABLERS = {
|
||||||
|
"Wan22Pipeline": enable_cache_for_wan22,
|
||||||
|
"LongCatImagePipeline": enable_cache_for_longcat_image,
|
||||||
|
"YourModelPipeline": enable_cache_for_your_model, # Add here
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 9e. Test Cache-DiT
|
||||||
|
|
||||||
|
```python
|
||||||
|
omni = Omni(
|
||||||
|
model="your-model-name",
|
||||||
|
cache_backend="cache_dit",
|
||||||
|
cache_config={
|
||||||
|
"Fn_compute_blocks": 1, "Bn_compute_blocks": 0,
|
||||||
|
"max_warmup_steps": 4, "residual_diff_threshold": 0.24,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
images = omni.generate("a beautiful landscape",
|
||||||
|
OmniDiffusionSamplingParams(num_inference_steps=50))
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verify**: 1) logs show cache enabled, 2) 1.5-2x speedup, 3) output quality acceptable vs baseline.
|
||||||
|
|
||||||
|
If quality degrades, lower `residual_diff_threshold` (try 0.12-0.18) or increase `max_warmup_steps` (try 6-8).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -407,30 +460,107 @@ See [references/parallelism-patterns.md](references/parallelism-patterns.md) for
|
|||||||
|
|
||||||
#### 10a. Tensor Parallelism (TP)
|
#### 10a. Tensor Parallelism (TP)
|
||||||
|
|
||||||
Replace compatible projections with vLLM parallel linears, preserve checkpoint
|
Shards DiT linear layers across GPUs. Requires code changes in the transformer.
|
||||||
fusion/loading, and use local head counts. Require query/KV head divisibility
|
|
||||||
and compare a multi-rank forward with the one-rank oracle.
|
**What to change in the transformer**:
|
||||||
|
1. Replace `nn.Linear` with `ColumnParallelLinear` / `RowParallelLinear` / `QKVParallelLinear`
|
||||||
|
2. Update `load_weights()` to handle QKV fusion with `stacked_params_mapping`
|
||||||
|
3. Use `self.to_qkv.num_heads` (local heads) instead of total heads for split sizes
|
||||||
|
|
||||||
|
```python
|
||||||
|
from vllm.model_executor.layers.linear import (
|
||||||
|
QKVParallelLinear, RowParallelLinear, ColumnParallelLinear,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Attention: QKV → RowParallel output
|
||||||
|
self.to_qkv = QKVParallelLinear(dim, head_dim, num_heads, num_kv_heads)
|
||||||
|
self.to_out = RowParallelLinear(dim, dim, input_is_parallel=True)
|
||||||
|
|
||||||
|
# FFN: ColumnParallel → RowParallel
|
||||||
|
self.w1 = ColumnParallelLinear(dim, ffn_dim)
|
||||||
|
self.w2 = RowParallelLinear(ffn_dim, dim, input_is_parallel=True)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Constraints**: `num_heads % tp_size == 0` and `num_kv_heads % tp_size == 0`.
|
||||||
|
|
||||||
|
**Test**: `--tensor-parallel-size 2`
|
||||||
|
|
||||||
#### 10b. Sequence Parallelism (SP / USP)
|
#### 10b. Sequence Parallelism (SP / USP)
|
||||||
|
|
||||||
Prefer the declarative `_sp_plan`. For packed variable-length attention or
|
Splits sequence tokens across GPUs. Non-intrusive via `_sp_plan` on the transformer class — no changes to `forward()`.
|
||||||
learned-sink LSE correction, keep model math explicit and reuse shared exchange
|
|
||||||
utilities. Validate uneven sequence splits, RoPE coordinates, and outputs
|
**What to change in the transformer**:
|
||||||
against the one-rank oracle.
|
|
||||||
|
Add `_sp_plan` class attribute:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from vllm_omni.diffusion.distributed.sp_plan import (
|
||||||
|
SequenceParallelInput, SequenceParallelOutput,
|
||||||
|
)
|
||||||
|
|
||||||
|
class YourTransformer(nn.Module):
|
||||||
|
_sp_plan = {
|
||||||
|
"blocks.0": {
|
||||||
|
"hidden_states": SequenceParallelInput(split_dim=1, expected_dims=3),
|
||||||
|
},
|
||||||
|
"proj_out": SequenceParallelOutput(gather_dim=1, expected_dims=3),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If inline tensor ops (e.g., `torch.cat`) exist between shard/gather points, extract them into `nn.Module` submodules so hooks can intercept them.
|
||||||
|
|
||||||
|
For RoPE that needs splitting, add an entry for the RoPE module with `split_output=True`.
|
||||||
|
|
||||||
|
**Test**: `--ulysses-degree 2` (offline) or `--usp 2` (online serving)
|
||||||
|
|
||||||
#### 10c. CFG Parallel
|
#### 10c. CFG Parallel
|
||||||
|
|
||||||
Confirm the model uses CFG. Then reuse `CFGParallelMixin`, overriding prediction
|
Distributes positive/negative CFG branches across 2 GPUs. Requires the pipeline to inherit `CFGParallelMixin`.
|
||||||
or recombination only for non-standard or multi-output pipelines. Distinguish a
|
|
||||||
packed positive/negative implementation from two independent branches and
|
**What to change in the pipeline**:
|
||||||
validate the two-rank result against the packed one-rank oracle.
|
|
||||||
|
```python
|
||||||
|
from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
|
||||||
|
|
||||||
|
class YourPipeline(nn.Module, CFGParallelMixin):
|
||||||
|
def diffuse(self, ...) -> torch.Tensor:
|
||||||
|
for i, t in enumerate(timesteps):
|
||||||
|
positive_kwargs = {...}
|
||||||
|
negative_kwargs = {...} if do_true_cfg else None
|
||||||
|
noise_pred = self.predict_noise_maybe_with_cfg(
|
||||||
|
do_true_cfg=do_true_cfg, true_cfg_scale=cfg_scale,
|
||||||
|
positive_kwargs=positive_kwargs, negative_kwargs=negative_kwargs,
|
||||||
|
)
|
||||||
|
latents = self.scheduler_step_maybe_with_cfg(
|
||||||
|
noise_pred, t, latents, do_true_cfg
|
||||||
|
)
|
||||||
|
return latents
|
||||||
|
```
|
||||||
|
|
||||||
|
Override `predict_noise()` if your transformer call is non-standard. Override `combine_cfg_noise()` for multi-output models (e.g., video + audio).
|
||||||
|
|
||||||
|
**Constraint**: Exactly 2 GPUs. Only for models using classifier-free guidance.
|
||||||
|
|
||||||
|
**Test**: `--cfg-parallel-size 2`
|
||||||
|
|
||||||
#### 10d. HSDP (Hybrid Sharded Data Parallel)
|
#### 10d. HSDP (Hybrid Sharded Data Parallel)
|
||||||
|
|
||||||
Declare layer shard conditions and ignored rank-local modules; preserve mixed
|
Shards transformer weights via PyTorch FSDP2 to reduce per-GPU VRAM. No code changes to the forward pass — just add a class attribute.
|
||||||
checkpoint dtypes. HSDP cannot combine with TP. Measure parameter loading,
|
|
||||||
FSDP materialization, warm HBM, and host PSS rather than assuming sharding saves
|
**What to change in the transformer**:
|
||||||
peak memory. Keep the resident layout as default if HSDP is worse.
|
|
||||||
|
```python
|
||||||
|
class YourTransformer(nn.Module):
|
||||||
|
@staticmethod
|
||||||
|
def _is_transformer_block(name: str, module) -> bool:
|
||||||
|
return "blocks" in name and name.split(".")[-1].isdigit()
|
||||||
|
|
||||||
|
_hsdp_shard_conditions = [_is_transformer_block]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Constraint**: Cannot combine with TP. For standalone HSDP, set `hsdp_shard_size` explicitly.
|
||||||
|
|
||||||
|
**Test**: `--use-hsdp` or `DiffusionParallelConfig(use_hsdp=True)`
|
||||||
|
|
||||||
#### 10e. Update parallelism documentation
|
#### 10e. Update parallelism documentation
|
||||||
|
|
||||||
@@ -469,12 +599,6 @@ Pipelines without `SupportsComponentDiscovery` fall back to scanning
|
|||||||
well-known attribute names (`transformer`, `text_encoder`, `vae`,
|
well-known attribute names (`transformer`, `text_encoder`, `vae`,
|
||||||
etc.), which fails for non-standard names.
|
etc.), which fails for non-standard names.
|
||||||
|
|
||||||
Keep model-specific checkpoint paths, nested block aliases, layout transforms,
|
|
||||||
and component lifecycles in the model package. Change a shared offloader only
|
|
||||||
for a general contract, demonstrate another consumer or a framework-level bug,
|
|
||||||
and add one focused shared regression. Avoid `if ModelName` branches in shared
|
|
||||||
backends.
|
|
||||||
|
|
||||||
### Step 12: Performance Profiling
|
### Step 12: Performance Profiling
|
||||||
|
|
||||||
After verifying correctness and implementing parallelism/caching, profile the model's performance to identify bottlenecks and ensure optimal execution.
|
After verifying correctness and implementing parallelism/caching, profile the model's performance to identify bottlenecks and ensure optimal execution.
|
||||||
@@ -484,12 +608,6 @@ See the [Profiling Single-Stage Diffusion](../../../docs/contributing/profiling.
|
|||||||
2. Using Nsight Systems (`nsys`) with `profiler: "cuda"` for low-overhead CUDA traces.
|
2. Using Nsight Systems (`nsys`) with `profiler: "cuda"` for low-overhead CUDA traces.
|
||||||
3. Controlling profiling via `omni.start_profile()` and `omni.stop_profile()`.
|
3. Controlling profiling via `omni.start_profile()` and `omni.stop_profile()`.
|
||||||
|
|
||||||
Report cold E2E, warm user latency, steady-state wave time, peak allocated and
|
|
||||||
reserved HBM, host PSS for the full process tree, and stage boundaries. State
|
|
||||||
whether prompt encoding and VAE/audio decoding are included. For multi-device
|
|
||||||
layouts, plot user latency against throughput per device and keep different
|
|
||||||
denoising-step counts on separate Pareto frontiers.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Pre-commit conventions
|
## Pre-commit conventions
|
||||||
@@ -517,7 +635,7 @@ shellcheck). In particular:
|
|||||||
3. **Use small models**: Test with smaller variants first
|
3. **Use small models**: Test with smaller variants first
|
||||||
4. **Check tensor shapes**: Most errors are reshape mismatches in attention
|
4. **Check tensor shapes**: Most errors are reshape mismatches in attention
|
||||||
5. **Add features incrementally**: Single GPU → TP → SP → CFG → HSDP → Cache-DiT
|
5. **Add features incrementally**: Single GPU → TP → SP → CFG → HSDP → Cache-DiT
|
||||||
6. **For custom models**: Run the pinned reference separately, then port the runtime natively; do not ship temporary imports from the reference implementation
|
6. **For custom models**: Get the model running with the original code first, then progressively replace components with vllm-omni equivalents
|
||||||
7. **Cache-DiT before parallelism tuning**: Cache-DiT is lossy — verify quality at baseline before combining with parallelism
|
7. **Cache-DiT before parallelism tuning**: Cache-DiT is lossy — verify quality at baseline before combining with parallelism
|
||||||
8. **Combine lossless + lossy**: e.g., TP + SP + Cache-DiT for maximum throughput
|
8. **Combine lossless + lossy**: e.g., TP + SP + Cache-DiT for maximum throughput
|
||||||
|
|
||||||
@@ -526,7 +644,6 @@ shellcheck). In particular:
|
|||||||
- [vllm-omni-test skill](../vllm-omni-test/SKILL.md) — L1–L4 markers, naming, Buildkite wiring, run commands
|
- [vllm-omni-test skill](../vllm-omni-test/SKILL.md) — L1–L4 markers, naming, Buildkite wiring, run commands
|
||||||
- [Transformer Adaptation](references/transformer-adaptation.md) — porting transformers from diffusers
|
- [Transformer Adaptation](references/transformer-adaptation.md) — porting transformers from diffusers
|
||||||
- [Custom Model Patterns](references/custom-model-patterns.md) — patterns for non-diffusers models
|
- [Custom Model Patterns](references/custom-model-patterns.md) — patterns for non-diffusers models
|
||||||
- [Native Model Integration Checklist](references/native-model-integration-checklist.md) — ownership boundaries, phase gates, qualification matrix, and review evidence
|
|
||||||
- [Parallelism Patterns](references/parallelism-patterns.md) — TP, SP/USP, CFG parallel, HSDP implementation details
|
- [Parallelism Patterns](references/parallelism-patterns.md) — TP, SP/USP, CFG parallel, HSDP implementation details
|
||||||
- [Cache-DiT Patterns](references/cache-dit-patterns.md) — cache-dit acceleration for standard and custom architectures
|
- [Cache-DiT Patterns](references/cache-dit-patterns.md) — cache-dit acceleration for standard and custom architectures
|
||||||
- [Troubleshooting](references/troubleshooting.md) — common errors and fixes
|
- [Troubleshooting](references/troubleshooting.md) — common errors and fixes
|
||||||
@@ -9,9 +9,7 @@ Three caching strategies:
|
|||||||
- **TaylorSeer**: Calibration-based prediction using Taylor expansion to estimate block outputs
|
- **TaylorSeer**: Calibration-based prediction using Taylor expansion to estimate block outputs
|
||||||
- **SCM** (Step Computation Masking): Dynamic step skipping based on configurable policies
|
- **SCM** (Step Computation Masking): Dynamic step skipping based on configurable policies
|
||||||
|
|
||||||
Speedup is model-, step-, and policy-dependent. Treat a cache-enabled run as
|
**Typical speedup**: 1.5-2.5x depending on model and configuration.
|
||||||
integration evidence until logs or a focused test show real hits and repeated
|
|
||||||
timings show an improvement over the uncached baseline.
|
|
||||||
|
|
||||||
**Official docs**: https://docs.vllm.ai/projects/vllm-omni/en/latest/design/feature/cache_dit
|
**Official docs**: https://docs.vllm.ai/projects/vllm-omni/en/latest/design/feature/cache_dit
|
||||||
|
|
||||||
@@ -245,10 +243,8 @@ vllm serve your-model --omni --port 8098 \
|
|||||||
|
|
||||||
**Verification checklist**:
|
**Verification checklist**:
|
||||||
1. Logs show "Cache-dit enabled successfully on xxx"
|
1. Logs show "Cache-dit enabled successfully on xxx"
|
||||||
2. A focused test or summary confirms at least one real cache hit
|
2. Performance: 1.5-2x speedup vs no cache
|
||||||
3. Quality is compared with `cache_backend=None`
|
3. Quality: compare output with `cache_backend=None`
|
||||||
4. Performance uses a realistic step count, repeated timings, and a policy
|
|
||||||
whose warmup does not consume the whole run
|
|
||||||
|
|
||||||
## Excluded Models
|
## Excluded Models
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ vllm_omni/diffusion/models/wan2_2/
|
|||||||
|
|
||||||
The transformer is loaded separately via `weights_sources` + `load_weights()`. Non-transformer components (VAE, text encoder) are loaded in `__init__` via `from_pretrained()`.
|
The transformer is loaded separately via `weights_sources` + `load_weights()`. Non-transformer components (VAE, text encoder) are loaded in `__init__` via `from_pretrained()`.
|
||||||
|
|
||||||
### External adapter (not native support)
|
### Custom model with external deps
|
||||||
|
|
||||||
```
|
```
|
||||||
vllm_omni/diffusion/models/<name>/
|
vllm_omni/diffusion/models/<name>/
|
||||||
@@ -28,10 +28,7 @@ examples/offline_inference/<task>/
|
|||||||
└── download_<name>.py # Downloads weights and/or clones code repo
|
└── download_<name>.py # Downloads weights and/or clones code repo
|
||||||
```
|
```
|
||||||
|
|
||||||
All weights are loaded eagerly in `__init__`. `load_weights()` is a no-op. The
|
All weights loaded eagerly in `__init__`. `load_weights()` is a no-op. External dependency imported with try/except.
|
||||||
external dependency is imported with try/except. Use this pattern only when the
|
|
||||||
requested scope explicitly allows an adapter; it does not satisfy a request for
|
|
||||||
a native vLLM-Omni implementation.
|
|
||||||
|
|
||||||
### Custom model with ported code (e.g., BAGEL)
|
### Custom model with ported code (e.g., BAGEL)
|
||||||
|
|
||||||
@@ -89,7 +86,7 @@ init → load ALL weights eagerly via custom helpers → load_weights() = no-op
|
|||||||
- `load_weights()` is `pass`
|
- `load_weights()` is `pass`
|
||||||
- Weights may come from multiple HF repos in different formats (`.pth`, `.safetensors`)
|
- Weights may come from multiple HF repos in different formats (`.pth`, `.safetensors`)
|
||||||
|
|
||||||
Use this only for an explicitly approved external adapter when:
|
Use this when:
|
||||||
- The original model has complex, well-tested loading code you don't want to rewrite
|
- The original model has complex, well-tested loading code you don't want to rewrite
|
||||||
- Weights span multiple HF repos
|
- Weights span multiple HF repos
|
||||||
- Weight format is non-standard (e.g., a single `.pth` file, not sharded safetensors)
|
- Weight format is non-standard (e.g., a single `.pth` file, not sharded safetensors)
|
||||||
@@ -115,14 +112,7 @@ Custom model `model_index.json` (minimal):
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The only **required** field is `_class_name` — it must match a key in
|
The only **required** field is `_class_name` — it must match a key in `_DIFFUSION_MODELS` in `registry.py`. Other fields are model-specific and accessible via `od_config.model_config` dict.
|
||||||
`_DIFFUSION_MODELS` in `registry.py`. Other fields are model-specific and
|
|
||||||
accessible via `od_config.model_config`.
|
|
||||||
|
|
||||||
When the released repository cannot be modified and contains neither this file
|
|
||||||
nor a root `config.json`, use the generic native-checkpoint signature resolver.
|
|
||||||
Match the exact Hub ID or a distinctive local file set; never infer support from
|
|
||||||
a model-name substring.
|
|
||||||
|
|
||||||
## External Dependency Management
|
## External Dependency Management
|
||||||
|
|
||||||
@@ -151,10 +141,6 @@ def download_dependency():
|
|||||||
|
|
||||||
Copy essential files from the original repo into `vllm_omni/diffusion/models/<name>/`. Adapt imports to use vllm-omni utilities. Benefits: no external dependency, no git clone step. Drawback: must maintain the ported code.
|
Copy essential files from the original repo into `vllm_omni/diffusion/models/<name>/`. Adapt imports to use vllm-omni utilities. Benefits: no external dependency, no git clone step. Drawback: must maintain the ported code.
|
||||||
|
|
||||||
This is the default for native model support. Keep the reference repository at
|
|
||||||
a pinned revision for architecture analysis and golden outputs, but do not
|
|
||||||
import it from production code.
|
|
||||||
|
|
||||||
## Multi-Modal Input/Output Protocols
|
## Multi-Modal Input/Output Protocols
|
||||||
|
|
||||||
Custom models that handle images, audio, or video I/O should implement protocol classes:
|
Custom models that handle images, audio, or video I/O should implement protocol classes:
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
# Native Diffusion Model Integration Checklist
|
|
||||||
|
|
||||||
Use this checklist for native non-Diffusers models, hybrid pipelines, and
|
|
||||||
model-specific optimization work.
|
|
||||||
|
|
||||||
## 1. Freeze the contract before coding
|
|
||||||
|
|
||||||
Record:
|
|
||||||
|
|
||||||
- Reference repository and immutable revision.
|
|
||||||
- Official checkpoint ID, local layout, license, and required auxiliary files.
|
|
||||||
- Pipeline stages: prompt/image encoding, denoising, video/image/audio decoding,
|
|
||||||
and muxing.
|
|
||||||
- Token packing, RoPE coordinates, attention sinks/LSE behavior, MoE layout,
|
|
||||||
scheduler equations, CFG formulation, dtypes, and checkpoint transforms.
|
|
||||||
- Output geometry, frame count/FPS, audio rate/channels, supported tasks, and
|
|
||||||
default generation steps.
|
|
||||||
- Available local hardware versus the official qualification hardware.
|
|
||||||
- Intended default deployment and optional optimization paths.
|
|
||||||
|
|
||||||
State whether the deliverable is a native implementation or an external
|
|
||||||
adapter. For native support, use the reference as an oracle only.
|
|
||||||
|
|
||||||
## 2. Use phase gates
|
|
||||||
|
|
||||||
| Phase | Required exit evidence |
|
|
||||||
|---|---|
|
|
||||||
| Architecture | Component/weight inventory; unsupported reference dependencies identified; ownership decisions documented |
|
|
||||||
| Native correctness | Strict checkpoint load; tiny forward or one-step golden vs pinned reference; output contract validated |
|
|
||||||
| Framework integration | Registry/discovery, shared request types, existing category example, serving route, docs, and recipe work without model-name branching in shared scripts |
|
|
||||||
| Lossless distribution | One-rank oracle vs each supported TP/SP/CFG/HSDP/VAE layout; released-checkpoint smoke for the recommended layout |
|
|
||||||
| Memory optimization | Ordinary/layerwise/DLO behavior, peak HBM, full-tree host PSS, and stage timeline; shared backend unchanged unless a general contract is proven |
|
|
||||||
| Lossy optimization | Cache hit demonstrated; quality delta measured; speed claim made only when warmup permits hits |
|
|
||||||
| Full qualification | Default-resolution E2E at official step count for every supported task; media metadata and hashes recorded |
|
|
||||||
| Review readiness | Focused tests, Ruff/format, strict docs, DCO, current-main rebase, issue/RFC for large changes, concise PR evidence and limitations |
|
|
||||||
|
|
||||||
Do not start performance tuning before native one-step parity. Do not claim a
|
|
||||||
feature from topology validation alone when released weights can exercise it.
|
|
||||||
|
|
||||||
## 3. Keep ownership narrow
|
|
||||||
|
|
||||||
Default placement:
|
|
||||||
|
|
||||||
| Concern | Owner |
|
|
||||||
|---|---|
|
|
||||||
| Architecture, checkpoint remap, packed attention math, nested block alias, auxiliary lifecycle | Model package |
|
|
||||||
| Kernel/version dispatch already useful to multiple models | Shared attention utility |
|
|
||||||
| Request-dependent example defaults | Typed model-extra entry consumed through a registry |
|
|
||||||
| Exact-ID/local-file detection for repositories without standard metadata | Generic native-checkpoint signature table |
|
|
||||||
| General offload/cache/HSDP bug | Shared layer plus one focused shared regression |
|
|
||||||
|
|
||||||
Before changing shared code, answer:
|
|
||||||
|
|
||||||
1. Is this a framework contract or only this checkpoint's layout?
|
|
||||||
2. Can the model expose an existing declarative hook instead?
|
|
||||||
3. Is there a second consumer or a framework-level failing test?
|
|
||||||
4. Can the shared change avoid importing or naming the model?
|
|
||||||
|
|
||||||
If the answers do not justify a shared change, keep it model-local.
|
|
||||||
|
|
||||||
## 4. Reuse examples without leaking model logic
|
|
||||||
|
|
||||||
- Reuse the existing `x_to_y.py` category script.
|
|
||||||
- Resolve the pipeline class through standard metadata or native signature
|
|
||||||
discovery, not path substrings.
|
|
||||||
- Put dynamic model defaults and validation in `model_extras`; let shared
|
|
||||||
examples consume only the generic typed API.
|
|
||||||
- Do not create image/speech/default abstractions without a real consumer.
|
|
||||||
- Add a dedicated example only when the shared request/output protocol cannot
|
|
||||||
express the model.
|
|
||||||
|
|
||||||
## 5. Build a bounded evidence matrix
|
|
||||||
|
|
||||||
Start with the recommended resident layout. Add only supported, useful points:
|
|
||||||
|
|
||||||
- Single request: TP, SP, or hybrid TP/SP.
|
|
||||||
- Throughput: DLO/DP layouts when concurrent requests are valid.
|
|
||||||
- CFG: compare CFG-parallel output with the packed-CFG oracle only if the model
|
|
||||||
actually uses CFG.
|
|
||||||
- HSDP: record loading and materialization peaks; it can use more HBM than a
|
|
||||||
resident SP layout.
|
|
||||||
- VAE patch parallelism: compare decoded tensors or media exactly where the
|
|
||||||
algorithm should be lossless.
|
|
||||||
- Cache: separate cache integration from acceleration evidence.
|
|
||||||
|
|
||||||
With four devices, qualify four-device layouts such as DP4, DP2SP2, SP4, or
|
|
||||||
CFG2xSP2. Do not present CFG2xSP4 or an official eight-device runtime as locally
|
|
||||||
validated.
|
|
||||||
|
|
||||||
For each measured layout record:
|
|
||||||
|
|
||||||
- Cold E2E and warm user latency.
|
|
||||||
- Steady-state wave time and throughput per device.
|
|
||||||
- Prompt, denoise, video decode, audio decode, and mux times.
|
|
||||||
- Peak allocated/reserved HBM and full-process-tree host PSS.
|
|
||||||
- Step count, seed, output geometry, frame/FPS/audio metadata, and parity metric.
|
|
||||||
|
|
||||||
Plot latency versus throughput/device. Keep one-step, four-step, and full-step
|
|
||||||
results separate because they are not quality-equivalent.
|
|
||||||
|
|
||||||
## 6. Keep tests proportional
|
|
||||||
|
|
||||||
Prefer a small set with distinct failure ownership:
|
|
||||||
|
|
||||||
1. Strict weight-key/dtype/load contract.
|
|
||||||
2. Tiny native golden or one-step reference parity.
|
|
||||||
3. One parametrized distributed-parity test covering supported layouts.
|
|
||||||
4. Pipeline/request/output geometry and serving smoke.
|
|
||||||
5. Shared-example/default test when the category script changes.
|
|
||||||
6. One shared regression only for a genuine shared-layer fix.
|
|
||||||
|
|
||||||
Avoid duplicating the same shape or configuration assertion across
|
|
||||||
model-specific files. Keep expensive released-checkpoint evidence in the PR or
|
|
||||||
recipe unless the repository's CI tier explicitly requires it.
|
|
||||||
|
|
||||||
## 7. Write evidence, not marketing
|
|
||||||
|
|
||||||
In the PR description include:
|
|
||||||
|
|
||||||
- A compact architecture/data-flow explanation.
|
|
||||||
- Default deployment and why it is recommended.
|
|
||||||
- Code-change counts by component.
|
|
||||||
- Accuracy and distributed-parity evidence tied to commands/scripts.
|
|
||||||
- Separate Pareto figures for different step counts.
|
|
||||||
- Supported versus validated versus planned optimizations.
|
|
||||||
- Hardware gaps and untested official-runtime claims.
|
|
||||||
|
|
||||||
Call a result a bounded local qualification unless it includes repeated timing
|
|
||||||
and variance. State whether latency includes text/image encoding and all
|
|
||||||
decoders. Preserve the reference revision and exact commands needed to
|
|
||||||
reproduce the evidence.
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
---
|
|
||||||
name: add-recipe
|
|
||||||
description: Add or update an in-repository vLLM-Omni model recipe with verified task, input, output, hardware, command, feature, and validation contracts. Use when creating files under recipes/, restructuring a recipe after review, documenting a newly supported model, or synchronizing recipe claims with support tables and shared feature guides.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Add a vLLM-Omni Recipe
|
|
||||||
|
|
||||||
## Source the contract
|
|
||||||
|
|
||||||
Read [`recipes/TEMPLATE.md`](../../../recipes/TEMPLATE.md) and
|
|
||||||
[`recipes/README.md`](../../../recipes/README.md) before editing. Inspect the
|
|
||||||
canonical model card/repository, implementation, shared examples, tests, and
|
|
||||||
available local qualification evidence.
|
|
||||||
|
|
||||||
Do not infer support from a model name, sibling recipe, registry entry, or
|
|
||||||
topology validator. Mark unexecuted configurations as configuration-only.
|
|
||||||
|
|
||||||
## Route by model family
|
|
||||||
|
|
||||||
Read only the contributor and user documentation relevant to the model:
|
|
||||||
|
|
||||||
| Family | Contributor guide | User-facing documentation to synchronize |
|
|
||||||
|---|---|---|
|
|
||||||
| Diffusion | [`adding a diffusion model`](../add-diffusion-model/SKILL.md) | `docs/user_guide/diffusion_features.md`, applicable diffusion feature guides, and shared image/video/audio examples |
|
|
||||||
| TTS | [`adding a TTS model`](../add-tts-model/SKILL.md) | `examples/offline_inference/text_to_speech/README.md`, `examples/online_serving/text_to_speech/README.md`, and `docs/serving/speech_api.md` |
|
|
||||||
| Omni | [`adding an omni model`](../../../docs/contributing/model/adding_omni_model.md) | model-family offline/online example docs, `docs/serving/chat_completions_api.md`, and `docs/user_guide/feature_compatibility.md` |
|
|
||||||
|
|
||||||
All families must update `docs/models/supported_models.md` and the matching row
|
|
||||||
in `recipes/README.md`. Do not add a modality-specific support document when
|
|
||||||
the repository has no such table; update the closest shared user contract.
|
|
||||||
|
|
||||||
## Structure the recipe
|
|
||||||
|
|
||||||
Keep the recipe task-oriented and use one hardware-specific file named
|
|
||||||
`recipes/<vendor>/<model>-<hardware>.md`. A recipe may contain multiple
|
|
||||||
deployment topologies on that hardware, but each additional accelerator model
|
|
||||||
or platform requires its own suffixed file.
|
|
||||||
|
|
||||||
1. **Summary:** vendor, exact model ID, runtime, modes, named hardware,
|
|
||||||
recommended deployment, and maintainer.
|
|
||||||
2. **Supported model contract:** put task, input, output, and provided-profile
|
|
||||||
tables before setup or commands.
|
|
||||||
3. **References:** link the canonical model source, shared examples, supported
|
|
||||||
model table, and feature matrix.
|
|
||||||
4. **Checkpoint/setup:** pin revisions when possible and state required assets.
|
|
||||||
5. **Hardware:** document the single accelerator named by the file suffix,
|
|
||||||
including every validated device-count/topology profile on it.
|
|
||||||
6. **Commands:** reuse shared `examples/` entrypoints unless the model contract
|
|
||||||
truly requires a dedicated script. Include offline and online paths that
|
|
||||||
were validated.
|
|
||||||
7. **Supported features:** use a compact model-specific topology/status table
|
|
||||||
with links to shared feature guides.
|
|
||||||
8. **Verification:** provide a quick command and exact expected output
|
|
||||||
contract.
|
|
||||||
9. **Qualification evidence:** report correctness, memory, and timing evidence
|
|
||||||
with its measurement scope and caveats.
|
|
||||||
|
|
||||||
## Separate hardware from software
|
|
||||||
|
|
||||||
For every locally validated hardware profile, record:
|
|
||||||
|
|
||||||
- accelerator vendor/model and per-device memory;
|
|
||||||
- number of devices;
|
|
||||||
- interconnect (`NVLink`, `PCIe`, or the platform equivalent);
|
|
||||||
- host memory when CPU staging/offload is material;
|
|
||||||
- whether the profile is runtime-qualified or configuration-only.
|
|
||||||
|
|
||||||
Record OS, Python, driver/runtime, framework versions, and the vLLM-Omni
|
|
||||||
revision in a separate software-environment table. Keep precision, worker
|
|
||||||
count, and DP/TP/SP/PP sizes with the deployment profile or exact command.
|
|
||||||
|
|
||||||
Never generalize a result from one accelerator family to another or combine
|
|
||||||
NVIDIA, AMD, NPU, or distinct accelerator models in one recipe. Create a
|
|
||||||
separate hardware-suffixed recipe and `recipes/README.md` row. Distinguish
|
|
||||||
upstream requirements from hardware exercised by the PR.
|
|
||||||
|
|
||||||
## Keep shared documentation concise
|
|
||||||
|
|
||||||
Link the applicable diffusion, TTS, omni, serving, or design guide for generic
|
|
||||||
feature semantics and launch instructions. The recipe should contain only the
|
|
||||||
model-specific status, valid topology, required flag difference, and evidence
|
|
||||||
boundary.
|
|
||||||
|
|
||||||
Put unsupported combinations in the same feature table. Avoid repeating the
|
|
||||||
same model-specific prose below the global feature matrix; the recipe is the
|
|
||||||
detailed source of truth.
|
|
||||||
|
|
||||||
## Report evidence precisely
|
|
||||||
|
|
||||||
For every performance or memory value, state:
|
|
||||||
|
|
||||||
- checkpoint/revision and workload;
|
|
||||||
- accelerator and device count;
|
|
||||||
- precision and topology;
|
|
||||||
- cold/warm scope, step count, and concurrency;
|
|
||||||
- peak HBM and host-memory metric when measured;
|
|
||||||
- output/quality guard and sample count;
|
|
||||||
- monitoring overhead or other known variance.
|
|
||||||
|
|
||||||
Call a single bounded run qualification evidence, not a benchmark. Do not add
|
|
||||||
a benchmark script unless the contribution explicitly requires one.
|
|
||||||
|
|
||||||
## Synchronize repository documentation
|
|
||||||
|
|
||||||
Update all applicable locations:
|
|
||||||
|
|
||||||
- the row in `recipes/README.md`;
|
|
||||||
- `docs/models/supported_models.md`;
|
|
||||||
- the family-specific documentation selected in **Route by model family**;
|
|
||||||
- shared example documentation when commands or flags change.
|
|
||||||
|
|
||||||
Keep global support tables compact. Link to the recipe instead of duplicating
|
|
||||||
its deployment explanation.
|
|
||||||
|
|
||||||
## Validate
|
|
||||||
|
|
||||||
Run, at minimum:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pre-commit run --files <changed recipe/docs/skill files>
|
|
||||||
mkdocs build --strict
|
|
||||||
git diff --check
|
|
||||||
```
|
|
||||||
|
|
||||||
Remove generated documentation artifacts after validation. Confirm every
|
|
||||||
recipe link resolves and every claimed profile has matching code or evidence.
|
|
||||||
@@ -499,13 +499,6 @@ Common pre-commit failures, recovery commands for missing sign-off, and the
|
|||||||
full `pre-commit run` invocation for a TTS model:
|
full `pre-commit run` invocation for a TTS model:
|
||||||
[references/precommit-dco.md](references/precommit-dco.md).
|
[references/precommit-dco.md](references/precommit-dco.md).
|
||||||
|
|
||||||
## Documentation and recipe
|
|
||||||
|
|
||||||
Follow the [`add-recipe` skill](../add-recipe/SKILL.md) to add or update the
|
|
||||||
in-repository model-family recipe, the `recipes/README.md` index, the supported
|
|
||||||
models table, TTS example documentation, and the speech API contract using
|
|
||||||
validated evidence.
|
|
||||||
|
|
||||||
## Integration Checklist
|
## Integration Checklist
|
||||||
|
|
||||||
Use this checklist when integrating a new TTS model:
|
Use this checklist when integrating a new TTS model:
|
||||||
@@ -550,7 +543,6 @@ Use this checklist when integrating a new TTS model:
|
|||||||
- [ ] Buildkite entries match level: `test-ready.yml` / `test-merge.yml` or nightly TTS job / `test-nightly.yml`
|
- [ ] Buildkite entries match level: `test-ready.yml` / `test-merge.yml` or nightly TTS job / `test-nightly.yml`
|
||||||
- [ ] Gradio demo working
|
- [ ] Gradio demo working
|
||||||
- [ ] Documentation added (offline + online docs, nav, supported models)
|
- [ ] Documentation added (offline + online docs, nav, supported models)
|
||||||
- [ ] In-repository recipe and `recipes/README.md` row added via the `add-recipe` skill
|
|
||||||
|
|
||||||
### Phase 4: Async Chunk
|
### Phase 4: Async Chunk
|
||||||
- [ ] Pipeline declares the async handoff processor
|
- [ ] Pipeline declares the async handoff processor
|
||||||
|
|||||||
@@ -26,9 +26,6 @@ self-check.
|
|||||||
|
|
||||||
- [`add-diffusion-model`](add-diffusion-model/SKILL.md): guides integration of
|
- [`add-diffusion-model`](add-diffusion-model/SKILL.md): guides integration of
|
||||||
a new diffusion model into `vllm-omni`
|
a new diffusion model into `vllm-omni`
|
||||||
- [`add-recipe`](add-recipe/SKILL.md): creates or updates in-repository model
|
|
||||||
recipes with verified task/input/output contracts, concrete hardware,
|
|
||||||
shared feature-guide links, exact commands, and qualification evidence
|
|
||||||
- [`add-tts-model`](add-tts-model/SKILL.md): covers integration of new TTS
|
- [`add-tts-model`](add-tts-model/SKILL.md): covers integration of new TTS
|
||||||
models and related serving workflows
|
models and related serving workflows
|
||||||
- [`diffusion-perf-opt`](diffusion-perf-opt/SKILL.md): guides diffusion model
|
- [`diffusion-perf-opt`](diffusion-perf-opt/SKILL.md): guides diffusion model
|
||||||
|
|||||||
@@ -123,11 +123,10 @@ it changes again, report the churn and wait for a stable target.
|
|||||||
|
|
||||||
For a trusted PR head, materialize the pinned head in an isolated detached
|
For a trusted PR head, materialize the pinned head in an isolated detached
|
||||||
worktree. A worktree freezes identity but is not a security sandbox. Treat fork
|
worktree. A worktree freezes identity but is not a security sandbox. Treat fork
|
||||||
heads as untrusted until the user and environment policy explicitly establish
|
heads as untrusted unless the user and environment policy explicitly establish
|
||||||
trust: execute their code only after that trust is recorded for this host,
|
otherwise: execute them only in a disposable, secret-free sandbox with restricted
|
||||||
with the trusted SHA noted in the review state and secrets kept out of the
|
filesystem, network, and resources; without one, use static SHA-addressed reads
|
||||||
execution scope; without recorded trust, use static SHA-addressed reads and CI
|
and CI evidence only. For a local review, freeze the committed, index, worktree,
|
||||||
evidence only. For a local review, freeze the committed, index, worktree,
|
|
||||||
and NUL-safe in-scope untracked contents. Follow
|
and NUL-safe in-scope untracked contents. Follow
|
||||||
[review-execution.md](references/process/review-execution.md) for trust gates,
|
[review-execution.md](references/process/review-execution.md) for trust gates,
|
||||||
state fingerprints, and byte-for-byte staleness checks.
|
state fingerprints, and byte-for-byte staleness checks.
|
||||||
@@ -197,7 +196,7 @@ style preferences as simplification findings.
|
|||||||
|
|
||||||
Before each validation group, verify the frozen SHA plus the tracked, index,
|
Before each validation group, verify the frozen SHA plus the tracked, index,
|
||||||
untracked, and ignored-file fingerprint, or recreate a pristine snapshot. On a
|
untracked, and ignored-file fingerprint, or recreate a pristine snapshot. On a
|
||||||
head the user explicitly trusted for this host, run an import/version preflight,
|
trusted head or inside the required sandbox, run an import/version preflight,
|
||||||
then the narrowest relevant tests and low-cost static checks. Bind every result
|
then the narrowest relevant tests and low-cost static checks. Bind every result
|
||||||
to the head SHA, snapshot fingerprint, and environment fingerprint. Never run
|
to the head SHA, snapshot fingerprint, and environment fingerprint. Never run
|
||||||
imports, tests, builds, hooks, or repo-configurable tooling from an untrusted
|
imports, tests, builds, hooks, or repo-configurable tooling from an untrusted
|
||||||
|
|||||||
@@ -22,19 +22,6 @@ Keep exact commands and report variability rather than a cherry-picked run.
|
|||||||
Use the repository's benchmark when it covers the claim; otherwise use the
|
Use the repository's benchmark when it covers the claim; otherwise use the
|
||||||
smallest reproducible workload that reaches the changed production path.
|
smallest reproducible workload that reaches the changed production path.
|
||||||
|
|
||||||
## Isolation per claim
|
|
||||||
|
|
||||||
Isolate one claim per comparison. When a PR stacks several changes (a fused or
|
|
||||||
restructured load path, a distilled step schedule, a new cache), request one
|
|
||||||
column per claim at equal steps/workload instead of one blended base-vs-head
|
|
||||||
delta, and name the unchanged stage or metric that pins equivalence.
|
|
||||||
|
|
||||||
When the changed path is runtime-switchable (feature flag or environment
|
|
||||||
variable), run every column on the same head and toggle the switch rather than
|
|
||||||
diffing against a base commit that cannot separate the stacked changes:
|
|
||||||
base, head with the switch off, head with the switch on, then head with the
|
|
||||||
switch on plus each further claim.
|
|
||||||
|
|
||||||
## Evidence table
|
## Evidence table
|
||||||
|
|
||||||
| Dimension | Typical evidence |
|
| Dimension | Typical evidence |
|
||||||
@@ -47,100 +34,6 @@ switch on plus each further claim.
|
|||||||
Every optimization needs correctness or quality evidence. A faster result on a
|
Every optimization needs correctness or quality evidence. A faster result on a
|
||||||
different workload, precision, seed, or topology is not a valid comparison.
|
different workload, precision, seed, or topology is not a valid comparison.
|
||||||
|
|
||||||
## E2e stage-attribution table
|
|
||||||
|
|
||||||
For an end-to-end latency claim, request the stage-attribution table the
|
|
||||||
repository's perf PRs use:
|
|
||||||
|
|
||||||
- Rows carry the benchmark's own field names: total e2e, per-stage execution,
|
|
||||||
postprocess, response encoding, and a request-to-output roll-up. Add a stage
|
|
||||||
handoff/idle row when the pipeline spans stages — connector transfer and
|
|
||||||
scheduling gaps are invisible in per-stage latency deltas.
|
|
||||||
- Sanity rows pin comparability: inference steps, output frames/pixels/samples,
|
|
||||||
and generated tokens held identical across columns.
|
|
||||||
- Report P50 and P100 from the stated warmup and measured counts. One
|
|
||||||
population per number: never mix cold-start and warm samples into one value.
|
|
||||||
- Name the baseline and candidate commit SHAs, and close with an isolation
|
|
||||||
statement naming the metric that stayed unchanged ("X remained effectively
|
|
||||||
unchanged, isolating the gain to Y").
|
|
||||||
|
|
||||||
When the serving path caches, captures, or regenerates at runtime (CUDA-graph
|
|
||||||
bucket growth, cache rebuilds, recompilation), medians hide the resulting tail.
|
|
||||||
Also request the event count and the maximum observed stall.
|
|
||||||
|
|
||||||
Component-level tables pair with, not replace, the e2e table: per-op reference
|
|
||||||
vs candidate timings (with the numerical-equality result per op) plus one
|
|
||||||
complete-pipeline check under the production shapes.
|
|
||||||
|
|
||||||
## Proportionality
|
|
||||||
|
|
||||||
When a PR adds a model and explicitly labels its numbers as smoke observations
|
|
||||||
rather than claims, do not demand the attribution machinery. Ask only for
|
|
||||||
evidence protecting the model's stated operating contract — for a
|
|
||||||
realtime/duplex model that is sustained cadence over a realistic session
|
|
||||||
(enough ticks to leave warmup), with any mid-session capture/regeneration
|
|
||||||
event and its stall reported, since a cadence that collapses mid-session is a
|
|
||||||
functional failure, not a perf claim.
|
|
||||||
|
|
||||||
## Realtime/duplex world models
|
|
||||||
|
|
||||||
Request the operating-contract evidence as serving metrics, not claims:
|
|
||||||
|
|
||||||
- Sustained per-tick latency over one realistic session: median, max, and the
|
|
||||||
argmax tick.
|
|
||||||
- Stall events with their causes.
|
|
||||||
- Peak memory at first versus last tick — session-owned state must not grow
|
|
||||||
per tick.
|
|
||||||
- Control latency from a submitted action to the tick that applies it.
|
|
||||||
- Realtime-versus-offline parity under the same controls, using the
|
|
||||||
repository's video-similarity helpers. Parity plotted over tick index is the
|
|
||||||
drift-over-horizon curve and the honest measure of session lifetime;
|
|
||||||
distribution-level suites (FVD, VBench) belong to model evaluation, not the
|
|
||||||
serving integration.
|
|
||||||
|
|
||||||
Watch the contract boundaries the model documents: if a control input is
|
|
||||||
tick-API-only, the parity pair must use a horizon both paths can run.
|
|
||||||
|
|
||||||
## Speech-generation (TTS) models
|
|
||||||
|
|
||||||
The streaming contract outranks the average — a synthesis that pauses
|
|
||||||
mid-stream is broken for realtime use regardless of its averages. Request:
|
|
||||||
|
|
||||||
- The benchmark's own speech metrics over one long utterance (enough audio to
|
|
||||||
leave warmup, tens of seconds): `audio_ttfp` (time to first packet),
|
|
||||||
`audio_rtf` (real-time factor; above 1.0 cannot keep up), `e2el`, and
|
|
||||||
`ttft`/`tpot` where tokens precede audio.
|
|
||||||
- Mid-utterance stalls as the benchmark's continuity fields, not prose:
|
|
||||||
`audio_underrun` percentiles and the `audio_continuity_ok` rate
|
|
||||||
(`vllm_omni/benchmarks/metrics/metrics.py`), computed by
|
|
||||||
`vllm_omni/benchmarks/audio_continuity.py` — the companion to `audio_ttfp`
|
|
||||||
and `audio_rtf`. A synthesis that bursts chunks fast enough on average but
|
|
||||||
underruns mid-stream fails the streaming contract even when the averages
|
|
||||||
pass.
|
|
||||||
- Quality as a paired comparison against the reference implementation under
|
|
||||||
the same text, speaker prompt, and seed; report sample rate and frame
|
|
||||||
count, and assert output completeness — truncated or dropped trailing audio
|
|
||||||
is a known failure class, not a quality nuance.
|
|
||||||
- For realtime or duplex TTS: interruption (barge-in) latency and the
|
|
||||||
per-session memory trend across turns.
|
|
||||||
|
|
||||||
## Omni models
|
|
||||||
|
|
||||||
Apply the e2e stage-attribution table directly to the voice-to-voice path of
|
|
||||||
omni (speech-to-speech and multimodal AR) models:
|
|
||||||
|
|
||||||
- TTFT for text output, `audio_ttfp` for audio output, and per-stage
|
|
||||||
ITL/TPOT cadence across the perception-understanding-generation chain.
|
|
||||||
- Cross-modal parity — the omni analogue of realtime-versus-offline parity:
|
|
||||||
the same semantic request through text and audio inputs, compared on output
|
|
||||||
content or timing.
|
|
||||||
- For duplex omni sessions: turn-taking latency, interruption handling, the
|
|
||||||
concurrent session count actually validated, and a per-turn memory trend —
|
|
||||||
session-owned KV state must not grow per turn. When either turn produces
|
|
||||||
audio, continuity is judged with the same `audio_underrun` and
|
|
||||||
`audio_continuity_ok` fields as TTS, since turn-taking latency alone does
|
|
||||||
not expose mid-utterance underruns.
|
|
||||||
|
|
||||||
## Reviewer verification ladder
|
## Reviewer verification ladder
|
||||||
|
|
||||||
1. Run base/head A/B on suitable hardware when affordable.
|
1. Run base/head A/B on suitable hardware when affordable.
|
||||||
|
|||||||
@@ -121,19 +121,6 @@ Search bounded callers and sibling implementations before reporting dead code,
|
|||||||
duplication, or a missed consumer. Keep new abstractions only when they have a
|
duplication, or a missed consumer. Keep new abstractions only when they have a
|
||||||
distinct live caller, invariant, or compatibility need.
|
distinct live caller, invariant, or compatibility need.
|
||||||
|
|
||||||
Verify absence and equality claims with whole-file evidence. A line window, a
|
|
||||||
grep for one symbol, or a commit message proves presence, never absence: to
|
|
||||||
assert that a file matches another version or lacks a change, diff or hash the
|
|
||||||
full files (for example `git diff <sha1>:<path> <sha2>:<path>` or the contents
|
|
||||||
API's size and SHA fields) before anchoring the finding. A verification
|
|
||||||
shortcut that would itself be wrong to run is not evidence.
|
|
||||||
|
|
||||||
For a value written or finalized in more than one place, establish which site
|
|
||||||
executes first on each entry path — and whether the earlier site makes the
|
|
||||||
later ones unreachable — before naming where a fix belongs. Enumerating all
|
|
||||||
call sites correctly still misses the bug when a path the enumeration ranked
|
|
||||||
last actually finalizes first and clears the state the proposed fix checks.
|
|
||||||
|
|
||||||
## Finding bar
|
## Finding bar
|
||||||
|
|
||||||
Anchor each finding to a changed `path:line`; name the trigger or call path,
|
Anchor each finding to a changed `path:line`; name the trigger or call path,
|
||||||
|
|||||||
@@ -39,13 +39,13 @@ isolated detached worktree. Run every source read, `rg` search, import, and test
|
|||||||
from that snapshot, not the caller's checkout. A detached worktree provides
|
from that snapshot, not the caller's checkout. A detached worktree provides
|
||||||
snapshot isolation, not a security boundary.
|
snapshot isolation, not a security boundary.
|
||||||
|
|
||||||
Treat a fork head as untrusted until the user and environment policy
|
Treat a fork head as untrusted unless the user and environment policy explicitly
|
||||||
explicitly establish trust. Without recorded trust, never run its imports,
|
establish trust. Never run its imports, tests, builds, hooks, package setup, or
|
||||||
tests, builds, hooks, package setup, or repo-configurable linters/plugins on
|
repo-configurable linters/plugins on the reviewer host. Execute them only in a
|
||||||
the reviewer host. Once the user explicitly trusts this pinned commit for
|
disposable sandbox or VM with no credentials or inherited secrets, no host agent
|
||||||
this host, record the trusted SHA with the review state and execute with
|
or service sockets, minimal read-only host mounts, disabled or explicitly
|
||||||
credentials, agent sockets, and other secrets out of scope. Without recorded
|
allowlisted network, resource/time limits, and destruction after the run. If
|
||||||
trust, limit the review to the remote diff, SHA-addressed
|
that boundary is unavailable, limit the review to the remote diff, SHA-addressed
|
||||||
reads such as `git show <head_sha>:<path>`, and existing CI evidence; report all
|
reads such as `git show <head_sha>:<path>`, and existing CI evidence; report all
|
||||||
executable validation as a gap.
|
executable validation as a gap.
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
You may find information about contributing to vLLM-Omni on [Contributing](https://vllm-omni.readthedocs.io/en/latest/contributing/).
|
You may find information about contributing to vLLM-Omni on [Contributing](https://vllm-omni.readthedocs.io/en/latest/contributing/).
|
||||||
|
|
||||||
AI-assisted contributions must follow the [AI Usage Policy](docs/contributing/README.md#ai-usage-policy), including disclosure, human review, and validation requirements.
|
|
||||||
|
|
||||||
Local `pre-commit` gates (SPDX, forbidden imports, `torch.cuda`, shellcheck,
|
Local `pre-commit` gates (SPDX, forbidden imports, `torch.cuda`, shellcheck,
|
||||||
mypy, test marks, TTS adapter ratchet, markdownlint, Buildkite schema, and
|
mypy, test marks, TTS adapter ratchet, markdownlint, Buildkite schema, and
|
||||||
how to extend allowlists) are documented in the
|
how to extend allowlists) are documented in the
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ vLLM-Omni is flexible and easy to use with:
|
|||||||
- Tensor, pipeline, data and expert parallelism support for distributed inference
|
- Tensor, pipeline, data and expert parallelism support for distributed inference
|
||||||
- Streaming outputs
|
- Streaming outputs
|
||||||
- OpenAI-compatible API server
|
- OpenAI-compatible API server
|
||||||
- [Full-duplex realtime serving](docs/serving/realtime_duplex_api.md) with streaming audio input and output
|
- Full-duplex realtime serving with streaming audio input and output (experimental)
|
||||||
|
|
||||||
vLLM-Omni seamlessly supports most popular open-source models on HuggingFace, including:
|
vLLM-Omni seamlessly supports most popular open-source models on HuggingFace, including:
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ The main entrypoint is:
|
|||||||
vllm serve Qwen/Qwen-Image --omni --port 8099
|
vllm serve Qwen/Qwen-Image --omni --port 8099
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Run a minimal benchmark:
|
2. Run a minimal benchmark:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 benchmarks/diffusion/diffusion_benchmark_serving.py \
|
python3 benchmarks/diffusion/diffusion_benchmark_serving.py \
|
||||||
@@ -28,7 +28,7 @@ python3 benchmarks/diffusion/diffusion_benchmark_serving.py \
|
|||||||
--num-prompts 5
|
--num-prompts 5
|
||||||
```
|
```
|
||||||
|
|
||||||
### Notes
|
**Notes**
|
||||||
|
|
||||||
- By default, image tasks talk to `http://<host>:<port>/v1/chat/completions`; video tasks talk to `/v1/videos`.
|
- By default, image tasks talk to `http://<host>:<port>/v1/chat/completions`; video tasks talk to `/v1/videos`.
|
||||||
- If you run the server on another host or port, pass `--base-url` accordingly.
|
- If you run the server on another host or port, pass `--base-url` accordingly.
|
||||||
@@ -140,21 +140,6 @@ Traffic / concurrency flags:
|
|||||||
- `--request-rate`: Target request rate (requests/second). If set to `inf`, the script sends all requests immediately.
|
- `--request-rate`: Target request rate (requests/second). If set to `inf`, the script sends all requests immediately.
|
||||||
- `--max-concurrency`: Max number of in-flight requests (default: `1`). This can hard-cap the achieved QPS: if it is too small, requests will queue behind the semaphore, and both achieved throughput and observed SLO attainment can be skewed.
|
- `--max-concurrency`: Max number of in-flight requests (default: `1`). This can hard-cap the achieved QPS: if it is too small, requests will queue behind the semaphore, and both achieved throughput and observed SLO attainment can be skewed.
|
||||||
|
|
||||||
### Video job timeout and failures
|
|
||||||
|
|
||||||
`--video-job-timeout` controls how long each `/v1/videos` job may be polled,
|
|
||||||
including time queued on the server (default: `900` seconds). For long video
|
|
||||||
jobs at high concurrency, use a larger budget, for example
|
|
||||||
`--video-job-timeout 1800`. This also applies to warmup jobs. The polling budget
|
|
||||||
starts after job creation; it excludes time waiting for the client concurrency
|
|
||||||
semaphore. Individual HTTP calls still use the aiohttp session timeout.
|
|
||||||
|
|
||||||
An expired job is counted as failed and deleted, which cancels queued or running
|
|
||||||
server generation. The benchmark continues processing the remaining requests.
|
|
||||||
The progress bar counts both successful and failed requests. The final report
|
|
||||||
shows the failure count and the first 10 errors; `--output-file` saves all errors
|
|
||||||
with their request IDs in `request_errors`.
|
|
||||||
|
|
||||||
### Batched warmup note
|
### Batched warmup note
|
||||||
|
|
||||||
For batched serving runs, warm the same in-flight shape you plan to measure.
|
For batched serving runs, warm the same in-flight shape you plan to measure.
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
@@ -46,7 +43,6 @@ class RequestFuncInput:
|
|||||||
video_paths: list[str] | None = None
|
video_paths: list[str] | None = None
|
||||||
request_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
request_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
||||||
default_bot_task: str | None = DEFAULT_EDITS_BOT_TASK
|
default_bot_task: str | None = DEFAULT_EDITS_BOT_TASK
|
||||||
video_job_timeout: float = 900.0
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -335,9 +331,6 @@ async def async_request_v1_videos(
|
|||||||
output = RequestFuncOutput()
|
output = RequestFuncOutput()
|
||||||
output.start_time = time.perf_counter()
|
output.start_time = time.perf_counter()
|
||||||
|
|
||||||
image_file = None
|
|
||||||
job_id = None
|
|
||||||
try:
|
|
||||||
files = dict(input.extra_body)
|
files = dict(input.extra_body)
|
||||||
if input.prompt:
|
if input.prompt:
|
||||||
files.setdefault("prompt", input.prompt)
|
files.setdefault("prompt", input.prompt)
|
||||||
@@ -357,6 +350,7 @@ async def async_request_v1_videos(
|
|||||||
for k, v in files.items():
|
for k, v in files.items():
|
||||||
form.add_field(k, str(v))
|
form.add_field(k, str(v))
|
||||||
|
|
||||||
|
image_file = None
|
||||||
if input.image_paths and input.video_paths:
|
if input.image_paths and input.video_paths:
|
||||||
output.error = "Only one of image_paths or video_paths can be provided"
|
output.error = "Only one of image_paths or video_paths can be provided"
|
||||||
output.success = False
|
output.success = False
|
||||||
@@ -389,10 +383,12 @@ async def async_request_v1_videos(
|
|||||||
content_type=_guess_mime_type(video_path),
|
content_type=_guess_mime_type(video_path),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
job_id = None
|
||||||
job_status = None
|
job_status = None
|
||||||
poll_json = {}
|
poll_json = {}
|
||||||
resp_json = {}
|
resp_json = {}
|
||||||
|
|
||||||
|
try:
|
||||||
# invoke a post request (POST /v1/videos)
|
# invoke a post request (POST /v1/videos)
|
||||||
async with session.post(input.api_url, data=form) as response:
|
async with session.post(input.api_url, data=form) as response:
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
@@ -410,7 +406,7 @@ async def async_request_v1_videos(
|
|||||||
|
|
||||||
# invoke a poll request (GET /v1/videos/{video_id})
|
# invoke a poll request (GET /v1/videos/{video_id})
|
||||||
poll_interval = 2.0 # Unit(s)
|
poll_interval = 2.0 # Unit(s)
|
||||||
timeout_seconds = input.video_job_timeout
|
timeout_seconds = 600.0
|
||||||
deadline = time.perf_counter() + timeout_seconds
|
deadline = time.perf_counter() + timeout_seconds
|
||||||
job_url = f"{input.api_url}/{job_id}"
|
job_url = f"{input.api_url}/{job_id}"
|
||||||
|
|
||||||
@@ -426,11 +422,8 @@ async def async_request_v1_videos(
|
|||||||
poll_json = await poll_response.json()
|
poll_json = await poll_response.json()
|
||||||
job_status = poll_json.get("status")
|
job_status = poll_json.get("status")
|
||||||
|
|
||||||
if job_status not in {"completed", "failed"} and time.perf_counter() >= deadline:
|
if time.perf_counter() >= deadline:
|
||||||
output.error = (
|
output.error = f"Timed out waiting for video job {job_id} to complete."
|
||||||
f"Timed out after {timeout_seconds:g}s waiting for video job {job_id} to complete. "
|
|
||||||
"Increase --video-job-timeout for long-running or queued video jobs."
|
|
||||||
)
|
|
||||||
output.success = False
|
output.success = False
|
||||||
return output
|
return output
|
||||||
|
|
||||||
@@ -459,7 +452,7 @@ async def async_request_v1_videos(
|
|||||||
elif "peak_memory_mb" in resp_json:
|
elif "peak_memory_mb" in resp_json:
|
||||||
output.peak_memory_mb = resp_json["peak_memory_mb"]
|
output.peak_memory_mb = resp_json["peak_memory_mb"]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
output.error = f"{type(e).__name__}: {e}"
|
output.error = str(e)
|
||||||
output.success = False
|
output.success = False
|
||||||
finally:
|
finally:
|
||||||
if image_file is not None:
|
if image_file is not None:
|
||||||
@@ -473,12 +466,12 @@ async def async_request_v1_videos(
|
|||||||
print(f"Failed to clean up video job {job_id}: {e}")
|
print(f"Failed to clean up video job {job_id}: {e}")
|
||||||
|
|
||||||
output.latency = time.perf_counter() - output.start_time
|
output.latency = time.perf_counter() - output.start_time
|
||||||
if pbar is not None:
|
|
||||||
pbar.update(1)
|
|
||||||
|
|
||||||
if output.success and input.slo_ms is not None:
|
if output.success and input.slo_ms is not None:
|
||||||
output.slo_achieved = (output.latency * 1000.0) <= float(input.slo_ms)
|
output.slo_achieved = (output.latency * 1000.0) <= float(input.slo_ms)
|
||||||
|
|
||||||
|
if pbar:
|
||||||
|
pbar.update(1)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# adapted from fastvideo
|
# adapted from fastvideo
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Benchmark online serving for diffusion models (Image/Video Generation).
|
Benchmark online serving for diffusion models (Image/Video Generation).
|
||||||
@@ -87,7 +87,6 @@ import base64
|
|||||||
import glob
|
import glob
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import math
|
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import tempfile
|
import tempfile
|
||||||
@@ -1117,11 +1116,6 @@ def calculate_metrics(
|
|||||||
"duration": total_duration,
|
"duration": total_duration,
|
||||||
"completed_requests": num_success,
|
"completed_requests": num_success,
|
||||||
"failed_requests": len(error_outputs),
|
"failed_requests": len(error_outputs),
|
||||||
"request_errors": [
|
|
||||||
{"request_id": req.request_id, "error": out.error}
|
|
||||||
for req, out in zip(requests_list, outputs)
|
|
||||||
if not out.success
|
|
||||||
],
|
|
||||||
"throughput_qps": num_success / total_duration if total_duration > 0 else 0,
|
"throughput_qps": num_success / total_duration if total_duration > 0 else 0,
|
||||||
"latency_mean": np.mean(latencies) if latencies else 0,
|
"latency_mean": np.mean(latencies) if latencies else 0,
|
||||||
"latency_median": np.median(latencies) if latencies else 0,
|
"latency_median": np.median(latencies) if latencies else 0,
|
||||||
@@ -1267,9 +1261,6 @@ def _default_endpoint_for_task(task: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
async def benchmark(args):
|
async def benchmark(args):
|
||||||
if not math.isfinite(args.video_job_timeout) or args.video_job_timeout <= 0:
|
|
||||||
raise ValueError("--video-job-timeout must be a positive finite number of seconds.")
|
|
||||||
|
|
||||||
# Construct base_url if not provided
|
# Construct base_url if not provided
|
||||||
if args.base_url is None:
|
if args.base_url is None:
|
||||||
args.base_url = f"http://{args.host}:{args.port}"
|
args.base_url = f"http://{args.host}:{args.port}"
|
||||||
@@ -1321,8 +1312,6 @@ async def benchmark(args):
|
|||||||
print("Loading requests...")
|
print("Loading requests...")
|
||||||
requests_list = dataset.get_requests()
|
requests_list = dataset.get_requests()
|
||||||
print(f"Prepared {len(requests_list)} requests from {args.dataset} dataset.")
|
print(f"Prepared {len(requests_list)} requests from {args.dataset} dataset.")
|
||||||
for req in requests_list:
|
|
||||||
req.video_job_timeout = args.video_job_timeout
|
|
||||||
|
|
||||||
if args.return_stage_metrics and args.endpoint in _STAGE_METRICS_ENDPOINTS:
|
if args.return_stage_metrics and args.endpoint in _STAGE_METRICS_ENDPOINTS:
|
||||||
for req in requests_list:
|
for req in requests_list:
|
||||||
@@ -1387,8 +1376,6 @@ async def benchmark(args):
|
|||||||
metrics["model"] = args.model
|
metrics["model"] = args.model
|
||||||
metrics["dataset"] = args.dataset
|
metrics["dataset"] = args.dataset
|
||||||
metrics["task"] = args.task
|
metrics["task"] = args.task
|
||||||
if args.endpoint == "/v1/videos":
|
|
||||||
metrics["video_job_timeout"] = args.video_job_timeout
|
|
||||||
if args.endpoint == "/v1/images/edits":
|
if args.endpoint == "/v1/images/edits":
|
||||||
metrics["bot_task"] = args.bot_task
|
metrics["bot_task"] = args.bot_task
|
||||||
|
|
||||||
@@ -1411,11 +1398,6 @@ async def benchmark(args):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
print("{:<40} {}/{:<15}".format("Successful requests:", metrics["completed_requests"], len(requests_list)))
|
print("{:<40} {}/{:<15}".format("Successful requests:", metrics["completed_requests"], len(requests_list)))
|
||||||
print("{:<40} {:<15}".format("Failed requests:", metrics["failed_requests"]))
|
|
||||||
for failure in metrics["request_errors"][:10]:
|
|
||||||
print(f"Request {failure['request_id']} failed: {failure['error']}")
|
|
||||||
if metrics["failed_requests"] > 10:
|
|
||||||
print("Showing first 10 failures; use --output-file to save all request errors.")
|
|
||||||
|
|
||||||
# Section 3: Performance Metrics
|
# Section 3: Performance Metrics
|
||||||
print(f"{'-' * 50}")
|
print(f"{'-' * 50}")
|
||||||
@@ -1499,13 +1481,6 @@ if __name__ == "__main__":
|
|||||||
help="Path to local dataset file (optional).",
|
help="Path to local dataset file (optional).",
|
||||||
)
|
)
|
||||||
parser.add_argument("--num-prompts", type=int, default=10, help="Number of prompts to benchmark.")
|
parser.add_argument("--num-prompts", type=int, default=10, help="Number of prompts to benchmark.")
|
||||||
parser.add_argument(
|
|
||||||
"--video-job-timeout",
|
|
||||||
type=float,
|
|
||||||
default=900.0,
|
|
||||||
help="Maximum polling time in seconds per video job, including server queue time (default: 900). "
|
|
||||||
"Increase this for long-running video generation or high concurrency.",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--max-concurrency",
|
"--max-concurrency",
|
||||||
type=int,
|
type=int,
|
||||||
|
|||||||
+10
-39
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
A model-agnostic serving benchmark for TTS models in vllm-omni. One CLI
|
A model-agnostic serving benchmark for TTS models in vllm-omni. One CLI
|
||||||
(`bench_tts.py`) + one YAML registry (`model_configs.yaml`) drive perf and
|
(`bench_tts.py`) + one YAML registry (`model_configs.yaml`) drive perf and
|
||||||
quality runs for every registered checkpoint: **Qwen3-TTS** (Base / CustomVoice / VoiceDesign)
|
quality runs for every registered checkpoint: **Qwen3-TTS** (Base / CustomVoice)
|
||||||
and **VoxCPM2** today, more to come.
|
and **VoxCPM2** today, more to come.
|
||||||
|
|
||||||
The same three task types — `voice_clone`, `default_voice`, `voice_design` —
|
The same three task types — `voice_clone`, `default_voice`, `voice_design` —
|
||||||
@@ -21,11 +21,6 @@ The server auto-loads its Deploy YAML from `vllm_omni/deploy/qwen3_tts.yaml`
|
|||||||
(Pipeline + Deploy schema introduced in #2383). No explicit `--deploy-config`
|
(Pipeline + Deploy schema introduced in #2383). No explicit `--deploy-config`
|
||||||
flag is needed for a registered model.
|
flag is needed for a registered model.
|
||||||
|
|
||||||
Start the checkpoint that matches the benchmark task below: `-Base` for
|
|
||||||
`voice_clone`, `-CustomVoice` for `default_voice`, or `-VoiceDesign` for
|
|
||||||
`voice_design`. Restart the server with the matching checkpoint when switching
|
|
||||||
tasks; changing only the benchmark's `--model` does not reload the server.
|
|
||||||
|
|
||||||
### 2. Run the benchmark (`vllm bench serve --omni`)
|
### 2. Run the benchmark (`vllm bench serve --omni`)
|
||||||
|
|
||||||
The primary, directly-controllable path. Copy-paste one of these and tweak
|
The primary, directly-controllable path. Copy-paste one of these and tweak
|
||||||
@@ -67,12 +62,12 @@ vllm bench serve --omni \
|
|||||||
--save-result --result-dir ./results
|
--save-result --result-dir ./results
|
||||||
```
|
```
|
||||||
|
|
||||||
#### voice_design (Qwen3-TTS-VoiceDesign, bundled seed_tts_design)
|
#### voice_design (Qwen3-TTS-CustomVoice, bundled seed_tts_design)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
vllm bench serve --omni \
|
vllm bench serve --omni \
|
||||||
--host 127.0.0.1 --port 8000 \
|
--host 127.0.0.1 --port 8000 \
|
||||||
--model Qwen/Qwen3-TTS-12Hz-1.7B-VoiceDesign \
|
--model Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice \
|
||||||
--backend openai-audio-speech \
|
--backend openai-audio-speech \
|
||||||
--endpoint /v1/audio/speech \
|
--endpoint /v1/audio/speech \
|
||||||
--dataset-name seed-tts-design \
|
--dataset-name seed-tts-design \
|
||||||
@@ -85,25 +80,6 @@ vllm bench serve --omni \
|
|||||||
--save-result --result-dir ./results
|
--save-result --result-dir ./results
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Set the sample rate for models that are not 24 kHz
|
|
||||||
|
|
||||||
Streamed PCM carries no header, so the harness derives `audio_duration` from the
|
|
||||||
byte count and a **default 24000 Hz** assumption
|
|
||||||
(`vllm_omni/metrics/definitions.py:DEFAULT_AUDIO_SAMPLE_RATE`). For a model that
|
|
||||||
emits another rate, export the real one or every duration-derived metric is
|
|
||||||
wrong by `real_sr / 24000`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Audio8 TTS, Fish Speech S2 Pro, Ming-omni-tts, ... all decode at 44.1 kHz
|
|
||||||
export VLLM_OMNI_BENCH_AUDIO_SAMPLE_RATE=44100
|
|
||||||
```
|
|
||||||
|
|
||||||
Without it, a 44.1 kHz model reports `audio_duration` 1.84x too long, so
|
|
||||||
`audio_rtf` looks 1.84x *better* than reality and `audio_underrun` /
|
|
||||||
`Streaming continuity OK rate` are measured against inflated chunk budgets.
|
|
||||||
A quick sanity check: compare `Mean AUDIO_DURATION (s)` against the actual
|
|
||||||
length of a saved WAV for the same prompt.
|
|
||||||
|
|
||||||
#### Streaming continuity (`audio_underrun`)
|
#### Streaming continuity (`audio_underrun`)
|
||||||
|
|
||||||
`audio_underrun` (seconds) is the per-request worst-case buffer deficit
|
`audio_underrun` (seconds) is the per-request worst-case buffer deficit
|
||||||
@@ -205,10 +181,10 @@ Outputs TTFP / RTF / throughput curves (and a markdown table) for every
|
|||||||
## Task types
|
## Task types
|
||||||
|
|
||||||
| Task | Dataset | Request body | Checkpoints that support it |
|
| Task | Dataset | Request body | Checkpoints that support it |
|
||||||
| --------------- | ----------------- | ----------------------------------------------------------------------- | ----------------------------- |
|
|-----------------|-------------------|-----------------------------------------------------|------------------------------------------|
|
||||||
| `voice_clone` | `seed-tts` | `ref_audio` + `ref_text` + `task_type=Base` | `Qwen3-TTS-*-Base`, `VoxCPM2` |
|
| `voice_clone` | `seed-tts` | `ref_audio` + `ref_text` + `task_type=Base` | `Qwen3-TTS-*-Base`, `VoxCPM2` |
|
||||||
| `default_voice` | `seed-tts-text` | `voice=Vivian` + `task_type=CustomVoice` | `Qwen3-TTS-*-CustomVoice` |
|
| `default_voice` | `seed-tts-text` | `voice=Vivian` + `task_type=CustomVoice` | `Qwen3-TTS-*-CustomVoice` |
|
||||||
| `voice_design` | `seed-tts-design` | `instructions=<natural-language description>` + `task_type=VoiceDesign` | `Qwen3-TTS-*-VoiceDesign` |
|
| `voice_design` | `seed-tts-design` | `instructions=<natural-language description>` + `task_type=VoiceDesign` | `Qwen3-TTS-*-CustomVoice` |
|
||||||
|
|
||||||
**`-CustomVoice` checkpoints do NOT ship `speaker_encoder` weights**, so
|
**`-CustomVoice` checkpoints do NOT ship `speaker_encoder` weights**, so
|
||||||
voice_clone requests raise `ValueError` at model runtime. Use `-Base` for
|
voice_clone requests raise `ValueError` at model runtime. Use `-Base` for
|
||||||
@@ -235,7 +211,7 @@ Then add the model's Deploy YAML under `vllm_omni/deploy/<model>.yaml`
|
|||||||
## Datasets
|
## Datasets
|
||||||
|
|
||||||
| Dataset | Bundled? | Format | Source |
|
| Dataset | Bundled? | Format | Source |
|
||||||
| ----------------- | -------- | ----------------------- | -------------------------------------------------------------------- |
|
|--------------------|----------|-------------------|----------------------------------------------------------------|
|
||||||
| `seed-tts-design` | ✅ | 5-field meta.lst | `benchmarks/build_dataset/seed_tts_design/en/meta.lst` (20 prompts) |
|
| `seed-tts-design` | ✅ | 5-field meta.lst | `benchmarks/build_dataset/seed_tts_design/en/meta.lst` (20 prompts) |
|
||||||
| `seed_tts_smoke` | ✅ | 4-field meta.lst | `benchmarks/build_dataset/seed_tts_smoke/en/meta.lst` (20 text-only) |
|
| `seed_tts_smoke` | ✅ | 4-field meta.lst | `benchmarks/build_dataset/seed_tts_smoke/en/meta.lst` (20 text-only) |
|
||||||
| `seed-tts` | ❌ | 4-field meta.lst + WAVs | Google-Drive: [BytedanceSpeech/seed-tts-eval][seedtts] (~1.2 GB) |
|
| `seed-tts` | ❌ | 4-field meta.lst + WAVs | Google-Drive: [BytedanceSpeech/seed-tts-eval][seedtts] (~1.2 GB) |
|
||||||
@@ -252,10 +228,10 @@ For manual voice_clone / default_voice runs against the full corpus, follow
|
|||||||
`tests/dfx/perf/tests/test_tts.json` wires three perf regimes plus quality:
|
`tests/dfx/perf/tests/test_tts.json` wires three perf regimes plus quality:
|
||||||
|
|
||||||
| eval_phase | concurrency | purpose | Baseline metrics |
|
| eval_phase | concurrency | purpose | Baseline metrics |
|
||||||
| ------------ | ----------- | -------------------------------------------------------- | ------------------------------------------ |
|
|---------------|-------------|---------------------------------------------------------|-----------------------------------------|
|
||||||
| `latency` | 1 | Single-request TTFP / RTF SLO | `median_audio_ttfp_ms`, `median_audio_rtf` |
|
| `latency` | 1 | Single-request TTFP / RTF SLO | `median_audio_ttfp_ms`, `median_audio_rtf` |
|
||||||
| `throughput` | 8 | Codec-batching cliff sentinel (PDF #272 concurrency≥8) | `median_audio_ttfp_ms`, `median_audio_rtf` |
|
| `throughput` | 8 | Codec-batching cliff sentinel (PDF #272 concurrency≥8) | `median_audio_ttfp_ms`, `median_audio_rtf` |
|
||||||
| `quality` | 4 | WER / SIM / UTMOS regression (disabled in CI by default) | `mean_audio_rtf` |
|
| `quality` | 4 | WER / SIM / UTMOS regression (disabled in CI by default)| `mean_audio_rtf` |
|
||||||
|
|
||||||
Why `median_*` for latency/throughput and `mean_*` for quality: latency
|
Why `median_*` for latency/throughput and `mean_*` for quality: latency
|
||||||
distributions have cold-start tails that drag the mean; quality aggregates
|
distributions have cold-start tails that drag the mean; quality aggregates
|
||||||
@@ -270,15 +246,10 @@ PR #2558 — quality runs are manual / release-validation, not nightly).
|
|||||||
Observed on H20-3e, Qwen3-TTS-1.7B (measured pre-merge on this branch):
|
Observed on H20-3e, Qwen3-TTS-1.7B (measured pre-merge on this branch):
|
||||||
|
|
||||||
| Task | Model | c=1 | c=4 | **c=8** | c=16 | c=32 |
|
| Task | Model | c=1 | c=4 | **c=8** | c=16 | c=32 |
|
||||||
| ------------ | ---------------- | --------------------- | ------------ | ----------------- | ------------- | ------------- |
|
|---------------|---------------|--------|--------|------------|--------|--------|
|
||||||
| voice_clone | 1.7B-Base | RTF 0.15 / TTFP 165ms | 0.28 / 412ms | **0.49 / 1701ms** | 0.72 / 3355ms | 0.77 / 3772ms |
|
| voice_clone | 1.7B-Base | RTF 0.15 / TTFP 165ms | 0.28 / 412ms | **0.49 / 1701ms** | 0.72 / 3355ms | 0.77 / 3772ms |
|
||||||
| voice_design | 1.7B-CustomVoice | RTF 0.08 / TTFP 53ms | 0.11 / 154ms | **0.21 / 872ms** | 0.33 / 1801ms | 0.38 / 1989ms |
|
| voice_design | 1.7B-CustomVoice | RTF 0.08 / TTFP 53ms | 0.11 / 154ms | **0.21 / 872ms** | 0.33 / 1801ms | 0.38 / 1989ms |
|
||||||
|
|
||||||
The historical `voice_design` row above lists a CustomVoice checkpoint, which
|
|
||||||
current task validation rejects for VoiceDesign requests. It does not establish
|
|
||||||
a VoiceDesign checkpoint baseline; rerun with `Qwen3-TTS-12Hz-1.7B-VoiceDesign`
|
|
||||||
before comparing performance.
|
|
||||||
|
|
||||||
Both models show a **4–6× TTFP jump from c=4 to c=8** while audio throughput
|
Both models show a **4–6× TTFP jump from c=4 to c=8** while audio throughput
|
||||||
saturates around c=4–8 — the codec-bs=1 bottleneck documented in
|
saturates around c=4–8 — the codec-bs=1 bottleneck documented in
|
||||||
vllm-project/vllm-omni#272. The `throughput` CI regime at c=8 is the
|
vllm-project/vllm-omni#272. The `throughput` CI regime at c=8 is the
|
||||||
@@ -286,7 +257,7 @@ sentinel for regressions in this area.
|
|||||||
|
|
||||||
## File layout
|
## File layout
|
||||||
|
|
||||||
```text
|
```
|
||||||
benchmarks/tts/
|
benchmarks/tts/
|
||||||
├── README.md (this file)
|
├── README.md (this file)
|
||||||
├── bench_tts.py CLI — serve-mode benchmark driver
|
├── bench_tts.py CLI — serve-mode benchmark driver
|
||||||
|
|||||||
@@ -17,23 +17,12 @@ models:
|
|||||||
extra_params:
|
extra_params:
|
||||||
lang: en
|
lang: en
|
||||||
text_normalization: true
|
text_normalization: true
|
||||||
# Audio8 TTS Preview: DualAR, 44.1 kHz. trust_remote_code stays false.
|
|
||||||
# Bench at 44.1 kHz: export VLLM_OMNI_BENCH_AUDIO_SAMPLE_RATE=44100, otherwise
|
|
||||||
# the streamed-PCM duration defaults to 24 kHz and RTF looks 1.84x too good.
|
|
||||||
Audio8/Audio8-TTS-Preview-0.6b:
|
|
||||||
supported_tasks: [default_voice, voice_clone]
|
|
||||||
backend: openai-audio-speech
|
|
||||||
endpoint: /v1/audio/speech
|
|
||||||
trust_remote_code: false
|
|
||||||
task_extra_body:
|
|
||||||
default_voice: {}
|
|
||||||
voice_clone: {}
|
|
||||||
|
|
||||||
# -CustomVoice checkpoints lack speaker_encoder weights, so voice_clone is
|
# -CustomVoice checkpoints lack speaker_encoder weights, so voice_clone is
|
||||||
# NOT supported (an attempt raises ValueError from _extract_speaker_embedding
|
# NOT supported (an attempt raises ValueError from _extract_speaker_embedding
|
||||||
# at model runtime). Use -Base for voice_clone.
|
# at model runtime). Use -Base for voice_clone.
|
||||||
Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice:
|
Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice:
|
||||||
supported_tasks: [default_voice]
|
supported_tasks: [default_voice, voice_design]
|
||||||
backend: openai-audio-speech
|
backend: openai-audio-speech
|
||||||
endpoint: /v1/audio/speech
|
endpoint: /v1/audio/speech
|
||||||
trust_remote_code: true
|
trust_remote_code: true
|
||||||
@@ -42,13 +31,6 @@ models:
|
|||||||
voice: Vivian
|
voice: Vivian
|
||||||
language: English
|
language: English
|
||||||
task_type: CustomVoice
|
task_type: CustomVoice
|
||||||
|
|
||||||
Qwen/Qwen3-TTS-12Hz-1.7B-VoiceDesign:
|
|
||||||
supported_tasks: [voice_design]
|
|
||||||
backend: openai-audio-speech
|
|
||||||
endpoint: /v1/audio/speech
|
|
||||||
trust_remote_code: true
|
|
||||||
task_extra_body:
|
|
||||||
voice_design:
|
voice_design:
|
||||||
task_type: VoiceDesign
|
task_type: VoiceDesign
|
||||||
language: English
|
language: English
|
||||||
|
|||||||
+23
-6
@@ -1,10 +1,27 @@
|
|||||||
# Target vLLM version: v0.29.0 (tag @ 98dff2a81d74).
|
# Target vllm version: v0.28.0 (tag v0.28.0 @ 2cf0a6915ce5).
|
||||||
# Use the matching release image and its coherent CUDA/PyTorch/FlashInfer
|
# Keep VLLM_BASE_TAG aligned with the target vLLM release on every rebase.
|
||||||
# runtime. Do not reinstall a commit wheel or repair dependencies on top of
|
#
|
||||||
# an older base image at a release boundary. For a future unreleased target,
|
# Release-boundary form: there is no precompiled-wheel pin here, because the
|
||||||
# restore an explicit wheel pin and validate its complete runtime stack.
|
# base image already ships exactly the target vLLM. Everything the runtime
|
||||||
|
# needs — torch, flashinfer, nvJitLink, numpy — comes from that image as one
|
||||||
|
# self-consistent set.
|
||||||
|
#
|
||||||
|
# This block reappears only when the rebase targets a vLLM commit that is NOT a
|
||||||
|
# released tag. During the 0.27 rebase, targeting v0.27.0rc1 on top of the
|
||||||
|
# v0.26.0 base image required reinstalling vLLM from wheels.vllm.ai and then
|
||||||
|
# hand-repairing the fallout: pinning torch ahead of flashinfer (installing it
|
||||||
|
# after bound flashinfer's TVM FFI runtime to the old torch and aborted engine
|
||||||
|
# core init), registering libnvJitLink.so.13 with ldconfig, and re-pinning numpy
|
||||||
|
# under numba's ceiling. All of it was compensation for a base image and a vLLM
|
||||||
|
# that disagreed. At a real release boundary they agree, so none of it is
|
||||||
|
# needed. The 0.28 rebase repeated the cycle: the v0.28.0rc / final-tag wheels
|
||||||
|
# rode on the v0.27.0 base image with the full reinstall block until the
|
||||||
|
# official v0.28.0 image shipped, at which point this file dropped back to the
|
||||||
|
# form you are reading. If you pin an untagged commit again, restore the
|
||||||
|
# reinstall block — agent/tasks/20_update_wheel_url.sh fails the run rather
|
||||||
|
# than letting the Dockerfile silently ship the wrong vLLM.
|
||||||
ARG VLLM_BASE_IMAGE=vllm/vllm-openai
|
ARG VLLM_BASE_IMAGE=vllm/vllm-openai
|
||||||
ARG VLLM_BASE_TAG=v0.29.0
|
ARG VLLM_BASE_TAG=v0.28.0
|
||||||
|
|
||||||
# We use registry-based layer caching for the dependencies,
|
# We use registry-based layer caching for the dependencies,
|
||||||
# where the tag is determined based on the hash of the contents
|
# where the tag is determined based on the hash of the contents
|
||||||
|
|||||||
+16
-4
@@ -1,7 +1,20 @@
|
|||||||
ARG VLLM_ASCEND_IMAGE=quay.io/atlas-ci/vllm-ascend
|
ARG VLLM_ASCEND_IMAGE=quay.io/atlas-ci/vllm-ascend
|
||||||
ARG VLLM_ASCEND_VERSION=v0.28.0
|
ARG VLLM_ASCEND_TAG=v0.28.0
|
||||||
ARG VLLM_ASCEND_DEVICE_SUFFIX=
|
FROM ${VLLM_ASCEND_IMAGE}:${VLLM_ASCEND_TAG}
|
||||||
FROM ${VLLM_ASCEND_IMAGE}:${VLLM_ASCEND_VERSION}${VLLM_ASCEND_DEVICE_SUFFIX}
|
|
||||||
|
# WORKDIR /vllm-workspace/vllm
|
||||||
|
# RUN git fetch origin --tags && git checkout v0.18.0
|
||||||
|
|
||||||
|
# WORKDIR /vllm-workspace/vllm-ascend
|
||||||
|
# RUN git fetch origin releases/v0.18.0 && git checkout d781902ce9dbda8ab1e11bb0f2f0c1bc508fee7a
|
||||||
|
# # Install vllm-ascend
|
||||||
|
# # Append `libascend_hal.so` path (devlib) to LD_LIBRARY_PATH
|
||||||
|
# RUN export PIP_EXTRA_INDEX_URL=https://mirrors.huaweicloud.com/ascend/repos/pypi && \
|
||||||
|
# source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
|
||||||
|
# source /usr/local/Ascend/nnal/atb/set_env.sh && \
|
||||||
|
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/Ascend/ascend-toolkit/latest/`uname -i`-linux/devlib && \
|
||||||
|
# python3 -m pip install -v -e /vllm-workspace/vllm-ascend/ --extra-index https://download.pytorch.org/whl/cpu/ && \
|
||||||
|
# python3 -m pip cache purge
|
||||||
|
|
||||||
ARG APP_DIR=/vllm-workspace/vllm-omni
|
ARG APP_DIR=/vllm-workspace/vllm-omni
|
||||||
WORKDIR ${APP_DIR}
|
WORKDIR ${APP_DIR}
|
||||||
@@ -11,7 +24,6 @@ RUN export PIP_EXTRA_INDEX_URL=https://mirrors.huaweicloud.com/ascend/repos/pypi
|
|||||||
source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
|
source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
|
||||||
source /usr/local/Ascend/nnal/atb/set_env.sh && \
|
source /usr/local/Ascend/nnal/atb/set_env.sh && \
|
||||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/Ascend/ascend-toolkit/latest/`uname -i`-linux/devlib && \
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/Ascend/ascend-toolkit/latest/`uname -i`-linux/devlib && \
|
||||||
python3 -m pip install -v "mindiesd==3.1.0" && \
|
|
||||||
python3 -m pip install -v -e /vllm-workspace/vllm-omni/ --no-build-isolation
|
python3 -m pip install -v -e /vllm-workspace/vllm-omni/ --no-build-isolation
|
||||||
|
|
||||||
RUN python3 -m pip install -v --no-deps \
|
RUN python3 -m pip install -v --no-deps \
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
ARG VLLM_ASCEND_IMAGE=quay.io/atlas-ci/vllm-ascend
|
||||||
|
ARG VLLM_ASCEND_TAG=v0.28.0-a3
|
||||||
|
FROM ${VLLM_ASCEND_IMAGE}:${VLLM_ASCEND_TAG}
|
||||||
|
|
||||||
|
# WORKDIR /vllm-workspace/vllm
|
||||||
|
# RUN git fetch origin --tags && git checkout v0.18.0
|
||||||
|
|
||||||
|
# WORKDIR /vllm-workspace/vllm-ascend
|
||||||
|
# RUN git fetch origin releases/v0.18.0 && git checkout d781902ce9dbda8ab1e11bb0f2f0c1bc508fee7a
|
||||||
|
# # Install vllm-ascend
|
||||||
|
# # Append `libascend_hal.so` path (devlib) to LD_LIBRARY_PATH
|
||||||
|
# RUN export PIP_EXTRA_INDEX_URL=https://mirrors.huaweicloud.com/ascend/repos/pypi && \
|
||||||
|
# source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
|
||||||
|
# source /usr/local/Ascend/nnal/atb/set_env.sh && \
|
||||||
|
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/Ascend/ascend-toolkit/latest/`uname -i`-linux/devlib && \
|
||||||
|
# python3 -m pip install -v -e /vllm-workspace/vllm-ascend/ --extra-index https://download.pytorch.org/whl/cpu/ && \
|
||||||
|
# python3 -m pip cache purge
|
||||||
|
|
||||||
|
ARG APP_DIR=/vllm-workspace/vllm-omni
|
||||||
|
WORKDIR ${APP_DIR}
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN export PIP_EXTRA_INDEX_URL=https://mirrors.huaweicloud.com/ascend/repos/pypi && \
|
||||||
|
source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
|
||||||
|
source /usr/local/Ascend/nnal/atb/set_env.sh && \
|
||||||
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/Ascend/ascend-toolkit/latest/`uname -i`-linux/devlib && \
|
||||||
|
python3 -m pip install -v -e /vllm-workspace/vllm-omni/ --no-build-isolation
|
||||||
|
|
||||||
|
RUN python3 -m pip install -v --no-deps \
|
||||||
|
"stepaudio2-minicpmo>=0.1.1" \
|
||||||
|
"step-audio2>=1.0.0"
|
||||||
|
|
||||||
|
ENV VLLM_TARGET_DEVICE=npu
|
||||||
|
ENV VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||||
|
|
||||||
|
ENTRYPOINT []
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
ARG VLLM_ASCEND_IMAGE=quay.io/atlas-ci/vllm-ascend
|
ARG VLLM_ASCEND_IMAGE=quay.io/atlas-ci/vllm-ascend
|
||||||
ARG VLLM_ASCEND_VERSION=v0.28.0
|
ARG VLLM_ASCEND_TAG=v0.28.0
|
||||||
ARG VLLM_ASCEND_DEVICE_SUFFIX=
|
FROM ${VLLM_ASCEND_IMAGE}:${VLLM_ASCEND_TAG}
|
||||||
FROM ${VLLM_ASCEND_IMAGE}:${VLLM_ASCEND_VERSION}${VLLM_ASCEND_DEVICE_SUFFIX}
|
|
||||||
|
|
||||||
ARG APP_DIR=/vllm-workspace/vllm-omni
|
ARG APP_DIR=/vllm-workspace/vllm-omni
|
||||||
WORKDIR ${APP_DIR}
|
WORKDIR ${APP_DIR}
|
||||||
|
COPY . .
|
||||||
|
|
||||||
RUN sed -i "s@^\(deb.*\)https\?://[a-z0-9.-]*\.ubuntu\.com@\1http://cache-service.nginx-pypi-cache.svc.cluster.local:8081@g" /etc/apt/sources.list
|
RUN sed -i "s@^\(deb.*\)https\?://[a-z0-9.-]*\.ubuntu\.com@\1http://cache-service.nginx-pypi-cache.svc.cluster.local:8081@g" /etc/apt/sources.list
|
||||||
|
|
||||||
@@ -22,9 +22,11 @@ RUN apt-get update && \
|
|||||||
rm -rf /var/cache/apt/* && \
|
rm -rf /var/cache/apt/* && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN python3 -m pip install -U pip && \
|
RUN source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
|
||||||
|
source /usr/local/Ascend/nnal/atb/set_env.sh && \
|
||||||
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/Ascend/ascend-toolkit/latest/`uname -i`-linux/devlib && \
|
||||||
|
python3 -m pip install -U pip && \
|
||||||
python3 -m pip install -v \
|
python3 -m pip install -v \
|
||||||
"mindiesd==3.1.0" \
|
|
||||||
"pytest>=7.0.0" \
|
"pytest>=7.0.0" \
|
||||||
"pytest-asyncio>=0.21.0" \
|
"pytest-asyncio>=0.21.0" \
|
||||||
"pytest-cov>=4.0.0" \
|
"pytest-cov>=4.0.0" \
|
||||||
@@ -46,13 +48,7 @@ RUN python3 -m pip install -U pip && \
|
|||||||
"datasets>=3.0.0" \
|
"datasets>=3.0.0" \
|
||||||
--index-url http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple \
|
--index-url http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple \
|
||||||
--trusted-host cache-service.nginx-pypi-cache.svc.cluster.local \
|
--trusted-host cache-service.nginx-pypi-cache.svc.cluster.local \
|
||||||
--default-timeout=60
|
--default-timeout=60 && \
|
||||||
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
RUN source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
|
|
||||||
source /usr/local/Ascend/nnal/atb/set_env.sh && \
|
|
||||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/Ascend/ascend-toolkit/latest/`uname -i`-linux/devlib && \
|
|
||||||
python3 -m pip install -v -e /vllm-workspace/vllm-omni/ --no-build-isolation \
|
python3 -m pip install -v -e /vllm-workspace/vllm-omni/ --no-build-isolation \
|
||||||
--index-url http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple \
|
--index-url http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple \
|
||||||
--trusted-host cache-service.nginx-pypi-cache.svc.cluster.local \
|
--trusted-host cache-service.nginx-pypi-cache.svc.cluster.local \
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
ARG VLLM_ASCEND_IMAGE=quay.io/atlas-ci/vllm-ascend
|
||||||
|
ARG VLLM_ASCEND_TAG=v0.28.0-a3
|
||||||
|
FROM ${VLLM_ASCEND_IMAGE}:${VLLM_ASCEND_TAG}
|
||||||
|
|
||||||
|
ARG APP_DIR=/vllm-workspace/vllm-omni
|
||||||
|
WORKDIR ${APP_DIR}
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN sed -i "s@^\(deb.*\)https\?://[a-z0-9.-]*\.ubuntu\.com@\1http://cache-service.nginx-pypi-cache.svc.cluster.local:8081@g" /etc/apt/sources.list
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
ffmpeg \
|
||||||
|
libgl1 \
|
||||||
|
libglib2.0-0 \
|
||||||
|
libgomp1 \
|
||||||
|
libsm6 \
|
||||||
|
libxext6 \
|
||||||
|
libxrender1 \
|
||||||
|
libxcb1 \
|
||||||
|
espeak-ng && \
|
||||||
|
rm -rf /var/cache/apt/* && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
|
||||||
|
source /usr/local/Ascend/nnal/atb/set_env.sh && \
|
||||||
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/Ascend/ascend-toolkit/latest/`uname -i`-linux/devlib && \
|
||||||
|
python3 -m pip install -U pip && \
|
||||||
|
python3 -m pip install -v \
|
||||||
|
"pytest>=7.0.0" \
|
||||||
|
"pytest-asyncio>=0.21.0" \
|
||||||
|
"pytest-cov>=4.0.0" \
|
||||||
|
"pytest-mock>=3.10.0" \
|
||||||
|
"openpyxl>=3.0.0" \
|
||||||
|
"psutil>=7.2.0" \
|
||||||
|
"soundfile>=0.13.1" \
|
||||||
|
"pyttsx3>=2.99" \
|
||||||
|
"opencc==1.4.1" \
|
||||||
|
"opencv-python>=4.12.0.88" \
|
||||||
|
"imageio[ffmpeg]>=0.6.0" \
|
||||||
|
"jiwer>=3.0.0" \
|
||||||
|
"zhon>=2.0.0" \
|
||||||
|
"zhconv>=1.4.2" \
|
||||||
|
"funasr>=1.0.0" \
|
||||||
|
"hyperpyyaml>=1.2.0" \
|
||||||
|
"onnx>=1.16.0" \
|
||||||
|
"librosa>=0.10.0" \
|
||||||
|
"torchmetrics>=1.9.0" \
|
||||||
|
"datasets>=3.0.0" \
|
||||||
|
--index-url http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple \
|
||||||
|
--trusted-host cache-service.nginx-pypi-cache.svc.cluster.local \
|
||||||
|
--default-timeout=60 && \
|
||||||
|
python3 -m pip install -v -e /vllm-workspace/vllm-omni/ --no-build-isolation \
|
||||||
|
--index-url http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple \
|
||||||
|
--trusted-host cache-service.nginx-pypi-cache.svc.cluster.local \
|
||||||
|
--default-timeout=60
|
||||||
|
|
||||||
|
# MiniCPM-o 4.5 Stage-2 vocoder assets: s3tokenizer plus flashcosyvoice, which
|
||||||
|
# is shipped by step-audio2. --no-deps keeps pip from replacing the Ascend torch
|
||||||
|
# build and from shadowing onnxruntime-cann with the vanilla onnxruntime wheel;
|
||||||
|
# the deps these two actually need are installed above.
|
||||||
|
RUN python3 -m pip install -v --no-deps \
|
||||||
|
"s3tokenizer>=0.3.0" \
|
||||||
|
"step-audio2>=1.0.0" \
|
||||||
|
--index-url http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple \
|
||||||
|
--trusted-host cache-service.nginx-pypi-cache.svc.cluster.local \
|
||||||
|
--default-timeout=60
|
||||||
|
|
||||||
|
ENV VLLM_TARGET_DEVICE=npu
|
||||||
|
ENV VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||||
|
|
||||||
|
ENTRYPOINT []
|
||||||
+2
-5
@@ -17,7 +17,6 @@ nav:
|
|||||||
- Streaming and Realtime:
|
- Streaming and Realtime:
|
||||||
- Realtime Audio: serving/realtime_api.md
|
- Realtime Audio: serving/realtime_api.md
|
||||||
- Full Duplex: serving/full_duplex_api.md
|
- Full Duplex: serving/full_duplex_api.md
|
||||||
- Realtime Duplex Reference: serving/realtime_duplex_api.md
|
|
||||||
- Streaming Video Input: serving/video_stream_api.md
|
- Streaming Video Input: serving/video_stream_api.md
|
||||||
- Streaming Video Output: serving/streaming_video_output_api.md
|
- Streaming Video Output: serving/streaming_video_output_api.md
|
||||||
- OpenPI Robot Policy: serving/openpi_api.md
|
- OpenPI Robot Policy: serving/openpi_api.md
|
||||||
@@ -66,14 +65,13 @@ nav:
|
|||||||
- ModelOpt: user_guide/quantization/modelopt.md
|
- ModelOpt: user_guide/quantization/modelopt.md
|
||||||
- AutoRound: user_guide/quantization/autoround.md
|
- AutoRound: user_guide/quantization/autoround.md
|
||||||
- msModelSlim: user_guide/quantization/msmodelslim.md
|
- msModelSlim: user_guide/quantization/msmodelslim.md
|
||||||
- TorchAO: user_guide/quantization/torchao.md
|
|
||||||
- Diffusion Acceleration:
|
- Diffusion Acceleration:
|
||||||
- Overview and Compatibility:
|
- Overview and Compatibility:
|
||||||
- Overview: user_guide/diffusion_features.md
|
- Overview: user_guide/diffusion_features.md
|
||||||
- Feature Compatibility: user_guide/feature_compatibility.md
|
- Feature Compatibility: user_guide/feature_compatibility.md
|
||||||
- CPU Offloading:
|
- CPU Offloading:
|
||||||
- Overview: user_guide/diffusion/cpu_offload.md
|
- Overview: user_guide/diffusion/cpu_offload.md
|
||||||
- Model-Level: user_guide/diffusion/offloader/module_offload.md
|
- Model-Level: user_guide/diffusion/offloader/cpu_offload.md
|
||||||
- Layerwise: user_guide/diffusion/offloader/layerwise_offload.md
|
- Layerwise: user_guide/diffusion/offloader/layerwise_offload.md
|
||||||
- Distributed Layerwise: user_guide/diffusion/offloader/distributed_layerwise_offload.md
|
- Distributed Layerwise: user_guide/diffusion/offloader/distributed_layerwise_offload.md
|
||||||
- Cache Acceleration:
|
- Cache Acceleration:
|
||||||
@@ -127,7 +125,6 @@ nav:
|
|||||||
- Async Chunk: design/feature/async_chunk.md
|
- Async Chunk: design/feature/async_chunk.md
|
||||||
- Async Diffusion Output: design/feature/async_diffusion_output.md
|
- Async Diffusion Output: design/feature/async_diffusion_output.md
|
||||||
- Async Omni Output Materialization: design/feature/omni_async_output_materialization.md
|
- Async Omni Output Materialization: design/feature/omni_async_output_materialization.md
|
||||||
- Prefill/Decode Phase Contract: design/feature/preprocess_phase_contract.md
|
|
||||||
- Automatic Prefix Caching: design/feature/prefix_caching.md
|
- Automatic Prefix Caching: design/feature/prefix_caching.md
|
||||||
- Realtime AR-Diffusion: design/feature/realtime_ar_diffusion.md
|
- Realtime AR-Diffusion: design/feature/realtime_ar_diffusion.md
|
||||||
- Communication:
|
- Communication:
|
||||||
@@ -153,7 +150,7 @@ nav:
|
|||||||
- Skip-Softmax: design/feature/skip_softmax.md
|
- Skip-Softmax: design/feature/skip_softmax.md
|
||||||
- CPU Offloading:
|
- CPU Offloading:
|
||||||
- Overview: design/feature/offloader/README.md
|
- Overview: design/feature/offloader/README.md
|
||||||
- Model-Level: design/feature/offloader/module_offload.md
|
- Model-Level: design/feature/offloader/cpu_offload.md
|
||||||
- Layerwise: design/feature/offloader/layerwise_offload.md
|
- Layerwise: design/feature/offloader/layerwise_offload.md
|
||||||
- Distributed Layerwise: design/feature/offloader/distributed_layerwise_offload.md
|
- Distributed Layerwise: design/feature/offloader/distributed_layerwise_offload.md
|
||||||
- Cache-DiT: design/feature/cache_dit.md
|
- Cache-DiT: design/feature/cache_dit.md
|
||||||
|
|||||||
+2
-1
@@ -23,6 +23,7 @@ Easy, fast, and cheap omni-modality model serving for everyone
|
|||||||
<a class="github-button" href="https://github.com/vllm-project/vllm-omni/fork" data-show-count="true" data-icon="octicon-repo-forked" data-size="large" aria-label="Fork">Fork</a>
|
<a class="github-button" href="https://github.com/vllm-project/vllm-omni/fork" data-show-count="true" data-icon="octicon-repo-forked" data-size="large" aria-label="Fork">Fork</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
[vLLM](https://github.com/vllm-project/vllm) was originally designed to support large language models for text-based autoregressive generation tasks. vLLM-Omni is a framework that extends its support for omni-modality model inference and serving:
|
[vLLM](https://github.com/vllm-project/vllm) was originally designed to support large language models for text-based autoregressive generation tasks. vLLM-Omni is a framework that extends its support for omni-modality model inference and serving:
|
||||||
@@ -51,7 +52,7 @@ vLLM-Omni is flexible and easy to use with:
|
|||||||
- Tensor, pipeline, data and expert parallelism support for distributed inference
|
- Tensor, pipeline, data and expert parallelism support for distributed inference
|
||||||
- Streaming outputs
|
- Streaming outputs
|
||||||
- OpenAI-compatible API server
|
- OpenAI-compatible API server
|
||||||
- [Full-duplex realtime serving](serving/realtime_duplex_api.md) with streaming audio input and output
|
- Full-duplex realtime serving with streaming audio input and output (experimental)
|
||||||
|
|
||||||
vLLM-Omni seamlessly supports most popular open-source models on HuggingFace, including:
|
vLLM-Omni seamlessly supports most popular open-source models on HuggingFace, including:
|
||||||
|
|
||||||
|
|||||||
@@ -15,36 +15,6 @@ Main entry points for vLLM-Omni inference and serving.
|
|||||||
- [vllm_omni.entrypoints.omni_base.OmniBase][]
|
- [vllm_omni.entrypoints.omni_base.OmniBase][]
|
||||||
- [vllm_omni.entrypoints.pd_utils.PDDisaggregationMixin][]
|
- [vllm_omni.entrypoints.pd_utils.PDDisaggregationMixin][]
|
||||||
|
|
||||||
## Clients
|
|
||||||
|
|
||||||
Client libraries that talk to a running vLLM-Omni server (the full-duplex Realtime client and its per-model session presets).
|
|
||||||
|
|
||||||
- [vllm_omni.clients.duplex.AudioDelta][]
|
|
||||||
- [vllm_omni.clients.duplex.AudioFormat][]
|
|
||||||
- [vllm_omni.clients.duplex.ConnectionResumed][]
|
|
||||||
- [vllm_omni.clients.duplex.DuplexClient][]
|
|
||||||
- [vllm_omni.clients.duplex.DuplexClientError][]
|
|
||||||
- [vllm_omni.clients.duplex.DuplexConnectionError][]
|
|
||||||
- [vllm_omni.clients.duplex.DuplexEvent][]
|
|
||||||
- [vllm_omni.clients.duplex.DuplexProtocolError][]
|
|
||||||
- [vllm_omni.clients.duplex.DuplexSessionClosedError][]
|
|
||||||
- [vllm_omni.clients.duplex.ErrorEvent][]
|
|
||||||
- [vllm_omni.clients.duplex.EventCollector][]
|
|
||||||
- [vllm_omni.clients.duplex.ListenDecision][]
|
|
||||||
- [vllm_omni.clients.duplex.ReconnectPolicy][]
|
|
||||||
- [vllm_omni.clients.duplex.ResponseCreated][]
|
|
||||||
- [vllm_omni.clients.duplex.ResponseDone][]
|
|
||||||
- [vllm_omni.clients.duplex.ResponseHandle][]
|
|
||||||
- [vllm_omni.clients.duplex.SessionClosed][]
|
|
||||||
- [vllm_omni.clients.duplex.SessionConfig][]
|
|
||||||
- [vllm_omni.clients.duplex.SessionCreated][]
|
|
||||||
- [vllm_omni.clients.duplex.SessionExpired][]
|
|
||||||
- [vllm_omni.clients.duplex.SessionResumed][]
|
|
||||||
- [vllm_omni.clients.duplex.SpeakDecision][]
|
|
||||||
- [vllm_omni.clients.duplex.TextDelta][]
|
|
||||||
- [vllm_omni.clients.duplex.TranscriptDelta][]
|
|
||||||
- [vllm_omni.clients.duplex.WebSocketTransport][]
|
|
||||||
|
|
||||||
## Inputs
|
## Inputs
|
||||||
|
|
||||||
Input data structures for multi-modal inputs.
|
Input data structures for multi-modal inputs.
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 272 KiB After Width: | Height: | Size: 274 KiB |
+5
-113
@@ -1,15 +1,11 @@
|
|||||||
# vLLM-Omni Benchmark CLI Guide
|
# vLLM-Omni Benchmark CLI Guide
|
||||||
|
|
||||||
The vllm bench command launches the vLLM-Omni benchmark to evaluate the performance of multimodal models.
|
The vllm bench command launches the vLLM-Omni benchmark to evaluate the performance of multimodal models.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
vLLM-Omni registers the `openai-chat-omni`, `openai-audio-speech`, `openai-image-edits-omni`, `daily-omni`, and `openai-realtime-duplex` serving benchmark backends. It also adds the `omniinteract` dataset.
|
vLLM-Omni registers the `openai-chat-omni`, `openai-audio-speech`, `openai-image-edits-omni`, `daily-omni`, and `openai-realtime-duplex` serving benchmark backends. It also adds the `omniinteract` dataset.
|
||||||
|
|
||||||
## Basic Parameter Description
|
## Basic Parameter Description
|
||||||
|
|
||||||
You can use `vllm bench serve --omni --help=all` to get descriptions of all parameters. The commonly used parameters are described below:
|
You can use `vllm bench serve --omni --help=all` to get descriptions of all parameters. The commonly used parameters are described below:
|
||||||
|
|
||||||
- `--omni`
|
- `--omni`
|
||||||
Enable Omni (multimodal) mode, supporting multimodal inputs and outputs such as images, videos, and audio.
|
Enable Omni (multimodal) mode, supporting multimodal inputs and outputs such as images, videos, and audio.
|
||||||
|
|
||||||
@@ -81,8 +77,8 @@ Specify to save benchmark results to a json file
|
|||||||
- `--random-prefix-len`
|
- `--random-prefix-len`
|
||||||
Number of fixed prefix tokens before the random context in a request.
|
Number of fixed prefix tokens before the random context in a request.
|
||||||
The total input length is the sum of random-prefix-len and a random
|
The total input length is the sum of random-prefix-len and a random
|
||||||
context length sampled from [input_len *(1 - range_ratio),
|
context length sampled from [input_len * (1 - range_ratio),
|
||||||
input_len* (1 + range_ratio)].Only the random and random-mm modes
|
input_len * (1 + range_ratio)].Only the random and random-mm modes
|
||||||
support this parameter.
|
support this parameter.
|
||||||
|
|
||||||
- `--random-input-len`
|
- `--random-input-len`
|
||||||
@@ -95,7 +91,7 @@ Specify to save benchmark results to a json file
|
|||||||
Range ratio for sampling input/output length,
|
Range ratio for sampling input/output length,
|
||||||
used only for random sampling. Must be in the range [0, 1) to define
|
used only for random sampling. Must be in the range [0, 1) to define
|
||||||
a symmetric sampling range
|
a symmetric sampling range
|
||||||
[length *(1 - range_ratio), length* (1 + range_ratio)].
|
[length * (1 - range_ratio), length * (1 + range_ratio)].
|
||||||
Only the random and random-mm modes support this parameter.
|
Only the random and random-mm modes support this parameter.
|
||||||
|
|
||||||
- `--random-mm-base-items-per-request`
|
- `--random-mm-base-items-per-request`
|
||||||
@@ -141,7 +137,6 @@ Specify to save benchmark results to a json file
|
|||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
### Online Benchmark
|
### Online Benchmark
|
||||||
|
|
||||||
<details class="admonition abstract" markdown="1">
|
<details class="admonition abstract" markdown="1">
|
||||||
<summary>Show more</summary>
|
<summary>Show more</summary>
|
||||||
|
|
||||||
@@ -167,9 +162,7 @@ vllm bench serve \
|
|||||||
--dataset-path ShareGPT_V3_unfiltered_cleaned_split.json \
|
--dataset-path ShareGPT_V3_unfiltered_cleaned_split.json \
|
||||||
--percentile-metrics ttft,tpot,itl,e2el
|
--percentile-metrics ttft,tpot,itl,e2el
|
||||||
```
|
```
|
||||||
|
|
||||||
If successful, you will see the following output:
|
If successful, you will see the following output:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
============ Serving Benchmark Result ============
|
============ Serving Benchmark Result ============
|
||||||
Successful requests: 2
|
Successful requests: 2
|
||||||
@@ -271,7 +264,6 @@ Median AUDIO_RTF: 0.47
|
|||||||
P99 AUDIO_RTF: 0.48
|
P99 AUDIO_RTF: 0.48
|
||||||
==================================================
|
==================================================
|
||||||
```
|
```
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
We use audio generation time / audio duration to calculate RTF.
|
We use audio generation time / audio duration to calculate RTF.
|
||||||
|
|
||||||
@@ -309,36 +301,12 @@ options apply. Use `--omniinteract-require-response` only for functional E2E cas
|
|||||||
Each completed case writes `output.wav`, `wav_transcript.json`, `events.json`, `result.json`, and a final `.done` marker under
|
Each completed case writes `output.wav`, `wav_transcript.json`, `events.json`, `result.json`, and a final `.done` marker under
|
||||||
`--omniinteract-output-dir`. The root also contains `batch_summary.json` and `official_eval_manifest.jsonl`; failed cases write
|
`--omniinteract-output-dir`. The root also contains `batch_summary.json` and `official_eval_manifest.jsonl`; failed cases write
|
||||||
`.failed.json`. Runs sharing one output root are serialized. Completion validates transport, response lifecycle, and artifacts,
|
`.failed.json`. Runs sharing one output root are serialized. Completion validates transport, response lifecycle, and artifacts,
|
||||||
not answer accuracy. Transcript timestamps are serialized playback-queue times. Playback ACKs report cumulative progress
|
not answer accuracy. Transcript timestamps are serialized playback-queue times. Clipped or cancelled outputs are ineligible and
|
||||||
incrementally along that serialized clock, like a live listener; the first ack for a response goes out as soon as its audio
|
omitted from the official manifest; `audio_clipped_bytes` records output beyond the rounded video horizon.
|
||||||
arrives, checkpointing the response's history position so a later committed user input updates it in place. A residual
|
|
||||||
`playback_ack_too_late` rejection is recorded as an artifact warning rather than failing the case. Clipped or cancelled
|
|
||||||
outputs are ineligible and omitted from the official manifest; `audio_clipped_bytes` records output beyond the rounded video
|
|
||||||
horizon.
|
|
||||||
|
|
||||||
TTFT, TTFP, and RTF start at client receipt of `response.created`. TPOT/ITL use engine stage-0 timing; ITL is emitted only when
|
TTFT, TTFP, and RTF start at client receipt of `response.created`. TPOT/ITL use engine stage-0 timing; ITL is emitted only when
|
||||||
every token interval is present.
|
every token interval is present.
|
||||||
|
|
||||||
The checked-in local performance configuration measures four deterministic cases from each OmniInteract subset (12 videos
|
|
||||||
total), with no benchmark warmups and a maximum concurrency of two. Each subset also sends one readiness request before its
|
|
||||||
measured cases. Run it from the repository root with:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export HF_HOME=/path/to/persistent/huggingface-cache
|
|
||||||
export BENCHMARK_DIR=tests/dfx/perf/results
|
|
||||||
bash tools/nightly/run_nightly_jobs.sh \
|
|
||||||
--test-type local \
|
|
||||||
--model-type omni \
|
|
||||||
--label-substr minicpmo_4_5_omniinteract
|
|
||||||
```
|
|
||||||
|
|
||||||
The first run downloads the pinned OmniInteract archive into `HF_HOME`; later runs reuse that cache.
|
|
||||||
|
|
||||||
It requires every case to commit its input, complete any emitted response lifecycles, and publish the expected WAV,
|
|
||||||
transcript, event, and result artifacts without errors. A valid LISTEN-only case may have no response audio or transcript
|
|
||||||
chunks. Official-manifest eligibility is reported separately because clipped or cancelled output is a benchmark-quality
|
|
||||||
signal, not a transport failure. This local performance test does not score answer accuracy.
|
|
||||||
|
|
||||||
### Multi-Modal Benchmark
|
### Multi-Modal Benchmark
|
||||||
|
|
||||||
<details class="admonition abstract" markdown="1">
|
<details class="admonition abstract" markdown="1">
|
||||||
@@ -363,7 +331,6 @@ vllm serve Qwen/Qwen2.5-Omni-7B --omni
|
|||||||
It is recommended to use the flag `--ignore-eos` to simulate real responses. You can set the size of the output via the arg `random-output-len`.
|
It is recommended to use the flag `--ignore-eos` to simulate real responses. You can set the size of the output via the arg `random-output-len`.
|
||||||
|
|
||||||
Then run the benchmarking script:
|
Then run the benchmarking script:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
vllm bench serve \
|
vllm bench serve \
|
||||||
--omni \
|
--omni \
|
||||||
@@ -433,79 +400,8 @@ How sampling works:
|
|||||||
- If a modality (e.g., image) reaches its limit from `--random-mm-limit-mm-per-prompt`, all buckets of that modality are excluded and the remaining bucket probabilities are renormalized before continuing.
|
- If a modality (e.g., image) reaches its limit from `--random-mm-limit-mm-per-prompt`, all buckets of that modality are excluded and the remaining bucket probabilities are renormalized before continuing.
|
||||||
This should be seen as an edge case, and if this behavior can be avoided by setting `--random-mm-limit-mm-per-prompt` to a large number. Note that this might result in errors due to engine config `--limit-mm-per-prompt`.
|
This should be seen as an edge case, and if this behavior can be avoided by setting `--random-mm-limit-mm-per-prompt` to a large number. Note that this might result in errors due to engine config `--limit-mm-per-prompt`.
|
||||||
- The resulting request contains synthetic image data in `multi_modal_data` (OpenAI Chat format). When `random-mm` is used with the OpenAI Chat backend, prompts remain text and MM content is attached via `multi_modal_data`.
|
- The resulting request contains synthetic image data in `multi_modal_data` (OpenAI Chat format). When `random-mm` is used with the OpenAI Chat backend, prompts remain text and MM content is attached via `multi_modal_data`.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Image / video generation
|
|
||||||
|
|
||||||
For `/v1/images/generations`, `/v1/images/edits`, and `/v1/videos`, set `--endpoint` to that path and omit `--backend`. The endpoint path is registered as the bench request adapter, so a separate named backend is not required.
|
|
||||||
|
|
||||||
Example (`/v1/images/generations`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
vllm bench serve --omni \
|
|
||||||
--endpoint /v1/images/generations \
|
|
||||||
--dataset-name random \
|
|
||||||
--model ~/models/Qwen/Qwen-Image \
|
|
||||||
--tokenizer ~/models/Qwen/Qwen-Image/tokenizer \
|
|
||||||
--max-concurrency 1 \
|
|
||||||
--num-warmups 2 \
|
|
||||||
--num-prompts 10 \
|
|
||||||
--random-input-len 64 \
|
|
||||||
--random-output-len 1 \
|
|
||||||
--ignore-eos \
|
|
||||||
--percentile-metrics e2el \
|
|
||||||
--extra-body '{
|
|
||||||
"num_inference_steps": 20,
|
|
||||||
"seed": 42,
|
|
||||||
"true_cfg_scale": 4.0
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
If successful, following output is like:
|
|
||||||
|
|
||||||
```text
|
|
||||||
============ Serving Benchmark Result ============
|
|
||||||
Successful requests: 3
|
|
||||||
Failed requests: 0
|
|
||||||
Maximum request concurrency: 1
|
|
||||||
Benchmark duration (s): 8.42
|
|
||||||
Request throughput (req/s): 0.36
|
|
||||||
Peak concurrent requests: 2.00
|
|
||||||
-------------------Peak Memory--------------------
|
|
||||||
Mean PEAK_MEMORY_MB (MB): 58832.00
|
|
||||||
Median PEAK_MEMORY_MB (MB): 58832.00
|
|
||||||
P99 PEAK_MEMORY_MB (MB): 58832.00
|
|
||||||
----------------End-to-end Latency----------------
|
|
||||||
Mean E2EL (ms): 2798.16
|
|
||||||
Median E2EL (ms): 2799.83
|
|
||||||
P99 E2EL (ms): 2800.03
|
|
||||||
================== Image Result ==================
|
|
||||||
Total images generated: 3
|
|
||||||
Image throughput (img/s): 0.36
|
|
||||||
Average pixels per image: 1048576.00
|
|
||||||
Mean denoise step latency (ms): 136.59
|
|
||||||
---------------- Image Generation ----------------
|
|
||||||
Mean IMAGE_GENERATION (ms): 2731.84
|
|
||||||
Median IMAGE_GENERATION (ms): 2732.02
|
|
||||||
P99 IMAGE_GENERATION (ms): 2734.65
|
|
||||||
==================================================
|
|
||||||
```
|
|
||||||
|
|
||||||
Use the same pattern with `--endpoint /v1/images/edits` or `--endpoint /v1/videos` (and model-specific `--extra-body` as needed). Pure image/video runs omit the Text Result section when there is no generated text.
|
|
||||||
|
|
||||||
`/v1/images/edits` defaults to **non-streaming JSON** (`stream=false`) so single-stage edit models are not rejected by the server. For multi-stage pipelines that need SSE (AR TTFT / image chunks), pass `"stream": true` in `--extra-body`.
|
|
||||||
|
|
||||||
`/v1/videos` is an async job API: the client creates a job, then polls until `completed`/`failed`. Measured **e2el** therefore includes client poll sleep and any overshoot after the job actually finishes. Tune polling via `--extra-body`:
|
|
||||||
|
|
||||||
- `poll_interval_s` (default `2.0`): sleep between status polls
|
|
||||||
- `poll_timeout_s` (default `21600`, i.e. 6 hours): give up waiting for the job
|
|
||||||
|
|
||||||
**VIDEO_RTF** prefers server-reported generation time when available:
|
|
||||||
|
|
||||||
- `video_rtf = video_generation_time_ms / 1000 / video_duration`, where `video_generation_time_ms` comes from response `stage_durations` (or `inference_time_s` as fallback)
|
|
||||||
- If generation time is missing, falls back to `e2el / video_duration` (this fallback *does* include poll overhead)
|
|
||||||
|
|
||||||
### Multi-Stage Benchmark
|
### Multi-Stage Benchmark
|
||||||
|
|
||||||
<details class="admonition abstract" markdown="1">
|
<details class="admonition abstract" markdown="1">
|
||||||
@@ -518,7 +414,6 @@ vllm serve --omni --port 29999 --model ~/Qwen3-Omni-30B-A3B-Instruct
|
|||||||
```
|
```
|
||||||
|
|
||||||
Then run the benchmarking script (remember to add the flag `--print-stage`):
|
Then run the benchmarking script (remember to add the flag `--print-stage`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
vllm bench serve --omni \
|
vllm bench serve --omni \
|
||||||
--dataset-name random \
|
--dataset-name random \
|
||||||
@@ -538,7 +433,6 @@ vllm bench serve --omni \
|
|||||||
```
|
```
|
||||||
|
|
||||||
Besides the "Serving Benchmark Result", there will be "Stage Benchmark Result" below:
|
Besides the "Serving Benchmark Result", there will be "Stage Benchmark Result" below:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
============= Stage Benchmark Result =============
|
============= Stage Benchmark Result =============
|
||||||
=============== Stage 0 (thinker) ================
|
=============== Stage 0 (thinker) ================
|
||||||
@@ -595,9 +489,7 @@ Mean AUDIO_RTF: 0.24
|
|||||||
Median AUDIO_RTF: 0.26
|
Median AUDIO_RTF: 0.26
|
||||||
P99 AUDIO_RTF: 0.27
|
P99 AUDIO_RTF: 0.27
|
||||||
```
|
```
|
||||||
|
|
||||||
Explanation:
|
Explanation:
|
||||||
|
|
||||||
- stage_gen_time: Time from submitting a request to a specific stage to that stage finishing generation.
|
- stage_gen_time: Time from submitting a request to a specific stage to that stage finishing generation.
|
||||||
|
|
||||||
- Serving TTFC (Time to First Chunk): Time from the HTTP request being accepted by the serving frontend to
|
- Serving TTFC (Time to First Chunk): Time from the HTTP request being accepted by the serving frontend to
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
This section lists the most common options for running vLLM-Omni.
|
This section lists the most common options for running vLLM-Omni.
|
||||||
|
|
||||||
For options within a vLLM Engine, please refer to the [vLLM 0.29 configuration guide](https://docs.vllm.ai/en/v0.29.0/configuration/index.html).
|
For options within a vLLM Engine, please refer to the [vLLM 0.28 configuration guide](https://docs.vllm.ai/en/v0.28.0/configuration/index.html).
|
||||||
|
|
||||||
Each model defines fixed topology in a registered `PipelineConfig` and runtime
|
Each model defines fixed topology in a registered `PipelineConfig` and runtime
|
||||||
overrides in a deploy YAML.
|
overrides in a deploy YAML.
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ their keys only.
|
|||||||
## Inherited vLLM variables
|
## Inherited vLLM variables
|
||||||
|
|
||||||
vLLM-Omni also reads variables through its aligned vLLM dependency. Refer to
|
vLLM-Omni also reads variables through its aligned vLLM dependency. Refer to
|
||||||
the [vLLM 0.29 environment-variable reference](https://docs.vllm.ai/en/v0.29.0/configuration/env_vars.html)
|
the [vLLM 0.28 environment-variable reference](https://docs.vllm.ai/en/v0.28.0/configuration/env_vars.html)
|
||||||
for their definitions. This includes vLLM launch, cache, logging, plugin, ROCm,
|
for their definitions. This includes vLLM launch, cache, logging, plugin, ROCm,
|
||||||
XPU, ModelScope, and FlashInfer workspace settings.
|
XPU, ModelScope, and FlashInfer workspace settings.
|
||||||
|
|
||||||
|
|||||||
@@ -262,28 +262,6 @@ or serving, explain the required L2/L3 environment and provide the exact command
|
|||||||
|
|
||||||
Repository skills guide the agent, but they do not replace contributor judgment, the accepted issue or RFC, required test evidence, or maintainer review. Review all generated changes before submitting them.
|
Repository skills guide the agent, but they do not replace contributor judgment, the accepted issue or RFC, required test evidence, or maintainer review. Review all generated changes before submitting them.
|
||||||
|
|
||||||
## AI Usage Policy
|
|
||||||
|
|
||||||
AI tools are welcome in vLLM-Omni contributions. Contributors, including maintainers, remain responsible for everything they submit. These requirements apply to pull requests, issues, discussions, and review comments:
|
|
||||||
|
|
||||||
- **Disclose AI assistance.** Name the tools used and describe their role in the submission, including assistance with code, tests, documentation, or writing.
|
|
||||||
- **Understand your changes.** Review every generated change and be able to explain its behavior, design choices, and interaction with vLLM-Omni without relying on AI to answer for you.
|
|
||||||
- **Validate before submitting.** Run relevant checks and report actual results. For model, kernel, or performance changes, include the hardware, model, configuration, and commands needed to reproduce accuracy or benchmark evidence. Clearly identify checks you could not run; generated claims are not test results.
|
|
||||||
- **Keep communication useful.** Verify technical claims, search for existing reports, and edit AI-assisted text for accuracy and brevity. Submit only content you have personally reviewed, and take responsibility for responding to review feedback.
|
|
||||||
- **Label generated media.** Model-generated images, video, and audio are valid examples or test artifacts for this multimodal project. Identify them as generated output and provide the model, inputs, and reproduction settings. Do not present them as ground-truth references or independent evidence of correctness.
|
|
||||||
|
|
||||||
For example, a PR description could include:
|
|
||||||
|
|
||||||
```text
|
|
||||||
AI assistance: Used Codex to draft the regression test and PR description.
|
|
||||||
I reviewed the changes and verified the test reproduces the reported failure.
|
|
||||||
Validation: <commands, results, hardware, and any checks not run>.
|
|
||||||
```
|
|
||||||
|
|
||||||
Maintainer review time is limited. Contributions that are unverified, misleading, or beyond the author's understanding may be closed. Repeated violations may lead to contribution restrictions. New contributors are welcome to ask for help and submit small, well-understood changes.
|
|
||||||
|
|
||||||
This policy is adapted from [Ghostty's AI Usage Policy](https://github.com/ghostty-org/ghostty/blob/main/AI_POLICY.md) for vLLM-Omni's contribution and multimodal validation workflows. The [coding-agent workflow](#using-repository-skills-with-coding-agents) provides practical guidance for applying it.
|
|
||||||
|
|
||||||
## Issues
|
## Issues
|
||||||
|
|
||||||
If you encounter a bug or have a feature request, please search existing issues first to see if it has already been reported. If not, please file a new issue, providing as much relevant information as possible.
|
If you encounter a bug or have a feature request, please search existing issues first to see if it has already been reported. If not, please file a new issue, providing as much relevant information as possible.
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ Canonical layout (prefer these paths for new changes):
|
|||||||
|
|
||||||
=== "NPU"
|
=== "NPU"
|
||||||
|
|
||||||
**Bootstrap:** [`npu/pipeline-npu.yml`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/npu/pipeline-npu.yml) + [`npu/bootstrap-upload-steps.yml`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/npu/bootstrap-upload-steps.yml)—same split as CUDA; builds A2/B3, A3, A5, and 310P CI images, then uploads child test pipelines.
|
**Bootstrap:** [`npu/pipeline-npu.yml`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/npu/pipeline-npu.yml) + [`npu/bootstrap-upload-steps.yml`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/npu/bootstrap-upload-steps.yml)—same split as CUDA; builds A2/B3 and A3 CI images, then uploads child test pipelines.
|
||||||
|
|
||||||
**Test YAML:** `npu/test-npu-ready.yml` (L2), `test-npu-nightly.yml` (L4).
|
**Test YAML:** `npu/test-npu-ready.yml` (L2), `test-npu-nightly.yml` (L4).
|
||||||
|
|
||||||
@@ -137,12 +137,7 @@ Canonical layout (prefer these paths for new changes):
|
|||||||
|
|
||||||
**Upload:** same as CUDA—`upload_pipeline.py --upload`.
|
**Upload:** same as CUDA—`upload_pipeline.py --upload`.
|
||||||
|
|
||||||
**Hardware in YAML:** `mirror_hardwares` preset (string), expanded to `agents`, top-level `image`, and `plugins`. NPU presets in `common/ci_mirror_hardwares.yml` are:
|
**Hardware in YAML:** `mirror_hardwares` preset (string), expanded to `agents`, top-level `image`, and `plugins`. Presets: `a2b3_npu_1`, `a2b3_npu_4`, `a3_npu_2` in `common/ci_mirror_hardwares.yml`.
|
||||||
|
|
||||||
- A2: `a2b3_npu_1`, `a2b3_npu_4`, `a2b3_npu_8`
|
|
||||||
- A3: `a3_npu_2`, `a3_npu_4`, `a3_npu_8`, `a3_npu_16`
|
|
||||||
- A5: `a5_npu_2`, `a5_npu_4`, `a5_npu_8`, `a5_npu_16`
|
|
||||||
- 310P: `310p_npu_1`, `310p_npu_2`, `310p_npu_4`
|
|
||||||
|
|
||||||
**Conventions**
|
**Conventions**
|
||||||
|
|
||||||
@@ -166,9 +161,7 @@ Canonical layout (prefer these paths for new changes):
|
|||||||
|
|
||||||
**Bootstrap:** [`amd/scripts/bootstrap-amd-omni.sh`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/amd/scripts/bootstrap-amd-omni.sh)—skip-ci, diff filtering, Jinja render, then `buildkite-agent pipeline upload`.
|
**Bootstrap:** [`amd/scripts/bootstrap-amd-omni.sh`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/amd/scripts/bootstrap-amd-omni.sh)—skip-ci, diff filtering, Jinja render, then `buildkite-agent pipeline upload`.
|
||||||
|
|
||||||
**Test YAML (data):** `amd/test-amd-ready.yml` (L2 / `ready`), `test-amd-merge.yml` (L3 / `merge-test` and `main`). On a PR carrying both labels, AMD combines both suites behind one image build. PR builds without either tier label retain the legacy L2 fallback for compatibility with the `amd-test` trigger. `DEBUG_TEST_YAML` remains an explicit override. AMD has no L4 file yet, so `nightly-test` does not select an additional suite.
|
**Test YAML (data):** `amd/test-amd-ready.yml` (L2 / PR), `test-amd-merge.yml` (L3 / main).
|
||||||
|
|
||||||
**Trigger boundary:** AMD label handling has two layers. First, the external `vllm-omni-amd-ci` Buildkite pipeline condition decides whether a GitHub label event creates a build. Only after that build starts does this repository's bootstrap inspect all current PR labels and select L2, L3, or both. Repository-side selection therefore cannot make a `merge-test` event start AMD CI by itself. The external condition must admit both `ready` and `merge-test`, while preserving the legacy `amd-test` trigger and non-PR `main` / scheduled builds. For PR builds without a `DEBUG_TEST_YAML` override, an unreadable label set fails the bootstrap instead of silently selecting the wrong tier. Debug overrides skip label lookup and are validated directly; invalid values, including whitespace-only values, fail the bootstrap. Keep `nightly-test` out of the AMD condition until an AMD L4 suite exists; otherwise it would start a build without providing nightly coverage.
|
|
||||||
|
|
||||||
**Rendering:** [`test-template-amd-omni.j2`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/amd/test-template-amd-omni.j2) wraps data steps with `amd-build` image build and `amd_<agent_pool>` queues. Do **not** hand-edit generated `pipeline.yaml`.
|
**Rendering:** [`test-template-amd-omni.j2`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/amd/test-template-amd-omni.j2) wraps data steps with `amd-build` image build and `amd_<agent_pool>` queues. Do **not** hand-edit generated `pipeline.yaml`.
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,6 @@ Defined in `pyproject.toml`:
|
|||||||
| `MI325` | Tests that require MI325 GPU (AMD/ROCm) * |
|
| `MI325` | Tests that require MI325 GPU (AMD/ROCm) * |
|
||||||
| `A2` | Tests that require A2 NPU * |
|
| `A2` | Tests that require A2 NPU * |
|
||||||
| `A3` | Tests that require A3 NPU * |
|
| `A3` | Tests that require A3 NPU * |
|
||||||
| `A5` | Tests that require A5 NPU * |
|
|
||||||
| `310P` | Tests that require 310P NPU * |
|
|
||||||
| `cards_{n}` | Tests that require *n* accelerator cards (`cards_1` … `cards_8`); auto-added from `num_cards` * |
|
| `cards_{n}` | Tests that require *n* accelerator cards (`cards_1` … `cards_8`); auto-added from `num_cards` * |
|
||||||
| `slow` | Slow tests (may skip in quick CI) |
|
| `slow` | Slow tests (may skip in quick CI) |
|
||||||
| `benchmark` | Benchmark tests (decorator on runner test functions; perf JSON uses `full_model` + type marker instead) |
|
| `benchmark` | Benchmark tests (decorator on runner test functions; perf JSON uses `full_model` + type marker instead) |
|
||||||
@@ -78,7 +76,7 @@ def test_video_to_audio()
|
|||||||
This decorator is intended to make hardware-aware, cross-platform test authoring easier and more robust for CI/CD environments. The `hardware_test` decorator in `vllm-omni/tests/helpers/mark.py` performs the following actions:
|
This decorator is intended to make hardware-aware, cross-platform test authoring easier and more robust for CI/CD environments. The `hardware_test` decorator in `vllm-omni/tests/helpers/mark.py` performs the following actions:
|
||||||
|
|
||||||
1. **Applies platform and resource markers**
|
1. **Applies platform and resource markers**
|
||||||
Adds the appropriate pytest markers for each specified hardware platform (e.g., `cuda`, `rocm`, `xpu`, `npu`) and resource type (e.g., `L4`, `H100`, `H200`, `B200`, `MI325`, `B60`, `A2`, `A3`, `A5`, `310P`).
|
Adds the appropriate pytest markers for each specified hardware platform (e.g., `cuda`, `rocm`, `xpu`, `npu`) and resource type (e.g., `L4`, `H100`, `H200`, `B200`, `MI325`, `B60`, `A2`, `A3`).
|
||||||
```python
|
```python
|
||||||
@pytest.mark.cuda
|
@pytest.mark.cuda
|
||||||
@pytest.mark.L4
|
@pytest.mark.L4
|
||||||
|
|||||||
@@ -779,31 +779,6 @@ turning them on. For Qwen-Image-style serving examples, document
|
|||||||
`--step-execution` as the feature gate and `--max-num-seqs N` as the
|
`--step-execution` as the feature gate and `--max-num-seqs N` as the
|
||||||
companion batching knob.
|
companion batching knob.
|
||||||
|
|
||||||
### Streaming Output and Mid-Stream Interactions
|
|
||||||
|
|
||||||
To add streaming generation with optional mid-stream prompt updates to a new diffusion pipeline (often a video generation pipeline):
|
|
||||||
|
|
||||||
0. **Model should internally support** chunked video emission and bounded VAE decode of a chunk.
|
|
||||||
1. **Implement stepwise execution** so interaction RPCs can be consumed at chunk
|
|
||||||
boundaries (see [Step Execution](#step-execution) above).
|
|
||||||
2. **Mix in** ``InteractionMixin`` on the pipeline class.
|
|
||||||
3. **Implement** ``peek_chunk_media(StepRequestState) -> ChunkMediaSpec`` to offer information
|
|
||||||
about the next chunk to generate.
|
|
||||||
This is called whenever one supported interaction modality needs frame-level calculation,
|
|
||||||
e.g., per-frame camera trajectory. If only chunk-level calculation is involved, peeking is skipped.
|
|
||||||
4. **Optionally implement** ``prepare_next_chunk(StepRequestState)`` if the
|
|
||||||
pipeline must rebuild something (e.g., per-chunk state) after an interaction is applied.
|
|
||||||
This function is called at chunk boundary.
|
|
||||||
5. **Register** supported modalities and handlers in ``vllm_omni/diffusion/interaction/registry.py``
|
|
||||||
(keyed by ``od_config.model_class_name`` → modality key as in ``req["multi_modal_data"]``).
|
|
||||||
|
|
||||||
Serve with ``--diffusion-streaming-output`` (auto-enables step execution). See
|
|
||||||
[Diffusion Execution Modes](../../user_guide/diffusion/execution_modes.md#streaming-output)
|
|
||||||
and the example script at `examples/online_serving/streaming_video_generation/`.
|
|
||||||
|
|
||||||
**Interaction payload contract:** Although ``OmniInteractionPrompt`` type annocation requires ``event_id``,
|
|
||||||
the WebSocket API payload may omit ``event_id`` and let the API layer assigns one.
|
|
||||||
|
|
||||||
### Cache Acceleration
|
### Cache Acceleration
|
||||||
|
|
||||||
#### TeaCache
|
#### TeaCache
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ Each stage is implemented as a separate model class that can be configured indep
|
|||||||
|
|
||||||
When adding a new model, you'll need to create the following structure:
|
When adding a new model, you'll need to create the following structure:
|
||||||
|
|
||||||
```text
|
```
|
||||||
vllm_omni/model_executor/models/
|
vllm_omni/model_executor/models/
|
||||||
└── your_model_name/ # Model directory (e.g., qwen3_omni)
|
└── your_model_name/ # Model directory (e.g., qwen3_omni)
|
||||||
├── __init__.py # Exports main model class
|
├── __init__.py # Exports main model class
|
||||||
@@ -222,16 +222,6 @@ __all__ = ["Qwen3OmniMoeForConditionalGeneration"]
|
|||||||
|
|
||||||
## Key Components
|
## Key Components
|
||||||
|
|
||||||
### Preprocess phase metadata
|
|
||||||
|
|
||||||
Models with `has_preprocess=True`, including out-of-tree plugins, can rely on
|
|
||||||
the runner's stable `_omni_is_prefill`, `_omni_prompt_len`, and
|
|
||||||
`_omni_num_computed_tokens` fields. Use request progress to distinguish prompt
|
|
||||||
prefill from decode: a one-token span can still be a prefill tail. See the
|
|
||||||
[runner-to-model phase contract](../../design/feature/preprocess_phase_contract.md)
|
|
||||||
for types, batched-hook semantics, MTP routing guarantees, and the correctness
|
|
||||||
workaround for vLLM-Omni 0.20.x and earlier.
|
|
||||||
|
|
||||||
### 1. Model Interfaces
|
### 1. Model Interfaces
|
||||||
|
|
||||||
Your model should implement the appropriate interfaces:
|
Your model should implement the appropriate interfaces:
|
||||||
@@ -432,25 +422,22 @@ The stage transition process follows these steps:
|
|||||||
Understanding the data structures is crucial for implementing stage transitions:
|
Understanding the data structures is crucial for implementing stage transitions:
|
||||||
|
|
||||||
**Input to your function:**
|
**Input to your function:**
|
||||||
|
|
||||||
- `stage_list[source_stage_id].engine_outputs`: List of `EngineCoreOutput` objects
|
- `stage_list[source_stage_id].engine_outputs`: List of `EngineCoreOutput` objects
|
||||||
- Each contains `outputs`: List of `RequestOutput` objects
|
- - Each contains `outputs`: List of `RequestOutput` objects
|
||||||
- Each `RequestOutput` has:
|
- Each `RequestOutput` has:
|
||||||
- `token_ids`: Generated token IDs
|
- - - `token_ids`: Generated token IDs
|
||||||
- `multimodal_output`: Dict with keys like `"code_predictor_codes"`, etc. These are the hidden states or intermediate outputs from the model's forward pass
|
- `multimodal_output`: Dict with keys like `"code_predictor_codes"`, etc.These are the hidden states or intermediate outputs from the model's forward pass
|
||||||
- `prompt_token_ids`: Original prompt token IDs
|
- `prompt_token_ids`: Original prompt token IDs
|
||||||
|
|
||||||
**Output from your function:**
|
**Output from your function:**
|
||||||
|
|
||||||
- Must return `list[OmniTokensPrompt]` where each `OmniTokensPrompt` contains:
|
- Must return `list[OmniTokensPrompt]` where each `OmniTokensPrompt` contains:
|
||||||
- `prompt_token_ids`: List[int] - Token IDs for the next stage
|
- - `prompt_token_ids`: List[int] - Token IDs for the next stage
|
||||||
- `additional_information`: Dict[str, Any] - Optional metadata (e.g., embeddings, hidden states)
|
- `additional_information`: Dict[str, Any] - Optional metadata (e.g., embeddings, hidden states)
|
||||||
- `multi_modal_data`: Optional multimodal data if needed
|
- `multi_modal_data`: Optional multimodal data if needed
|
||||||
|
|
||||||
### How Model Outputs Are Stored
|
### How Model Outputs Are Stored
|
||||||
|
|
||||||
The model's `forward()` method returns an `OmniOutput` object that contains:
|
The model's `forward()` method returns an `OmniOutput` object that contains:
|
||||||
|
|
||||||
- `text_hidden_states`: Final hidden states for text generation
|
- `text_hidden_states`: Final hidden states for text generation
|
||||||
- `multimodal_outputs`: Dict containing intermediate outputs
|
- `multimodal_outputs`: Dict containing intermediate outputs
|
||||||
|
|
||||||
@@ -477,7 +464,6 @@ def forward(self, ...):
|
|||||||
```
|
```
|
||||||
|
|
||||||
These keys are then accessible in your stage transition function:
|
These keys are then accessible in your stage transition function:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# In stage_input_processors/qwen3_omni.py
|
# In stage_input_processors/qwen3_omni.py
|
||||||
thinker_prefill_embeddings = output.multimodal_output["0"] # Access by key
|
thinker_prefill_embeddings = output.multimodal_output["0"] # Access by key
|
||||||
@@ -507,7 +493,7 @@ thinker_hidden_states = output.multimodal_output["24"]
|
|||||||
Create stage transition processors in `vllm_omni/model_executor/stage_input_processors/your_model_name.py`. Each inter-stage edge should provide a **coherent processor set** rather than a single monolithic function:
|
Create stage transition processors in `vllm_omni/model_executor/stage_input_processors/your_model_name.py`. Each inter-stage edge should provide a **coherent processor set** rather than a single monolithic function:
|
||||||
|
|
||||||
| Suffix | Role | Runs when |
|
| Suffix | Role | Runs when |
|
||||||
| -------- | ------ | ----------- |
|
|--------|------|-----------|
|
||||||
| `*_full_payload` | Worker-side payload producer | `async_chunk=false`; accumulates tensors and ships via connector |
|
| `*_full_payload` | Worker-side payload producer | `async_chunk=false`; accumulates tensors and ships via connector |
|
||||||
| `*_async_chunk` | Scheduler-side streaming producer | `async_chunk=true`; emits per-chunk payloads |
|
| `*_async_chunk` | Scheduler-side streaming producer | `async_chunk=true`; emits per-chunk payloads |
|
||||||
| `*_token_only` | Orchestrator placeholder builder | `async_chunk=false`; allocates downstream prompt slots only |
|
| `*_token_only` | Orchestrator placeholder builder | `async_chunk=false`; allocates downstream prompt slots only |
|
||||||
@@ -568,16 +554,7 @@ For comprehensive testing guidelines, please refer to the [Test Writing Guide](.
|
|||||||
|
|
||||||
## Adding a Model Recipe
|
## Adding a Model Recipe
|
||||||
|
|
||||||
After implementing and testing your model, add a recipe under this repository's
|
After implementing and testing your model, please add a model recipe to the [vllm-project/recipes](https://github.com/vllm-project/recipes) repository. This helps other users understand how to use your model with vLLM-Omni.
|
||||||
`recipes/` directory. Follow the
|
|
||||||
[`add-recipe` skill](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/add-recipe/SKILL.md)
|
|
||||||
and [`recipes/TEMPLATE.md`](https://github.com/vllm-project/vllm-omni/blob/main/recipes/TEMPLATE.md),
|
|
||||||
then update the model row in
|
|
||||||
[`recipes/README.md`](https://github.com/vllm-project/vllm-omni/blob/main/recipes/README.md).
|
|
||||||
The external
|
|
||||||
[vllm-project/recipes](https://github.com/vllm-project/recipes) repository can
|
|
||||||
be used as a structural reference, but it is not the destination for a
|
|
||||||
vLLM-Omni model recipe.
|
|
||||||
|
|
||||||
### What to Include
|
### What to Include
|
||||||
|
|
||||||
@@ -591,10 +568,15 @@ Your recipe should include:
|
|||||||
3. **Usage Examples**: Command-line examples demonstrating how to run the model
|
3. **Usage Examples**: Command-line examples demonstrating how to run the model
|
||||||
4. **Configuration Details**: Important configuration parameters and their meanings
|
4. **Configuration Details**: Important configuration parameters and their meanings
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
For reference, see the [LongCat recipe example](https://github.com/vllm-project/recipes/pull/179) which demonstrates the expected format and structure.
|
||||||
|
|
||||||
### Recipe Location
|
### Recipe Location
|
||||||
|
|
||||||
Create `recipes/<vendor>/<model-family>.md` and keep commands, feature status,
|
Create your recipe file in the appropriate directory structure:
|
||||||
hardware evidence, and limitations specific to the model family.
|
- For organization-specific models: `OrganizationName/ModelName.md`
|
||||||
|
- For general models: `ModelName.md`
|
||||||
|
|
||||||
The recipe should be a Markdown file that provides clear, reproducible instructions for users to get started with your model.
|
The recipe should be a Markdown file that provides clear, reproducible instructions for users to get started with your model.
|
||||||
|
|
||||||
@@ -608,7 +590,7 @@ Adding a new model to vLLM-Omni involves:
|
|||||||
4. **Define pipeline topology and deploy defaults** in `pipeline.py` and `vllm_omni/deploy/`
|
4. **Define pipeline topology and deploy defaults** in `pipeline.py` and `vllm_omni/deploy/`
|
||||||
5. **Implement stage input processors** for stage transitions
|
5. **Implement stage input processors** for stage transitions
|
||||||
6. **Write tests** to verify functionality
|
6. **Write tests** to verify functionality
|
||||||
7. **Add an in-repository model recipe** under `recipes/` and update its index (see [Adding a Model Recipe](#adding-a-model-recipe))
|
7. **Add model recipe** to the [vllm-project/recipes](https://github.com/vllm-project/recipes) repository (see [Adding a Model Recipe](#adding-a-model-recipe) section)
|
||||||
|
|
||||||
### Qwen3-Omni Reference Files
|
### Qwen3-Omni Reference Files
|
||||||
|
|
||||||
@@ -625,7 +607,6 @@ For a complete reference implementation, see:
|
|||||||
- **Testing**: `vllm_omni/tests/e2e/offline_inference/test_qwen3_omni.py`
|
- **Testing**: `vllm_omni/tests/e2e/offline_inference/test_qwen3_omni.py`
|
||||||
|
|
||||||
For more information, see:
|
For more information, see:
|
||||||
|
|
||||||
- [Architecture Overview](../../design/architecture_overview.md)
|
- [Architecture Overview](../../design/architecture_overview.md)
|
||||||
- [Supported Models](../../models/supported_models.md)
|
- [Supported Models](../../models/supported_models.md)
|
||||||
- [Pipeline and Deploy Configuration Guide](../../configuration/stage_configs.md)
|
- [Pipeline and Deploy Configuration Guide](../../configuration/stage_configs.md)
|
||||||
@@ -991,13 +991,10 @@ git push origin your-branch --force-with-lease
|
|||||||
|
|
||||||
## Adding a Model Recipe
|
## Adding a Model Recipe
|
||||||
|
|
||||||
After implementing and testing your model, add a recipe under this repository's
|
After implementing and testing your model, add a model recipe to the
|
||||||
`recipes/` directory. Follow the
|
[vllm-project/recipes](https://github.com/vllm-project/recipes) repository so users can
|
||||||
[`add-recipe` skill](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/add-recipe/SKILL.md)
|
get started quickly. See [Adding an Omni-Modality Model](./adding_omni_model.md#adding-a-model-recipe)
|
||||||
and [`recipes/TEMPLATE.md`](https://github.com/vllm-project/vllm-omni/blob/main/recipes/TEMPLATE.md),
|
for the expected format.
|
||||||
update the model row in
|
|
||||||
[`recipes/README.md`](https://github.com/vllm-project/vllm-omni/blob/main/recipes/README.md),
|
|
||||||
and synchronize the relevant TTS example and speech API documentation.
|
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
@@ -1014,7 +1011,7 @@ Adding a TTS model to vLLM-Omni involves:
|
|||||||
8. **Online serving** - add all 5 integration points to `serving_speech.py` in one commit
|
8. **Online serving** - add all 5 integration points to `serving_speech.py` in one commit
|
||||||
9. **Tests** - cover single request, batching, and streaming
|
9. **Tests** - cover single request, batching, and streaming
|
||||||
10. **Pre-commit + DCO** - run `pre-commit` before pushing; sign every commit with `git commit -s`
|
10. **Pre-commit + DCO** - run `pre-commit` before pushing; sign every commit with `git commit -s`
|
||||||
11. **Model recipe** - add under the in-repository `recipes/` directory and update its index
|
11. **Model recipe** - add to [vllm-project/recipes](https://github.com/vllm-project/recipes)
|
||||||
12. **Invariants** - re-check I1–I5 (streaming contract, consumer hygiene, hot-loop discipline, validation pyramid, per-request state) at the end of every phase
|
12. **Invariants** - re-check I1–I5 (streaming contract, consumer hygiene, hot-loop discipline, validation pyramid, per-request state) at the end of every phase
|
||||||
|
|
||||||
### Qwen3-TTS Reference Files
|
### Qwen3-TTS Reference Files
|
||||||
|
|||||||
@@ -22,15 +22,11 @@ A pipeline opts in by implementing `SupportsARDiffusionPipeline`. Its immutable
|
|||||||
- named fixed-length cross-attention KV, model-specific scratch geometry, and
|
- named fixed-length cross-attention KV, model-specific scratch geometry, and
|
||||||
the pipeline's requested session-capacity upper bound.
|
the pipeline's requested session-capacity upper bound.
|
||||||
|
|
||||||
The runner binds an `ARDiffusionKVState` only around one runner invocation
|
The runner binds an `ARDiffusionKVState` only around one `forward()` call. The
|
||||||
(`execute_model` or `execute_stepwise`). The pipeline may use it during that
|
pipeline may use it during that context but must not retain it. The session
|
||||||
context but must not retain it. Scratch and committed pages stay on the
|
survives subsequent requests with the same `session_id`. Request reset, explicit
|
||||||
runner-owned session object, so unbinding does not drop an in-flight stepwise
|
close, LRU eviction, and forward exceptions all release runner-owned KV and call
|
||||||
chunk. Tick-mode sessions survive subsequent requests with the same
|
the pipeline's reset/close lifecycle hook. Cross-attention KV is allocated lazily
|
||||||
`session_id`. On the stepwise path the session id is the request id and is
|
|
||||||
released when that request finishes or fails. Request reset, explicit close,
|
|
||||||
LRU eviction, and forward exceptions all release runner-owned KV and call the
|
|
||||||
pipeline's reset/close lifecycle hook. Cross-attention KV is allocated lazily
|
|
||||||
per session and logical KV branch, and is released on the same path. A pipeline
|
per session and logical KV branch, and is released on the same path. A pipeline
|
||||||
publishes one named cache transactionally by yielding exactly one `(k, v)` pair
|
publishes one named cache transactionally by yielding exactly one `(k, v)` pair
|
||||||
per layer:
|
per layer:
|
||||||
@@ -52,12 +48,11 @@ successful forward. The runner also exposes `reset_session()` and
|
|||||||
|
|
||||||
## Current execution limits
|
## Current execution limits
|
||||||
|
|
||||||
The experimental runner supports `max_num_seqs=1`. Request-batch execution is
|
The experimental runner supports request-mode execution with
|
||||||
still rejected. Step execution is allowed only when the loaded pipeline
|
`max_num_seqs=1`. It rejects step execution and request-batch execution at load
|
||||||
implements `SupportsStepExecution`; other AR-Diffusion pipelines still fail at
|
time, and its inherited batch/step entry points also fail explicitly. Supporting
|
||||||
load if `step_execution=True`. Capable pipelines bind KV around each
|
those paths requires a batch-aware state-binding contract rather than silently
|
||||||
`execute_stepwise` invocation instead of inheriting the generic runner entry
|
bypassing `bind_ar_diffusion_state()`.
|
||||||
point unwrapped.
|
|
||||||
|
|
||||||
The implementation may retain multiple sessions per model instance. It selects
|
The implementation may retain multiple sessions per model instance. It selects
|
||||||
the largest feasible capacity up to the pipeline's `session_capacity`, based on
|
the largest feasible capacity up to the pipeline's `session_capacity`, based on
|
||||||
|
|||||||
@@ -323,24 +323,18 @@ inputs, fields, and ownership rules are described below.
|
|||||||
```mermaid
|
```mermaid
|
||||||
flowchart TB
|
flowchart TB
|
||||||
layer1["Layer 1 · Authoring inputs<br/>PipelineConfig + DeployConfig"]
|
layer1["Layer 1 · Authoring inputs<br/>PipelineConfig + DeployConfig"]
|
||||||
layer2["Layer 2 · Production resolution boundary<br/>resolve_omni_config()<br/>(StageConfigFactory + VllmOmniConfig internally)"]
|
layer2["Layer 2 · Resolve once<br/>StageConfigFactory.create_from_model()<br/>VllmOmniConfig.from_pipeline_config()"]
|
||||||
layer3["Layer 3 · Startup hand-off<br/>OmniConfigResolution<br/>PipelineConfig + temporary OmegaConf stage bridge"]
|
layer3["Layer 3 · Transport-safe control plane<br/>VllmOmniConfig"]
|
||||||
layer4["Layer 4 · Runtime launch planning<br/>StageRuntime"]
|
layer4["Layer 4 · Runtime launch planning<br/>StageRuntime"]
|
||||||
layer5["Layer 5 · Engine materialization<br/>VllmConfig / OmniDiffusionConfig"]
|
layer5["Layer 5 · Engine materialization<br/>VllmConfig / OmniDiffusionConfig"]
|
||||||
|
|
||||||
layer1 --> layer2 --> layer3 --> layer4 --> layer5
|
layer1 --> layer2 --> layer3 --> layer4 --> layer5
|
||||||
```
|
```
|
||||||
|
|
||||||
The production resolution boundary is `resolve_omni_config()` in
|
The single resolution boundary is implemented by
|
||||||
|
`StageConfigFactory.create_from_model()` and
|
||||||
|
`VllmOmniConfig.from_pipeline_config()` in
|
||||||
[`vllm_omni/config`](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/config).
|
[`vllm_omni/config`](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/config).
|
||||||
It delegates typed construction to `StageConfigFactory.create_from_model()` and
|
|
||||||
`VllmOmniConfig.from_pipeline_config()`, then returns an
|
|
||||||
`OmniConfigResolution` consumed by both `AsyncOmniEngine` and headless startup.
|
|
||||||
Until `StageRuntime` consumes typed stage configs directly, this envelope carries
|
|
||||||
the effective `PipelineConfig` alongside OmegaConf-compatible `stage_configs` as
|
|
||||||
a temporary runtime bridge; both views describe the same resolved topology,
|
|
||||||
including injected stages.
|
|
||||||
|
|
||||||
The legacy `stage_args` YAML path has been removed. Model topology now resolves
|
The legacy `stage_args` YAML path has been removed. Model topology now resolves
|
||||||
through `PipelineConfig`, with runtime overrides supplied by `DeployConfig`.
|
through `PipelineConfig`, with runtime overrides supplied by `DeployConfig`.
|
||||||
|
|
||||||
@@ -360,12 +354,9 @@ The important ownership rules are:
|
|||||||
deploy-time defaults; it does not redefine the model graph.
|
deploy-time defaults; it does not redefine the model graph.
|
||||||
3. CLI and Python overrides are applied at the resolution boundary, with
|
3. CLI and Python overrides are applied at the resolution boundary, with
|
||||||
per-stage overrides taking precedence over global values where supported.
|
per-stage overrides taking precedence over global values where supported.
|
||||||
4. `OmniConfigResolution` is the sole startup hand-off. Its `pipeline_config`
|
4. `StageRuntime` owns launch planning and replica lifecycle. `ReplicaInitPlan`
|
||||||
and temporary `stage_configs` compatibility view must describe the same
|
|
||||||
topology.
|
|
||||||
5. `StageRuntime` owns launch planning and replica lifecycle. `ReplicaInitPlan`
|
|
||||||
is runtime-private state, not a user configuration object.
|
is runtime-private state, not a user configuration object.
|
||||||
6. `VllmConfig` and the enriched `OmniDiffusionConfig` are materialized in the
|
5. `VllmConfig` and the enriched `OmniDiffusionConfig` are materialized in the
|
||||||
process that owns the corresponding engine.
|
process that owns the corresponding engine.
|
||||||
|
|
||||||
## Main features
|
## Main features
|
||||||
@@ -427,7 +418,7 @@ The public interfaces map onto the same engine and stage boundaries:
|
|||||||
flowchart LR
|
flowchart LR
|
||||||
offline["Offline Python<br/>Omni.generate()"] --> engine["AsyncOmniEngine"]
|
offline["Offline Python<br/>Omni.generate()"] --> engine["AsyncOmniEngine"]
|
||||||
online["OpenAI-compatible serving<br/>vllm serve ... --omni"] --> engine
|
online["OpenAI-compatible serving<br/>vllm serve ... --omni"] --> engine
|
||||||
duplex["Duplex WebSocket<br/>/v1/realtime?duplex=1 or /v1/duplex"] --> engine
|
duplex["Experimental duplex WebSocket<br/>/v1/duplex or realtime duplex"] --> engine
|
||||||
engine --> stages["Configured AR and diffusion stages"]
|
engine --> stages["Configured AR and diffusion stages"]
|
||||||
stages --> result["Streaming or final multimodal output"]
|
stages --> result["Streaming or final multimodal output"]
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -150,17 +150,8 @@ that do not belong in the shared contract should be stored in `state.extra`.
|
|||||||
Queueing and lifecycle metadata remain in the scheduler's request state.
|
Queueing and lifecycle metadata remain in the scheduler's request state.
|
||||||
|
|
||||||
Current native pipelines that explicitly enable step execution include
|
Current native pipelines that explicitly enable step execution include
|
||||||
Qwen-Image, BAGEL, HunyuanImage3, and Helios. Step execution alone does not
|
Qwen-Image, HunyuanImage3, and Helios. Step execution alone does not imply
|
||||||
imply continuous-batching support: Qwen-Image accepts batched step states.
|
continuous-batching support: Qwen-Image accepts batched step states.
|
||||||
BAGEL accepts batched step states for image generation with its default,
|
|
||||||
think-mode, and single-stage deploy configs. Only the diffusion stage uses the
|
|
||||||
step protocol in two-stage deployments; explicit single-stage text output
|
|
||||||
retains complete-request execution. BAGEL requires at least two inference steps
|
|
||||||
because it schedules `num_inference_steps - 1` denoising updates, and its step
|
|
||||||
path does not currently support sequence parallelism or a diffusion cache
|
|
||||||
backend. When a finished stepwise request is followed by an explicit text
|
|
||||||
fallback wave, the runner retires its step state and paged diffusion-KV rows
|
|
||||||
before the full forward dispatch.
|
|
||||||
HunyuanImage3 accepts batched step states only when its resolved self-attention
|
HunyuanImage3 accepts batched step states only when its resolved self-attention
|
||||||
backend is `TORCH_SDPA`; otherwise it rejects groups larger than one request.
|
backend is `TORCH_SDPA`; otherwise it rejects groups larger than one request.
|
||||||
Configure `DIFFUSION_ATTENTION_BACKEND=TORCH_SDPA` or
|
Configure `DIFFUSION_ATTENTION_BACKEND=TORCH_SDPA` or
|
||||||
|
|||||||
@@ -5,27 +5,23 @@ The three strategies have separate user and design pages:
|
|||||||
|
|
||||||
| Strategy | User guide | Design contract |
|
| Strategy | User guide | Design contract |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Model-level | [Guide](../../../user_guide/diffusion/offloader/module_offload.md) | [Design](module_offload.md) |
|
| Model-level | [Guide](../../../user_guide/diffusion/offloader/cpu_offload.md) | [Design](cpu_offload.md) |
|
||||||
| Layerwise | [Guide](../../../user_guide/diffusion/offloader/layerwise_offload.md) | [Design](layerwise_offload.md) |
|
| Layerwise | [Guide](../../../user_guide/diffusion/offloader/layerwise_offload.md) | [Design](layerwise_offload.md) |
|
||||||
| Distributed layerwise | [Guide](../../../user_guide/diffusion/offloader/distributed_layerwise_offload.md) | [Design](distributed_layerwise_offload.md) |
|
| Distributed layerwise | [Guide](../../../user_guide/diffusion/offloader/distributed_layerwise_offload.md) | [Design](distributed_layerwise_offload.md) |
|
||||||
|
|
||||||
## Strategy selection
|
## Strategy selection
|
||||||
|
|
||||||
`OffloadConfig.from_od_config()` converts diffusion configuration into one
|
`OffloadConfig.from_od_config()` converts diffusion configuration into one
|
||||||
`OffloadStrategy`. The public config separates component selection from
|
`OffloadStrategy`. If callers set multiple flags, selection is deterministic:
|
||||||
policy:
|
|
||||||
|
|
||||||
- `mode="module"` selects model-level offload;
|
1. `DISTRIBUTED_LAYERWISE`;
|
||||||
- `mode="layer"` with rank-local transfers selects ordinary layerwise
|
2. `LAYERWISE`;
|
||||||
offload; and
|
3. `MODEL_LEVEL`; and
|
||||||
- AllGather transfer or resident layers selects the distributed layerwise
|
4. `NONE`.
|
||||||
backend that implements those capabilities.
|
|
||||||
|
|
||||||
The compatibility boolean flags retain their historical priority (distributed
|
The factory logs when a higher-priority strategy disables another. It derives
|
||||||
layerwise, layerwise, then model-level). A compact config rejects a conflicting
|
parallel and HSDP state from `DiffusionParallelConfig`; callers do not provide
|
||||||
legacy strategy or non-default legacy DLO tuning. The factory derives parallel
|
a separate offload group size.
|
||||||
and HSDP state from `DiffusionParallelConfig`; callers do not provide a
|
|
||||||
separate offload group size.
|
|
||||||
|
|
||||||
`get_offload_backend()` then validates platform offload support, resolves the
|
`get_offload_backend()` then validates platform offload support, resolves the
|
||||||
device, and creates exactly one backend. Returning `None` means offloading is
|
device, and creates exactly one backend. Returning `None` means offloading is
|
||||||
@@ -43,21 +39,11 @@ Every backend implements `OffloadBackend`:
|
|||||||
`disable()` does not promise to restore the pipeline's original device
|
`disable()` does not promise to restore the pipeline's original device
|
||||||
placement. The caller owns any subsequent rematerialization.
|
placement. The caller owns any subsequent rematerialization.
|
||||||
|
|
||||||
An enable failure must remove every partially installed hook. Rank-local
|
|
||||||
backends restore ordinary tensors so the pipeline can be retried. A failed
|
|
||||||
multi-rank AllGather startup must not enter unmatched recovery collectives;
|
|
||||||
that worker is safely discarded after local resource cleanup.
|
|
||||||
|
|
||||||
Hooks are registered through `HookRegistry` and `ModelHook`; offload backends
|
Hooks are registered through `HookRegistry` and `ModelHook`; offload backends
|
||||||
must use distinct hook names and remove only hooks they own.
|
must use distinct hook names and remove only hooks they own.
|
||||||
|
|
||||||
## Discovery and topology
|
## Discovery and topology
|
||||||
|
|
||||||
`resolve_offload_plan(pipeline, config)` is the single topology entry point.
|
|
||||||
Every backend calls it once when `enable()` starts and then consumes the
|
|
||||||
resolved components, block stacks, resident heads, and staged-residency flags
|
|
||||||
it returns. Backends do not re-read model declarations.
|
|
||||||
|
|
||||||
Pipeline component discovery prefers `SupportsComponentDiscovery` declarations:
|
Pipeline component discovery prefers `SupportsComponentDiscovery` declarations:
|
||||||
|
|
||||||
- `_dit_modules`;
|
- `_dit_modules`;
|
||||||
@@ -66,26 +52,16 @@ Pipeline component discovery prefers `SupportsComponentDiscovery` declarations:
|
|||||||
- `_resident_modules`.
|
- `_resident_modules`.
|
||||||
|
|
||||||
Dotted paths are supported. Legacy pipelines may use the fallback scan of
|
Dotted paths are supported. Legacy pipelines may use the fallback scan of
|
||||||
well-known attribute names; it now warns once per pipeline class, and new
|
well-known attribute names, but new integrations should declare components
|
||||||
integrations must declare components explicitly.
|
explicitly.
|
||||||
|
|
||||||
Block topology comes from the pipeline `OffloadPlan` first: `block_attrs` maps
|
Ordinary layerwise offload obtains topology from declared
|
||||||
each DiT path to its ordered block containers, `encoder_block_attrs` declares
|
`_layerwise_offload_blocks_attrs` (with a deprecated singular-name
|
||||||
streamable encoder stacks, `on_demand_component_paths` marks pipeline-managed
|
compatibility path). Distributed layerwise offload may instead use a pipeline
|
||||||
residency, `resident_dit_paths` marks the DiTs that may hold resident layers,
|
`OffloadPlan`, then falls back to declared block attributes and its documented
|
||||||
and `encoder_dlo_weight_replication` marks the encoders whose loader-produced
|
compatibility discovery. Discovery metadata describes structure only; the
|
||||||
weights are safe for AllGather. DiTs absent from the plan fall back to
|
backend remains responsible for transfer, synchronization, and storage
|
||||||
`_layerwise_offload_blocks_attrs` (including the deprecated singular-name
|
ownership.
|
||||||
compatibility path).
|
|
||||||
|
|
||||||
The resolver is pure: it moves no tensor, installs no hook, writes no module
|
|
||||||
attribute, and reads no process group — multi-rank facts come from
|
|
||||||
`OffloadConfig`. It owns topology validation, so a configuration the model
|
|
||||||
cannot serve fails before the first component is placed. Explicit component
|
|
||||||
selection turns every declaration problem into an error, while the
|
|
||||||
compatibility topology (no component selector) keeps the historical
|
|
||||||
warn-and-skip behavior. Metadata still describes structure only; the backend
|
|
||||||
remains responsible for transfer, synchronization, and storage ownership.
|
|
||||||
|
|
||||||
## Cross-strategy invariants
|
## Cross-strategy invariants
|
||||||
|
|
||||||
|
|||||||
+4
-11
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Model-level offload enforces mutual exclusion between pipeline component
|
Model-level offload enforces mutual exclusion between pipeline component
|
||||||
groups. For commands and model support, see the
|
groups. For commands and model support, see the
|
||||||
[model-level user guide](../../../user_guide/diffusion/offloader/module_offload.md).
|
[model-level user guide](../../../user_guide/diffusion/offloader/cpu_offload.md).
|
||||||
|
|
||||||
## Generic hook path
|
## Generic hook path
|
||||||
|
|
||||||
@@ -10,15 +10,10 @@ groups. For commands and model support, see the
|
|||||||
makes encoders and VAEs device resident for initialization, then installs
|
makes encoders and VAEs device resident for initialization, then installs
|
||||||
`SequentialOffloadHook` instances:
|
`SequentialOffloadHook` instances:
|
||||||
|
|
||||||
- each DiT hook offloads selected encoders and other selected DiTs before
|
- each DiT hook offloads all encoders and other DiTs before loading itself;
|
||||||
loading itself;
|
- each encoder hook offloads every DiT before loading itself; and
|
||||||
- each encoder hook offloads selected DiTs before loading itself; and
|
|
||||||
- VAEs are not part of the mutual-exclusion hook set.
|
- VAEs are not part of the mutual-exclusion hook set.
|
||||||
|
|
||||||
All execution-stage modules still receive a hook so an unselected resident
|
|
||||||
stage can evict a selected component before it runs. Only components listed in
|
|
||||||
`diffusion_offload_config.components` are eligible to move to CPU.
|
|
||||||
|
|
||||||
The hook moves parameters and buffers without recursively calling
|
The hook moves parameters and buffers without recursively calling
|
||||||
`module.to()`. This avoids recursion through modules that retain references to
|
`module.to()`. This avoids recursion through modules that retain references to
|
||||||
other transformer blocks. Host tensors are pinned when configured; DTensors
|
other transformer blocks. Host tensors are pinned when configured; DTensors
|
||||||
@@ -41,9 +36,7 @@ contract:
|
|||||||
|
|
||||||
- only the executing component is device resident;
|
- only the executing component is device resident;
|
||||||
- enable and disable are idempotent;
|
- enable and disable are idempotent;
|
||||||
- transfers use the supplied device, pinning, and HSDP settings;
|
- transfers use the supplied device, pinning, and HSDP settings; and
|
||||||
- explicit component selection is either honored or rejected before partial
|
|
||||||
setup; and
|
|
||||||
- disabling removes all model-local offload hooks or contexts.
|
- disabling removes all model-local offload hooks or contexts.
|
||||||
|
|
||||||
The delegation is currently duck typed. If another independent implementation
|
The delegation is currently duck typed. If another independent implementation
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
# Distributed Layerwise Offload
|
# Distributed Layerwise Offload
|
||||||
|
|
||||||
This document describes distributed layerwise offload (DLO) for diffusion
|
This document describes distributed layerwise offload (DLO) for diffusion
|
||||||
models. DLO keeps only a small number of selected DiT or text-encoder blocks
|
models. DLO keeps only a small number of DiT blocks on the accelerator and
|
||||||
on the accelerator and streams the remaining blocks from host memory. The
|
streams the remaining blocks from host memory. The distributed backend can
|
||||||
distributed backend can either shard those host-side weights across an
|
either shard those host-side weights across an existing parallel group or keep
|
||||||
existing parallel group or keep complete rank-local block sources and avoid
|
complete rank-local block sources and avoid an additional collective.
|
||||||
an additional collective.
|
|
||||||
|
|
||||||
For user-facing commands, see the
|
For user-facing commands, see the
|
||||||
[distributed layerwise offloading guide](../../../user_guide/diffusion/offloader/distributed_layerwise_offload.md)
|
[distributed layerwise offloading guide](../../../user_guide/diffusion/offloader/distributed_layerwise_offload.md)
|
||||||
@@ -39,11 +38,10 @@ detailed contracts and validation boundaries.
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
DLO is implemented for multi-device diffusion execution. The default public
|
DLO is implemented for multi-device diffusion execution. The default
|
||||||
transfer is `rank-local`; setting a selected component's
|
AllGather path is the primary path for DP and SP deployments. The
|
||||||
`layer_options.NAME.weight_transfer` to `allgather` enables weight sharding across a
|
`--dlo-no-use-allgather` path streams complete blocks independently and adds no
|
||||||
compatible DP or SP group. Transfers are configured independently for `dit`
|
DLO weight collective.
|
||||||
and `text_encoder`.
|
|
||||||
|
|
||||||
Host storage is selected separately from the transfer protocol. The loader can
|
Host storage is selected separately from the transfer protocol. The loader can
|
||||||
produce a direct-checkpoint mmap plan for a proven-compatible runtime layout;
|
produce a direct-checkpoint mmap plan for a proven-compatible runtime layout;
|
||||||
@@ -111,7 +109,7 @@ checkpoint adapter beside the ordinary loader.
|
|||||||
|
|
||||||
### AllGather path
|
### AllGather path
|
||||||
|
|
||||||
For a component configured with `weight_transfer="allgather"`, each rank stores approximately
|
With the default `dlo_use_allgather=True`, each rank stores approximately
|
||||||
`1 / group_size` of each streamable block in pinned host memory. The next
|
`1 / group_size` of each streamable block in pinned host memory. The next
|
||||||
block's shard is copied to a device buffer and reconstructed with
|
block's shard is copied to a device buffer and reconstructed with
|
||||||
`all_gather_into_tensor` on a communication stream while the current block is
|
`all_gather_into_tensor` on a communication stream while the current block is
|
||||||
@@ -134,8 +132,9 @@ source used to prepare each rank's persistent shard. They can be closed after
|
|||||||
shard preparation. Across the AllGather group, those private shards total
|
shard preparation. Across the AllGather group, those private shards total
|
||||||
approximately one runtime model copy.
|
approximately one runtime model copy.
|
||||||
|
|
||||||
An effective DLO group size of one performs no collective; it follows the
|
An effective DLO group size of one performs no collective, even when
|
||||||
rank-local transfer path described below.
|
`dlo_use_allgather=True`; it follows the rank-local transfer path described
|
||||||
|
below.
|
||||||
|
|
||||||
When DP is greater than one, the engine can process one request per DP rank in
|
When DP is greater than one, the engine can process one request per DP rank in
|
||||||
the same denoising wave. Because AllGather is a collective, all participating
|
the same denoising wave. Because AllGather is a collective, all participating
|
||||||
@@ -143,10 +142,9 @@ requests must take the same execution path at every denoising step.
|
|||||||
|
|
||||||
### Rank-local path without DLO AllGather
|
### Rank-local path without DLO AllGather
|
||||||
|
|
||||||
With `weight_transfer="rank-local"`, DLO forces the affected component's internal
|
With `--dlo-no-use-allgather`, DLO forces its internal offload shard size to
|
||||||
offload shard size to one and streams complete blocks using H2D copies only.
|
one and streams complete blocks using H2D copies only. The host backing may be
|
||||||
The host backing may be either a loader-approved checkpoint mapping or
|
either a loader-approved checkpoint mapping or ordinary runtime tensors.
|
||||||
ordinary runtime tensors.
|
|
||||||
|
|
||||||
For direct mmap, each process retains immutable safetensors views and uses two
|
For direct mmap, each process retains immutable safetensors views and uses two
|
||||||
bounded pinned host staging slots. Processes on the same node that map the same
|
bounded pinned host staging slots. Processes on the same node that map the same
|
||||||
@@ -206,7 +204,7 @@ adopt it.
|
|||||||
> optimizations without changing AllGather behavior.
|
> optimizations without changing AllGather behavior.
|
||||||
|
|
||||||
Final-layout Host Weight Runtime (HWR) backing is opt-in and currently applies
|
Final-layout Host Weight Runtime (HWR) backing is opt-in and currently applies
|
||||||
only to a selected rank-local DiT. Enable it with
|
only to no-AllGather DLO. Enable it with
|
||||||
`--host-weight-runtime-mode preferred` (or `required`) and
|
`--host-weight-runtime-mode preferred` (or `required`) and
|
||||||
`--host-weight-runtime-root <node-local-root>`.
|
`--host-weight-runtime-root <node-local-root>`.
|
||||||
|
|
||||||
@@ -424,8 +422,8 @@ failure.
|
|||||||
collective. When the model declares the final-layout contract, HWR keys the
|
collective. When the model declares the final-layout contract, HWR keys the
|
||||||
reusable artifact by TP rank/size and SP layout.
|
reusable artifact by TP rank/size and SP layout.
|
||||||
- **HSDP + SP:** the general parallel configuration permits HSDP over SP, but
|
- **HSDP + SP:** the general parallel configuration permits HSDP over SP, but
|
||||||
each selected component must use `weight_transfer="rank-local"`. HSDP remains
|
DLO must use `--dlo-no-use-allgather`. HSDP remains responsible for weight
|
||||||
responsible for weight materialization and synchronization.
|
materialization and synchronization.
|
||||||
- **HSDP + DP or TP:** rejected independently by the diffusion parallel
|
- **HSDP + DP or TP:** rejected independently by the diffusion parallel
|
||||||
configuration.
|
configuration.
|
||||||
|
|
||||||
@@ -449,9 +447,8 @@ recorded layouts (they all keep plain 1-byte dtypes over ordinary strided
|
|||||||
views: online INT8 has an int8 weight plus fp32 scale, online MXFP8 has an
|
views: online INT8 has an int8 weight plus fp32 scale, online MXFP8 has an
|
||||||
fp8 weight plus e8m0 block scale, each with a contiguous or transposed-view
|
fp8 weight plus e8m0 block scale, each with a contiguous or transposed-view
|
||||||
finalized tensor, all covered by the same physical-order packing as online
|
finalized tensor, all covered by the same physical-order packing as online
|
||||||
FP8). Other online methods must set
|
FP8). Other online methods must use `--dlo-no-use-allgather` or disable
|
||||||
`layer_options.dit.weight_transfer="rank-local"` or disable online quantization
|
online quantization until their runtime layouts are validated.
|
||||||
until their runtime layouts are validated.
|
|
||||||
|
|
||||||
The Host Weight Runtime representation, publication, and no-AllGather consumer
|
The Host Weight Runtime representation, publication, and no-AllGather consumer
|
||||||
contracts are merged; see
|
contracts are merged; see
|
||||||
|
|||||||
@@ -36,14 +36,12 @@ dependencies, not incidental global synchronization, define correctness.
|
|||||||
## Topology contract
|
## Topology contract
|
||||||
|
|
||||||
A DiT declares ordered block-container attributes using
|
A DiT declares ordered block-container attributes using
|
||||||
`_layerwise_offload_blocks_attrs` or an `OffloadPlan`. A text encoder declares
|
`_layerwise_offload_blocks_attrs` or an `OffloadPlan`. Each resolved item must
|
||||||
its block-list paths through `OffloadPlan.encoder_block_attrs`. Each resolved
|
be an executable `nn.Module`; ordering must match forward execution. Multiple
|
||||||
item must be an executable `nn.Module`; ordering must match forward execution.
|
containers are concatenated in execution order.
|
||||||
Multiple containers are streamed as separate hook rings.
|
|
||||||
|
|
||||||
Non-block state of a selected DiT or text encoder remains device resident.
|
Non-block DiT modules, encoders, VAEs, and declared resident modules are not
|
||||||
Unselected components, VAEs, and declared resident modules are not streamed by
|
streamed by this backend.
|
||||||
this backend.
|
|
||||||
|
|
||||||
## Invariants and limitations
|
## Invariants and limitations
|
||||||
|
|
||||||
@@ -52,8 +50,7 @@ this backend.
|
|||||||
- Blocks with heterogeneous shapes and dtypes use their recorded metadata;
|
- Blocks with heterogeneous shapes and dtypes use their recorded metadata;
|
||||||
implementations must not assume identical blocks.
|
implementations must not assume identical blocks.
|
||||||
- The ring is initialized before the first forward so block zero is available.
|
- The ring is initialized before the first forward so block zero is available.
|
||||||
- This backend uses rank-local host weights. Multi-device compute may remain
|
- This backend is single-device; distributed weight reconstruction belongs to
|
||||||
active, but cross-rank weight reconstruction belongs to
|
|
||||||
[Distributed Layerwise Offload](distributed_layerwise_offload.md).
|
[Distributed Layerwise Offload](distributed_layerwise_offload.md).
|
||||||
|
|
||||||
Shared selection and lifecycle behavior is defined in the
|
Shared selection and lifecycle behavior is defined in the
|
||||||
|
|||||||
@@ -1,172 +0,0 @@
|
|||||||
# Runner-to-model prefill/decode phase contract
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Autoregressive models with a custom `preprocess` hook need to distinguish
|
|
||||||
prompt processing from decoding. A one-token span can be either a complete
|
|
||||||
one-token prompt, the last chunk of a longer prompt, or a decode step. Using
|
|
||||||
span length as the phase signal can replace a prompt embedding with a generated
|
|
||||||
audio embedding and advance teacher-forced text too early without an exception.
|
|
||||||
|
|
||||||
[Issue #4382](https://github.com/vllm-project/vllm-omni/issues/4382) requests a
|
|
||||||
stable contract for the metadata and routing guards introduced by
|
|
||||||
[PR #3662](https://github.com/vllm-project/vllm-omni/pull/3662).
|
|
||||||
The shared runner already implements those guards. This design documents the
|
|
||||||
existing interface and adds runner-level regression coverage rather than
|
|
||||||
introducing a second phase detector or changing scheduling policy.
|
|
||||||
|
|
||||||
## Scope and objectives
|
|
||||||
|
|
||||||
- Make the three existing phase keys safe to depend on in out-of-tree models.
|
|
||||||
- Preserve prompt embeddings and model state on a one-token prefill tail.
|
|
||||||
- Keep normal and batched decode routing consistent in mixed batches.
|
|
||||||
- Explain the correctness workaround required on older releases.
|
|
||||||
|
|
||||||
This contract does not enable chunked prefill for models whose other state
|
|
||||||
handling does not support it. It does not change the scheduler, introduce new
|
|
||||||
kwargs, or standardize other `_omni_*` fields. The implementation adds
|
|
||||||
documentation and regression coverage; no hot-path allocation is added.
|
|
||||||
|
|
||||||
## Design
|
|
||||||
|
|
||||||
### Ownership and data flow
|
|
||||||
|
|
||||||
```text
|
|
||||||
Scheduler / current input batch
|
|
||||||
prompt_token_ids + num_computed_tokens_cpu (before this step)
|
|
||||||
|
|
|
||||||
OmniGPUModelRunner._preprocess
|
|
||||||
|
|
|
||||||
per-request phase metadata
|
|
||||||
/ \
|
|
||||||
prefill / other spans single-token decode
|
|
||||||
preprocess preprocess or preprocess_decode_batch
|
|
||||||
| |
|
|
||||||
prompt embedding runner-managed talker_mtp
|
|
||||||
\ /
|
|
||||||
model forward
|
|
||||||
```
|
|
||||||
|
|
||||||
The producer is `OmniGPUModelRunner._preprocess` in
|
|
||||||
`vllm_omni/worker/gpu_model_runner.py`. `GPUARModelRunner` and
|
|
||||||
`GPUGenerationModelRunner` inherit it. The current `OmniNPUModelRunner` also
|
|
||||||
inherits this method; device-specific execution still needs its own hardware
|
|
||||||
validation. A plugin runner that overrides preprocessing is responsible for
|
|
||||||
preserving this interface.
|
|
||||||
|
|
||||||
### Stable model-facing fields
|
|
||||||
|
|
||||||
The following names, types, and meanings are a supported interface for in-tree
|
|
||||||
and out-of-tree model hooks despite the leading underscore. Models should treat
|
|
||||||
them as read-only runner-owned values. Changes to their meanings or removal
|
|
||||||
require an explicit compatibility/migration plan.
|
|
||||||
|
|
||||||
| Key | Python type | Meaning |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `_omni_prompt_len` | `int` | Length of the current request state's `prompt_token_ids`. This is the stage's prompt length, not the current chunk size or raw text length. |
|
|
||||||
| `_omni_num_computed_tokens` | `int` | The row's `input_batch.num_computed_tokens_cpu` value **before** processing the scheduled span. It includes already-computed/cached progress, not just tokens computed in the current call. |
|
|
||||||
| `_omni_is_prefill` | `bool` | Exactly `_omni_num_computed_tokens < _omni_prompt_len`. Equality and greater progress mean decode. |
|
|
||||||
|
|
||||||
The runner refreshes the fields after current request state has been gathered,
|
|
||||||
immediately before selecting the per-row hook. Existing values in intermediate
|
|
||||||
model state cannot override the current phase. Row indices follow the current
|
|
||||||
input batch (including any reordering), not request arrival order. A resumed
|
|
||||||
or streaming request is classified from its **current** prompt/progress values;
|
|
||||||
the phase is not latched for the lifetime of the request.
|
|
||||||
|
|
||||||
The normal hook receives these fields as keyword arguments:
|
|
||||||
|
|
||||||
```python
|
|
||||||
def preprocess(self, input_ids, input_embeds, **info):
|
|
||||||
if info["_omni_is_prefill"]:
|
|
||||||
offset = info["_omni_num_computed_tokens"]
|
|
||||||
# Select the scheduled slice of the model's prompt embeddings.
|
|
||||||
...
|
|
||||||
else:
|
|
||||||
# Advance decode-only text/audio state.
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
For `preprocess_decode_batch(input_ids=..., req_infos=...)`, each `req_infos`
|
|
||||||
entry contains the same fields, aligned with its corresponding input row.
|
|
||||||
Every such row has `_omni_is_prefill == False`. The optional earlier
|
|
||||||
`preprocess_batch` hook is a separate whole-batch preparation hook; these freshly
|
|
||||||
computed per-row fields are not promised at that earlier boundary.
|
|
||||||
|
|
||||||
### Routing guarantee
|
|
||||||
|
|
||||||
With `has_preprocess=True`, the batched decode hook is eligible only when it is
|
|
||||||
callable, the runner has `talker_mtp`, the scheduled span is one token, and
|
|
||||||
`_omni_is_prefill` is false. Otherwise the normal `preprocess` hook runs.
|
|
||||||
|
|
||||||
Runner-managed MTP is likewise restricted to single-token decode rows. A prefill
|
|
||||||
row, including a one-token tail, is never added to that MTP batch: the runner
|
|
||||||
does not consume its `mtp_inputs`, generate codes for it, or overwrite its
|
|
||||||
preprocessed embedding with an MTP embedding. Decode rows in the same step
|
|
||||||
continue to receive their MTP outputs at their own token offsets. Models may
|
|
||||||
still implement their own model-specific work inside `preprocess`.
|
|
||||||
|
|
||||||
| Prompt length | Computed before step | Scheduled span | Phase | Runner MTP eligible |
|
|
||||||
| --- | --- | --- | --- | --- |
|
|
||||||
| 5 | 0 | 4 | Prefill | No |
|
|
||||||
| 5 | 4 | 1 | Prefill tail | No |
|
|
||||||
| 5 | 5 | 1 | Decode | Yes |
|
|
||||||
| 5 | 6 | 1 | Decode | Yes |
|
|
||||||
| 1 | 0 | 1 | Prefill | No |
|
|
||||||
| 5 | 5 | 2 | Decode | No (not a single-token span) |
|
|
||||||
|
|
||||||
### Compatibility
|
|
||||||
|
|
||||||
!!! warning "vLLM-Omni 0.20.x and earlier"
|
|
||||||
AR talker models with custom preprocessing that infer phase from span length
|
|
||||||
must use `enable_chunked_prefill: false` for correctness on these releases.
|
|
||||||
They lack the phase metadata and the runner's prefill-tail MTP protection.
|
|
||||||
A model-only heuristic cannot prevent the older runner from overwriting a
|
|
||||||
one-token prompt embedding. Disabling chunking avoids split tails; it does
|
|
||||||
not make span length a reliable phase detector for every possible prompt.
|
|
||||||
|
|
||||||
The mechanism landed in #3662 (v0.21.0rc2 / v0.22.0 and later); this document
|
|
||||||
formalizes that existing behavior. Prefer upgrading the matching vLLM and
|
|
||||||
vLLM-Omni release pair and consuming the explicit phase keys. Do not silently
|
|
||||||
fall back to `input_ids.numel() > 1` when the model requires chunking correctness.
|
|
||||||
For a custom or backported runtime, verify both metadata and MTP guards.
|
|
||||||
|
|
||||||
## Correctness and testing plan
|
|
||||||
|
|
||||||
Runner tests call the production `_preprocess` and `_talker_mtp_forward` methods
|
|
||||||
with CPU buffers and a deterministic MTP model. They inspect kwargs at the model
|
|
||||||
boundary, resulting embeddings, and per-request generated codes. Coverage must
|
|
||||||
include a multi-step prompt split with a one-token tail followed by decode,
|
|
||||||
mixed prefill/decode batches in different orders, normal/batched decode hooks,
|
|
||||||
adjacent decode requests in the same hook call with exact per-request codes,
|
|
||||||
single-token prompts, cached progress, and decode spans longer than one token.
|
|
||||||
No test should pass merely because MTP was disabled for every row.
|
|
||||||
|
|
||||||
Real-weight validation uses Qwen3-TTS CustomVoice through the full talker and
|
|
||||||
code2wav pipeline. Record the actual scheduled prompt progress, assert that at
|
|
||||||
least one one-token prefill tail was observed, check its hook metadata and MTP
|
|
||||||
exclusion, and require finite non-empty output audio. Compare to an unchunked
|
|
||||||
run with the same real input, greedy sampling, and `VLLM_BATCH_INVARIANT=1`.
|
|
||||||
Greedy sampling alone does not guarantee identical codes across different
|
|
||||||
prefill shapes: floating-point reduction differences can change an argmax and
|
|
||||||
diverge in subsequent autoregressive steps. Invariant kernels keep this exact
|
|
||||||
comparison focused on the phase contract. The two engines must be initialized
|
|
||||||
separately because their chunking settings and token budgets differ. GPU tests belong under
|
|
||||||
`tests/e2e/features/`; existing model tests remain useful adjacent regression
|
|
||||||
coverage. Functional audio checks do not establish throughput or all-model
|
|
||||||
semantic parity; this change makes no performance claim.
|
|
||||||
|
|
||||||
## Open questions and discussions
|
|
||||||
|
|
||||||
There are no new field names or execution modes to choose. Future runner
|
|
||||||
implementations, including Model Runner V2, should preserve these semantics or
|
|
||||||
provide an explicit migration path. Hardware validation beyond the tested
|
|
||||||
platform remains separate from the shared Python routing tests.
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
- [Issue #4382](https://github.com/vllm-project/vllm-omni/issues/4382)
|
|
||||||
- [Original metadata and guards, #3662](https://github.com/vllm-project/vllm-omni/pull/3662)
|
|
||||||
- [Qwen2.5-Omni consumer fix, #5019](https://github.com/vllm-project/vllm-omni/pull/5019)
|
|
||||||
- [Adding an Omni model](../../contributing/model/adding_omni_model.md)
|
|
||||||
- [Test writing guide](../../contributing/ci/test_writing_guide.md)
|
|
||||||
@@ -84,8 +84,8 @@ dictionary narrows this global scope through runtime layer-prefix routing.
|
|||||||
|
|
||||||
The factory uses Omni-specific overrides for methods whose diffusion behavior
|
The factory uses Omni-specific overrides for methods whose diffusion behavior
|
||||||
or platform dispatch is not provided by the vLLM registry. The current override
|
or platform dispatch is not provided by the vLLM registry. The current override
|
||||||
set includes INT8, BitsAndBytes, MXFP8, MXFP4, MXFP4 dual-scale, INC/AutoRound,
|
set includes INT8, BitsAndBytes, MXFP8, MXFP4, MXFP4 dual-scale, and INC/
|
||||||
and TorchAO. Other methods, such as FP8, GGUF, and ModelOpt, are resolved through
|
AutoRound. Other methods, such as FP8, GGUF, and ModelOpt, are resolved through
|
||||||
vLLM's registry when their configuration is compatible.
|
vLLM's registry when their configuration is compatible.
|
||||||
|
|
||||||
## Per-component routing
|
## Per-component routing
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="760" height="460" viewBox="0 0 760 460" role="img" aria-labelledby="title desc">
|
|
||||||
<title id="title">MAGI-2 DLO one-step Pareto frontier</title>
|
|
||||||
<desc id="desc">Warm user latency in seconds versus throughput per device. DP1SP4 is 5.735 seconds and 0.0436 outputs per second per device, DP2SP2 is 6.785 and 0.0737, and DP4 is 9.997 and 0.1000.</desc>
|
|
||||||
<rect width="760" height="460" fill="#ffffff"/>
|
|
||||||
<style>
|
|
||||||
text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; fill: #111827; }
|
|
||||||
.title { font-size: 20px; font-weight: 600; }
|
|
||||||
.axis-label { font-size: 14px; font-weight: 500; }
|
|
||||||
.tick { font-size: 12px; fill: #4b5563; }
|
|
||||||
.point-label { font-size: 13px; font-weight: 600; }
|
|
||||||
.value-label { font-size: 11px; fill: #4b5563; }
|
|
||||||
.grid { stroke: #e5e7eb; stroke-width: 1; }
|
|
||||||
.axis { stroke: #6b7280; stroke-width: 1.5; }
|
|
||||||
.frontier { fill: none; stroke: #2563eb; stroke-width: 3; }
|
|
||||||
.point { fill: #2563eb; stroke: #ffffff; stroke-width: 2; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<text x="380" y="28" text-anchor="middle" class="title">One diffusion step</text>
|
|
||||||
|
|
||||||
<g aria-hidden="true">
|
|
||||||
<line x1="85" y1="309" x2="700" y2="309" class="grid"/>
|
|
||||||
<line x1="85" y1="226" x2="700" y2="226" class="grid"/>
|
|
||||||
<line x1="85" y1="143" x2="700" y2="143" class="grid"/>
|
|
||||||
<line x1="85" y1="61" x2="700" y2="61" class="grid"/>
|
|
||||||
<line x1="85" y1="40" x2="85" y2="350" class="axis"/>
|
|
||||||
<line x1="85" y1="350" x2="700" y2="350" class="axis"/>
|
|
||||||
|
|
||||||
<text x="73" y="313" text-anchor="end" class="tick">0.04</text>
|
|
||||||
<text x="73" y="230" text-anchor="end" class="tick">0.06</text>
|
|
||||||
<text x="73" y="147" text-anchor="end" class="tick">0.08</text>
|
|
||||||
<text x="73" y="65" text-anchor="end" class="tick">0.10</text>
|
|
||||||
|
|
||||||
<text x="85" y="370" text-anchor="middle" class="tick">5</text>
|
|
||||||
<text x="197" y="370" text-anchor="middle" class="tick">6</text>
|
|
||||||
<text x="309" y="370" text-anchor="middle" class="tick">7</text>
|
|
||||||
<text x="421" y="370" text-anchor="middle" class="tick">8</text>
|
|
||||||
<text x="532" y="370" text-anchor="middle" class="tick">9</text>
|
|
||||||
<text x="644" y="370" text-anchor="middle" class="tick">10</text>
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<text x="392" y="414" text-anchor="middle" class="axis-label">Warm user latency (seconds) — lower is better</text>
|
|
||||||
<text x="20" y="195" transform="rotate(-90 20 195)" text-anchor="middle" class="axis-label">Throughput/device (outputs/s) — higher is better</text>
|
|
||||||
|
|
||||||
<polyline points="167,294 285,169 644,61" class="frontier"/>
|
|
||||||
|
|
||||||
<circle cx="167" cy="294" r="7" class="point"/>
|
|
||||||
<text x="179" y="288" class="point-label">DP1SP4</text>
|
|
||||||
<text x="179" y="305" class="value-label">5.735 s, 0.0436</text>
|
|
||||||
|
|
||||||
<circle cx="285" cy="169" r="7" class="point"/>
|
|
||||||
<text x="297" y="163" class="point-label">DP2SP2</text>
|
|
||||||
<text x="297" y="180" class="value-label">6.785 s, 0.0737</text>
|
|
||||||
|
|
||||||
<circle cx="644" cy="61" r="7" class="point"/>
|
|
||||||
<text x="632" y="84" text-anchor="end" class="point-label">DP4</text>
|
|
||||||
<text x="632" y="101" text-anchor="end" class="value-label">9.997 s, 0.1000</text>
|
|
||||||
|
|
||||||
<text x="700" y="444" text-anchor="end" class="tick">4x NVIDIA L20X · warm qualification run</text>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,65 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="760" height="460" viewBox="0 0 760 460" role="img" aria-labelledby="title desc">
|
|
||||||
<title id="title">MAGI-2 DLO four-step Pareto frontier</title>
|
|
||||||
<desc id="desc">Warm user latency in seconds versus throughput per device. DP1SP4 is 8.647 seconds and 0.0289 outputs per second per device, DP2SP2 is 11.682 and 0.0428, and DP4 is 20.957 and 0.0477.</desc>
|
|
||||||
<rect width="760" height="460" fill="#ffffff"/>
|
|
||||||
<style>
|
|
||||||
text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; fill: #111827; }
|
|
||||||
.title { font-size: 20px; font-weight: 600; }
|
|
||||||
.axis-label { font-size: 14px; font-weight: 500; }
|
|
||||||
.tick { font-size: 12px; fill: #4b5563; }
|
|
||||||
.point-label { font-size: 13px; font-weight: 600; }
|
|
||||||
.value-label { font-size: 11px; fill: #4b5563; }
|
|
||||||
.grid { stroke: #e5e7eb; stroke-width: 1; }
|
|
||||||
.axis { stroke: #6b7280; stroke-width: 1.5; }
|
|
||||||
.frontier { fill: none; stroke: #2563eb; stroke-width: 3; }
|
|
||||||
.point { fill: #2563eb; stroke: #ffffff; stroke-width: 2; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<text x="380" y="28" text-anchor="middle" class="title">Four diffusion steps</text>
|
|
||||||
|
|
||||||
<g aria-hidden="true">
|
|
||||||
<line x1="85" y1="350" x2="700" y2="350" class="grid"/>
|
|
||||||
<line x1="85" y1="288" x2="700" y2="288" class="grid"/>
|
|
||||||
<line x1="85" y1="226" x2="700" y2="226" class="grid"/>
|
|
||||||
<line x1="85" y1="164" x2="700" y2="164" class="grid"/>
|
|
||||||
<line x1="85" y1="102" x2="700" y2="102" class="grid"/>
|
|
||||||
<line x1="85" y1="40" x2="700" y2="40" class="grid"/>
|
|
||||||
<line x1="85" y1="40" x2="85" y2="350" class="axis"/>
|
|
||||||
<line x1="85" y1="350" x2="700" y2="350" class="axis"/>
|
|
||||||
|
|
||||||
<text x="73" y="354" text-anchor="end" class="tick">0.025</text>
|
|
||||||
<text x="73" y="292" text-anchor="end" class="tick">0.030</text>
|
|
||||||
<text x="73" y="230" text-anchor="end" class="tick">0.035</text>
|
|
||||||
<text x="73" y="168" text-anchor="end" class="tick">0.040</text>
|
|
||||||
<text x="73" y="106" text-anchor="end" class="tick">0.045</text>
|
|
||||||
<text x="73" y="44" text-anchor="end" class="tick">0.050</text>
|
|
||||||
|
|
||||||
<text x="85" y="370" text-anchor="middle" class="tick">8</text>
|
|
||||||
<text x="173" y="370" text-anchor="middle" class="tick">10</text>
|
|
||||||
<text x="261" y="370" text-anchor="middle" class="tick">12</text>
|
|
||||||
<text x="349" y="370" text-anchor="middle" class="tick">14</text>
|
|
||||||
<text x="436" y="370" text-anchor="middle" class="tick">16</text>
|
|
||||||
<text x="524" y="370" text-anchor="middle" class="tick">18</text>
|
|
||||||
<text x="612" y="370" text-anchor="middle" class="tick">20</text>
|
|
||||||
<text x="700" y="370" text-anchor="middle" class="tick">22</text>
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<text x="392" y="414" text-anchor="middle" class="axis-label">Warm user latency (seconds) — lower is better</text>
|
|
||||||
<text x="20" y="195" transform="rotate(-90 20 195)" text-anchor="middle" class="axis-label">Throughput/device (outputs/s) — higher is better</text>
|
|
||||||
|
|
||||||
<polyline points="113,302 247,129 654,69" class="frontier"/>
|
|
||||||
|
|
||||||
<circle cx="113" cy="302" r="7" class="point"/>
|
|
||||||
<text x="125" y="296" class="point-label">DP1SP4</text>
|
|
||||||
<text x="125" y="313" class="value-label">8.647 s, 0.0289</text>
|
|
||||||
|
|
||||||
<circle cx="247" cy="129" r="7" class="point"/>
|
|
||||||
<text x="259" y="123" class="point-label">DP2SP2</text>
|
|
||||||
<text x="259" y="140" class="value-label">11.682 s, 0.0428</text>
|
|
||||||
|
|
||||||
<circle cx="654" cy="69" r="7" class="point"/>
|
|
||||||
<text x="642" y="92" text-anchor="end" class="point-label">DP4</text>
|
|
||||||
<text x="642" y="109" text-anchor="end" class="value-label">20.957 s, 0.0477</text>
|
|
||||||
|
|
||||||
<text x="700" y="444" text-anchor="end" class="tick">4x NVIDIA L20X · warm qualification run</text>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.6 KiB |
@@ -17,14 +17,11 @@ implementation contract; it is not, by itself, a general support claim.
|
|||||||
|
|
||||||
### Runtime and stage execution
|
### Runtime and stage execution
|
||||||
|
|
||||||
- [Full-Duplex Runtime (MiniCPM-o 4.5)](fullduplex.md)
|
|
||||||
- [Full-Duplex Runtime (PersonaPlex)](fullduplex-personaplex.md)
|
|
||||||
- [Disaggregated Inference](feature/disaggregated_inference.md)
|
- [Disaggregated Inference](feature/disaggregated_inference.md)
|
||||||
- [Host Weight Runtime](feature/host_weight_runtime.md)
|
- [Host Weight Runtime](feature/host_weight_runtime.md)
|
||||||
- [Async Chunk](feature/async_chunk.md)
|
- [Async Chunk](feature/async_chunk.md)
|
||||||
- [Async Diffusion Output](feature/async_diffusion_output.md)
|
- [Async Diffusion Output](feature/async_diffusion_output.md)
|
||||||
- [Async Omni Output Materialization](feature/omni_async_output_materialization.md)
|
- [Async Omni Output Materialization](feature/omni_async_output_materialization.md)
|
||||||
- [Runner-to-model Prefill/Decode Phase Contract](feature/preprocess_phase_contract.md)
|
|
||||||
- [Automatic Prefix Caching in Omni Models](feature/prefix_caching.md)
|
- [Automatic Prefix Caching in Omni Models](feature/prefix_caching.md)
|
||||||
- [Realtime AR-Diffusion Sessions](feature/realtime_ar_diffusion.md)
|
- [Realtime AR-Diffusion Sessions](feature/realtime_ar_diffusion.md)
|
||||||
|
|
||||||
@@ -67,7 +64,7 @@ The design contracts separate selection mechanics from backend algorithms:
|
|||||||
#### CPU offloading
|
#### CPU offloading
|
||||||
|
|
||||||
- [Overview and Shared Contracts](feature/offloader/README.md)
|
- [Overview and Shared Contracts](feature/offloader/README.md)
|
||||||
- [Model-Level Offload](feature/offloader/module_offload.md)
|
- [Model-Level Offload](feature/offloader/cpu_offload.md)
|
||||||
- [Layerwise Offload](feature/offloader/layerwise_offload.md)
|
- [Layerwise Offload](feature/offloader/layerwise_offload.md)
|
||||||
- [Distributed Layerwise Offload](feature/offloader/distributed_layerwise_offload.md)
|
- [Distributed Layerwise Offload](feature/offloader/distributed_layerwise_offload.md)
|
||||||
|
|
||||||
|
|||||||
@@ -8,44 +8,22 @@ owners:
|
|||||||
- "@SamitHuang"
|
- "@SamitHuang"
|
||||||
- "@fhfuih"
|
- "@fhfuih"
|
||||||
primary_code_paths:
|
primary_code_paths:
|
||||||
- vllm_omni/diffusion/diffusion_engine.py
|
|
||||||
- vllm_omni/diffusion/request.py
|
|
||||||
- vllm_omni/diffusion/data.py
|
|
||||||
- vllm_omni/diffusion/sched/**
|
- vllm_omni/diffusion/sched/**
|
||||||
- vllm_omni/diffusion/executor/**
|
- vllm_omni/diffusion/executor/**
|
||||||
- vllm_omni/diffusion/worker/**
|
- vllm_omni/diffusion/worker/**
|
||||||
related_code_paths:
|
related_code_paths:
|
||||||
- vllm_omni/diffusion/stage_diffusion_client.py
|
|
||||||
- vllm_omni/diffusion/stage_diffusion_proc.py
|
|
||||||
- vllm_omni/diffusion/inline_stage_diffusion_client.py
|
|
||||||
- vllm_omni/diffusion/ipc.py
|
|
||||||
- vllm_omni/diffusion/hooks/**
|
- vllm_omni/diffusion/hooks/**
|
||||||
- vllm_omni/diffusion/postprocess/**
|
- vllm_omni/diffusion/postprocess/**
|
||||||
depends_on:
|
depends_on:
|
||||||
- ../engine_orchestration.md
|
- ../engine_orchestration.md
|
||||||
- ../stage_runtime.md
|
|
||||||
- ../input_output_modality_contracts.md
|
- ../input_output_modality_contracts.md
|
||||||
- diffusion_model_integration.md
|
- diffusion_model_integration.md
|
||||||
validation_paths:
|
validation_paths:
|
||||||
- tests/diffusion/test_diffusion_engine.py
|
- tests/diffusion/diffusion_backend/**
|
||||||
- tests/diffusion/test_diffusion_engine_cleanup.py
|
- tests/diffusion/hooks/**
|
||||||
- tests/diffusion/test_diffusion_engine_dummy_run.py
|
|
||||||
- tests/diffusion/test_diffusion_engine_rpc_routing.py
|
|
||||||
- tests/diffusion/test_diffusion_scheduler.py
|
|
||||||
- tests/diffusion/test_diffusion_model_runner.py
|
|
||||||
- tests/diffusion/test_diffusion_worker.py
|
|
||||||
- tests/diffusion/test_multiproc_engine_concurrency.py
|
|
||||||
- tests/diffusion/test_uniproc_executor.py
|
|
||||||
- tests/diffusion/test_result_pump.py
|
|
||||||
- tests/diffusion/test_async_output_worker.py
|
|
||||||
- tests/diffusion/test_diffusion_ipc.py
|
|
||||||
- tests/diffusion/test_diffusion_streaming_output.py
|
|
||||||
- tests/diffusion/test_stage_diffusion_proc.py
|
|
||||||
- tests/diffusion/test_inline_stage_diffusion_client.py
|
|
||||||
upstream_refs:
|
upstream_refs:
|
||||||
- diffusers.DiffusionPipeline
|
- diffusers.DiffusionPipeline
|
||||||
last_reviewed: 2026-09-02
|
last_reviewed: 2026-07-16
|
||||||
last_verified_commit: e51fe6ec1b9a9a0e14bb1fdb296d61b6593b93c6
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Diffusion runtime
|
# Diffusion runtime
|
||||||
@@ -53,380 +31,6 @@ last_verified_commit: e51fe6ec1b9a9a0e14bb1fdb296d61b6593b93c6
|
|||||||
The diffusion runtime owns request admission, scheduling, execution, progress,
|
The diffusion runtime owns request admission, scheduling, execution, progress,
|
||||||
output, cancellation, and cleanup inside a diffusion stage.
|
output, cancellation, and cleanup inside a diffusion stage.
|
||||||
|
|
||||||
It is easiest to think of the runtime as a small control loop:
|
|
||||||
|
|
||||||
1. the **scheduler** chooses ready requests;
|
|
||||||
2. the **executor** sends that choice to the worker layer;
|
|
||||||
3. each **worker** manages its device and delegates model work to a **runner**;
|
|
||||||
4. the runner calls the model pipeline and returns per-request results; and
|
|
||||||
5. the engine feeds those results back to the scheduler and output streams.
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
|
|
||||||
This page describes the runtime plumbing. Model loading and pipeline
|
|
||||||
contracts belong to [Diffusion model integration](diffusion_model_integration.md).
|
|
||||||
Batch compatibility and step-state details belong to
|
|
||||||
[Diffusion continuous batching](continuous_batching.md).
|
|
||||||
|
|
||||||
## Goals and non-goals
|
|
||||||
|
|
||||||
The runtime aims to keep request policy separate from device execution. It
|
|
||||||
also keeps request identity stable from admission through the final output,
|
|
||||||
including cancellation and failures.
|
|
||||||
|
|
||||||
This module does **not** choose the next Omni stage, place stage replicas, or
|
|
||||||
define a model's denoising algorithm:
|
|
||||||
|
|
||||||
- cross-stage routing belongs to [Engine orchestration](../engine_orchestration.md);
|
|
||||||
- process placement and replica lifecycle belong to
|
|
||||||
[Stage runtime](../stage_runtime.md); and
|
|
||||||
- model-specific work belongs to
|
|
||||||
[Diffusion model integration](diffusion_model_integration.md).
|
|
||||||
|
|
||||||
## Runtime at a glance
|
|
||||||
|
|
||||||
The stage owns `DiffusionEngine` and a `DiffusionExecutor` backend. The inline
|
|
||||||
stage client keeps that stack in the caller process; a process-backed stage
|
|
||||||
runs it inside `StageDiffusionProc`.
|
|
||||||
|
|
||||||
The executor then chooses how the worker runs:
|
|
||||||
|
|
||||||
- **`uni`** (default when `num_gpus == 1`): `UniProcDiffusionExecutor` builds
|
|
||||||
one in-process worker. There is no worker subprocess and no shared-memory
|
|
||||||
RPC.
|
|
||||||
- **`mp`** (default when `num_gpus > 1`, or when set explicitly):
|
|
||||||
`MultiprocDiffusionExecutor` starts one `WorkerProc` per device.
|
|
||||||
|
|
||||||
Either way, each worker owns its device, distributed state,
|
|
||||||
`DiffusionWorker`, `DiffusionModelRunner`, and pipeline instance.
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
flowchart TB
|
|
||||||
client["Stage client"]
|
|
||||||
|
|
||||||
subgraph stage["Diffusion stage process"]
|
|
||||||
stageProc["StageDiffusionProc<br/>stage transport and lifecycle"]
|
|
||||||
engine["DiffusionEngine<br/>admission and control loop"]
|
|
||||||
scheduler["RequestScheduler or StepScheduler<br/>request state and policy"]
|
|
||||||
executor["DiffusionExecutor<br/>uni or mp backend"]
|
|
||||||
streams["Per-request output streams"]
|
|
||||||
|
|
||||||
stageProc --> engine
|
|
||||||
engine --> scheduler
|
|
||||||
scheduler -->|"DiffusionSchedulerOutput"| engine
|
|
||||||
engine --> executor
|
|
||||||
engine --> streams
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph workers["Worker layer"]
|
|
||||||
workerProc["WorkerProc<br/>mp IPC loop only"]
|
|
||||||
worker["DiffusionWorker<br/>device and distributed setup"]
|
|
||||||
runner["DiffusionModelRunner<br/>model state and execution"]
|
|
||||||
pipeline["Diffusion pipeline<br/>model-specific computation"]
|
|
||||||
|
|
||||||
workerProc --> worker
|
|
||||||
worker --> runner --> pipeline
|
|
||||||
end
|
|
||||||
|
|
||||||
client -->|"process-backed: ZMQ"| stageProc
|
|
||||||
client -.->|"inline: direct call"| engine
|
|
||||||
executor -->|"mp: broadcast / result queues"| workerProc
|
|
||||||
executor -.->|"uni: in-process call"| worker
|
|
||||||
streams -->|"process-backed"| stageProc
|
|
||||||
stageProc -->|"ZMQ results"| client
|
|
||||||
streams -.->|"inline"| client
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! info "Stage process vs worker process"
|
|
||||||
|
|
||||||
A deployed stage may already run in a `StageDiffusionProc` child process.
|
|
||||||
That is separate from the optional `mp` worker processes. With `uni`, the
|
|
||||||
worker lives in the same process as the engine.
|
|
||||||
|
|
||||||
## Component responsibilities
|
|
||||||
|
|
||||||
| Component | Owns | Does not own |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `DiffusionEngine` | Admission, the busy loop, scheduler/executor coordination, RPC ordering, output streams, warmup, abort routing | Batch policy details, device setup, model computation |
|
|
||||||
| `BaseScheduler` | Request states, waiting/running sets, capacity, compatibility, terminal transitions | IPC, worker calls, output formatting |
|
|
||||||
| `RequestScheduler` | Complete-request waves and optional admission delay for request-level batching | Denoising-step progress |
|
|
||||||
| `StepScheduler` | Per-request denoising progress and step-wise completion | Pipeline tensors and model state |
|
|
||||||
| `DiffusionExecutor` | Execution backend contract, worker RPC, health, shutdown | Admission and request-state transitions |
|
|
||||||
| `UniProcDiffusionExecutor` | Single in-process worker for `num_gpus == 1`; no IPC or async output pump | Multi-GPU execution |
|
|
||||||
| `MultiprocDiffusionExecutor` | Worker processes, shared-memory message queues, result dispatch, worker monitoring | In-process single-GPU path |
|
|
||||||
| `WorkerProc` | One `mp` worker process's IPC loop and reply rules | Scheduling policy; unused by `uni` |
|
|
||||||
| `DiffusionWorker` | Device/distributed setup, LoRA activation, profiling, sleep/wake, runner delegation | Request admission |
|
|
||||||
| `DiffusionModelRunner` | Pipeline loading, request-local model state, cache/compile setup, request or step execution | Queueing and cross-stage routing |
|
|
||||||
|
|
||||||
The boundary between policy and execution is
|
|
||||||
`DiffusionSchedulerOutput`. It contains newly admitted request payloads,
|
|
||||||
IDs for requests whose runner state is already cached, finished IDs,
|
|
||||||
optional KV-prefetch work, and per-request `diffusion_kv_metadata` on
|
|
||||||
`NewRequestData` envelopes when paged Diffusion KV is enabled. Executors and
|
|
||||||
workers consume this output; they do not decide what should run next.
|
|
||||||
|
|
||||||
`BaseScheduler.initialize()` sets `max_num_running_reqs` from
|
|
||||||
`od_config.max_num_seqs` (default 1). The engine may override that capacity
|
|
||||||
for distributed layerwise offload with AllGather DP concurrency.
|
|
||||||
|
|
||||||
## One scheduling tick
|
|
||||||
|
|
||||||
Async requests share one engine busy loop. Worker calls and control RPCs pass
|
|
||||||
through that loop, so they cannot race on the executor transport.
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
sequenceDiagram
|
|
||||||
participant Caller
|
|
||||||
participant Engine as DiffusionEngine
|
|
||||||
participant Scheduler
|
|
||||||
participant Executor
|
|
||||||
participant Worker
|
|
||||||
participant Runner
|
|
||||||
|
|
||||||
Caller->>Engine: add request
|
|
||||||
Engine->>Scheduler: add_request(request)
|
|
||||||
Engine->>Scheduler: schedule()
|
|
||||||
Scheduler-->>Engine: DiffusionSchedulerOutput
|
|
||||||
Engine->>Executor: execute_batch() or execute_step()
|
|
||||||
Executor->>Worker: run worker method
|
|
||||||
Worker->>Runner: execute model or one step
|
|
||||||
Runner-->>Worker: RunnerOutput(s)
|
|
||||||
Worker-->>Executor: result
|
|
||||||
Executor-->>Engine: BaseRunnerOutput
|
|
||||||
Engine->>Scheduler: update_from_output(...)
|
|
||||||
Scheduler-->>Engine: finished request IDs
|
|
||||||
Engine-->>Caller: chunk or final output
|
|
||||||
```
|
|
||||||
|
|
||||||
The engine catches request execution errors and turns them into per-request
|
|
||||||
error outputs. A dead worker group is different: the executor marks itself
|
|
||||||
failed, health checks raise `EngineDeadError`, and the owning stage client
|
|
||||||
handles the stage-level failure.
|
|
||||||
|
|
||||||
## Execution modes
|
|
||||||
|
|
||||||
The engine resolves one mode at startup and binds the matching scheduler and
|
|
||||||
executor call.
|
|
||||||
|
|
||||||
| Mode | Scheduler | Executor call | Runner path |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Request batch | `RequestScheduler` | `execute_batch()` | `execute_model()` for one request, or `execute_model_batch()` for a fused batch |
|
|
||||||
| Step batch | `StepScheduler` | `execute_step()` | `execute_stepwise()` |
|
|
||||||
|
|
||||||
**Request mode** runs a complete pipeline forward for each scheduled wave. A
|
|
||||||
single-request wave is the conservative path. A multi-request wave usually
|
|
||||||
uses fused `execute_model_batch()` and requires the pipeline to declare
|
|
||||||
request-batch support.
|
|
||||||
|
|
||||||
**Distributed layerwise offload with AllGather (DLO DP concurrency)** is a
|
|
||||||
separate multiproc dispatch path. It activates when
|
|
||||||
`data_parallel_size > 1`, `enable_distributed_layerwise_offload` is set, and
|
|
||||||
`dlo_use_allgather` is true. The engine then sets `dp_concurrent = True` and
|
|
||||||
raises `scheduler.max_num_running_reqs` to `dp_size`, overriding the
|
|
||||||
`max_num_seqs` value from `initialize()`. The scheduler still emits a
|
|
||||||
multi-request `DiffusionSchedulerOutput`; the multiproc executor routes that
|
|
||||||
wave through `execute_request()` instead of fused `execute_model_batch()`.
|
|
||||||
|
|
||||||
Optional admission coalescing can fill a `dp_size` wave: when
|
|
||||||
`request_batch_max_wait_ms > 0`, `RequestScheduler` may wait briefly before
|
|
||||||
the first schedule of a wave (under `dp_concurrent`, the stable window is
|
|
||||||
`min(0.3s, wait/2)`). With the default `request_batch_max_wait_ms == 0`,
|
|
||||||
there is no wait.
|
|
||||||
|
|
||||||
Before dispatch, `MultiprocDiffusionExecutor.execute_request()` rejects waves
|
|
||||||
whose requests differ in sampling-parameter compatibility or `extra_args`
|
|
||||||
(AllGather requires every DP rank to follow the same forward schedule). Each
|
|
||||||
worker rank then picks one envelope from the wave:
|
|
||||||
`req[dp_rank % len(req)]`, so every rank enters the same collective while
|
|
||||||
computing different requests.
|
|
||||||
|
|
||||||
**Step mode** keeps `StepRequestState` in the runner. New requests run
|
|
||||||
`prepare_encode()` once; every tick runs `denoise_step()` and
|
|
||||||
`step_scheduler()`; completed requests run `post_decode()`. The scheduler keeps
|
|
||||||
only lifecycle and progress metadata—it does not hold model tensors.
|
|
||||||
|
|
||||||
**Step mode is also the path for streaming diffusion output**. Enabling
|
|
||||||
`streaming_output` turns on step execution if needed. Chunk-capable pipelines
|
|
||||||
can emit intermediate outputs through the same request stream; final-only step
|
|
||||||
pipelines still emit only the final result. If the pipeline does not implement
|
|
||||||
step execution, initialization fails.
|
|
||||||
|
|
||||||
!!! tip
|
|
||||||
|
|
||||||
For user-facing flags and examples, see
|
|
||||||
[Diffusion execution modes](../../../user_guide/diffusion/execution_modes.md).
|
|
||||||
That guide explains how to select a mode; this page explains what happens
|
|
||||||
after the choice is made.
|
|
||||||
|
|
||||||
## Request state and identity
|
|
||||||
|
|
||||||
The scheduler is the source of truth for an admitted request. Its normal state
|
|
||||||
flow is:
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
stateDiagram-v2
|
|
||||||
[*] --> WAITING: add_request
|
|
||||||
WAITING --> RUNNING: schedule
|
|
||||||
WAITING --> FINISHED_ABORTED: abort
|
|
||||||
RUNNING --> FINISHED_ABORTED: abort
|
|
||||||
RUNNING --> FINISHED_COMPLETED: successful output
|
|
||||||
RUNNING --> FINISHED_ERROR: failed or missing output
|
|
||||||
FINISHED_COMPLETED --> [*]: deliver and remove state
|
|
||||||
FINISHED_ABORTED --> [*]: deliver and remove state
|
|
||||||
FINISHED_ERROR --> [*]: deliver and remove state
|
|
||||||
```
|
|
||||||
|
|
||||||
`PREEMPTED` and `BaseScheduler.preempt_request()` exist on the scheduler API,
|
|
||||||
but the engine loop does not call them today—only scheduler unit tests do.
|
|
||||||
|
|
||||||
`request_id` ties together scheduler state, runner state, executor results, and
|
|
||||||
the output queue. Batch positions are temporary and must never replace request
|
|
||||||
identity when results are mapped back.
|
|
||||||
|
|
||||||
Only compatible requests enter the same running wave. The scheduler compares a
|
|
||||||
mode-specific sampling-parameter key and stops at the first incompatible
|
|
||||||
waiting request. This is intentionally conservative and can cause
|
|
||||||
head-of-line blocking.
|
|
||||||
|
|
||||||
## Executor and IPC
|
|
||||||
|
|
||||||
`DiffusionExecutor` is the backend interface. Built-in backends are selected by
|
|
||||||
`distributed_executor_backend`:
|
|
||||||
|
|
||||||
| Backend | When chosen | Worker layout |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `uni` | Default for `num_gpus == 1`, or set explicitly | One in-process worker |
|
|
||||||
| `mp` | Default for `num_gpus > 1`, or set explicitly | One worker process per device |
|
|
||||||
|
|
||||||
Ray and external-launcher diffusion backends are not implemented. A custom
|
|
||||||
`DiffusionExecutor` subclass or import path is also accepted.
|
|
||||||
|
|
||||||
### Uniproc backend
|
|
||||||
|
|
||||||
`UniProcDiffusionExecutor` constructs `WorkerWrapperBase` in the engine process
|
|
||||||
and calls worker methods directly. It avoids a second model load, MessageQueue
|
|
||||||
rings, ZMQ IPC sockets, and `/dev/shm` tensor packing. RPC timeouts are
|
|
||||||
accepted for interface parity but are not enforced: a hung worker blocks the
|
|
||||||
calling thread. Sticky accelerator faults mark the executor dead through
|
|
||||||
failure callbacks; ordinary request errors stay per-request.
|
|
||||||
|
|
||||||
### Multiproc backend
|
|
||||||
|
|
||||||
`MultiprocDiffusionExecutor`:
|
|
||||||
|
|
||||||
1. creates a broadcast queue shared by all workers;
|
|
||||||
2. spawns one worker process per configured device;
|
|
||||||
3. waits until every worker reports ready;
|
|
||||||
4. sends generation and control calls as RPC messages;
|
|
||||||
5. applies rank-aware reply rules so only expected ranks respond; and
|
|
||||||
6. monitors worker process sentinels and fails the executor if a worker dies.
|
|
||||||
|
|
||||||
In request mode on this backend, each async output produces two correlated
|
|
||||||
messages keyed by `async_output_id`:
|
|
||||||
|
|
||||||
- `COMPUTE_DONE` — the forward finished and the device can start the next
|
|
||||||
request.
|
|
||||||
- `OUTPUT_READY` — background D2H/SHM packing finished and the final output
|
|
||||||
is ready.
|
|
||||||
|
|
||||||
The worker queues background packing work before it enqueues `COMPUTE_DONE`,
|
|
||||||
but either message may reach the executor first. The result pump and
|
|
||||||
`execute_batch()` must handle both orderings. Step mode keeps the synchronous
|
|
||||||
result path and does not start those pumps.
|
|
||||||
|
|
||||||
See [Async diffusion output](../../feature/async_diffusion_output.md) for the
|
|
||||||
multiproc request-mode timeline.
|
|
||||||
|
|
||||||
## Worker and runner boundary
|
|
||||||
|
|
||||||
On the `mp` path, `WorkerProc` receives messages and calls methods through
|
|
||||||
`WorkerWrapperBase`. On the `uni` path, the executor owns that wrapper
|
|
||||||
directly. In both cases, `DiffusionWorker` handles the parts tied to a device:
|
|
||||||
distributed initialization, model-runner construction, LoRA activation,
|
|
||||||
profiling, and memory sleep/wake. It delegates actual model work to
|
|
||||||
`DiffusionModelRunner`.
|
|
||||||
|
|
||||||
The runner owns long-lived model-side state:
|
|
||||||
|
|
||||||
- the loaded pipeline and compilation setup;
|
|
||||||
- cache and offload integration;
|
|
||||||
- random-generator setup;
|
|
||||||
- request batches for complete forwards; and
|
|
||||||
- `StepRequestState` plus `InputBatch` for step execution.
|
|
||||||
|
|
||||||
This split keeps infrastructure out of model pipelines. A pipeline receives a
|
|
||||||
request batch or step state and performs model work; it should not inspect
|
|
||||||
engine queues or change scheduler state.
|
|
||||||
|
|
||||||
## Lifecycle and cleanup
|
|
||||||
|
|
||||||
### Startup
|
|
||||||
|
|
||||||
`DiffusionEngine.make_engine()` resolves the engine class, constructs the
|
|
||||||
executor and scheduler, then normally runs a small dummy request to warm up the
|
|
||||||
model.
|
|
||||||
|
|
||||||
Warmup is skipped only when distributed layerwise offload with AllGather
|
|
||||||
is enabled (via `enable_distributed_layerwise_offload` and `dlo_use_allgather`)
|
|
||||||
and `max(data_parallel_size, sequence_parallel_size) > 1`, because
|
|
||||||
the dummy run sends one request while AllGather needs every shard rank to
|
|
||||||
enter the same collective. If initialization or warmup fails, the runtime
|
|
||||||
closes scheduler state and worker resources before returning the error.
|
|
||||||
|
|
||||||
### Cancellation
|
|
||||||
|
|
||||||
`abort()` places request IDs on an abort queue. The busy loop marks those
|
|
||||||
requests `FINISHED_ABORTED`; finalization removes scheduler state and emits an
|
|
||||||
aborted output when a consumer still exists. The runner removes cached
|
|
||||||
step-mode state when it receives a scheduler output that reports the finished
|
|
||||||
request ID.
|
|
||||||
|
|
||||||
On the multiproc request-mode async path, abort or consumer drop while output
|
|
||||||
is still materializing should release the associated async-output bookkeeping
|
|
||||||
so late results are not retained after the request ends
|
|
||||||
*(pending #6253/#6439/#6580)*. Today, an unconsumed `OUTPUT_READY` is cached
|
|
||||||
by design until `wait_output_ready()` or executor teardown. Dropping an
|
|
||||||
output-stream consumer removes that consumer's queue. It does not take
|
|
||||||
ownership of scheduler cleanup.
|
|
||||||
|
|
||||||
### Shutdown and worker failure
|
|
||||||
|
|
||||||
`DiffusionEngine.close()` is idempotent. It stops the busy loop, wakes pending
|
|
||||||
streams with an error, closes scheduler state, and shuts down the executor.
|
|
||||||
|
|
||||||
- **`mp`**: the executor asks workers to stop, waits for them, then terminates
|
|
||||||
workers that miss the grace period. Shutdown marks unfinished RPC and
|
|
||||||
async-output futures as failed, then clears them. Completed async outputs
|
|
||||||
cached for later `wait_output_ready()` calls are dropped with the executor
|
|
||||||
object.
|
|
||||||
- **`uni`**: the executor shuts down the in-process worker, drops the final
|
|
||||||
model reference, and empties the accelerator cache so a later engine can reuse
|
|
||||||
the device.
|
|
||||||
|
|
||||||
!!! warning
|
|
||||||
|
|
||||||
Do not continue using a worker group after a fatal collective timeout or
|
|
||||||
unexpected worker exit. Distributed state may be incomplete. The
|
|
||||||
multiprocess executor deliberately fails closed so the stage can restart.
|
|
||||||
The uniproc executor fails closed when the accelerator context itself is
|
|
||||||
poisoned.
|
|
||||||
|
|
||||||
## Extension boundaries
|
|
||||||
|
|
||||||
- A custom engine may set `default_diffusion_model_runner_cls`; an explicit
|
|
||||||
`diffusion_model_runner_cls` configuration still wins.
|
|
||||||
- Tests and custom engine integrations may inject a `BaseScheduler` subclass.
|
|
||||||
`SchedulerInterface` remains only as a deprecated compatibility name.
|
|
||||||
- `distributed_executor_backend` may be `"uni"`, `"mp"`, a custom `DiffusionExecutor`
|
|
||||||
subclass, or an import path. A backend must preserve scheduler output,
|
|
||||||
request identity, health, and cleanup contracts. Use `"mp"` when you need
|
|
||||||
process isolation or multi-GPU; `"uni"` is the single-GPU default.
|
|
||||||
- Worker extensions go through `WorkerWrapperBase`. They add worker methods;
|
|
||||||
they do not become a second scheduler or request lifecycle.
|
|
||||||
|
|
||||||
These are advanced Python integration points, not stable end-user CLI
|
|
||||||
customization surfaces.
|
|
||||||
|
|
||||||
## Candidate invariants
|
## Candidate invariants
|
||||||
|
|
||||||
### DIFF-RUNTIME-INV-001: One lifecycle owner
|
### DIFF-RUNTIME-INV-001: One lifecycle owner
|
||||||
@@ -437,50 +41,19 @@ until completion, cancellation, or failure.
|
|||||||
### DIFF-RUNTIME-INV-002: Execution follows scheduler output
|
### DIFF-RUNTIME-INV-002: Execution follows scheduler output
|
||||||
|
|
||||||
**Rule:** Executors and workers MUST execute scheduler decisions without
|
**Rule:** Executors and workers MUST execute scheduler decisions without
|
||||||
admitting, reordering, or forwarding requests independently. Distributed
|
admitting, reordering, or forwarding requests independently.
|
||||||
layerwise offload with AllGather is an exception at dispatch time: the
|
|
||||||
scheduler may schedule a multi-request wave, but each DP rank executes one
|
|
||||||
envelope from that wave so every rank enters the same collective schedule.
|
|
||||||
|
|
||||||
### DIFF-RUNTIME-INV-003: Terminal cleanup is complete
|
### DIFF-RUNTIME-INV-003: Terminal cleanup is complete
|
||||||
|
|
||||||
**Rule:** Every terminal path MUST release request state, temporary tensors,
|
**Rule:** Every terminal path MUST release request state, temporary tensors,
|
||||||
hooks, and runtime-owned resources. Async-output bookkeeping on abort or
|
hooks, and runtime-owned resources.
|
||||||
consumer drop before consumption is also required *(pending #6253/#6439/#6580)*.
|
|
||||||
|
|
||||||
### DIFF-RUNTIME-INV-004: Optional features use runtime hooks
|
### DIFF-RUNTIME-INV-004: Optional features use runtime hooks
|
||||||
|
|
||||||
**Rule:** Cache, profiling, offload, and parallel features SHOULD integrate at
|
**Rule:** Cache, profiling, offload, and parallel features SHOULD integrate at
|
||||||
defined hooks instead of creating another request lifecycle.
|
defined hooks instead of creating another request lifecycle.
|
||||||
|
|
||||||
### DIFF-RUNTIME-INV-005: Results keep request identity
|
|
||||||
|
|
||||||
**Rule:** Batched and asynchronous results MUST be mapped by stable request ID,
|
|
||||||
not by assumed completion order.
|
|
||||||
|
|
||||||
## Safe-change guide
|
## Safe-change guide
|
||||||
|
|
||||||
Test the smallest affected slice, then cover its neighboring boundary:
|
Test success, cancellation, failure, shutdown, multiple requests, and resource
|
||||||
|
cleanup.
|
||||||
| Change area | Minimum evidence |
|
|
||||||
| --- | --- |
|
|
||||||
| Admission or state transitions | `test_diffusion_scheduler.py`, including duplicate IDs, compatibility, abort, and missing output |
|
|
||||||
| Engine loop or output delivery | `test_diffusion_engine.py`, `test_diffusion_engine_cleanup.py`, `test_diffusion_engine_rpc_routing.py` |
|
|
||||||
| Executor or IPC | `test_multiproc_engine_concurrency.py`, `test_uniproc_executor.py`, `test_result_pump.py`, `test_diffusion_ipc.py`, `test_async_output_worker.py` |
|
|
||||||
| Worker or runner | `test_diffusion_worker.py`, `test_diffusion_model_runner.py` |
|
|
||||||
| Stage boundary | `test_stage_diffusion_proc.py`, `test_inline_stage_diffusion_client.py` |
|
|
||||||
| Warmup or streaming | `test_diffusion_engine_dummy_run.py`, `test_diffusion_streaming_output.py` |
|
|
||||||
|
|
||||||
Always exercise success, cancellation, per-request failure, fatal worker
|
|
||||||
failure, repeated shutdown, one request, and multiple compatible requests.
|
|
||||||
For step-mode changes, also test partial progress and cleanup of runner state.
|
|
||||||
|
|
||||||
## Related documents
|
|
||||||
|
|
||||||
- [Diffusion module overview](index.md)
|
|
||||||
- [Diffusion model integration](diffusion_model_integration.md)
|
|
||||||
- [Diffusion continuous batching](continuous_batching.md)
|
|
||||||
- [Diffusion execution modes](../../../user_guide/diffusion/execution_modes.md)
|
|
||||||
- [Async diffusion output](../../feature/async_diffusion_output.md)
|
|
||||||
- [Engine orchestration](../engine_orchestration.md)
|
|
||||||
- [Stage runtime](../stage_runtime.md)
|
|
||||||
@@ -28,9 +28,6 @@ related_code_paths:
|
|||||||
- vllm_omni/engine/stage_pool.py
|
- vllm_omni/engine/stage_pool.py
|
||||||
- vllm_omni/outputs/output_processor.py
|
- vllm_omni/outputs/output_processor.py
|
||||||
- vllm_omni/distributed/omni_coordinator/**
|
- vllm_omni/distributed/omni_coordinator/**
|
||||||
# Duplex kernel design is owned by ../fullduplex.md; listed here because the
|
|
||||||
# orchestrator hosts the duplex control plane.
|
|
||||||
- vllm_omni/engine/duplex/**
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- input_output_modality_contracts.md
|
- input_output_modality_contracts.md
|
||||||
- error_contracts.md
|
- error_contracts.md
|
||||||
@@ -47,8 +44,7 @@ validation_paths:
|
|||||||
- tests/engine/test_orchestrator_stage_input_bridge.py
|
- tests/engine/test_orchestrator_stage_input_bridge.py
|
||||||
- tests/engine/test_cfg_companion_lifecycle.py
|
- tests/engine/test_cfg_companion_lifecycle.py
|
||||||
- tests/engine/test_rpc_result_router.py
|
- tests/engine/test_rpc_result_router.py
|
||||||
- tests/engine/duplex/**
|
- tests/e2e/features/fullduplex/engine/**
|
||||||
- tests/engine/test_duplex_import_boundary.py
|
|
||||||
upstream_refs:
|
upstream_refs:
|
||||||
- vllm.v1.engine.EngineCoreRequest
|
- vllm.v1.engine.EngineCoreRequest
|
||||||
- vllm.v1.engine.EngineCoreOutputs
|
- vllm.v1.engine.EngineCoreOutputs
|
||||||
|
|||||||
@@ -26,18 +26,9 @@ primary_code_paths:
|
|||||||
- vllm_omni/entrypoints/client_request_state.py
|
- vllm_omni/entrypoints/client_request_state.py
|
||||||
- vllm_omni/entrypoints/stage_utils.py
|
- vllm_omni/entrypoints/stage_utils.py
|
||||||
- vllm_omni/entrypoints/utils.py
|
- vllm_omni/entrypoints/utils.py
|
||||||
- vllm_omni/entrypoints/duplex/**
|
|
||||||
- vllm_omni/entrypoints/duplex_request_client.py
|
|
||||||
- vllm_omni/clients/**
|
|
||||||
primary_path_exceptions:
|
primary_path_exceptions:
|
||||||
- path: vllm_omni/entrypoints/openai/errors.py
|
- path: vllm_omni/entrypoints/openai/errors.py
|
||||||
owner: error_contracts.md
|
owner: error_contracts.md
|
||||||
- path: vllm_omni/entrypoints/duplex/**
|
|
||||||
owner: ../fullduplex.md
|
|
||||||
- path: vllm_omni/entrypoints/duplex_request_client.py
|
|
||||||
owner: ../fullduplex.md
|
|
||||||
- path: vllm_omni/clients/**
|
|
||||||
owner: ../fullduplex.md
|
|
||||||
related_code_paths:
|
related_code_paths:
|
||||||
- vllm_omni/errors.py
|
- vllm_omni/errors.py
|
||||||
- vllm_omni/inputs/**
|
- vllm_omni/inputs/**
|
||||||
|
|||||||
@@ -410,8 +410,8 @@ Notes:
|
|||||||
- `stages[].max_num_seqs` controls stage-level batching.
|
- `stages[].max_num_seqs` controls stage-level batching.
|
||||||
- Thinker/Talker commonly use `enforce_eager: false` for CUDA Graph paths.
|
- Thinker/Talker commonly use `enforce_eager: false` for CUDA Graph paths.
|
||||||
- Code2Wav often remains eager (`enforce_eager: true`) depending on runtime behavior.
|
- Code2Wav often remains eager (`enforce_eager: true`) depending on runtime behavior.
|
||||||
- The Qwen3-Omni deploy config pins `moe_backend: triton` for the Thinker and Talker stages. Triton has been more
|
- Qwen3-Omni defaults `VLLM_USE_FLASHINFER_MOE_FP16=0`. The Triton has been more stable & faster
|
||||||
stable and faster than the FlashInfer CUTLASS unquantized MoE backend on recent vLLM rebases.
|
than the FlashInfer CUTLASS unquantized MoE backend on recent vLLM rebases.
|
||||||
|
|
||||||
#### 2) Enable async chunk
|
#### 2) Enable async chunk
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
!!! important
|
!!! important
|
||||||
vLLM-Omni is released against the matching upstream vLLM major/minor version. The 0.29 development line requires vLLM 0.29.x; the source-install instructions pin vLLM 0.29.0. Published vLLM-Omni 0.28.0 wheels and images still require vLLM 0.28.x.
|
vLLM-Omni is released against the matching upstream vLLM major/minor version. vLLM-Omni 0.28.x requires vLLM 0.28.x; the stable v0.28.0 instructions pin vLLM 0.28.0.
|
||||||
|
|
||||||
vLLM-Omni supports the following hardware platforms:
|
vLLM-Omni supports the following hardware platforms:
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ vLLM-Omni is a Python library that supports the following GPU variants. The libr
|
|||||||
|
|
||||||
### Pre-built wheels
|
### Pre-built wheels
|
||||||
|
|
||||||
The source-install instructions target vLLM 0.29.0. Until vLLM-Omni 0.29.0 artifacts are published, the CUDA/ROCm pre-built examples below remain on the matching 0.28.0 release pair.
|
|
||||||
|
|
||||||
Note: Pre-built wheels are currently available for vLLM-Omni 0.11.0rc1, 0.12.0rc1, 0.14.0rc1, 0.14.0, 0.16.0, 0.18.0, 0.20.0, 0.21.0, 0.22.0, 0.23.0, 0.24.0, 0.25.0, 0.26.0, and 0.28.0. If you need a newer unreleased revision, please [build from source](https://docs.vllm.ai/projects/vllm-omni/en/latest/getting_started/installation/gpu/#build-wheel-from-source).
|
Note: Pre-built wheels are currently available for vLLM-Omni 0.11.0rc1, 0.12.0rc1, 0.14.0rc1, 0.14.0, 0.16.0, 0.18.0, 0.20.0, 0.21.0, 0.22.0, 0.23.0, 0.24.0, 0.25.0, 0.26.0, and 0.28.0. If you need a newer unreleased revision, please [build from source](https://docs.vllm.ai/projects/vllm-omni/en/latest/getting_started/installation/gpu/#build-wheel-from-source).
|
||||||
|
|
||||||
=== "NVIDIA CUDA"
|
=== "NVIDIA CUDA"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
# --8<-- [end:requirements]
|
# --8<-- [end:requirements]
|
||||||
# --8<-- [start:set-up-using-python]
|
# --8<-- [start:set-up-using-python]
|
||||||
|
|
||||||
vLLM-Omni depends on the matching major/minor release of vLLM. The 0.29 development line uses vLLM 0.29.x. Published 0.28.0 wheels and images use vLLM 0.28.x.
|
vLLM-Omni depends on the matching major/minor release of vLLM. The vLLM-Omni 0.28.x release line uses vLLM 0.28.x.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
PyTorch installed via `conda` will statically link `NCCL` library, which can cause issues when vLLM tries to use `NCCL`. See <gh-issue:8420> for more details.
|
PyTorch installed via `conda` will statically link `NCCL` library, which can cause issues when vLLM tries to use `NCCL`. See <gh-issue:8420> for more details.
|
||||||
@@ -18,8 +18,6 @@ Therefore, it is recommended to install vLLM and vLLM-Omni with a **fresh new**
|
|||||||
|
|
||||||
#### Installation of vLLM
|
#### Installation of vLLM
|
||||||
|
|
||||||
These pre-built wheel instructions install the published vLLM-Omni 0.28.0 release. For the 0.29 development line, use the source-install instructions below.
|
|
||||||
|
|
||||||
vLLM-Omni is built based on vLLM. Please install it with command below.
|
vLLM-Omni is built based on vLLM. Please install it with command below.
|
||||||
```bash
|
```bash
|
||||||
uv pip install vllm==0.28.0 --torch-backend=auto
|
uv pip install vllm==0.28.0 --torch-backend=auto
|
||||||
@@ -28,12 +26,12 @@ uv pip install vllm==0.28.0 --torch-backend=auto
|
|||||||
#### Installation of vLLM-Omni
|
#### Installation of vLLM-Omni
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv pip install vllm-omni==0.28.0
|
uv pip install vllm-omni
|
||||||
```
|
```
|
||||||
|
|
||||||
To run Gradio demos, also install the optional extras:
|
To run Gradio demos, also install the optional extras:
|
||||||
```bash
|
```bash
|
||||||
uv pip install 'vllm-omni[demo]==0.28.0'
|
uv pip install 'vllm-omni[demo]'
|
||||||
```
|
```
|
||||||
|
|
||||||
# --8<-- [end:pre-built-wheels]
|
# --8<-- [end:pre-built-wheels]
|
||||||
@@ -41,13 +39,13 @@ uv pip install 'vllm-omni[demo]==0.28.0'
|
|||||||
# --8<-- [start:build-wheel-from-source]
|
# --8<-- [start:build-wheel-from-source]
|
||||||
|
|
||||||
#### Installation of vLLM
|
#### Installation of vLLM
|
||||||
If you do not need to modify source code of vLLM, you can directly install the stable 0.29.0 release version of the library
|
If you do not need to modify source code of vLLM, you can directly install the stable 0.28.0 release version of the library
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv pip install vllm==0.29.0 --torch-backend=auto
|
uv pip install vllm==0.28.0 --torch-backend=auto
|
||||||
```
|
```
|
||||||
|
|
||||||
The 0.29.0 release of vLLM ships CUDA 13.0-compatible binaries by default. If you need a different CUDA variant or want to reuse an existing PyTorch installation, build vLLM from source instead.
|
The 0.28.0 release of vLLM ships CUDA 13.0-compatible binaries by default. If you need a different CUDA variant or want to reuse an existing PyTorch installation, build vLLM from source instead.
|
||||||
|
|
||||||
#### Installation of vLLM-Omni
|
#### Installation of vLLM-Omni
|
||||||
Since vllm-omni is rapidly evolving, it's recommended to install it from source
|
Since vllm-omni is rapidly evolving, it's recommended to install it from source
|
||||||
@@ -68,12 +66,12 @@ If you want to check, modify or debug with source code of vLLM, install the libr
|
|||||||
```bash
|
```bash
|
||||||
git clone https://github.com/vllm-project/vllm.git
|
git clone https://github.com/vllm-project/vllm.git
|
||||||
cd vllm
|
cd vllm
|
||||||
git checkout v0.29.0
|
git checkout v0.28.0
|
||||||
```
|
```
|
||||||
Set up environment variables to get pre-built wheels. If there are internet problems, just download the whl file manually. And set `VLLM_PRECOMPILED_WHEEL_LOCATION` as your local absolute path of whl file.
|
Set up environment variables to get pre-built wheels. If there are internet problems, just download the whl file manually. And set `VLLM_PRECOMPILED_WHEEL_LOCATION` as your local absolute path of whl file.
|
||||||
```bash
|
```bash
|
||||||
#For CUDA 13.0 (the default for v0.29.0; the wheel filename has no `+cu130` suffix)
|
#For CUDA 13.0 (the default for v0.28.0; the wheel filename has no `+cu130` suffix)
|
||||||
export VLLM_PRECOMPILED_WHEEL_LOCATION=https://github.com/vllm-project/vllm/releases/download/v0.29.0/vllm-0.29.0-cp38-abi3-manylinux_2_28_x86_64.whl
|
export VLLM_PRECOMPILED_WHEEL_LOCATION=https://github.com/vllm-project/vllm/releases/download/v0.28.0/vllm-0.28.0-cp38-abi3-manylinux_2_28_x86_64.whl
|
||||||
```
|
```
|
||||||
Install vllm with command below (If you have no existing PyTorch).
|
Install vllm with command below (If you have no existing PyTorch).
|
||||||
```bash
|
```bash
|
||||||
@@ -133,7 +131,7 @@ If you want to specify the base vLLM version:
|
|||||||
```bash
|
```bash
|
||||||
DOCKER_BUILDKIT=1 docker build \
|
DOCKER_BUILDKIT=1 docker build \
|
||||||
-f docker/Dockerfile.cuda \
|
-f docker/Dockerfile.cuda \
|
||||||
--build-arg BASE_IMAGE=vllm/vllm-openai:v0.29.0 \
|
--build-arg BASE_IMAGE=vllm/vllm-openai:v0.28.0 \
|
||||||
-t vllm-omni-cuda .
|
-t vllm-omni-cuda .
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ vLLM-Omni current recommends the steps in under setup through Docker Images.
|
|||||||
|
|
||||||
#### Installation of vLLM
|
#### Installation of vLLM
|
||||||
|
|
||||||
These pre-built wheel instructions install the published vLLM-Omni 0.28.0 release. For the 0.29 development line, use the source-install instructions below.
|
|
||||||
|
|
||||||
vLLM-Omni is built based on vLLM. Please install it with command below.
|
vLLM-Omni is built based on vLLM. Please install it with command below.
|
||||||
```bash
|
```bash
|
||||||
uv pip install vllm==0.28.0+rocm723 --extra-index-url https://wheels.vllm.ai/rocm/0.28.0/rocm723
|
uv pip install vllm==0.28.0+rocm723 --extra-index-url https://wheels.vllm.ai/rocm/0.28.0/rocm723
|
||||||
@@ -24,7 +22,7 @@ uv pip install vllm==0.28.0+rocm723 --extra-index-url https://wheels.vllm.ai/roc
|
|||||||
# we need to add --no-build-isolation as the torch
|
# we need to add --no-build-isolation as the torch
|
||||||
# is not obtained from pypi, we have to install using the
|
# is not obtained from pypi, we have to install using the
|
||||||
# torch installed in our environment
|
# torch installed in our environment
|
||||||
uv pip install vllm-omni==0.28.0
|
uv pip install vllm-omni
|
||||||
|
|
||||||
# Optional if want to run Qwen3 TTS
|
# Optional if want to run Qwen3 TTS
|
||||||
uv pip uninstall onnxruntime # should be removed before we can install onnxruntime-rocm
|
uv pip uninstall onnxruntime # should be removed before we can install onnxruntime-rocm
|
||||||
@@ -36,13 +34,13 @@ uv pip install onnxruntime-rocm
|
|||||||
# --8<-- [start:build-wheel-from-source]
|
# --8<-- [start:build-wheel-from-source]
|
||||||
|
|
||||||
#### Installation of vLLM
|
#### Installation of vLLM
|
||||||
If you do not need to modify source code of vLLM, you can directly install the stable 0.29.0 release version of the library
|
If you do not need to modify source code of vLLM, you can directly install the stable 0.28.0 release version of the library
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv pip install vllm==0.29.0+rocm723 --extra-index-url https://wheels.vllm.ai/rocm/0.29.0/rocm723
|
uv pip install vllm==0.28.0+rocm723 --extra-index-url https://wheels.vllm.ai/rocm/0.28.0/rocm723
|
||||||
```
|
```
|
||||||
|
|
||||||
The pre-built 0.29.0 vLLM wheel targets ROCm 7.2.3. If you need a different ROCm stack or want to reuse an existing PyTorch installation, build vLLM from source instead.
|
The pre-built 0.28.0 vLLM wheel targets ROCm 7.2.3. If you need a different ROCm stack or want to reuse an existing PyTorch installation, build vLLM from source instead.
|
||||||
|
|
||||||
#### Installation of vLLM-Omni
|
#### Installation of vLLM-Omni
|
||||||
Since vllm-omni is rapidly evolving, it's recommended to install it from source
|
Since vllm-omni is rapidly evolving, it's recommended to install it from source
|
||||||
@@ -60,7 +58,7 @@ If you want to check, modify or debug with source code of vLLM, install the libr
|
|||||||
```bash
|
```bash
|
||||||
git clone https://github.com/vllm-project/vllm.git
|
git clone https://github.com/vllm-project/vllm.git
|
||||||
cd vllm
|
cd vllm
|
||||||
git checkout v0.29.0
|
git checkout v0.28.0
|
||||||
python3 -m pip install -r requirements/rocm.txt
|
python3 -m pip install -r requirements/rocm.txt
|
||||||
python3 setup.py develop
|
python3 setup.py develop
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -7,34 +7,13 @@ For detailed hardware and software requirements, please refer to the [vLLM-Ascen
|
|||||||
|
|
||||||
The recommended way to use vLLM-Omni on NPU is through the vLLM-Ascend pre-built Docker images:
|
The recommended way to use vLLM-Omni on NPU is through the vLLM-Ascend pre-built Docker images:
|
||||||
|
|
||||||
=== "A2"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export IMAGE=quay.io/atlas-ci/vllm-ascend:v0.28.0
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "A3"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export IMAGE=quay.io/atlas-ci/vllm-ascend:v0.28.0-a3
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "A5"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export IMAGE=quay.io/atlas-ci/vllm-ascend:v0.28.0-a5
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "310P (Experimental)"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export IMAGE=quay.io/atlas-ci/vllm-ascend:v0.28.0-310p
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# vLLM-Ascend image
|
||||||
|
# Atlas A2: quay.io/atlas-ci/vllm-ascend:v0.28.0
|
||||||
|
# Atlas A3: quay.io/atlas-ci/vllm-ascend:v0.28.0-a3
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
--name vllm-omni-npu \
|
--name vllm-omni-npu \
|
||||||
--shm-size=64g \
|
--shm-size=1g \
|
||||||
--device /dev/davinci0 \
|
--device /dev/davinci0 \
|
||||||
--device /dev/davinci1 \
|
--device /dev/davinci1 \
|
||||||
--device /dev/davinci2 \
|
--device /dev/davinci2 \
|
||||||
@@ -48,8 +27,8 @@ docker run --rm \
|
|||||||
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
|
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
|
||||||
-v /etc/ascend_install.info:/etc/ascend_install.info \
|
-v /etc/ascend_install.info:/etc/ascend_install.info \
|
||||||
-v /root/.cache:/root/.cache \
|
-v /root/.cache:/root/.cache \
|
||||||
-p 8091:8091 \
|
-p 8000:8000 \
|
||||||
-it "$IMAGE" bash
|
-it quay.io/atlas-ci/vllm-ascend:v0.28.0-a3 bash
|
||||||
|
|
||||||
# Inside the container, install vLLM-Omni from source
|
# Inside the container, install vLLM-Omni from source
|
||||||
cd /vllm-workspace
|
cd /vllm-workspace
|
||||||
@@ -93,44 +72,17 @@ Supported images as following.
|
|||||||
|
|
||||||
| image name | Hardware | OS |
|
| image name | Hardware | OS |
|
||||||
|-|-|-|
|
|-|-|-|
|
||||||
| image-tag | A2 | Ubuntu |
|
| image-tag | Atlas A2 | Ubuntu |
|
||||||
| image-tag-a3 | A3 | Ubuntu |
|
| image-tag-a3 | Atlas A3 | Ubuntu |
|
||||||
| image-tag-a5 | A5 | Ubuntu |
|
|
||||||
| image-tag-310p | 310P (experimental) | Ubuntu |
|
|
||||||
|
|
||||||
Here's an example deployment command that has been verified on 4 x NPUs:
|
Here's an example deployment command that has been verified on 4 x NPUs:
|
||||||
|
|
||||||
=== "A2"
|
```bash
|
||||||
|
# Atlas A2: quay.io/ascend/vllm-omni:v0.28.0
|
||||||
```bash
|
# Atlas A3: quay.io/ascend/vllm-omni:v0.28.0-a3
|
||||||
export IMAGE=quay.io/ascend/vllm-omni:v0.28.0
|
docker run --rm \
|
||||||
docker run --rm \
|
|
||||||
--name vllm-omni-a2 \
|
|
||||||
--shm-size=64g \
|
|
||||||
--device /dev/davinci0 \
|
|
||||||
--device /dev/davinci1 \
|
|
||||||
--device /dev/davinci2 \
|
|
||||||
--device /dev/davinci3 \
|
|
||||||
--device /dev/davinci_manager \
|
|
||||||
--device /dev/devmm_svm \
|
|
||||||
--device /dev/hisi_hdc \
|
|
||||||
-v /usr/local/dcmi:/usr/local/dcmi \
|
|
||||||
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
|
|
||||||
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
|
|
||||||
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
|
|
||||||
-v /etc/ascend_install.info:/etc/ascend_install.info \
|
|
||||||
-v ~/.cache:/root/.cache \
|
|
||||||
-p 8091:8091 \
|
|
||||||
-it "$IMAGE" bash
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "A3"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export IMAGE=quay.io/ascend/vllm-omni:v0.28.0-a3
|
|
||||||
docker run --rm \
|
|
||||||
--name vllm-omni-a3 \
|
--name vllm-omni-a3 \
|
||||||
--shm-size=64g \
|
--shm-size=4g \
|
||||||
--device /dev/davinci0 \
|
--device /dev/davinci0 \
|
||||||
--device /dev/davinci1 \
|
--device /dev/davinci1 \
|
||||||
--device /dev/davinci2 \
|
--device /dev/davinci2 \
|
||||||
@@ -142,23 +94,6 @@ Here's an example deployment command that has been verified on 4 x NPUs:
|
|||||||
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
|
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
|
||||||
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
|
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
|
||||||
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
|
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
|
||||||
-v /etc/ascend_install.info:/etc/ascend_install.info \
|
|
||||||
-v ~/.cache:/root/.cache \
|
|
||||||
-p 8091:8091 \
|
|
||||||
-it "$IMAGE" bash
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "A5"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export IMAGE=quay.io/ascend/vllm-omni:v0.28.0-a5
|
|
||||||
docker run --rm \
|
|
||||||
--name vllm-omni-a5 \
|
|
||||||
--shm-size=64g \
|
|
||||||
--device /dev/davinci0 \
|
|
||||||
--device /dev/davinci1 \
|
|
||||||
--device /dev/davinci2 \
|
|
||||||
--device /dev/davinci3 \
|
|
||||||
--device /dev/davinci_manager \
|
--device /dev/davinci_manager \
|
||||||
--device /dev/devmm_svm \
|
--device /dev/devmm_svm \
|
||||||
--device /dev/hisi_hdc \
|
--device /dev/hisi_hdc \
|
||||||
@@ -169,70 +104,21 @@ Here's an example deployment command that has been verified on 4 x NPUs:
|
|||||||
-v /etc/ascend_install.info:/etc/ascend_install.info \
|
-v /etc/ascend_install.info:/etc/ascend_install.info \
|
||||||
-v ~/.cache:/root/.cache \
|
-v ~/.cache:/root/.cache \
|
||||||
-p 8091:8091 \
|
-p 8091:8091 \
|
||||||
-it "$IMAGE" bash
|
-it quay.io/ascend/vllm-omni:v0.28.0-a3 bash
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "310P (Experimental)"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export IMAGE=quay.io/ascend/vllm-omni:v0.28.0-310p
|
|
||||||
docker run --rm \
|
|
||||||
--name vllm-omni-310p \
|
|
||||||
--shm-size=64g \
|
|
||||||
--device /dev/davinci0 \
|
|
||||||
--device /dev/davinci1 \
|
|
||||||
--device /dev/davinci2 \
|
|
||||||
--device /dev/davinci3 \
|
|
||||||
--device /dev/davinci_manager \
|
|
||||||
--device /dev/devmm_svm \
|
|
||||||
--device /dev/hisi_hdc \
|
|
||||||
-v /usr/local/dcmi:/usr/local/dcmi \
|
|
||||||
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
|
|
||||||
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
|
|
||||||
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
|
|
||||||
-v /etc/ascend_install.info:/etc/ascend_install.info \
|
|
||||||
-v ~/.cache:/root/.cache \
|
|
||||||
-p 8091:8091 \
|
|
||||||
-it "$IMAGE" bash
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
You can use this docker image to serve models the same way you would with in vLLM! To do so, make sure you overwrite the default entrypoint (`vllm serve --omni`) which works only for models supported in the vLLM-Omni project.
|
You can use this docker image to serve models the same way you would with in vLLM! To do so, make sure you overwrite the default entrypoint (`vllm serve --omni`) which works only for models supported in the vLLM-Omni project.
|
||||||
|
|
||||||
Or build the image from **source code**:
|
Or build IMAGE from **source code**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/vllm-project/vllm-omni.git
|
git clone https://github.com/vllm-project/vllm-omni.git
|
||||||
cd vllm-omni
|
cd vllm-omni
|
||||||
|
# A2
|
||||||
|
# docker build -t vllm-omni-dev-image:latest -f ./docker/Dockerfile.npu .
|
||||||
|
# A3
|
||||||
|
docker build -t vllm-omni-dev-image:latest -f ./docker/Dockerfile.npu.a3 .
|
||||||
```
|
```
|
||||||
|
|
||||||
All hardware variants use `docker/Dockerfile.npu`. Choose the device suffix for your hardware:
|
|
||||||
|
|
||||||
=== "A2"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build -t vllm-omni-dev-image:latest -f docker/Dockerfile.npu .
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "A3"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build -t vllm-omni-dev-image:latest -f docker/Dockerfile.npu \
|
|
||||||
--build-arg VLLM_ASCEND_DEVICE_SUFFIX=-a3 .
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "A5"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build -t vllm-omni-dev-image:latest -f docker/Dockerfile.npu \
|
|
||||||
--build-arg VLLM_ASCEND_DEVICE_SUFFIX=-a5 .
|
|
||||||
```
|
|
||||||
|
|
||||||
=== "310P (Experimental)"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build -t vllm-omni-dev-image:latest -f docker/Dockerfile.npu \
|
|
||||||
--build-arg VLLM_ASCEND_DEVICE_SUFFIX=-310p .
|
|
||||||
```
|
|
||||||
|
|
||||||
# --8<-- [end:pre-built-images]
|
# --8<-- [end:pre-built-images]
|
||||||
@@ -19,10 +19,10 @@ uv venv --python 3.12 --seed
|
|||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
|
|
||||||
# On CUDA
|
# On CUDA
|
||||||
uv pip install vllm==0.29.0 --torch-backend=auto
|
uv pip install vllm==0.28.0 --torch-backend=auto
|
||||||
|
|
||||||
# On ROCm
|
# On ROCm
|
||||||
uv pip install vllm==0.29.0+rocm723 --extra-index-url https://wheels.vllm.ai/rocm/0.29.0/rocm723
|
uv pip install vllm==0.28.0+rocm723 --extra-index-url https://wheels.vllm.ai/rocm/0.28.0/rocm723
|
||||||
|
|
||||||
git clone https://github.com/vllm-project/vllm-omni.git
|
git clone https://github.com/vllm-project/vllm-omni.git
|
||||||
cd vllm-omni
|
cd vllm-omni
|
||||||
@@ -34,7 +34,7 @@ For additional installation methods — please see the [installation guide](inst
|
|||||||
!!! note
|
!!! note
|
||||||
It is important to install the same major & minor version of vLLM and vLLM Omni, otherwise things may not work as expected. If the versions are misaligned, you will see a warning when you import vLLM Omni.
|
It is important to install the same major & minor version of vLLM and vLLM Omni, otherwise things may not work as expected. If the versions are misaligned, you will see a warning when you import vLLM Omni.
|
||||||
|
|
||||||
If you are seeing strange behavior with the `vllm` command not handling the `--omni` flag correctly, you most likely have a version mismatch with vLLM < `0.29.0` and vLLM Omni `0.29.0`, as vLLM Omni no longer hijacks the vLLM entrypoint. Updating vLLM should resolve this issue.
|
If you are seeing strange behavior with the `vllm` command not handling the `--omni` flag correctly, you most likely have a version mismatch with vLLM < `0.28.0` and vLLM Omni `0.28.0`, as vLLM Omni no longer hijacks the vLLM entrypoint. Updating vLLM should resolve this issue.
|
||||||
|
|
||||||
## Offline Inference
|
## Offline Inference
|
||||||
|
|
||||||
|
|||||||
@@ -22,13 +22,6 @@ CATEGORIES = {
|
|||||||
"name": "Entry Points",
|
"name": "Entry Points",
|
||||||
"description": "Main entry points for vLLM-Omni inference and serving.",
|
"description": "Main entry points for vLLM-Omni inference and serving.",
|
||||||
},
|
},
|
||||||
"clients": {
|
|
||||||
"name": "Clients",
|
|
||||||
"description": (
|
|
||||||
"Client libraries that talk to a running vLLM-Omni server "
|
|
||||||
"(the full-duplex Realtime client and its per-model session presets)."
|
|
||||||
),
|
|
||||||
},
|
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"name": "Inputs",
|
"name": "Inputs",
|
||||||
"description": "Input data structures for multi-modal inputs.",
|
"description": "Input data structures for multi-modal inputs.",
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ def extract_omni_serve_subparser_init():
|
|||||||
"make_arg_parser": lambda parser: parser, # no-op for doc
|
"make_arg_parser": lambda parser: parser, # no-op for doc
|
||||||
"_ensure_vllm_platform": lambda: None, # no-op for doc
|
"_ensure_vllm_platform": lambda: None, # no-op for doc
|
||||||
"_nonneg_finite_float": float,
|
"_nonneg_finite_float": float,
|
||||||
"_parse_stage_overrides": __import__("json").loads,
|
|
||||||
"VLLM_SUBCMD_PARSER_EPILOG": "",
|
"VLLM_SUBCMD_PARSER_EPILOG": "",
|
||||||
"logger": logger,
|
"logger": logger,
|
||||||
"DummySubparsers": DummySubparsers,
|
"DummySubparsers": DummySubparsers,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ th {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
| Architecture | Models | Example HF Models | NVIDIA GPU | AMD GPU | Ascend NPU | Intel GPU | Recipe |
|
| Architecture | Models | Example HF Models | NVIDIA GPU | AMD GPU | Ascend NPU | Intel GPU | Recipe |
|
||||||
| -------------- | -------- | ------------------- | ------------ | --------- | ----- | ----------- | -------- |
|
|--------------|--------|-------------------|------------|---------|-----|-----------|--------|
|
||||||
| `Qwen3OmniMoeForConditionalGeneration` | Qwen3-Omni | `Qwen/Qwen3-Omni-30B-A3B-Instruct` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/Qwen/Qwen3-Omni.md) |
|
| `Qwen3OmniMoeForConditionalGeneration` | Qwen3-Omni | `Qwen/Qwen3-Omni-30B-A3B-Instruct` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/Qwen/Qwen3-Omni.md) |
|
||||||
| `Qwen2_5OmniForConditionalGeneration` | Qwen2.5-Omni | `Qwen/Qwen2.5-Omni-7B`, `Qwen/Qwen2.5-Omni-3B` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
| `Qwen2_5OmniForConditionalGeneration` | Qwen2.5-Omni | `Qwen/Qwen2.5-Omni-7B`, `Qwen/Qwen2.5-Omni-3B` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
||||||
| `MingFlashOmniForConditionalGeneration` + `MingImagePipeline` | Ming-flash-omni-2.0 (omni-speech + imagegen<sup>1</sup>) | `Jonathan1909/Ming-flash-omni-2.0` | ✅︎ | | | | — |
|
| `MingFlashOmniForConditionalGeneration` + `MingImagePipeline` | Ming-flash-omni-2.0 (omni-speech + imagegen<sup>1</sup>) | `Jonathan1909/Ming-flash-omni-2.0` | ✅︎ | | | | — |
|
||||||
@@ -55,7 +55,6 @@ th {
|
|||||||
| `SanaVideoPipeline` | SANA-Video-2B T2V (native 480p/720p; Diffusers adapter validated at both resolutions) | `Efficient-Large-Model/SANA-Video_2B_480p_diffusers`, `Efficient-Large-Model/SANA-Video_2B_720p_diffusers` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/NVIDIA/SANA-Video-2B.md) |
|
| `SanaVideoPipeline` | SANA-Video-2B T2V (native 480p/720p; Diffusers adapter validated at both resolutions) | `Efficient-Large-Model/SANA-Video_2B_480p_diffusers`, `Efficient-Large-Model/SANA-Video_2B_720p_diffusers` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/NVIDIA/SANA-Video-2B.md) |
|
||||||
| `SanaImageToVideoPipeline` | SANA-Video-2B I2V (native and Diffusers adapter validated at 480p/720p) | `Efficient-Large-Model/SANA-Video_2B_480p_diffusers`, `Efficient-Large-Model/SANA-Video_2B_720p_diffusers` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/NVIDIA/SANA-Video-2B.md) |
|
| `SanaImageToVideoPipeline` | SANA-Video-2B I2V (native and Diffusers adapter validated at 480p/720p) | `Efficient-Large-Model/SANA-Video_2B_480p_diffusers`, `Efficient-Large-Model/SANA-Video_2B_720p_diffusers` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/NVIDIA/SANA-Video-2B.md) |
|
||||||
| `MiniMaxH3Pipeline` | MiniMax H3 T2VA, first/last-keyframe FL2VA, and mixed-reference Ref2VA | `MiniMaxAI/MiniMax-H3` | ✅︎ | ✅︎ | | | [Published](https://recipes.vllm.ai/MiniMaxAI/MiniMax-H3) |
|
| `MiniMaxH3Pipeline` | MiniMax H3 T2VA, first/last-keyframe FL2VA, and mixed-reference Ref2VA | `MiniMaxAI/MiniMax-H3` | ✅︎ | ✅︎ | | | [Published](https://recipes.vllm.ai/MiniMaxAI/MiniMax-H3) |
|
||||||
| `Magi2Pipeline` | MAGI-2 native Preview-stage T2VA and I2VA (272p/540p) | `sand-ai/MAGI-2-preview` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/SandAI/MAGI-2-preview-L20X.md) |
|
|
||||||
| `DreamZeroPipeline` | DreamZero-DROID | `GEAR-Dreams/DreamZero-DROID` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
| `DreamZeroPipeline` | DreamZero-DROID | `GEAR-Dreams/DreamZero-DROID` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
||||||
| `Pi0Pipeline` | π0 (Pi-Zero) VLA | `lerobot/pi0_base` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/lerobot/Pi0.md) |
|
| `Pi0Pipeline` | π0 (Pi-Zero) VLA | `lerobot/pi0_base` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/lerobot/Pi0.md) |
|
||||||
| `HeliosPipeline`, `HeliosPyramidPipeline` | Helios | `BestWishYsh/Helios-Base`, `BestWishYsh/Helios-Mid`, `BestWishYsh/Helios-Distilled` | ✅︎ | ✅︎ | ✅︎ | | — |
|
| `HeliosPipeline`, `HeliosPyramidPipeline` | Helios | `BestWishYsh/Helios-Base`, `BestWishYsh/Helios-Mid`, `BestWishYsh/Helios-Distilled` | ✅︎ | ✅︎ | ✅︎ | | — |
|
||||||
@@ -64,13 +63,12 @@ th {
|
|||||||
| `LongCatImageEditPipeline` | LongCat-Image-Edit | `meituan-longcat/LongCat-Image-Edit` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
| `LongCatImageEditPipeline` | LongCat-Image-Edit | `meituan-longcat/LongCat-Image-Edit` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
||||||
| `LongCatVideoAvatarPipeline` | LongCat-Video-Avatar-1.5 A2V/AI2V (native single-speaker and multi-speaker AI2V/AVC) | `meituan-longcat/LongCat-Video-Avatar-1.5` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/meituan-longcat/LongCat-Video-Avatar-1.5.md) |
|
| `LongCatVideoAvatarPipeline` | LongCat-Video-Avatar-1.5 A2V/AI2V (native single-speaker and multi-speaker AI2V/AVC) | `meituan-longcat/LongCat-Video-Avatar-1.5` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/meituan-longcat/LongCat-Video-Avatar-1.5.md) |
|
||||||
| `BooguImagePipeline` | Boogu-Image | `Boogu/Boogu-Image-0.1-Base`, `Boogu/Boogu-Image-0.1-Edit`, `Boogu/Boogu-Image-0.1-Edit-Turbo` | ✅︎ | | | ✅︎ | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/Boogu/Boogu-Image.md) |
|
| `BooguImagePipeline` | Boogu-Image | `Boogu/Boogu-Image-0.1-Base`, `Boogu/Boogu-Image-0.1-Edit`, `Boogu/Boogu-Image-0.1-Edit-Turbo` | ✅︎ | | | ✅︎ | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/Boogu/Boogu-Image.md) |
|
||||||
| `BooguImageTurboPipeline` | Boogu-Image Turbo distilled T2I | `Boogu/Boogu-Image-0.1-Turbo` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/Boogu/Boogu-Image.md) |
|
|
||||||
| `StableDiffusionXLPipeline` | Stable-Diffusion-XL | `stabilityai/stable-diffusion-xl-base-1.0` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
| `StableDiffusionXLPipeline` | Stable-Diffusion-XL | `stabilityai/stable-diffusion-xl-base-1.0` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
||||||
| `StableDiffusion3Pipeline` | Stable-Diffusion-3 | `stabilityai/stable-diffusion-3.5-medium` | ✅︎ | ✅︎ | | ✅︎ | — |
|
| `StableDiffusion3Pipeline` | Stable-Diffusion-3 | `stabilityai/stable-diffusion-3.5-medium` | ✅︎ | ✅︎ | | ✅︎ | — |
|
||||||
| `CosyVoice3Model` | CosyVoice3 | `FunAudioLLM/Fun-CosyVoice3-0.5B-2512` | ✅︎ | ✅︎ | | ✅︎ | — |
|
| `CosyVoice3Model` | CosyVoice3 | `FunAudioLLM/Fun-CosyVoice3-0.5B-2512` | ✅︎ | ✅︎ | | ✅︎ | — |
|
||||||
| `OmniVoiceModel` | OmniVoice | `k2-fsa/OmniVoice` | ✅︎ | | | ✅︎ | — |
|
| `OmniVoiceModel` | OmniVoice | `k2-fsa/OmniVoice` | ✅︎ | | | ✅︎ | — |
|
||||||
| `VoxCPM2TalkerForConditionalGeneration` | VoxCPM2 | `openbmb/VoxCPM2` | ✅︎ | | | ✅︎ | — |
|
| `VoxCPM2TalkerForConditionalGeneration` | VoxCPM2 | `openbmb/VoxCPM2` | ✅︎ | | | ✅︎ | — |
|
||||||
| `DotsTTSForConditionalGeneration` | dots.tts | `dots-studio/dots.tts-soar` | ✅︎ | | | | — |
|
| `DotsTTSForConditionalGeneration` | dots.tts | `rednote-hilab/dots.tts-soar` | ✅︎ | | | | — |
|
||||||
| `MammothModa2ForConditionalGeneration` | MammothModa2-Preview | `bytedance-research/MammothModa2-Preview` | ✅︎ | ✅︎ | | | — |
|
| `MammothModa2ForConditionalGeneration` | MammothModa2-Preview | `bytedance-research/MammothModa2-Preview` | ✅︎ | ✅︎ | | | — |
|
||||||
| `MammothModa2ForConditionalGeneration` | MammothModa2-Dev (AR-only image understanding) | `bytedance-research/MammothModa2-Dev` | ✅︎ | | | | — |
|
| `MammothModa2ForConditionalGeneration` | MammothModa2-Dev (AR-only image understanding) | `bytedance-research/MammothModa2-Dev` | ✅︎ | | | | — |
|
||||||
| `Flux2KleinPipeline` | FLUX.2-klein | `black-forest-labs/FLUX.2-klein-4B`, `black-forest-labs/FLUX.2-klein-9B` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
| `Flux2KleinPipeline` | FLUX.2-klein | `black-forest-labs/FLUX.2-klein-4B`, `black-forest-labs/FLUX.2-klein-9B` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
||||||
@@ -97,18 +95,17 @@ th {
|
|||||||
| `MiMoV2ASRForCausalLM` | MiMo-V2.5-ASR | `XiaomiMiMo/MiMo-V2.5-ASR` | ✅︎ | ✅︎ | | | — |
|
| `MiMoV2ASRForCausalLM` | MiMo-V2.5-ASR | `XiaomiMiMo/MiMo-V2.5-ASR` | ✅︎ | ✅︎ | | | — |
|
||||||
| `Flux2Pipeline` | FLUX.2-dev | `black-forest-labs/FLUX.2-dev` | ✅︎ | ✅︎ | | | — |
|
| `Flux2Pipeline` | FLUX.2-dev | `black-forest-labs/FLUX.2-dev` | ✅︎ | ✅︎ | | | — |
|
||||||
| `FishSpeechSlowARForConditionalGeneration` | Fish Speech S2 Pro | `fishaudio/s2-pro` | ✅︎ | ✅︎ | | ✅︎ | — |
|
| `FishSpeechSlowARForConditionalGeneration` | Fish Speech S2 Pro | `fishaudio/s2-pro` | ✅︎ | ✅︎ | | ✅︎ | — |
|
||||||
| `Audio8TTSSlowARForConditionalGeneration` | Audio8 TTS Preview | `Audio8/Audio8-TTS-Preview-0.6b` | ✅︎ | | | | — |
|
|
||||||
| `SenseNovaU1Pipeline` | SenseNova-U1 (DiT-only), SenseNova-U1.5 | `SenseNova/SenseNova-U1-8B-MoT`, `sensenova/SenseNova-U1.5-8B-MoT` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/SenseNova/SenseNova-U1.5.md) |
|
| `SenseNovaU1Pipeline` | SenseNova-U1 (DiT-only), SenseNova-U1.5 | `SenseNova/SenseNova-U1-8B-MoT`, `sensenova/SenseNova-U1.5-8B-MoT` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/SenseNova/SenseNova-U1.5.md) |
|
||||||
| `LancePipeline` | Lance | `bytedance-research/Lance` | ✅︎ | | | | — |
|
| `LancePipeline` | Lance | `bytedance-research/Lance` | ✅︎ | | | | — |
|
||||||
| `HunyuanVideo15Pipeline` | HunyuanVideo-1.5-T2V | `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-480p_t2v`, `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-720p_t2v` | ✅︎ | ✅︎ | | | — |
|
| `HunyuanVideo15Pipeline` | HunyuanVideo-1.5-T2V | `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-480p_t2v`, `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-720p_t2v` | ✅︎ | ✅︎ | | | — |
|
||||||
| `HunyuanVideo15ImageToVideoPipeline` | HunyuanVideo-1.5-I2V | `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-480p_i2v`, `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-720p_i2v` | ✅︎ | ✅︎ | | | — |
|
| `HunyuanVideo15ImageToVideoPipeline` | HunyuanVideo-1.5-I2V | `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-480p_i2v`, `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-720p_i2v` | ✅︎ | ✅︎ | | | — |
|
||||||
| `VoxtralTTSForConditionalGeneration` | Voxtral TTS | `mistralai/Voxtral-4B-TTS-2603` | ✅︎ | ✅︎ | | | — |
|
| `VoxtralTTSForConditionalGeneration` | Voxtral TTS | `mistralai/Voxtral-4B-TTS-2603` | ✅︎ | ✅︎ | | | — |
|
||||||
| `CovoAudioForConditionalGeneration` | Covo-Audio-Chat | `tencent/Covo-Audio-Chat` | ✅︎ | | | | — |
|
| `CovoAudioForConditionalGeneration` | Covo-Audio-Chat | `tencent/Covo-Audio-Chat` | ✅︎ | | | | — |
|
||||||
| `DyninOmniForConditionalGeneration` | Dynin-Omni | `snu-aidas/Dynin-Omni` | ✅︎ | | | ✅︎ | — |
|
|`DyninOmniForConditionalGeneration` | Dynin-Omni | `snu-aidas/Dynin-Omni` | ✅︎ | | | ✅︎ | — |
|
||||||
| `MiniCPMO45OmniForConditionalGeneration` | MiniCPM-o 4.5 | `openbmb/MiniCPM-o-4_5` | ✅︎ | | ✅︎ | | — |
|
| `MiniCPMO45OmniForConditionalGeneration` | MiniCPM-o 4.5 | `openbmb/MiniCPM-o-4_5` | ✅︎ | | ✅︎ | | — |
|
||||||
| `ErnieImagePipeline` | ERNIE-Image | `baidu/ERNIE-Image`, `baidu/ERNIE-Image-Turbo` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
| `ErnieImagePipeline` | ERNIE-Image | `baidu/ERNIE-Image`, `baidu/ERNIE-Image-Turbo` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — |
|
||||||
| `GepardTalkerForConditionalGeneration` | Gepard-1.0 | `nineninesix/gepard-1.0` | ✅︎ | | | ✅︎ | — |
|
| `GepardTalkerForConditionalGeneration` | Gepard-1.0 | `nineninesix/gepard-1.0` | ✅︎ | | | ✅︎ | — |
|
||||||
| `HiDreamImagePipeline` | HiDream-I1-Full | `HiDream-ai/HiDream-I1-Full` | ✅︎ | ✅︎ | | | — |
|
|`HiDreamImagePipeline` | HiDream-I1-Full | `HiDream-ai/HiDream-I1-Full` | ✅︎ | ✅︎ | | | — |
|
||||||
| `HiDreamO1ImagePipeline` | HiDream-O1-Image | `HiDream-ai/HiDream-O1-Image` | ✅︎ | | | | — |
|
| `HiDreamO1ImagePipeline` | HiDream-O1-Image | `HiDream-ai/HiDream-O1-Image` | ✅︎ | | | | — |
|
||||||
|
|
||||||
The `Recipe` column links the corresponding deployment recipe. `Published` is
|
The `Recipe` column links the corresponding deployment recipe. `Published` is
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ Completions for conversational or heterogeneous omni pipelines, rather than as
|
|||||||
the default wrapper for every generation task.
|
the default wrapper for every generation task.
|
||||||
|
|
||||||
| Task | Endpoint | Request | Response | Details |
|
| Task | Endpoint | Request | Response | Details |
|
||||||
| ------ | ---------- | --------- | ---------- | --------- |
|
|------|----------|---------|----------|---------|
|
||||||
| Conversation or multimodal understanding/generation | `POST /v1/chat/completions` | JSON | OpenAI-style JSON or SSE | [Chat Completions](chat_completions_api.md) |
|
| Conversation or multimodal understanding/generation | `POST /v1/chat/completions` | JSON | OpenAI-style JSON or SSE | [Chat Completions](chat_completions_api.md) |
|
||||||
| Text-to-speech | `POST /v1/audio/speech` | JSON | Audio bytes or SSE | [Speech](speech_api.md) |
|
| Text-to-speech | `POST /v1/audio/speech` | JSON | Audio bytes or SSE | [Speech](speech_api.md) |
|
||||||
| Sound, music, or ambient audio generation | `POST /v1/audio/generate` | JSON | Audio bytes | [Audio Generation](audio_generate_api.md) |
|
| Sound, music, or ambient audio generation | `POST /v1/audio/generate` | JSON | Audio bytes | [Audio Generation](audio_generate_api.md) |
|
||||||
@@ -141,7 +141,7 @@ These WebSocket APIs have different event schemas and cannot be used
|
|||||||
interchangeably.
|
interchangeably.
|
||||||
|
|
||||||
| Workload | Endpoint | Interaction model | Details |
|
| Workload | Endpoint | Interaction model | Details |
|
||||||
| ---------- | ---------- | ------------------- | --------- |
|
|----------|----------|-------------------|---------|
|
||||||
| Incremental text input for speech synthesis | `WS /v1/audio/speech/stream` | Send text events and receive audio | [Streaming Text to Speech](speech_api.md#streaming-text-input-websocket) |
|
| Incremental text input for speech synthesis | `WS /v1/audio/speech/stream` | Send text events and receive audio | [Streaming Text to Speech](speech_api.md#streaming-text-input-websocket) |
|
||||||
| Live video understanding | `WS /v1/video/chat/stream` | Send video frames and receive text/audio | [Streaming Video Input](video_stream_api.md) |
|
| Live video understanding | `WS /v1/video/chat/stream` | Send video frames and receive text/audio | [Streaming Video Input](video_stream_api.md) |
|
||||||
| Turn-based realtime audio | `WS /v1/realtime` | Stream one audio input and receive transcript/audio events | [Realtime Audio](realtime_api.md) |
|
| Turn-based realtime audio | `WS /v1/realtime` | Stream one audio input and receive transcript/audio events | [Realtime Audio](realtime_api.md) |
|
||||||
@@ -158,7 +158,7 @@ ordinary realtime handler when duplex is unavailable.
|
|||||||
## Related Endpoints
|
## Related Endpoints
|
||||||
|
|
||||||
| Purpose | Endpoints | Reference |
|
| Purpose | Endpoints | Reference |
|
||||||
| --------- | ----------- | ----------- |
|
|---------|-----------|-----------|
|
||||||
| Discovery and readiness | `GET /health`, `GET /v1/models` | This page |
|
| Discovery and readiness | `GET /health`, `GET /v1/models` | This page |
|
||||||
| Batched conversations | `POST /v1/chat/completions/batch` | [Batch requests](chat_completions_api.md#batch-requests) |
|
| Batched conversations | `POST /v1/chat/completions/batch` | [Batch requests](chat_completions_api.md#batch-requests) |
|
||||||
| Batched speech | `POST /v1/audio/speech/batch` | [Batch speech generation](speech_api.md#batch-speech-generation) |
|
| Batched speech | `POST /v1/audio/speech/batch` | [Batch speech generation](speech_api.md#batch-speech-generation) |
|
||||||
@@ -168,10 +168,11 @@ ordinary realtime handler when duplex is unavailable.
|
|||||||
|
|
||||||
## Standalone Experimental Servers
|
## Standalone Experimental Servers
|
||||||
|
|
||||||
JoyVL provides a stateful interaction orchestrator in front of another model
|
PersonaPlex also provides a Moshi-compatible WebSocket server, while JoyVL
|
||||||
server. It is a separate process with its own routes; they are not additional
|
provides a stateful interaction orchestrator in front of another model server.
|
||||||
|
These are separate processes with their own routes; they are not additional
|
||||||
paths on every `vllm serve --omni` instance. See [Standalone Experimental
|
paths on every `vllm serve --omni` instance. See [Standalone Experimental
|
||||||
Servers](standalone_servers.md) before deploying it.
|
Servers](standalone_servers.md) before deploying either one.
|
||||||
|
|
||||||
## Compatibility Notes
|
## Compatibility Notes
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ with open("cat.wav", "wb") as f:
|
|||||||
|
|
||||||
### Endpoint
|
### Endpoint
|
||||||
|
|
||||||
```text
|
```
|
||||||
POST /v1/audio/generate
|
POST /v1/audio/generate
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
@@ -63,7 +63,7 @@ Content-Type: application/json
|
|||||||
### Request Parameters
|
### Request Parameters
|
||||||
|
|
||||||
| Parameter | Type | Default | Description |
|
| Parameter | Type | Default | Description |
|
||||||
| ----------- | ------ | --------- | ------------- |
|
|-----------|------|---------|-------------|
|
||||||
| `input` | string | **required** | Text prompt describing the audio to generate |
|
| `input` | string | **required** | Text prompt describing the audio to generate |
|
||||||
| `model` | string | server's model | Model to use (optional, should match server if specified) |
|
| `model` | string | server's model | Model to use (optional, should match server if specified) |
|
||||||
| `response_format` | string | "wav" | Audio format: wav, mp3, flac, pcm, opus |
|
| `response_format` | string | "wav" | Audio format: wav, mp3, flac, pcm, opus |
|
||||||
@@ -72,7 +72,7 @@ Content-Type: application/json
|
|||||||
#### Diffusion Parameters
|
#### Diffusion Parameters
|
||||||
|
|
||||||
| Parameter | Type | Default | Description |
|
| Parameter | Type | Default | Description |
|
||||||
| ----------- | ------ | --------- | ------------- |
|
|-----------|------|---------|-------------|
|
||||||
| `audio_length` | float | null | Audio duration in seconds (default value is the max ~47s for `stable-audio-open-1.0`) |
|
| `audio_length` | float | null | Audio duration in seconds (default value is the max ~47s for `stable-audio-open-1.0`) |
|
||||||
| `audio_start` | float | 0.0 | Audio start time in seconds |
|
| `audio_start` | float | 0.0 | Audio start time in seconds |
|
||||||
| `negative_prompt` | string | null | Text describing what to avoid in generation |
|
| `negative_prompt` | string | null | Text describing what to avoid in generation |
|
||||||
@@ -85,7 +85,7 @@ Content-Type: application/json
|
|||||||
Returns binary audio data with the appropriate `Content-Type` header:
|
Returns binary audio data with the appropriate `Content-Type` header:
|
||||||
|
|
||||||
| `response_format` | Content-Type |
|
| `response_format` | Content-Type |
|
||||||
| -------------------- | -------------- |
|
|--------------------|--------------|
|
||||||
| `wav` | `audio/wav` |
|
| `wav` | `audio/wav` |
|
||||||
| `mp3` | `audio/mpeg` |
|
| `mp3` | `audio/mpeg` |
|
||||||
| `flac` | `audio/flac` |
|
| `flac` | `audio/flac` |
|
||||||
@@ -210,7 +210,7 @@ with open("thunder.wav", "wb") as f:
|
|||||||
Controls how closely the generated audio follows the text prompt.
|
Controls how closely the generated audio follows the text prompt.
|
||||||
|
|
||||||
| Range | Behaviour |
|
| Range | Behaviour |
|
||||||
| ------- | ----------- |
|
|-------|-----------|
|
||||||
| 3 - 5 | More creative / varied output |
|
| 3 - 5 | More creative / varied output |
|
||||||
| 7 (default) | Balanced adherence |
|
| 7 (default) | Balanced adherence |
|
||||||
| 10+ | Strict adherence to the prompt |
|
| 10+ | Strict adherence to the prompt |
|
||||||
@@ -220,7 +220,7 @@ Controls how closely the generated audio follows the text prompt.
|
|||||||
Controls the number of denoising steps in the diffusion process.
|
Controls the number of denoising steps in the diffusion process.
|
||||||
|
|
||||||
| Steps | Quality | Speed | Use Case |
|
| Steps | Quality | Speed | Use Case |
|
||||||
| ------- | --------- | ------- | ---------- |
|
|-------|---------|-------|----------|
|
||||||
| 50 | Good | Fast | Quick previews |
|
| 50 | Good | Fast | Quick previews |
|
||||||
| 100 | Very Good | Medium | General purpose |
|
| 100 | Very Good | Medium | General purpose |
|
||||||
| 150+ | Excellent | Slow | Final / critical audio |
|
| 150+ | Excellent | Slow | Final / critical audio |
|
||||||
@@ -240,7 +240,7 @@ Describes characteristics to avoid. Common negative prompts include:
|
|||||||
## Supported Models
|
## Supported Models
|
||||||
|
|
||||||
| Model | Description |
|
| Model | Description |
|
||||||
| ----- | ----------- |
|
|-------|-------------|
|
||||||
| `stabilityai/stable-audio-open-1.0` | Open-source audio generation model, up to ~47 seconds, 44.1 kHz stereo |
|
| `stabilityai/stable-audio-open-1.0` | Open-source audio generation model, up to ~47 seconds, 44.1 kHz stereo |
|
||||||
|
|
||||||
## Error Responses
|
## Error Responses
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
# Full-Duplex WebSocket API
|
# Full-Duplex WebSocket API
|
||||||
|
|
||||||
vLLM-Omni provides a full-duplex runtime for models that can
|
vLLM-Omni provides an experimental full-duplex runtime for models that can
|
||||||
continue receiving speech while producing speech. It adds persistent session
|
continue receiving speech while producing speech. It adds persistent session
|
||||||
state, model-specific turn policy, overlap handling, playback acknowledgement,
|
state, model-specific turn policy, overlap handling, playback acknowledgement,
|
||||||
and optional session resume.
|
and optional session resume.
|
||||||
|
|
||||||
Full duplex is distinct from the turn-based [Realtime Audio API](realtime_api.md).
|
Full duplex is distinct from the turn-based [Realtime Audio API](realtime_api.md).
|
||||||
|
|
||||||
This page is the endpoint overview. For the complete wire contract, the
|
|
||||||
`vllm_omni.clients.duplex.DuplexClient` Python library, and the per-model
|
|
||||||
capability gates, see the [Realtime Duplex API guide](realtime_duplex_api.md).
|
|
||||||
|
|
||||||
## Choose an Endpoint
|
## Choose an Endpoint
|
||||||
|
|
||||||
| Endpoint | Protocol | Recommended use |
|
| Endpoint | Protocol | Recommended use |
|
||||||
| --- | --- | --- |
|
|----------|----------|-----------------|
|
||||||
| `WS /v1/realtime?duplex=1` | OpenAI Realtime-style event projection | Applications and browser clients |
|
| `WS /v1/realtime?duplex=1` | OpenAI Realtime-style event projection | Applications and browser clients |
|
||||||
| `WS /v1/duplex` | Native vLLM-Omni duplex events | Runtime integration and low-level testing |
|
| `WS /v1/duplex` | Native vLLM-Omni duplex events | Runtime integration and low-level testing |
|
||||||
|
|
||||||
@@ -45,10 +41,8 @@ and control plane as part of their registered pipeline.
|
|||||||
|
|
||||||
The current unified-runtime integrations are:
|
The current unified-runtime integrations are:
|
||||||
|
|
||||||
- MiniCPM-o 4.5, using `vllm_omni/deploy/minicpmo_4_5.yaml`
|
- MiniCPM-o 4.5, using `vllm_omni/deploy/minicpmo_4_5_duplex.yaml`;
|
||||||
(`session_mode: duplex`);
|
- PersonaPlex, whose default `vllm_omni/deploy/personaplex.yaml` enables duplex.
|
||||||
- PersonaPlex, whose default `vllm_omni/deploy/personaplex.yaml` enables duplex;
|
|
||||||
- Nemotron VoiceChat, via its registered duplex plugin package.
|
|
||||||
|
|
||||||
JoyVL is a separate HTTP interaction orchestrator and does not use these
|
JoyVL is a separate HTTP interaction orchestrator and does not use these
|
||||||
WebSocket endpoints. See [Standalone Experimental Servers](standalone_servers.md).
|
WebSocket endpoints. See [Standalone Experimental Servers](standalone_servers.md).
|
||||||
@@ -59,7 +53,7 @@ Start the duplex deployment:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
vllm serve openbmb/MiniCPM-o-4_5 --omni \
|
vllm serve openbmb/MiniCPM-o-4_5 --omni \
|
||||||
--deploy-config vllm_omni/deploy/minicpmo_4_5.yaml \
|
--deploy-config vllm_omni/deploy/minicpmo_4_5_duplex.yaml \
|
||||||
--trust-remote-code \
|
--trust-remote-code \
|
||||||
--port 8091
|
--port 8091
|
||||||
```
|
```
|
||||||
@@ -118,5 +112,5 @@ applications should use the provided Realtime client where possible.
|
|||||||
|
|
||||||
See the [MiniCPM-o example](https://github.com/vllm-project/vllm-omni/tree/main/examples/online_serving/minicpmo),
|
See the [MiniCPM-o example](https://github.com/vllm-project/vllm-omni/tree/main/examples/online_serving/minicpmo),
|
||||||
[PersonaPlex example](https://github.com/vllm-project/vllm-omni/tree/main/examples/online_serving/personaplex),
|
[PersonaPlex example](https://github.com/vllm-project/vllm-omni/tree/main/examples/online_serving/personaplex),
|
||||||
and the [full-duplex runtime design](../design/fullduplex.md)
|
and [full-duplex runtime design](https://github.com/vllm-project/vllm-omni/blob/main/vllm_omni/experimental/fullduplex/DESIGN.md)
|
||||||
for model-specific validation and architecture details.
|
for model-specific validation and architecture details.
|
||||||
@@ -30,6 +30,7 @@ curl -s -D >(grep -i x-request-id >&2) \
|
|||||||
-F "output_format=png"
|
-F "output_format=png"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
**Using OpenAI SDK:**
|
**Using OpenAI SDK:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -71,7 +72,7 @@ with open("edit_out_http.jpeg", "wb") as f:
|
|||||||
|
|
||||||
### Endpoint
|
### Endpoint
|
||||||
|
|
||||||
```text
|
```
|
||||||
POST /v1/images/edits
|
POST /v1/images/edits
|
||||||
Content-Type: multipart/form-data
|
Content-Type: multipart/form-data
|
||||||
```
|
```
|
||||||
@@ -81,7 +82,7 @@ Content-Type: multipart/form-data
|
|||||||
#### OpenAI Standard Parameters
|
#### OpenAI Standard Parameters
|
||||||
|
|
||||||
| Parameter | Type | Default | Description |
|
| Parameter | Type | Default | Description |
|
||||||
| ----------- | ------ | --------- | ------------- |
|
|-----------|------|---------|-------------|
|
||||||
| `prompt` | string | **required** | A text description of the desired image |
|
| `prompt` | string | **required** | A text description of the desired image |
|
||||||
| `model` | string | server's model | Model to use (optional, should match server if specified) |
|
| `model` | string | server's model | Model to use (optional, should match server if specified) |
|
||||||
| `image` | string or array | **required** | The image(s) to edit. |
|
| `image` | string or array | **required** | The image(s) to edit. |
|
||||||
@@ -97,7 +98,7 @@ Content-Type: multipart/form-data
|
|||||||
#### vllm-omni Extension Parameters
|
#### vllm-omni Extension Parameters
|
||||||
|
|
||||||
| Parameter | Type | Default | Description |
|
| Parameter | Type | Default | Description |
|
||||||
| ----------- | ------ | --------- | ------------- |
|
|-----------|------|---------|-------------|
|
||||||
| `url` | string or array | None | The image(s) to edit. |
|
| `url` | string or array | None | The image(s) to edit. |
|
||||||
| `negative_prompt` | string | null | Text describing what to avoid in the image |
|
| `negative_prompt` | string | null | Text describing what to avoid in the image |
|
||||||
| `num_inference_steps` | integer | model defaults | Number of diffusion steps |
|
| `num_inference_steps` | integer | model defaults | Number of diffusion steps |
|
||||||
@@ -211,6 +212,7 @@ Use the `ar_delta` events for progressive display of the AR-generated
|
|||||||
recaption. Decode the `b64_json` field from the final `image` event to get the
|
recaption. Decode the `b64_json` field from the final `image` event to get the
|
||||||
edited image.
|
edited image.
|
||||||
|
|
||||||
|
|
||||||
## Parameter Handling
|
## Parameter Handling
|
||||||
|
|
||||||
The API passes parameters directly to the diffusion pipeline without model-specific transformation:
|
The API passes parameters directly to the diffusion pipeline without model-specific transformation:
|
||||||
@@ -264,7 +266,6 @@ curl http://localhost:8000/v1/images/edits \
|
|||||||
### Out of Memory
|
### Out of Memory
|
||||||
|
|
||||||
If you encounter OOM errors:
|
If you encounter OOM errors:
|
||||||
|
|
||||||
1. Reduce image size: `"size": "512x512"`
|
1. Reduce image size: `"size": "512x512"`
|
||||||
2. Reduce inference steps: `"num_inference_steps": 25`
|
2. Reduce inference steps: `"num_inference_steps": 25`
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ curl -o dragon.png -X POST http://localhost:8000/v1/images/generations \
|
|||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
**Using Python:**
|
**Using Python:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -122,7 +123,7 @@ response = client.images.generate(
|
|||||||
|
|
||||||
### Endpoint
|
### Endpoint
|
||||||
|
|
||||||
```text
|
```
|
||||||
POST /v1/images/generations
|
POST /v1/images/generations
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
@@ -132,7 +133,7 @@ Content-Type: application/json
|
|||||||
#### OpenAI Standard Parameters
|
#### OpenAI Standard Parameters
|
||||||
|
|
||||||
| Parameter | Type | Default | Description |
|
| Parameter | Type | Default | Description |
|
||||||
| ----------- | ------ | --------- | ------------- |
|
|-----------|------|---------|-------------|
|
||||||
| `prompt` | string | **required** | Text description of the desired image |
|
| `prompt` | string | **required** | Text description of the desired image |
|
||||||
| `model` | string | server's model | Model to use (optional, should match server if specified) |
|
| `model` | string | server's model | Model to use (optional, should match server if specified) |
|
||||||
| `n` | integer | 1 | Number of images to generate (1-10) |
|
| `n` | integer | 1 | Number of images to generate (1-10) |
|
||||||
@@ -143,7 +144,7 @@ Content-Type: application/json
|
|||||||
#### vllm-omni Extension Parameters
|
#### vllm-omni Extension Parameters
|
||||||
|
|
||||||
| Parameter | Type | Default | Description |
|
| Parameter | Type | Default | Description |
|
||||||
| ----------- | ------ | --------- | ------------- |
|
|-----------|------|---------|-------------|
|
||||||
| `negative_prompt` | string | null | Text describing what to avoid in the image |
|
| `negative_prompt` | string | null | Text describing what to avoid in the image |
|
||||||
| `num_inference_steps` | integer | model defaults | Number of diffusion steps |
|
| `num_inference_steps` | integer | model defaults | Number of diffusion steps |
|
||||||
| `guidance_scale` | float | model defaults | Classifier-free guidance scale (typically 0.0-20.0) |
|
| `guidance_scale` | float | model defaults | Classifier-free guidance scale (typically 0.0-20.0) |
|
||||||
@@ -266,7 +267,6 @@ curl http://localhost:8000/v1/images/generations \
|
|||||||
### Out of Memory
|
### Out of Memory
|
||||||
|
|
||||||
If you encounter OOM errors:
|
If you encounter OOM errors:
|
||||||
|
|
||||||
1. Reduce image size: `"size": "512x512"`
|
1. Reduce image size: `"size": "512x512"`
|
||||||
2. Reduce inference steps: `"num_inference_steps": 25`
|
2. Reduce inference steps: `"num_inference_steps": 25`
|
||||||
3. Generate fewer images: `"n": 1`
|
3. Generate fewer images: `"n": 1`
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ connect
|
|||||||
<- msgpack(policy_server_config)
|
<- msgpack(policy_server_config)
|
||||||
|
|
||||||
infer
|
infer
|
||||||
-> msgpack({"endpoint": "infer", "session_id": "...", "seed": <optional int>, ...observation})
|
-> msgpack({"endpoint": "infer", "session_id": "...", ...observation})
|
||||||
<- msgpack(ndarray | dict[str, ndarray])
|
<- msgpack(ndarray | dict[str, ndarray])
|
||||||
|
|
||||||
reset
|
reset
|
||||||
@@ -92,12 +92,6 @@ frames are not observation messages.
|
|||||||
- The policy pipeline owns observation transforms and persistent model state,
|
- The policy pipeline owns observation transforms and persistent model state,
|
||||||
normally keyed by `session_id`; the API layer forwards the raw observation
|
normally keyed by `session_id`; the API layer forwards the raw observation
|
||||||
dictionary.
|
dictionary.
|
||||||
- An optional integer `seed` in an inference message becomes the engine
|
|
||||||
request's `sampling_params.seed`. A policy whose sampling consumes the
|
|
||||||
request generator (GR00T-N1.7) returns the same action chunk for the same
|
|
||||||
observation and seed. If omitted, the engine assigns a random per-request
|
|
||||||
seed, so unseeded inferences are independent of each other. The API layer
|
|
||||||
consumes `seed`; it is not forwarded inside the observation.
|
|
||||||
|
|
||||||
## Limits and Errors
|
## Limits and Errors
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ receive incremental transcription and synthesized response audio. This is a
|
|||||||
turn-based streaming API: it starts one generation over an audio stream and
|
turn-based streaming API: it starts one generation over an audio stream and
|
||||||
finishes after the client closes that input stream.
|
finishes after the client closes that input stream.
|
||||||
|
|
||||||
For a model that listens while it is already speaking, use the
|
For a model that listens while it is already speaking, use the experimental
|
||||||
[Full-Duplex API](full_duplex_api.md) instead.
|
[Full-Duplex API](full_duplex_api.md) instead.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
@@ -35,7 +35,7 @@ Messages in both directions are JSON text frames. Audio carried inside an
|
|||||||
event is base64-encoded raw PCM16.
|
event is base64-encoded raw PCM16.
|
||||||
|
|
||||||
| Direction | Event | Purpose |
|
| Direction | Event | Purpose |
|
||||||
| ----------- | ------- | --------- |
|
|-----------|-------|---------|
|
||||||
| Server to client | `session.created` | Confirms that the WebSocket connection is ready |
|
| Server to client | `session.created` | Confirms that the WebSocket connection is ready |
|
||||||
| Client to server | `session.update` | Selects and validates the served model |
|
| Client to server | `session.update` | Selects and validates the served model |
|
||||||
| Client to server | `input_audio_buffer.commit` with `final: false` | Starts generation over the incoming stream |
|
| Client to server | `input_audio_buffer.commit` with `final: false` | Starts generation over the incoming stream |
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
+12
-31
@@ -279,15 +279,10 @@ curl -X POST http://localhost:8091/v1/audio/voices \
|
|||||||
|
|
||||||
## Streaming Text Input (WebSocket)
|
## Streaming Text Input (WebSocket)
|
||||||
|
|
||||||
The `/v1/audio/speech/stream` WebSocket endpoint accepts text incrementally.
|
The `/v1/audio/speech/stream` WebSocket endpoint accepts text incrementally and generates audio per sentence as boundaries are detected.
|
||||||
By default (`split_granularity=none`) it buffers until `input.done` and
|
|
||||||
synthesizes that flush as **one** TTS request, which keeps long-form timbre
|
|
||||||
stable. Set `split_granularity` to `sentence` or `clause` to emit a request
|
|
||||||
at each detected boundary (lower time-to-first-audio for STT/LLM pipelines).
|
|
||||||
|
|
||||||
> Note: `stream_audio` only changes how **audio bytes** are framed (one WAV/PCM
|
> Note: text input is always streamed incrementally. Audio output remains sentence-scoped:
|
||||||
> payload vs chunked PCM). Text segmentation is controlled separately by
|
> use `stream_audio=false` for one binary frame per sentence, or `stream_audio=true` for one or more PCM chunks per sentence.
|
||||||
> `split_granularity`.
|
|
||||||
|
|
||||||
### WebSocket Protocol
|
### WebSocket Protocol
|
||||||
|
|
||||||
@@ -319,16 +314,14 @@ upstream LLM) pays the WebSocket handshake once instead of once per utterance.
|
|||||||
|
|
||||||
- The session config is sticky. Send `input.text` again straight after
|
- The session config is sticky. Send `input.text` again straight after
|
||||||
`session.done` to reuse it, or send another `session.config` first to change
|
`session.done` to reuse it, or send another `session.config` first to change
|
||||||
voice, format, or reference audio. A `session.config` sent in the middle of
|
voice, format, or reference audio. A `session.config` sent while text is
|
||||||
an utterance is rejected so no pending input is silently dropped and so a
|
still buffered is rejected so no pending input is silently dropped.
|
||||||
split utterance cannot end up half in one voice and half in another.
|
- An utterance is the flush unit, not a linguistic one: it is whatever text was
|
||||||
- An utterance is the flush unit, not a linguistic one: it is one `input.done`
|
buffered when `input.done` arrived, of any length, synthesized as one request.
|
||||||
cycle. `utterance_index` counts those flushes across the connection, so it
|
`utterance_index` counts those flushes across the connection, so it tells you
|
||||||
tells you which `input.done` a frame belongs to. `sentence_index` counts the
|
which `input.done` a frame belongs to. `sentence_index` counts within one
|
||||||
TTS requests inside one flush and so pairs with `total_sentences`: with the
|
flush and so pairs with `total_sentences`, which means every utterance reports
|
||||||
default `split_granularity=none` that is always `sentence_index: 0` of
|
`sentence_index: 0` of `total_sentences: 1` (or `0` for an empty buffer).
|
||||||
`total_sentences: 1` (or `0` for an empty buffer), while `sentence` or
|
|
||||||
`clause` counts the linguistic units actually synthesized.
|
|
||||||
- End the connection with `session.close`, or by closing the socket. An idle
|
- End the connection with `session.close`, or by closing the socket. An idle
|
||||||
connection is still closed after the server's idle timeout, which now also
|
connection is still closed after the server's idle timeout, which now also
|
||||||
applies to the gap between utterances.
|
applies to the gap between utterances.
|
||||||
@@ -339,15 +332,7 @@ All REST API parameters are supported, plus:
|
|||||||
|
|
||||||
| Parameter | Type | Default | Description |
|
| Parameter | Type | Default | Description |
|
||||||
| ----------- | ------ | --------- | ------------- |
|
| ----------- | ------ | --------- | ------------- |
|
||||||
| `stream_audio` | bool | false | Stream one or more PCM chunks for each TTS request over WebSocket |
|
| `stream_audio` | bool | false | Stream one or more PCM chunks for the buffered input over WebSocket |
|
||||||
| `split_granularity` | string | `"none"` | `"none"`: one request per `input.done`. `"sentence"`: split on `.!?` plus CJK `。!?…`, Indic danda `।॥`, and Arabic `؟`. `"clause"`: also split on `,;,;،؛`. |
|
|
||||||
| `seed` | integer | null | Forwarded to the speech engine for this session |
|
|
||||||
|
|
||||||
ASCII punctuation only ends a unit when whitespace or `input.done` follows it,
|
|
||||||
and decimals (`3.14`), thousands separators (`1,000`), abbreviations (`Dr.`,
|
|
||||||
`e.g.`) and initials (`J. R.`) are not treated as boundaries. A punctuation run
|
|
||||||
and any closing quote or bracket stay with the unit they close, so `Wait...`
|
|
||||||
and `He said "Hello."` are one request each.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DELETE /v1/audio/voices/{name}
|
DELETE /v1/audio/voices/{name}
|
||||||
@@ -767,10 +752,6 @@ Fish Speech uses `ref_audio` and `ref_text` for voice cloning (no `task_type` ne
|
|||||||
| ------- | ------------- |
|
| ------- | ------------- |
|
||||||
| `k2-fsa/OmniVoice` | Pure-diffusion TTS. Supports voice cloning via `ref_audio` (with optional `ref_text`); no built-in voice presets. |
|
| `k2-fsa/OmniVoice` | Pure-diffusion TTS. Supports voice cloning via `ref_audio` (with optional `ref_text`); no built-in voice presets. |
|
||||||
|
|
||||||
OmniVoice uses packed variable-length attention for batched generator execution. The attention operator accepts FP16 and BF16 inputs, so its query,
|
|
||||||
key, and value tensors are evaluated in BF16 even when the stage is configured with `dtype: float32`; the attention output is converted back to the model's
|
|
||||||
hidden-state dtype before the output projection. Consequently, a float32 stage configuration does not imply FP32 attention arithmetic.
|
|
||||||
|
|
||||||
### VoxCPM2
|
### VoxCPM2
|
||||||
|
|
||||||
| Model | Description |
|
| Model | Description |
|
||||||
|
|||||||
@@ -1,19 +1,61 @@
|
|||||||
# Standalone Experimental Servers
|
# Standalone Experimental Servers
|
||||||
|
|
||||||
Most vLLM-Omni endpoints run on the unified server started with
|
Most vLLM-Omni endpoints run on the unified server started with
|
||||||
`vllm serve <model> --omni`. The experimental package also contains one
|
`vllm serve <model> --omni`. The experimental full-duplex package also contains
|
||||||
separate user-facing server process; its routes are not added to the unified
|
two separate user-facing server processes. Their routes are not added to the
|
||||||
API server.
|
unified API server.
|
||||||
|
|
||||||
| Server | Transport | Role |
|
| Server | Transport | Role |
|
||||||
| --- | --- | --- |
|
|--------|-----------|------|
|
||||||
|
| PersonaPlex compatibility server | WebSocket | Hosts the official PersonaPlex browser protocol and a raw-PCM alternative |
|
||||||
| JoyVL interaction server | HTTP | Adds state, memory, proactive decisions, and delegation in front of a separate OpenAI-compatible model backend |
|
| JoyVL interaction server | HTTP | Adds state, memory, proactive decisions, and delegation in front of a separate OpenAI-compatible model backend |
|
||||||
|
|
||||||
PersonaPlex no longer ships a standalone compatibility server: it is served
|
## PersonaPlex Compatibility Server
|
||||||
through the unified duplex path (`vllm_omni/deploy/personaplex.yaml`) over
|
|
||||||
[`WS /v1/realtime?duplex=1`](full_duplex_api.md); see the
|
Use this server when a client requires the official Moshi/PersonaPlex wire
|
||||||
[PersonaPlex example](https://github.com/vllm-project/vllm-omni/tree/main/examples/online_serving/personaplex)
|
protocol or the bundled browser UI. For the engine-owned unified duplex path,
|
||||||
for its clients.
|
use [`WS /v1/realtime?duplex=1`](full_duplex_api.md) instead.
|
||||||
|
|
||||||
|
Start it with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
HF_TOKEN=... CUDA_VISIBLE_DEVICES=0 python -m \
|
||||||
|
vllm_omni.experimental.fullduplex.personaplex.serving.server \
|
||||||
|
--port 8091
|
||||||
|
```
|
||||||
|
|
||||||
|
| Route | Purpose |
|
||||||
|
|-------|---------|
|
||||||
|
| `GET /` | Official PersonaPlex browser client, when its assets are available |
|
||||||
|
| `GET /health` | Readiness check |
|
||||||
|
| `WS /api/chat` | Moshi-compatible tagged binary protocol with Opus audio |
|
||||||
|
| `WS /v1/audio/duplex` | Simpler float32 raw-PCM protocol |
|
||||||
|
|
||||||
|
### `/api/chat` Protocol
|
||||||
|
|
||||||
|
The first byte of every binary frame is a message tag:
|
||||||
|
|
||||||
|
| Direction | Tag | Payload |
|
||||||
|
|-----------|-----|---------|
|
||||||
|
| Server to client | `0x00` | Ready handshake |
|
||||||
|
| Client to server | `0x01` | Opus microphone audio at 24 kHz |
|
||||||
|
| Server to client | `0x01` | Opus response audio |
|
||||||
|
| Server to client | `0x02` | UTF-8 inner-monologue text |
|
||||||
|
|
||||||
|
The optional `text_prompt` and `voice_prompt` query parameters select a persona
|
||||||
|
and voice. The default server admits one conversation; use `--batch-size N` to
|
||||||
|
configure multiple lockstep slots. Connections beyond capacity close with
|
||||||
|
WebSocket code 1013.
|
||||||
|
|
||||||
|
### `/v1/audio/duplex` Protocol
|
||||||
|
|
||||||
|
Send `{"type":"open","persona":"...","voice":"..."}` as a JSON text frame,
|
||||||
|
then exchange binary float32 PCM frames. The server returns generated float32
|
||||||
|
audio as binary frames and text as `{"type":"text","text":"..."}`. Send
|
||||||
|
`{"type":"close"}` and wait for `{"type":"done"}` to flush and finish.
|
||||||
|
|
||||||
|
See the [PersonaPlex example](https://github.com/vllm-project/vllm-omni/tree/main/examples/online_serving/personaplex)
|
||||||
|
for the browser and headless clients.
|
||||||
|
|
||||||
## JoyVL Interaction Server
|
## JoyVL Interaction Server
|
||||||
|
|
||||||
@@ -38,7 +80,7 @@ python -m vllm_omni.experimental.fullduplex.joyvl.serving.server \
|
|||||||
```
|
```
|
||||||
|
|
||||||
| Method and route | Purpose |
|
| Method and route | Purpose |
|
||||||
| ------------------ | --------- |
|
|------------------|---------|
|
||||||
| `GET /health` | Readiness check |
|
| `GET /health` | Readiness check |
|
||||||
| `GET /v1/models` | Reports the configured interaction model |
|
| `GET /v1/models` | Reports the configured interaction model |
|
||||||
| `POST /v1/chat/completions` | Processes one frame or interaction tick |
|
| `POST /v1/chat/completions` | Processes one frame or interaction tick |
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ immediately followed by one binary WebSocket frame containing fragmented MP4
|
|||||||
bytes.
|
bytes.
|
||||||
|
|
||||||
| Direction | Event or frame | Purpose |
|
| Direction | Event or frame | Purpose |
|
||||||
| ----------- | ---------------- | --------- |
|
|-----------|----------------|---------|
|
||||||
| Client to server | `session.start` | Starts generation with a prompt and video parameters |
|
| Client to server | `session.start` | Starts generation with a prompt and video parameters |
|
||||||
| Server to client | `video.start` | Confirms the request ID, format, and accepted configuration |
|
| Server to client | `video.start` | Confirms the request ID, format, and accepted configuration |
|
||||||
| Server to client | `video.chunk_metadata` | Describes the next binary media frame |
|
| Server to client | `video.chunk_metadata` | Describes the next binary media frame |
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ WebSocket /v1/video/chat/stream
|
|||||||
### Protocol
|
### Protocol
|
||||||
|
|
||||||
| Direction | Type | Required fields | Description |
|
| Direction | Type | Required fields | Description |
|
||||||
| ----------- | ------ | ----------------- | ------------- |
|
|-----------|------|-----------------|-------------|
|
||||||
| Client -> Server | `session.config` | none | First message. Configures output modalities, frame sampling, EVS, and prompts. |
|
| Client -> Server | `session.config` | none | First message. Configures output modalities, frame sampling, EVS, and prompts. |
|
||||||
| Client -> Server | `video.frame` | `data` | Base64 JPEG/PNG frame. |
|
| Client -> Server | `video.frame` | `data` | Base64 JPEG/PNG frame. |
|
||||||
| Client -> Server | `audio.chunk` | `data` | Base64 PCM16 16 kHz mono audio bytes. |
|
| Client -> Server | `audio.chunk` | `data` | Base64 PCM16 16 kHz mono audio bytes. |
|
||||||
@@ -53,7 +53,7 @@ WebSocket /v1/video/chat/stream
|
|||||||
### `session.config` Fields
|
### `session.config` Fields
|
||||||
|
|
||||||
| Field | Type | Default | Description |
|
| Field | Type | Default | Description |
|
||||||
| ------- | ------ | --------- | ------------- |
|
|-------|------|---------|-------------|
|
||||||
| `model` | string or null | null | Optional model name. Usually omitted because the server hosts one model. |
|
| `model` | string or null | null | Optional model name. Usually omitted because the server hosts one model. |
|
||||||
| `modalities` | list[string] | `["text", "audio"]` | Output modalities. Use `["text"]`, `["audio"]`, or both. |
|
| `modalities` | list[string] | `["text", "audio"]` | Output modalities. Use `["text"]`, `["audio"]`, or both. |
|
||||||
| `num_frames` | integer, 1-128 | `4` | Number of buffered frames sampled for each query. |
|
| `num_frames` | integer, 1-128 | `4` | Number of buffered frames sampled for each query. |
|
||||||
@@ -69,7 +69,7 @@ WebSocket /v1/video/chat/stream
|
|||||||
The server accepts these legacy field names and rewrites them before validation. New clients should send the canonical names above.
|
The server accepts these legacy field names and rewrites them before validation. New clients should send the canonical names above.
|
||||||
|
|
||||||
| Legacy field | Canonical field |
|
| Legacy field | Canonical field |
|
||||||
| -------------- | ----------------- |
|
|--------------|-----------------|
|
||||||
| `num_sample_frames` | `num_frames` |
|
| `num_sample_frames` | `num_frames` |
|
||||||
| `evs_enabled` | `enable_frame_filter` |
|
| `evs_enabled` | `enable_frame_filter` |
|
||||||
| `evs_threshold` | `frame_filter_threshold` |
|
| `evs_threshold` | `frame_filter_threshold` |
|
||||||
@@ -77,7 +77,7 @@ The server accepts these legacy field names and rewrites them before validation.
|
|||||||
### Environment Variables
|
### Environment Variables
|
||||||
|
|
||||||
| Variable | Values | Default | Description |
|
| Variable | Values | Default | Description |
|
||||||
| -------- | ------ | ------- | ----------- |
|
|----------|--------|---------|-------------|
|
||||||
| `VLLM_VIDEO_ASYNC_CHUNK` | `on`, `off` | `on` | Wire-level streaming switch. `off` buffers server-side deltas and emits coalesced outputs at the end of a query. |
|
| `VLLM_VIDEO_ASYNC_CHUNK` | `on`, `off` | `on` | Wire-level streaming switch. `off` buffers server-side deltas and emits coalesced outputs at the end of a query. |
|
||||||
| `VLLM_VIDEO_AUDIO_DELTA_MODE` | `fast`, `slow` | `fast` | Audio delta extraction strategy. `fast` emits only newly produced chunks; `slow` recomputes from accumulated audio and exists for A/B verification. |
|
| `VLLM_VIDEO_AUDIO_DELTA_MODE` | `fast`, `slow` | `fast` | Audio delta extraction strategy. `fast` emits only newly produced chunks; `slow` recomputes from accumulated audio and exists for A/B verification. |
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ curl -L "http://localhost:8091/v1/videos/${video_id}/content" -o output.mp4
|
|||||||
### Endpoints
|
### Endpoints
|
||||||
|
|
||||||
| Endpoint | Method | Description |
|
| Endpoint | Method | Description |
|
||||||
| ---------- | -------- | ------------- |
|
|----------|--------|-------------|
|
||||||
| `/v1/videos` | `POST` | Create an asynchronous video generation job |
|
| `/v1/videos` | `POST` | Create an asynchronous video generation job |
|
||||||
| `/v1/videos/sync` | `POST` | Generate a video synchronously and return raw video bytes |
|
| `/v1/videos/sync` | `POST` | Generate a video synchronously and return raw video bytes |
|
||||||
| `/v1/videos/{video_id}` | `GET` | Retrieve job status and metadata |
|
| `/v1/videos/{video_id}` | `GET` | Retrieve job status and metadata |
|
||||||
@@ -56,7 +56,7 @@ curl -L "http://localhost:8091/v1/videos/${video_id}/content" -o output.mp4
|
|||||||
#### OpenAI-style fields
|
#### OpenAI-style fields
|
||||||
|
|
||||||
| Parameter | Type | Default | Description |
|
| Parameter | Type | Default | Description |
|
||||||
| ----------- | ------ | --------- | ------------- |
|
|-----------|------|---------|-------------|
|
||||||
| `prompt` | string | **required** | Text prompt for video generation |
|
| `prompt` | string | **required** | Text prompt for video generation |
|
||||||
| `model` | string | server's model | Optional model name |
|
| `model` | string | server's model | Optional model name |
|
||||||
| `seconds` | string | null | Requested clip duration in seconds |
|
| `seconds` | string | null | Requested clip duration in seconds |
|
||||||
@@ -66,10 +66,8 @@ curl -L "http://localhost:8091/v1/videos/${video_id}/content" -o output.mp4
|
|||||||
#### vLLM-Omni extension fields
|
#### vLLM-Omni extension fields
|
||||||
|
|
||||||
| Parameter | Type | Default | Description |
|
| Parameter | Type | Default | Description |
|
||||||
| ----------- | ------ | --------- | ------------- |
|
|-----------|------|---------|-------------|
|
||||||
| `input_reference` | file | null | Uploaded reference image or video for image-to-video/video-to-video requests |
|
| `input_reference` | file | null | Uploaded reference image or video for image-to-video/video-to-video requests |
|
||||||
| `control_reference` | file | null | Optional uploaded image/video control, up to 512 MiB, for models that declare control-upload support |
|
|
||||||
| `control_type` | string | null | Model control name associated with `control_reference`; currently Cosmos3 supports `edge`, `blur`, `depth`, `seg`, and `wsm` |
|
|
||||||
| `image_reference` | string | null | JSON-encoded reference image payload; do not combine with `input_reference` or `video_reference` |
|
| `image_reference` | string | null | JSON-encoded reference image payload; do not combine with `input_reference` or `video_reference` |
|
||||||
| `video_reference` | string | null | JSON-encoded reference video payload; do not combine with `input_reference` or `image_reference` |
|
| `video_reference` | string | null | JSON-encoded reference video payload; do not combine with `input_reference` or `image_reference` |
|
||||||
| `audio_reference` | string | null | JSON-encoded audio reference for speech-to-video: `{"audio_url": "..."}` — supports HTTP(s) URLs or base64 data URLs |
|
| `audio_reference` | string | null | JSON-encoded audio reference for speech-to-video: `{"audio_url": "..."}` — supports HTTP(s) URLs or base64 data URLs |
|
||||||
@@ -179,23 +177,6 @@ corresponding addition. `negative_metadata_mode` accepts `same`, `inverse`, or
|
|||||||
`none` and defaults to `same` for transfer. See the Cosmos3 recipe for complete
|
`none` and defaults to `same` for transfer. See the Cosmos3 recipe for complete
|
||||||
examples.
|
examples.
|
||||||
|
|
||||||
A client that cannot place the control on the server filesystem can upload one
|
|
||||||
control with `control_reference` and identify it with `control_type`. The API
|
|
||||||
streams the upload to request-scoped storage, supplies its path to the model,
|
|
||||||
and removes it after synchronous or asynchronous generation completes. Other
|
|
||||||
options for the selected control can remain in `extra_params`; do not also set
|
|
||||||
`control` or `control_path` there. Uploads larger than 512 MiB are rejected.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -s http://localhost:8091/v1/videos/sync \
|
|
||||||
-F "prompt=Preserve the scene while following the world-state control" \
|
|
||||||
-F "input_reference=@input.mp4;type=video/mp4" \
|
|
||||||
-F "control_reference=@wsm.mp4;type=video/mp4" \
|
|
||||||
-F "control_type=wsm" \
|
|
||||||
-F 'extra_params={"wsm":{"control_weight":1.0}}' \
|
|
||||||
-o output.mp4
|
|
||||||
```
|
|
||||||
|
|
||||||
HTTP redirects for `image_reference.image_url` follow vLLM's
|
HTTP redirects for `image_reference.image_url` follow vLLM's
|
||||||
`VLLM_MEDIA_URL_ALLOW_REDIRECTS` setting. Before starting the server, set it to
|
`VLLM_MEDIA_URL_ALLOW_REDIRECTS` setting. Before starting the server, set it to
|
||||||
`1` (the default) to allow redirects or `0` to reject them. A redirect target
|
`1` (the default) to allow redirects or `0` to reject them. A redirect target
|
||||||
@@ -222,6 +203,7 @@ curl -s http://localhost:8091/v1/videos \
|
|||||||
-F "fps=16"
|
-F "fps=16"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Synchronous Generation
|
### Synchronous Generation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+1
-1
@@ -18,4 +18,4 @@ A: AWQ is available through the inherited vLLM quantization registry, and vLLM-O
|
|||||||
|
|
||||||
> Q: Does vLLM-Omni support multimodal streaming input and output?
|
> Q: Does vLLM-Omni support multimodal streaming input and output?
|
||||||
|
|
||||||
A: Yes, for specific models and serving paths. Current capabilities include [streaming video input](../serving/video_stream_api.md), [streaming diffusion output](../user_guide/diffusion/execution_modes.md#streaming-output), and [full-duplex realtime audio](../serving/realtime_duplex_api.md). Check the model and API documentation because input and output support is model-specific.
|
A: Yes, for specific models and serving paths. Current capabilities include [streaming video input](../serving/video_stream_api.md), [streaming diffusion output](../user_guide/diffusion/execution_modes.md#streaming-output), and experimental full-duplex real-time audio described in the [project overview](../README.md). Check the model and API documentation because input and output support is model-specific.
|
||||||
@@ -12,7 +12,7 @@ implementations to reduce numerical drift and sampling divergence.
|
|||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install kernels==0.16.1
|
pip install kernels==0.14.1
|
||||||
```
|
```
|
||||||
|
|
||||||
If `kernels` is unavailable, an explicit `FLASH_ATTN_HUB` or
|
If `kernels` is unavailable, an explicit `FLASH_ATTN_HUB` or
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ For the shared factory, discovery, and lifecycle contract, see the
|
|||||||
|
|
||||||
| Strategy | Device residency | Parallel scope | Guide |
|
| Strategy | Device residency | Parallel scope | Guide |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Model-level (sequential) | One pipeline component group at a time | Single device | [Model-Level Offloading](offloader/module_offload.md) |
|
| Model-level (sequential) | One pipeline component group at a time | Single device | [Model-Level Offloading](offloader/cpu_offload.md) |
|
||||||
| Layerwise (blockwise) | One transformer block, with next-block prefetch | Single device | [Layerwise Offloading](offloader/layerwise_offload.md) |
|
| Layerwise (blockwise) | One transformer block, with next-block prefetch | Single device | [Layerwise Offloading](offloader/layerwise_offload.md) |
|
||||||
| Distributed layerwise | Fixed two-block device buffer; optional host-weight sharding and AllGather | Multiple GPU/NPU ranks | [Distributed Layerwise Offloading](offloader/distributed_layerwise_offload.md) |
|
| Distributed layerwise | Fixed two-block device buffer; optional host-weight sharding and AllGather | Multiple GPU/NPU ranks | [Distributed Layerwise Offloading](offloader/distributed_layerwise_offload.md) |
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ higher-priority strategy is selected.
|
|||||||
|
|
||||||
## Quick selection
|
## Quick selection
|
||||||
|
|
||||||
- Use [model-level offloading](offloader/module_offload.md) when swapping whole
|
- Use [model-level offloading](offloader/cpu_offload.md) when swapping whole
|
||||||
encoders and DiTs is enough to fit and phase-boundary transfers are
|
encoders and DiTs is enough to fit and phase-boundary transfers are
|
||||||
acceptable.
|
acceptable.
|
||||||
- Use [layerwise offloading](offloader/layerwise_offload.md) for compute-heavy video
|
- Use [layerwise offloading](offloader/layerwise_offload.md) for compute-heavy video
|
||||||
@@ -63,7 +63,7 @@ These headings preserve links to sections that moved into dedicated guides.
|
|||||||
|
|
||||||
## Model-level (Sequential) Offloading
|
## Model-level (Sequential) Offloading
|
||||||
|
|
||||||
See [Model-Level Offloading](offloader/module_offload.md).
|
See [Model-Level Offloading](offloader/cpu_offload.md).
|
||||||
|
|
||||||
## Layerwise (Blockwise) Offloading
|
## Layerwise (Blockwise) Offloading
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ are exposed.
|
|||||||
## Choose a Mode
|
## Choose a Mode
|
||||||
|
|
||||||
| Goal | CLI configuration |
|
| Goal | CLI configuration |
|
||||||
| --- | --- |
|
|---|---|
|
||||||
| Serial request execution | `--max-num-seqs 1` |
|
| Serial request execution | `--max-num-seqs 1` |
|
||||||
| Fused request-level batching | `--max-num-seqs N` |
|
| Fused request-level batching | `--max-num-seqs N` |
|
||||||
| Single-request step execution | `--step-execution --max-num-seqs 1` |
|
| Single-request step execution | `--step-execution --max-num-seqs 1` |
|
||||||
@@ -94,16 +94,8 @@ validating a model or debugging correctness, then increase it for
|
|||||||
multi-request throughput.
|
multi-request throughput.
|
||||||
|
|
||||||
Step execution is capability-based, not a generic switch for every diffusion
|
Step execution is capability-based, not a generic switch for every diffusion
|
||||||
model. Qwen-Image supports step-wise continuous batching. BAGEL supports
|
model. Qwen-Image supports step-wise continuous batching. HunyuanImage3 also
|
||||||
step-wise continuous batching for image generation with `bagel.yaml`,
|
supports it, but only when its resolved self-attention backend is `TORCH_SDPA`;
|
||||||
`bagel_think.yaml`, and `bagel_single_stage.yaml`. In the two-stage topologies,
|
|
||||||
only the diffusion stage uses step execution; the autoregressive Thinker is
|
|
||||||
unchanged. Explicit text-output requests in the single-stage topology retain
|
|
||||||
the complete-request path. Use at least two inference steps for BAGEL image
|
|
||||||
requests because BAGEL schedules `num_inference_steps - 1` denoising updates.
|
|
||||||
BAGEL step execution does not currently support sequence parallelism or a
|
|
||||||
diffusion cache backend. HunyuanImage3 also supports step execution, but only
|
|
||||||
when its resolved self-attention backend is `TORCH_SDPA`;
|
|
||||||
set `DIFFUSION_ATTENTION_BACKEND=TORCH_SDPA` or configure
|
set `DIFFUSION_ATTENTION_BACKEND=TORCH_SDPA` or configure
|
||||||
`diffusion_attention_config.default.backend=TORCH_SDPA` before using
|
`diffusion_attention_config.default.backend=TORCH_SDPA` before using
|
||||||
`--max-num-seqs >1`. See the
|
`--max-num-seqs >1`. See the
|
||||||
@@ -177,10 +169,8 @@ wait
|
|||||||
The scheduler may batch these requests when their sampling parameters are
|
The scheduler may batch these requests when their sampling parameters are
|
||||||
compatible. See the
|
compatible. See the
|
||||||
[Image Generation API](../../serving/image_generation_api.md) for response
|
[Image Generation API](../../serving/image_generation_api.md) for response
|
||||||
formats and additional client examples.
|
formats and additional client examples. Streaming models can use
|
||||||
|
model-specific streaming endpoints documented by their serving guide.
|
||||||
Streaming models can use model-specific streaming endpoints documented at
|
|
||||||
[Streaming Video Output API](../../serving/streaming_video_output_api.md).
|
|
||||||
|
|
||||||
## Python API
|
## Python API
|
||||||
|
|
||||||
@@ -243,7 +233,7 @@ For step execution, set `step_execution: true` and remove
|
|||||||
## CLI Reference
|
## CLI Reference
|
||||||
|
|
||||||
| Flag | Default | Effect |
|
| Flag | Default | Effect |
|
||||||
| --- | ---: | --- |
|
|---|---:|---|
|
||||||
| `--step-execution` | disabled | Select step-wise scheduling |
|
| `--step-execution` | disabled | Select step-wise scheduling |
|
||||||
| `--max-num-seqs` | `1` for diffusion stages | Set request- or step-scheduler capacity |
|
| `--max-num-seqs` | `1` for diffusion stages | Set request- or step-scheduler capacity |
|
||||||
| `--request-batch-max-wait-ms` | `0` | Wait for burst coalescing in request mode |
|
| `--request-batch-max-wait-ms` | `0` | Wait for burst coalescing in request mode |
|
||||||
|
|||||||
@@ -249,14 +249,8 @@ MiniMax-H3 supports two few-step mechanisms that must not be conflated:
|
|||||||
- **Checkpoint-pinned schedule**: a merged release writes `base_schedule` into
|
- **Checkpoint-pinned schedule**: a merged release writes `base_schedule` into
|
||||||
`model_index.json`. Requests must pass `num_inference_steps` as the interval
|
`model_index.json`. Requests must pass `num_inference_steps` as the interval
|
||||||
count (for example `4` for `[1.0, 0.7, 0.4, 0.15, 0.0]`).
|
count (for example `4` for `[1.0, 0.7, 0.4, 0.15, 0.0]`).
|
||||||
- **Runtime Turbo LoRA**: each LightX2V Turbo artifact carries its own contract,
|
- **Runtime Turbo LoRA**: LightX2V Turbo artifacts request five sigma points and
|
||||||
read from its filename. A four-step artifact requests five sigma points and an
|
enforce `flow_shift=6`, `audio_flow_shift=3`.
|
||||||
eight-step one requests nine; the 768p retrains enforce `flow_shift=6` and the
|
|
||||||
544p artifacts `flow_shift=12`. `audio_flow_shift=3` across the family. A
|
|
||||||
request that does not match the loaded artifact is rejected by name. Alpha
|
|
||||||
comes from the artifact's metadata, or 8 when it declares none. `ref2v`
|
|
||||||
artifacts require `--task-type ref2va`; `fl2v` artifacts serve T2VA and FL2VA.
|
|
||||||
The ComfyUI exports use a fused-QKV layout and are not supported.
|
|
||||||
- **Runtime native LoRA**: FlashGen-style artifacts declare
|
- **Runtime native LoRA**: FlashGen-style artifacts declare
|
||||||
`key_format=minimax-h3-native` and embed `base_schedule` in safetensors
|
`key_format=minimax-h3-native` and embed `base_schedule` in safetensors
|
||||||
metadata. When active, the adapter schedule overrides the base checkpoint and
|
metadata. When active, the adapter schedule overrides the base checkpoint and
|
||||||
|
|||||||
+7
-21
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
Model-level, or sequential, offloading keeps only the pipeline component group
|
Model-level, or sequential, offloading keeps only the pipeline component group
|
||||||
currently executing on the accelerator. It is the simplest offload strategy
|
currently executing on the accelerator. It is the simplest offload strategy
|
||||||
and is selected with `diffusion_offload_config.mode="module"`.
|
and is selected with `--enable-cpu-offload`.
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
Pre-forward hooks enforce mutual exclusion between DiT and encoder modules:
|
Pre-forward hooks enforce mutual exclusion between DiT and encoder modules:
|
||||||
|
|
||||||
- before an encoder runs, selected DiTs move to CPU;
|
- before an encoder runs, the DiT moves to CPU;
|
||||||
- before a DiT runs, selected encoders and other selected DiTs move to CPU; and
|
- before a DiT runs, encoders and other DiTs move to CPU; and
|
||||||
- VAE modules remain on the accelerator.
|
- VAE modules remain on the accelerator.
|
||||||
|
|
||||||
Pinned host memory reduces transfer overhead. Transfers occur at phase
|
Pinned host memory reduces transfer overhead. Transfers occur at phase
|
||||||
@@ -22,28 +22,15 @@ from vllm_omni import Omni
|
|||||||
|
|
||||||
omni = Omni(
|
omni = Omni(
|
||||||
model="Wan-AI/Wan2.2-T2V-A14B-Diffusers",
|
model="Wan-AI/Wan2.2-T2V-A14B-Diffusers",
|
||||||
diffusion_offload_config={
|
enable_cpu_offload=True,
|
||||||
"mode": "module",
|
|
||||||
"components": ["dit", "text_encoder"],
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
vllm serve Wan-AI/Wan2.2-T2V-A14B-Diffusers \
|
vllm serve Wan-AI/Wan2.2-T2V-A14B-Diffusers \
|
||||||
--omni \
|
--omni --enable-cpu-offload
|
||||||
--diffusion-offload-config \
|
|
||||||
'{"mode":"module","components":["dit","text_encoder"]}'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
List a component to select it for offload. Module mode rejects `layer_options`
|
|
||||||
such as `weight_transfer` and `resident_layers`. The
|
|
||||||
`enable_cpu_offload=True` compatibility entry point remains supported. New
|
|
||||||
integrations should prefer the explicit config; existing model-specific stage
|
|
||||||
lifecycles do not need to migrate until equivalent component coverage exists.
|
|
||||||
For example, MiniMax-H3's compatibility lifecycle also stages its VAEs, while
|
|
||||||
the compact selector intentionally covers only `dit` and `text_encoder`.
|
|
||||||
|
|
||||||
## Model integration
|
## Model integration
|
||||||
|
|
||||||
Pipelines should implement `SupportsComponentDiscovery`:
|
Pipelines should implement `SupportsComponentDiscovery`:
|
||||||
@@ -86,10 +73,9 @@ while reusing sequential `.to()` movers.
|
|||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
- Transfers are rank-local; module mode does not shard host payloads or add a
|
- Single device only.
|
||||||
weight AllGather across ranks.
|
|
||||||
- Higher cold-start latency.
|
- Higher cold-start latency.
|
||||||
- Transfers between encoder and denoising phases add latency.
|
- Transfers between encoder and denoising phases add latency.
|
||||||
|
|
||||||
See the [model-level design](../../../design/feature/offloader/module_offload.md)
|
See the [model-level design](../../../design/feature/offloader/cpu_offload.md)
|
||||||
for lifecycle and extension invariants.
|
for lifecycle and extension invariants.
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
# Distributed Layerwise Offloading
|
# Distributed Layerwise Offloading
|
||||||
|
|
||||||
Distributed layerwise offloading (DLO) extends block streaming to multi-device
|
Distributed layerwise offloading (DLO) extends block streaming to multi-device
|
||||||
deployments. Each selected component chooses its transfer independently. With
|
deployments. With AllGather enabled, each rank stores roughly `1 / dp_size` of
|
||||||
`allgather`, each rank stores roughly one shard per member of the effective DLO
|
the host weights and reconstructs each layer at runtime. Without AllGather,
|
||||||
group (DP, or SP when DP is one) and reconstructs each layer at runtime. With
|
each rank streams a complete block independently. Compatible TP1 deployments
|
||||||
`rank-local`, each rank streams a complete loader-produced block independently.
|
can share checkpoint-backed host pages among processes on the same node;
|
||||||
Compatible TP1 DiT deployments can share checkpoint-backed host pages among
|
otherwise DLO streams the ordinary loader's rank-local tensors.
|
||||||
processes on the same node; otherwise DLO streams the ordinary loader's
|
|
||||||
rank-local tensors.
|
|
||||||
|
|
||||||
See the [DLO feature design](../../../design/feature/offloader/distributed_layerwise_offload.md)
|
See the [DLO feature design](../../../design/feature/offloader/distributed_layerwise_offload.md)
|
||||||
for the implementation contract and compatibility matrix.
|
for the implementation contract and compatibility matrix.
|
||||||
@@ -26,120 +24,52 @@ Slots: slot 0: Layer N slot 1: Layer N+1
|
|||||||
AllGather communicates only request-independent weight shards, so data-
|
AllGather communicates only request-independent weight shards, so data-
|
||||||
parallel ranks may process different requests concurrently.
|
parallel ranks may process different requests concurrently.
|
||||||
|
|
||||||
The public API describes intent in one nested configuration:
|
|
||||||
|
|
||||||
| Level | Setting | Question answered |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Granularity | `mode` | move a complete component (`module`) or stream its blocks (`layer`) |
|
|
||||||
| Selection | `components` list | whether `dit` and/or `text_encoder` may move to CPU |
|
|
||||||
| Per-component layer options | `layer_options` | choose rank-local or AllGather weight transfer and optionally retain leading DiT blocks |
|
|
||||||
|
|
||||||
`weight_transfer` applies only to model weights. It does not change encoder
|
|
||||||
activations or the encoder's compute parallelism. `rank-local` copies each
|
|
||||||
rank's loader-produced block to its device. `allgather` stores one shard of
|
|
||||||
that block per rank, copies each shard to its device, and reconstructs the
|
|
||||||
complete block with a device-side AllGather before compute.
|
|
||||||
|
|
||||||
The historical `enable_cpu_offload`, `enable_layerwise_offload`, and
|
|
||||||
`enable_distributed_layerwise_offload` fields remain compatibility aliases
|
|
||||||
for existing callers and model-specific stage lifecycles. Existing
|
|
||||||
combinations retain their priority (`distributed layerwise` > `layerwise` >
|
|
||||||
`module`). A compact config rejects conflicting compatibility strategies and
|
|
||||||
non-default legacy DLO tuning.
|
|
||||||
`distributed-layerwise` remains an internal backend name; users select
|
|
||||||
`mode="layer"`, and the runtime chooses the capable backend.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Four SP ranks; Wan declares replicated text-encoder weights, so both
|
# Four ranks with sharded host weights and AllGather
|
||||||
# selected components can use AllGather safely.
|
vllm serve /path/to/model --omni \
|
||||||
vllm serve Wan-AI/Wan2.2-T2V-A14B-Diffusers --omni \
|
--enable-distributed-layerwise-offload \
|
||||||
--diffusion-offload-config \
|
--data-parallel-size 4
|
||||||
'{"mode":"layer","components":["dit","text_encoder"],"layer_options":{"dit":{"weight_transfer":"allgather"},"text_encoder":{"weight_transfer":"allgather"}}}' \
|
|
||||||
--usp 4
|
|
||||||
|
|
||||||
# Mix transfers independently: sharded DiT, loader-produced encoder layout
|
# Standard-loader rank-local weights, without DLO AllGather
|
||||||
vllm serve /path/to/model --omni \
|
vllm serve /path/to/model --omni \
|
||||||
--diffusion-offload-config \
|
--enable-distributed-layerwise-offload \
|
||||||
'{"mode":"layer","components":["dit","text_encoder"],"layer_options":{"dit":{"weight_transfer":"allgather"},"text_encoder":{"weight_transfer":"rank-local"}}}' \
|
--data-parallel-size 4 \
|
||||||
--usp 4
|
--dlo-no-use-allgather
|
||||||
|
|
||||||
# Full-topology rank-local DLO for an existing model-specific lifecycle
|
# Sequence parallel deployment
|
||||||
vllm serve /path/to/model --omni \
|
vllm serve /path/to/model --omni \
|
||||||
--enable-distributed-layerwise-offload \
|
--enable-distributed-layerwise-offload \
|
||||||
--dlo-no-use-allgather \
|
|
||||||
--usp 4
|
--usp 4
|
||||||
```
|
```
|
||||||
|
|
||||||
A compact layer config whose selected components are all `rank-local` and
|
|
||||||
whose `resident_layers` is zero resolves to the ordinary layerwise backend. It
|
|
||||||
uses the ordinary loader and does not request DLO's direct-checkpoint mmap.
|
|
||||||
Keep the compatibility DLO flags for a model-specific full-topology rank-local
|
|
||||||
lifecycle; do not add resident layers solely to force backend selection.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from vllm_omni import Omni
|
from vllm_omni import Omni
|
||||||
|
|
||||||
omni = Omni(
|
omni = Omni(
|
||||||
model="/path/to/model",
|
model="/path/to/model",
|
||||||
diffusion_offload_config={
|
enable_distributed_layerwise_offload=True,
|
||||||
"mode": "layer",
|
dlo_use_allgather=True,
|
||||||
"components": ["dit", "text_encoder"],
|
|
||||||
"layer_options": {
|
|
||||||
"dit": {
|
|
||||||
"weight_transfer": "rank-local",
|
|
||||||
"resident_layers": 20,
|
|
||||||
},
|
|
||||||
"text_encoder": {
|
|
||||||
"weight_transfer": "allgather",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"pin_memory": True,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Flags
|
## Flags
|
||||||
|
|
||||||
| Setting | Meaning | Default |
|
| Flag | Meaning | Default |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `diffusion_offload_config.mode` | `module` or `layer` granularity | required |
|
| `--enable-distributed-layerwise-offload` | Enable DLO | `false` |
|
||||||
| `diffusion_offload_config.components` | Non-empty list containing `dit`, `text_encoder`, or both | required |
|
| `--data-parallel-size N` | DP ranks and AllGather weight-sharding group | `1` |
|
||||||
| `layer_options.NAME.weight_transfer` | `rank-local` or `allgather` | `rank-local` |
|
| `--dlo-use-allgather` | Shard host weights and reconstruct with AllGather | `true` |
|
||||||
| `layer_options.dit.resident_layers` | Leading main-DiT blocks kept on device; requires `rank-local` and model-declared resident paths | `0` |
|
| `--dlo-no-use-allgather` | Stream complete rank-local blocks without a DLO weight collective | `false` |
|
||||||
| `diffusion_offload_config.pin_memory` | Pin streamed host memory for faster H2D copies | `true` |
|
| `--dlo-resident-layers N` | Keep N leading main-DiT blocks on device; requires no-AllGather and model-declared resident paths | `0` |
|
||||||
| `--data-parallel-size N` | DP ranks; DP is the DLO group when greater than one, otherwise SP is used | `1` |
|
|
||||||
| `--host-weight-runtime-mode {disabled,preferred,required}` | HWR policy: no interaction, populate on a miss, or require an exact hit | `disabled` |
|
| `--host-weight-runtime-mode {disabled,preferred,required}` | HWR policy: no interaction, populate on a miss, or require an exact hit | `disabled` |
|
||||||
| `--host-weight-runtime-root PATH` | Writable node-local HWR store shared by workers in one storage domain; required for `preferred` and `required` | unset |
|
| `--host-weight-runtime-root PATH` | Writable node-local HWR store shared by workers in one storage domain; required for `preferred` and `required` | unset |
|
||||||
| `--dlo-host-registration-limit-gib N` | Optional per-worker ceiling for registering an HWR mmap; zero adds no ceiling | `0` |
|
| `--dlo-host-registration-limit-gib N` | Optional per-worker ceiling for registering an HWR mmap; zero adds no ceiling | `0` |
|
||||||
|
|
||||||
HWR and host-registration tuning remain on the compatibility DLO interface and
|
|
||||||
cannot be combined with `diffusion_offload_config` in this release.
|
|
||||||
|
|
||||||
## Component and weight-transfer matrix
|
|
||||||
|
|
||||||
| Component | `allgather` | `rank-local` |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| DiT | Shard each loader-visible block across the DLO DP group, or the SP group when DP is one | Stream each rank's complete loader-produced block |
|
|
||||||
| Text encoder | Same shard + AllGather path when the model declares identical encoder weights across the DLO group | Stream each rank's complete encoder block, including encoder-TP shards |
|
|
||||||
|
|
||||||
The text encoder's compute group and weight-transfer group are separate
|
|
||||||
concepts. An encoder TP group owns different parameter shards, so it is not a
|
|
||||||
valid AllGather offload group. Models opt in through
|
|
||||||
`OffloadPlan.encoder_dlo_weight_replication`; otherwise multi-rank encoder
|
|
||||||
AllGather fails at startup with guidance to use `rank-local`. This makes SP
|
|
||||||
AllGather available to replicated encoders without silently corrupting an
|
|
||||||
encoder-TP layout.
|
|
||||||
|
|
||||||
`resident_layers` remains a DiT-only setting and currently requires the DiT
|
|
||||||
transfer to be `rank-local`.
|
|
||||||
|
|
||||||
## Host-weight loading
|
## Host-weight loading
|
||||||
|
|
||||||
When the distributed backend is selected by AllGather, resident DiT layers, or
|
The diffusion loader chooses host storage before DLO is enabled. It first
|
||||||
the compatibility DLO flag, the diffusion loader chooses host storage before
|
|
||||||
DLO is enabled. It first
|
|
||||||
attempts to build a complete, validated direct-checkpoint mmap plan. If names,
|
attempts to build a complete, validated direct-checkpoint mmap plan. If names,
|
||||||
coverage, shape, dtype, topology, or loader-callback compatibility cannot be
|
coverage, shape, dtype, topology, or loader-callback compatibility cannot be
|
||||||
proven, it runs the ordinary model loader instead. DLO consumes that result and
|
proven, it runs the ordinary model loader instead. DLO consumes that result and
|
||||||
@@ -167,20 +97,20 @@ With direct checkpoint mmap, the loader:
|
|||||||
6. preserves `post_load_weights()` and `validate_loaded_weights()` lifecycle
|
6. preserves `post_load_weights()` and `validate_loaded_weights()` lifecycle
|
||||||
hooks.
|
hooks.
|
||||||
|
|
||||||
For a DiT using `allgather` with a group larger than one, each process copies
|
For AllGather with a group larger than one, each process copies only its
|
||||||
only its persistent shard and then releases the source mapping. For a DiT using
|
persistent shard and then releases the source mapping. For no-AllGather, each
|
||||||
`rank-local`, each process keeps the mapping open and packs complete blocks
|
process keeps the mapping open and packs complete blocks through two bounded
|
||||||
through two bounded pinned staging slots. Processes mapping the same files on
|
pinned staging slots. Processes mapping the same files on one node share the
|
||||||
one node share the immutable pages; rank-local transfer still performs a
|
immutable pages; no-AllGather still performs a complete-block H2D copy in each
|
||||||
complete-block H2D copy in each process.
|
process.
|
||||||
|
|
||||||
When the effective DLO group size is one, `weight_transfer="allgather"` does not
|
When the effective DLO group size is one, `dlo_use_allgather=True` does not
|
||||||
perform a collective and uses the same rank-local transfer behavior.
|
perform a collective and uses the same rank-local transfer behavior.
|
||||||
|
|
||||||
### Final-layout Host Weight Runtime
|
### Final-layout Host Weight Runtime
|
||||||
|
|
||||||
HWR is an opt-in startup optimization for models that declare the final-layout
|
HWR is an opt-in startup optimization for models that declare the final-layout
|
||||||
BF16 restore contract. Use it only when the selected DiT uses `rank-local`:
|
BF16 restore contract. Use it only with no-AllGather DLO:
|
||||||
|
|
||||||
The validated BF16 model contracts currently cover MiniMax H3 and
|
The validated BF16 model contracts currently cover MiniMax H3 and
|
||||||
`black-forest-labs/FLUX.2-klein-4B`. FLUX.2-klein-9B shares the same model
|
`black-forest-labs/FLUX.2-klein-4B`. FLUX.2-klein-9B shares the same model
|
||||||
@@ -274,7 +204,7 @@ H2D behavior.
|
|||||||
#### Registered direct H2D
|
#### Registered direct H2D
|
||||||
|
|
||||||
Registration is attempted automatically only for an eligible warm HWR hit when
|
Registration is attempted automatically only for an eligible warm HWR hit when
|
||||||
the existing `pin_cpu_memory` policy is enabled. A successful path is:
|
`pin_cpu_memory` is enabled. A successful path is:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
shared read-only HWR mmap -> existing rotating HBM block buffer -> GPU kernel
|
shared read-only HWR mmap -> existing rotating HBM block buffer -> GPU kernel
|
||||||
@@ -287,10 +217,10 @@ kernels access host memory directly.
|
|||||||
CUDA requires read-only host-registration capability for the immutable HWR
|
CUDA requires read-only host-registration capability for the immutable HWR
|
||||||
mapping. Unsupported capability, a positive registration limit smaller than
|
mapping. Unsupported capability, a positive registration limit smaller than
|
||||||
the complete page-aligned mapping, or a safely rolled-back registration error
|
the complete page-aligned mapping, or a safely rolled-back registration error
|
||||||
falls back to bounded staging. Programmatic compatibility configurations can
|
falls back to bounded staging. Programmatic configurations can set
|
||||||
set `pin_cpu_memory=False` to disable registration explicitly.
|
`pin_cpu_memory=False` to disable registration explicitly. A successful
|
||||||
A successful registration locks the complete mapped range in host memory for
|
registration locks the complete mapped range in host memory for that worker's
|
||||||
that worker's lifetime, so use
|
lifetime, so use
|
||||||
`--dlo-host-registration-limit-gib` when an operator-enforced ceiling is
|
`--dlo-host-registration-limit-gib` when an operator-enforced ceiling is
|
||||||
required.
|
required.
|
||||||
|
|
||||||
@@ -298,8 +228,8 @@ Shutdown drains H2D work, releases hook/source references, unregisters every
|
|||||||
range, and only then closes the HWR lease. AllGather and direct checkpoint mmap
|
range, and only then closes the HWR lease. AllGather and direct checkpoint mmap
|
||||||
retain their existing transfer paths.
|
retain their existing transfer paths.
|
||||||
|
|
||||||
When HWR is disabled, DLO is disabled, or the DiT uses `allgather`, the loader
|
When HWR is disabled, DLO is disabled, or AllGather is enabled, the loader does
|
||||||
does not resolve HWR sources or construct its store.
|
not resolve HWR sources or construct its store.
|
||||||
|
|
||||||
## Declarative topology
|
## Declarative topology
|
||||||
|
|
||||||
@@ -311,54 +241,38 @@ from vllm_omni.diffusion.offloader import OffloadPlan
|
|||||||
|
|
||||||
class MyPipeline(nn.Module):
|
class MyPipeline(nn.Module):
|
||||||
_dit_modules = ["transformer"]
|
_dit_modules = ["transformer"]
|
||||||
_encoder_modules = ["prompt_model"]
|
|
||||||
_offload_plan = OffloadPlan(
|
_offload_plan = OffloadPlan(
|
||||||
block_attrs={"transformer": ("blocks",)},
|
block_attrs={"transformer": ("blocks",)},
|
||||||
offload_submodules={"context_encoder": "layers"},
|
offload_submodules={"context_encoder": "layers"},
|
||||||
encoder_component_types={"prompt_model": "text_encoder"},
|
|
||||||
encoder_block_attrs={"prompt_model": ("encoder.layers",)},
|
|
||||||
encoder_dlo_weight_replication=frozenset({"prompt_model"}),
|
|
||||||
on_demand_component_paths=frozenset({"prompt_model"}),
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
`encoder_component_types` maps arbitrary encoder paths to the public
|
When no plan exists, discovery falls back to
|
||||||
`text_encoder` selector. `encoder_dlo_weight_replication` is the explicit
|
`_layerwise_offload_blocks_attrs` and then heuristic attribute lookup.
|
||||||
safety declaration for reusing the DiT DLO group. On-demand encoder non-block
|
|
||||||
state is loaded and offloaded by its pipeline phase.
|
|
||||||
|
|
||||||
When no plan exists, DiT discovery falls back to
|
|
||||||
`_layerwise_offload_blocks_attrs` and then heuristic attribute lookup;
|
|
||||||
undeclared auxiliary components remain resident.
|
|
||||||
|
|
||||||
## Data-parallel concurrency
|
## Data-parallel concurrency
|
||||||
|
|
||||||
With `data_parallel_size > 1` and AllGather enabled, the scheduler can process
|
With `data_parallel_size > 1` and AllGather enabled, the scheduler can process
|
||||||
up to `dp_size` requests per denoising step. Concurrent requests must resolve
|
up to `dp_size` requests per denoising step. Every concurrent request must set
|
||||||
to the same denoise schedule, so every request must provide the same explicit
|
the same explicit `num_inference_steps`; `None` is rejected because every rank
|
||||||
`num_inference_steps`. Pipeline defaults are rejected because different request
|
must enter each collective.
|
||||||
modes can resolve the same `None` value to different schedules.
|
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
- Direct checkpoint mmap currently requires TP1. TP greater than one is
|
- Direct checkpoint mmap currently requires TP1. TP greater than one is
|
||||||
outside the Phase A shared-mmap support scope and falls back before model
|
outside the Phase A shared-mmap support scope and falls back before model
|
||||||
mutation to the ordinary TP-aware loader. DLO can stream that runtime layout,
|
mutation to the ordinary TP-aware loader. DLO can stream that runtime layout,
|
||||||
and eligible DiT rank-local configurations may use HWR final-layout artifacts,
|
and eligible no-AllGather configurations may use HWR final-layout artifacts,
|
||||||
but direct checkpoint mmap provides no shared-mmap host-memory guarantee for
|
but direct checkpoint mmap provides no shared-mmap host-memory guarantee for
|
||||||
TP greater than one.
|
TP greater than one.
|
||||||
- HSDP with `allgather` on any selected component is rejected to avoid double
|
- HSDP plus AllGather is rejected to avoid double sharding. HSDP without
|
||||||
sharding. HSDP with rank-local transfers has limited end-to-end validation.
|
AllGather has limited end-to-end validation.
|
||||||
- With data parallelism, `allgather` cannot be combined with TeaCache or
|
|
||||||
Cache-DiT on any selected component. Prompt-embedding cache is also
|
|
||||||
incompatible when the text encoder uses `allgather`. Rank-local cache hits
|
|
||||||
could otherwise make ranks enter different weight collectives.
|
|
||||||
- Per-tensor online FP8 linears use the ordinary loader and can run with either
|
- Per-tensor online FP8 linears use the ordinary loader and can run with either
|
||||||
DiT transfer path. With DiT `allgather`, every rank temporarily materializes
|
DLO transfer path. With AllGather, every rank temporarily materializes the
|
||||||
the complete FP8 model in host memory before DLO retains only its shard.
|
complete FP8 model in host memory before DLO retains only its shard. Other
|
||||||
Other online quantization methods require rank-local transfer for the
|
online quantization methods require no-AllGather until their runtime layouts
|
||||||
affected component until their runtime layouts are validated.
|
are validated.
|
||||||
- Resident leading layers require DiT `rank-local` transfer and a model
|
- Resident leading layers require `--dlo-no-use-allgather` and a model
|
||||||
`OffloadPlan` that declares eligible `resident_dit_paths`.
|
`OffloadPlan` that declares eligible `resident_dit_paths`.
|
||||||
- DP concurrency requires an explicit, identical inference-step count.
|
- DP concurrency requires an explicit, identical inference-step count.
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,8 @@ stream.
|
|||||||
| ... | ... | ... | ... |
|
| ... | ... | ... | ... |
|
||||||
| last block | Prefetch block 0 | Compute last block | Free last block |
|
| last block | Prefetch block 0 | Compute last block | Free last block |
|
||||||
|
|
||||||
Selected, plan-declared text-encoder blocks can use the same rank-local
|
Encoders, VAE modules, and non-block DiT modules such as embeddings and norms
|
||||||
streaming mechanism. Image encoders, VAEs, and non-block DiT modules remain
|
remain device resident.
|
||||||
device resident.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -29,44 +28,15 @@ from vllm_omni import Omni
|
|||||||
|
|
||||||
omni = Omni(
|
omni = Omni(
|
||||||
model="Wan-AI/Wan2.2-T2V-A14B-Diffusers",
|
model="Wan-AI/Wan2.2-T2V-A14B-Diffusers",
|
||||||
diffusion_offload_config={
|
enable_layerwise_offload=True,
|
||||||
"mode": "layer",
|
|
||||||
"components": ["dit"],
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
vllm serve Wan-AI/Wan2.2-T2V-A14B-Diffusers \
|
vllm serve Wan-AI/Wan2.2-T2V-A14B-Diffusers \
|
||||||
--omni \
|
--omni --enable-layerwise-offload
|
||||||
--diffusion-offload-config '{"mode":"layer","components":["dit"]}'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Component selection
|
|
||||||
|
|
||||||
Add `dit`, `text_encoder`, or both to the `components` list. Omitting
|
|
||||||
`layer_options` uses safe rank-local defaults:
|
|
||||||
|
|
||||||
- `["dit"]` streams only DiT blocks.
|
|
||||||
- `["text_encoder"]` streams only declared text-encoder blocks.
|
|
||||||
- Listing both streams both components.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# DiT-only layer offload
|
|
||||||
vllm serve /path/to/model --omni \
|
|
||||||
--diffusion-offload-config \
|
|
||||||
'{"mode":"layer","components":["dit"]}'
|
|
||||||
|
|
||||||
# Stream a model-declared text encoder while keeping the DiT resident
|
|
||||||
vllm serve /path/to/model --omni \
|
|
||||||
--diffusion-offload-config \
|
|
||||||
'{"mode":"layer","components":["text_encoder"]}'
|
|
||||||
```
|
|
||||||
|
|
||||||
Encoder categories are resolved from `OffloadPlan.encoder_component_types`
|
|
||||||
first. A name-based fallback is retained for pipelines that predate
|
|
||||||
`OffloadPlan`.
|
|
||||||
|
|
||||||
## Model integration
|
## Model integration
|
||||||
|
|
||||||
Transformer classes declare containers of executable blocks:
|
Transformer classes declare containers of executable blocks:
|
||||||
@@ -83,29 +53,13 @@ class Flux2Transformer2DModel(nn.Module):
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
Auxiliary components use declarative pipeline metadata:
|
See the [layerwise design](../../../design/feature/offloader/layerwise_offload.md) for
|
||||||
|
the discovery and hook invariants. `OffloadPlan` is a separate declarative
|
||||||
```python
|
topology path for distributed layerwise offload.
|
||||||
from vllm_omni.diffusion.offloader import OffloadPlan
|
|
||||||
|
|
||||||
|
|
||||||
class MyPipeline(nn.Module):
|
|
||||||
_encoder_modules = ["prompt_model"]
|
|
||||||
_offload_plan = OffloadPlan(
|
|
||||||
encoder_component_types={"prompt_model": "text_encoder"},
|
|
||||||
encoder_block_attrs={"prompt_model": ("encoder.layers",)},
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
See the [layerwise design](../../../design/feature/offloader/layerwise_offload.md)
|
|
||||||
for the discovery and hook invariants. Both ordinary and distributed layerwise
|
|
||||||
offload consume the same `OffloadPlan` metadata.
|
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
- The default weight transfer is `rank-local`. Set a selected component's
|
- Single device only.
|
||||||
`weight_transfer` to `allgather` to shard its host weights across a
|
|
||||||
compatible multi-device group; backend selection is automatic.
|
|
||||||
- Setup consolidates and pins block parameters, increasing cold-start time.
|
- Setup consolidates and pins block parameters, increasing cold-start time.
|
||||||
- Performance depends on block compute time and host-to-device bandwidth;
|
- Performance depends on block compute time and host-to-device bandwidth;
|
||||||
lightweight blocks may not hide transfers.
|
lightweight blocks may not hide transfers.
|
||||||
@@ -120,10 +120,18 @@ Additional requirements:
|
|||||||
| Parameter | Type | Default | Description |
|
| Parameter | Type | Default | Description |
|
||||||
|-----------|------|---------|-------------|
|
|-----------|------|---------|-------------|
|
||||||
| `vae_use_tiling` | bool | False | Must be set to `True` when using VAE patch parallelism. |
|
| `vae_use_tiling` | bool | False | Must be set to `True` when using VAE patch parallelism. |
|
||||||
|
| `vae_stack_tiling` | `"auto"` \| `"true"` \| `"false"` | `"false"` | For VAEs with native support (currently MiniMax H3), batch local decoder tiles into fewer model calls. `"auto"` enables it when the request has at least two tiles per VAE-parallel rank. |
|
||||||
|
|
||||||
!!! note "Automatic VAE Tiling"
|
!!! note "Automatic VAE Tiling"
|
||||||
When `vae_patch_parallel_size > 1` and the model has a distributed VAE (`DistributedVaeMixin`), the system automatically sets `vae_use_tiling=True` if not already enabled.
|
When `vae_patch_parallel_size > 1` and the model has a distributed VAE (`DistributedVaeMixin`), the system automatically sets `vae_use_tiling=True` if not already enabled.
|
||||||
|
|
||||||
|
!!! tip "MiniMax H3 stacked tiling"
|
||||||
|
MiniMax H3 supports lossless native stacked tiling. Enable it with
|
||||||
|
`--vae-stack-tiling auto` (or `true`) to batch each rank's spatial tiles
|
||||||
|
into one decoder call per temporal window. `auto` keeps the sequential
|
||||||
|
path for shapes that do not provide multiple tiles per rank, while
|
||||||
|
`false` remains the default to avoid increasing the VAE activation peak.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Spatially-Sharded Decode (Wan)
|
## Spatially-Sharded Decode (Wan)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# Diffusion Advanced Features
|
# Diffusion Advanced Features
|
||||||
|
|
||||||
<!-- markdownlint-disable MD028 MD060 -->
|
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Overview](#overview)
|
- [Overview](#overview)
|
||||||
@@ -32,6 +30,7 @@ Cache methods trade minimal quality for significant speedup. Quality loss is typ
|
|||||||
| **[TeaCache](diffusion/cache_acceleration/teacache.md)** | Adaptive caching using modulated inputs | Quick setup, balanced quality/speed on single GPU |
|
| **[TeaCache](diffusion/cache_acceleration/teacache.md)** | Adaptive caching using modulated inputs | Quick setup, balanced quality/speed on single GPU |
|
||||||
| **[Cache-DiT](diffusion/cache_acceleration/cache_dit.md)** | Multiple caching techniques: DBCache, TaylorSeer, SCM | Fine-grained control, tunable quality-speed tradeoff |
|
| **[Cache-DiT](diffusion/cache_acceleration/cache_dit.md)** | Multiple caching techniques: DBCache, TaylorSeer, SCM | Fine-grained control, tunable quality-speed tradeoff |
|
||||||
|
|
||||||
|
|
||||||
#### Lossless Acceleration
|
#### Lossless Acceleration
|
||||||
|
|
||||||
Parallelism methods distribute computation across GPUs without quality loss (mathematically equivalent to single-GPU).
|
Parallelism methods distribute computation across GPUs without quality loss (mathematically equivalent to single-GPU).
|
||||||
@@ -73,6 +72,7 @@ Extension methods add specialized capabilities to diffusion models beyond standa
|
|||||||
| **[LoRA Inference](diffusion/lora.md)** | Enables inference with Low-Rank Adaptation (LoRA) adapters weights | Reinforcement learning extensions |
|
| **[LoRA Inference](diffusion/lora.md)** | Enables inference with Low-Rank Adaptation (LoRA) adapters weights | Reinforcement learning extensions |
|
||||||
| **[Frame Interpolation](diffusion/frame_interpolation.md)** | Inserts intermediate video frames after generation for smoother motion | Video generation pipelines that need higher temporal smoothness |
|
| **[Frame Interpolation](diffusion/frame_interpolation.md)** | Inserts intermediate video frames after generation for smoother motion | Video generation pipelines that need higher temporal smoothness |
|
||||||
|
|
||||||
|
|
||||||
### Execution Modes
|
### Execution Modes
|
||||||
|
|
||||||
Execution modes control how the diffusion pipeline processes requests and
|
Execution modes control how the diffusion pipeline processes requests and
|
||||||
@@ -116,7 +116,7 @@ The following tables show which models support each feature:
|
|||||||
|
|
||||||
| Model | ⚡TeaCache | ⚡Cache-DiT | 🔀SP (Ulysses & Ring) | 🔀CFG-Parallel | 🔀Tensor-Parallel | 🔀Pipeline-Parallel | 🔀HSDP | 💾CPU Offload (Layerwise) | 💾VAE-Patch-Parallel | 💾Quantization | 🔄Step Execution |
|
| Model | ⚡TeaCache | ⚡Cache-DiT | 🔀SP (Ulysses & Ring) | 🔀CFG-Parallel | 🔀Tensor-Parallel | 🔀Pipeline-Parallel | 🔀HSDP | 💾CPU Offload (Layerwise) | 💾VAE-Patch-Parallel | 💾Quantization | 🔄Step Execution |
|
||||||
|--------------------------|:---------:|:----------:|:---------------------:|:--------------:|:-----------------:|:-------------------:|:------:|:-------------------------:|:--------------------:|:--------------:|:----------------:|
|
|--------------------------|:---------:|:----------:|:---------------------:|:--------------:|:-----------------:|:-------------------:|:------:|:-------------------------:|:--------------------:|:--------------:|:----------------:|
|
||||||
| **Bagel** | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
| **Bagel** | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||||
| **Boogu-Image** | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
| **Boogu-Image** | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| **FLUX.1-dev** | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ |
|
| **FLUX.1-dev** | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ |
|
||||||
| **FLUX.1-schnell** | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ |
|
| **FLUX.1-schnell** | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ |
|
||||||
@@ -147,13 +147,11 @@ The following tables show which models support each feature:
|
|||||||
| **Cosmos3** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (decode) | ✅ | ❌ |
|
| **Cosmos3** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (decode) | ✅ | ❌ |
|
||||||
|
|
||||||
> Notes:
|
> Notes:
|
||||||
>
|
|
||||||
> 1. Nextstep_1(T2I) does not support cache acceleration methods such as TeaCache or Cache-DiT.
|
> 1. Nextstep_1(T2I) does not support cache acceleration methods such as TeaCache or Cache-DiT.
|
||||||
> 2. `Tongyi-MAI/Z-Image-Turbo` is a distilled model with minimal NFEs; CFG-Parallel is not necessary.
|
> 2. `Tongyi-MAI/Z-Image-Turbo` is a distilled model with minimal NFEs; CFG-Parallel is not necessary.
|
||||||
> 3. Cosmos3 T2I uses `Cosmos3OmniDiffusersPipeline` with `modalities=["image"]`. Model-level CPU offload swaps the nested UND reasoner and GEN generator pathways; layerwise offload remains available for blockwise GEN/UND offload.
|
> 3. Cosmos3 T2I uses `Cosmos3OmniDiffusersPipeline` with `modalities=["image"]`. Model-level CPU offload swaps the nested UND reasoner and GEN generator pathways; layerwise offload remains available for blockwise GEN/UND offload.
|
||||||
> 4. Krea 2 currently supports single-GPU inference plus LoRA, Cache-DiT, HSDP, CPU/layerwise offload, and VAE-patch-parallel (decode). TP/SP/CFG-Parallel are not yet wired. The few-step distilled (Turbo) checkpoint uses `is_distilled=true` (fixed timestep shift `mu=1.15`); generate at 2048x2048 by default with `num_inference_steps≈8` and `guidance_scale=0`. The Raw checkpoint uses 1024x1024, `num_inference_steps=28`, and `guidance_scale=4.5`.
|
> 4. Krea 2 currently supports single-GPU inference plus LoRA, Cache-DiT, HSDP, CPU/layerwise offload, and VAE-patch-parallel (decode). TP/SP/CFG-Parallel are not yet wired. The few-step distilled (Turbo) checkpoint uses `is_distilled=true` (fixed timestep shift `mu=1.15`); generate at 2048x2048 by default with `num_inference_steps≈8` and `guidance_scale=0`. The Raw checkpoint uses 1024x1024, `num_inference_steps=28`, and `guidance_scale=4.5`.
|
||||||
> 5. HunyuanImage3 supports step execution. Multi-request step execution requires `TORCH_SDPA`; see [Diffusion Execution Modes](diffusion/execution_modes.md#step-execution).
|
> 5. HunyuanImage3 supports step execution. Multi-request step execution requires `TORCH_SDPA`; see [Diffusion Execution Modes](diffusion/execution_modes.md#step-execution).
|
||||||
> 6. BAGEL step execution supports image generation with `bagel.yaml`, `bagel_think.yaml`, and `bagel_single_stage.yaml`; two-stage Thinker execution and explicit single-stage text output remain on their existing complete-request paths. Image requests require `num_inference_steps >= 2`. BAGEL step execution cannot currently be combined with sequence parallelism or a diffusion cache backend; see [Diffusion Execution Modes](diffusion/execution_modes.md#step-execution).
|
|
||||||
|
|
||||||
### VideoGen
|
### VideoGen
|
||||||
|
|
||||||
@@ -162,16 +160,15 @@ The following tables show which models support each feature:
|
|||||||
| **Wan2.2** | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ (encode/decode) | ❌ | ❌ |
|
| **Wan2.2** | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ (encode/decode) | ❌ | ❌ |
|
||||||
| **Wan2.2-S2V** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (encode/decode) | ❌ | ❌ |
|
| **Wan2.2-S2V** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (encode/decode) | ❌ | ❌ |
|
||||||
| **Wan2.1-VACE** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (decode) | ❌ | ❌ |
|
| **Wan2.1-VACE** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (decode) | ❌ | ❌ |
|
||||||
| **LTX-2** | ❌ | ✅ | ✅ (Ulysses only) | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (decode) | ❌ | ❌ |
|
| **LTX-2** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (decode) | ❌ | ❌ |
|
||||||
| **LTX-2.3** | ❌ | ✅ | ✅ (Ulysses only) | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (decode) | ❌ | ❌ |
|
| **LTX-2.3** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (decode) | ❌ | ❌ |
|
||||||
| **LTX-2.5** | ❌ | ❓ (one-stage) | ✅* (Ulysses only) | ✅ (Full only) | ❓ | ❌ | ✅ | ✅ | ✅ (decode) | ❓ (FP8) | ❌ |
|
| **LTX-2.5** | ❌ | ❓ (one-stage) | ❓ (Ulysses only) | ✅ (Full only) | ❓ | ❌ | ✅ | ✅ | ✅ (decode) | ❓ (FP8) | ❌ |
|
||||||
| **SANA-Video-2B T2V I2V** | ❌ | ❌ | ✅ (`--usp`, frame-sharded) | ✅ | ✅ (TP=2 only) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
| **SANA-Video-2B T2V I2V** | ❌ | ❌ | ❌ | ✅ | ✅ (TP=2 only) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| **Helios** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅* |
|
| **Helios** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅* |
|
||||||
| **HunyuanVideo-1.5 T2V I2V** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (encode/decode) | ✅ | ❌ |
|
| **HunyuanVideo-1.5 T2V I2V** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (encode/decode) | ✅ | ❌ |
|
||||||
| **Cosmos3** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (encode/decode) | ✅ | ❌ |
|
| **Cosmos3** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ (encode/decode) | ✅ | ❌ |
|
||||||
| **LongCat-Video-Avatar-1.5** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
| **LongCat-Video-Avatar-1.5** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| **MiniMax-H3** | ✅ (FL2VA) | ✅ | ✅ | ❌ | ✅ (DiT/TE) | ❌ | ✅ | ✅ | ✅ (tile) | ✅ (DiT) | ❌ |
|
| **MiniMax-H3** | ✅ (FL2VA) | ✅ | ✅ | ❌ | ✅ (DiT/TE) | ❌ | ✅ | ✅ | ✅ (tile) | ✅ (DiT) | ❌ |
|
||||||
| **MAGI-2 Preview** | ❌ | ✅ | ✅ (Ulysses) | ✅ (2-way) | ✅ | ❌ | ✅ | ✅ (1-GPU/LW; DLO DP-AG/SP no-AG) | ✅ (tile) | ❌ | ❌ |
|
|
||||||
| **SANA-WM** | ❌ | ❌ | ❌<sup>5</sup> | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
| **SANA-WM** | ❌ | ❌ | ❌<sup>5</sup> | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||||
|
|
||||||
> Notes:
|
> Notes:
|
||||||
@@ -183,6 +180,7 @@ The following tables show which models support each feature:
|
|||||||
|
|
||||||
> **Step execution note:** Helios supports single-request step execution only;
|
> **Step execution note:** Helios supports single-request step execution only;
|
||||||
> use `max_num_seqs=1`.
|
> use `max_num_seqs=1`.
|
||||||
|
|
||||||
**Frame Interpolation Support**
|
**Frame Interpolation Support**
|
||||||
|
|
||||||
- **Supported**: Wan2.2 text-to-video, image-to-video, and TI2V pipelines; SANA-Video-2B native text-to-video and image-to-video pipelines
|
- **Supported**: Wan2.2 text-to-video, image-to-video, and TI2V pipelines; SANA-Video-2B native text-to-video and image-to-video pipelines
|
||||||
@@ -194,6 +192,7 @@ The following tables show which models support each feature:
|
|||||||
|-----------------------|:---------:|:----------:|:---------------------:|:--------------:|:-----------------:|:-------------------:|:------:|:-------------------------:|:--------------------:|:--------------:|:----------------:|
|
|-----------------------|:---------:|:----------:|:---------------------:|:--------------:|:-----------------:|:-------------------:|:------:|:-------------------------:|:--------------------:|:--------------:|:----------------:|
|
||||||
| **Stable-Audio-Open** | ✅ | ❌ | ❓ | ❓ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ |
|
| **Stable-Audio-Open** | ✅ | ❌ | ❓ | ❓ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ |
|
||||||
|
|
||||||
|
|
||||||
## Feature Compatibility
|
## Feature Compatibility
|
||||||
|
|
||||||
**Legend:**
|
**Legend:**
|
||||||
@@ -232,6 +231,7 @@ The following tables show which models support each feature:
|
|||||||
5. The compatibility matrix uses FP8 as the representative quantization method.
|
5. The compatibility matrix uses FP8 as the representative quantization method.
|
||||||
6. Step Execution is not compatible with any diffusion cache backend. LoRA is supported, but each scheduled batch must use a single adapter (requests with different `lora_request` or `lora_scale` are kept in separate batches).
|
6. Step Execution is not compatible with any diffusion cache backend. LoRA is supported, but each scheduled batch must use a single adapter (requests with different `lora_request` or `lora_scale` are kept in separate batches).
|
||||||
|
|
||||||
|
|
||||||
## Multi-Thread Weight Loading
|
## Multi-Thread Weight Loading
|
||||||
|
|
||||||
The loading guide now lives at [Diffusion Startup and
|
The loading guide now lives at [Diffusion Startup and
|
||||||
|
|||||||
@@ -126,7 +126,11 @@ python examples/offline_inference/text_to_speech/cosyvoice3/end2end.py \
|
|||||||
## Fish Speech S2 Pro
|
## Fish Speech S2 Pro
|
||||||
|
|
||||||
4B dual-AR text-to-speech model from FishAudio with the DAC codec at 44.1 kHz.
|
4B dual-AR text-to-speech model from FishAudio with the DAC codec at 44.1 kHz.
|
||||||
No extra packages are required; the DAC codec is vendored in vLLM-Omni.
|
|
||||||
|
### Prerequisites
|
||||||
|
```bash
|
||||||
|
pip install fish-speech
|
||||||
|
```
|
||||||
|
|
||||||
### Quick start
|
### Quick start
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -60,50 +60,6 @@ vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni --port 8091 \
|
|||||||
|
|
||||||
See [`bagel_single_stage.yaml`](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel_single_stage.yaml) for configuration. The `pipeline: bagel_single_stage` field selects the single-stage topology from the pipeline registry.
|
See [`bagel_single_stage.yaml`](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel_single_stage.yaml) for configuration. The `pipeline: bagel_single_stage` field selects the single-stage topology from the pipeline registry.
|
||||||
|
|
||||||
### Step Execution and Continuous Batching
|
|
||||||
|
|
||||||
Image generation supports step execution with all three BAGEL deploy configs.
|
|
||||||
The global flag is applied only to diffusion stages:
|
|
||||||
|
|
||||||
- With `bagel.yaml` or `bagel_think.yaml`, Stage 1 uses step execution and the
|
|
||||||
Stage 0 Thinker remains autoregressive.
|
|
||||||
- With `bagel_single_stage.yaml`, image requests use step execution in Stage 0.
|
|
||||||
Explicit `text2text` and `img2text` requests use the same complete-request
|
|
||||||
text path as they do without `--step-execution`.
|
|
||||||
|
|
||||||
Start with the deploy file's default diffusion capacity of one:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni --port 8091 \
|
|
||||||
--deploy-config vllm_omni/deploy/bagel.yaml \
|
|
||||||
--step-execution
|
|
||||||
```
|
|
||||||
|
|
||||||
To enable step-wise continuous batching, override `max_num_seqs` on the
|
|
||||||
diffusion stage. Use Stage 1 for either two-stage config:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni --port 8091 \
|
|
||||||
--deploy-config vllm_omni/deploy/bagel.yaml \
|
|
||||||
--step-execution \
|
|
||||||
--stage-overrides '{"1":{"max_num_seqs":4}}'
|
|
||||||
```
|
|
||||||
|
|
||||||
Use Stage 0 for the single-stage config:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni --port 8091 \
|
|
||||||
--deploy-config vllm_omni/deploy/bagel_single_stage.yaml \
|
|
||||||
--step-execution \
|
|
||||||
--stage-overrides '{"0":{"max_num_seqs":4}}'
|
|
||||||
```
|
|
||||||
|
|
||||||
BAGEL image requests require `num_inference_steps >= 2`: the original BAGEL
|
|
||||||
schedule uses `num_inference_steps - 1` denoising updates. The scheduler batches
|
|
||||||
only requests with compatible effective image sizes and BAGEL CFG/renormalization
|
|
||||||
settings. Sequence parallelism and diffusion cache backends such as TeaCache or
|
|
||||||
Cache-DiT are not currently supported together with BAGEL step execution.
|
|
||||||
|
|
||||||
### Tensor Parallelism (TP)
|
### Tensor Parallelism (TP)
|
||||||
|
|
||||||
For larger models or multi-GPU environments, enable TP via CLI:
|
For larger models or multi-GPU environments, enable TP via CLI:
|
||||||
@@ -247,13 +203,6 @@ curl http://localhost:8091/v1/chat/completions \
|
|||||||
-d @payload.json
|
-d @payload.json
|
||||||
```
|
```
|
||||||
|
|
||||||
BAGEL img2img derives its generated image size from the input image. It
|
|
||||||
preserves the input aspect ratio, aligns dimensions to the latent stride, and
|
|
||||||
applies the checkpoint size limit; explicit `height` and `width` values do not
|
|
||||||
override this model-specific resize policy. In step mode, the effective size is
|
|
||||||
resolved before scheduler admission so requests with different resulting
|
|
||||||
shapes are not combined.
|
|
||||||
|
|
||||||
### Image to Text (img2text)
|
### Image to Text (img2text)
|
||||||
|
|
||||||
**Python client:**
|
**Python client:**
|
||||||
@@ -318,8 +267,8 @@ curl http://localhost:8091/v1/chat/completions \
|
|||||||
| `--server` / `-s` | `http://localhost:8091` | Server URL |
|
| `--server` / `-s` | `http://localhost:8091` | Server URL |
|
||||||
| `--image-url` / `-i` | `None` | Input image URL or local path (img2img/img2text) |
|
| `--image-url` / `-i` | `None` | Input image URL or local path (img2img/img2text) |
|
||||||
| `--modality` / `-m` | `text2img` | `text2img`, `img2img`, `img2text`, `text2text` |
|
| `--modality` / `-m` | `text2img` | `text2img`, `img2img`, `img2text`, `text2text` |
|
||||||
| `--height` | `512` | Text-to-image output height; BAGEL img2img derives its size from the input image |
|
| `--height` | `512` | Image height in pixels |
|
||||||
| `--width` | `512` | Text-to-image output width; BAGEL img2img derives its size from the input image |
|
| `--width` | `512` | Image width in pixels |
|
||||||
| `--steps` | `25` | Number of inference steps |
|
| `--steps` | `25` | Number of inference steps |
|
||||||
| `--seed` | `42` | Random seed |
|
| `--seed` | `42` | Random seed |
|
||||||
| `--negative` | `None` | Negative prompt for CFG |
|
| `--negative` | `None` | Negative prompt for CFG |
|
||||||
@@ -344,7 +293,6 @@ python openai_chat_client.py \
|
|||||||
| File | Description |
|
| File | Description |
|
||||||
| :--- | :---------- |
|
| :--- | :---------- |
|
||||||
| [`bagel.yaml`](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel.yaml) | Two-stage default (Thinker + DiT on GPU 0) |
|
| [`bagel.yaml`](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel.yaml) | Two-stage default (Thinker + DiT on GPU 0) |
|
||||||
| [`bagel_think.yaml`](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel_think.yaml) | Two-stage think mode (Thinker + DiT) |
|
|
||||||
| [`bagel_single_stage.yaml`](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel_single_stage.yaml) | Single-stage (DiT only) |
|
| [`bagel_single_stage.yaml`](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel_single_stage.yaml) | Single-stage (DiT only) |
|
||||||
|
|
||||||
### Key Deploy YAML Fields
|
### Key Deploy YAML Fields
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ implemented with clear Diffusers or vLLM-Omni behavior.
|
|||||||
- Sequence parallel execution
|
- Sequence parallel execution
|
||||||
- TeaCache / Cache-DiT acceleration
|
- TeaCache / Cache-DiT acceleration
|
||||||
- Step-wise execution (continuous batching)
|
- Step-wise execution (continuous batching)
|
||||||
- Component-selective `diffusion_offload_config` (the legacy whole-pipeline CPU-offload options remain supported)
|
|
||||||
|
|
||||||
For these features, it is recommended to use natively supported pipelines instead.
|
For these features, it is recommended to use natively supported pipelines instead.
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni --port 8091
|
|||||||
|
|
||||||
The default deployment configuration situated at `vllm_omni/deploy/qwen3_omni_moe.yaml` is resolved and loaded
|
The default deployment configuration situated at `vllm_omni/deploy/qwen3_omni_moe.yaml` is resolved and loaded
|
||||||
automatically via the model registry, obviating the necessity for the `--deploy-config` flag in standard deployment topologies.
|
automatically via the model registry, obviating the necessity for the `--deploy-config` flag in standard deployment topologies.
|
||||||
The bundled Qwen3-Omni setup explicitly sets `moe_backend: triton` for the Thinker and Talker stages. This keeps
|
The bundled Qwen3-Omni setup defaults `VLLM_USE_FLASHINFER_MOE_FP16=0`. This keeps the Thinker & Talker on vLLM's
|
||||||
both stages on vLLM's Triton unquantized MoE path and avoids the unstable FlashInfer CUTLASS unquantized MoE path on
|
Triton unquantized MoE path and avoids the performance regression observed with the FlashInfer CUTLASS unquantized MoE
|
||||||
some GPUs.
|
backend.
|
||||||
Asynchronous chunk streaming is **enabled by default** within the bundled configuration.
|
Asynchronous chunk streaming is **enabled by default** within the bundled configuration.
|
||||||
|
|
||||||
To explicitly utilize a custom deployment YAML, specify the configuration path:
|
To explicitly utilize a custom deployment YAML, specify the configuration path:
|
||||||
@@ -87,9 +87,15 @@ vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni --port 8091 \
|
|||||||
--stage-overrides '{"1": {"gpu_memory_utilization": 0.5}}'
|
--stage-overrides '{"1": {"gpu_memory_utilization": 0.5}}'
|
||||||
```
|
```
|
||||||
|
|
||||||
To experiment with another supported MoE backend, set `moe_backend` in the
|
To experiment with the FlashInfer FP16 MoE path, set `VLLM_USE_FLASHINFER_MOE_FP16=1` before launching the server:
|
||||||
deployment YAML for both the Thinker and Talker stages. For the stage-based
|
```bash
|
||||||
CLI, pass `--moe-backend` directly on each stage command.
|
VLLM_USE_FLASHINFER_MOE_FP16=1 \
|
||||||
|
vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni --port 8091
|
||||||
|
```
|
||||||
|
|
||||||
|
For the stage-based CLI, you usually do **not** need `--stage-overrides` for
|
||||||
|
that kind of change. Since each command launches one stage, just pass the knob
|
||||||
|
directly on that stage command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
CUDA_VISIBLE_DEVICES=1 vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni \
|
CUDA_VISIBLE_DEVICES=1 vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni \
|
||||||
|
|||||||
Loaded 100 of 954 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user