rebase: target the official vLLM 0.31.0 release
Use upstream release images at db9527a46873, preserve custom processor conditioning, and include weekly jobs in full Buildkite release validation. Signed-off-by: tzhouam <tzhouam@connect.ust.hk>
This commit is contained in:
1 parent
008fa25263
commit
ed876de879
15 files changed
+142
-45
No files matched your search
@@ -33,3 +33,13 @@ steps:
|
||||
- python3 .buildkite/common/scripts/upload_pipeline.py --upload --all .buildkite/cuda/test-nightly.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# Include the slow model cases moved from nightly into weekly for release validation.
|
||||
- label: "Upload Weekly Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1"
|
||||
commands:
|
||||
- python3 .buildkite/common/scripts/upload_pipeline.py --upload --all .buildkite/cuda/test-weekly.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
@@ -12,24 +12,24 @@ from pathlib import Path
|
||||
def main() -> None:
|
||||
dockerfile = Path(__file__).resolve().parents[3] / "docker" / "Dockerfile.ci"
|
||||
match = re.search(
|
||||
r"^ARG VLLM_PRECOMPILED_WHEEL_COMMIT=([0-9a-f]{40})$",
|
||||
r"^ARG VLLM_VERSION=([0-9]+\.[0-9]+\.[0-9]+)$",
|
||||
dockerfile.read_text(),
|
||||
re.MULTILINE,
|
||||
)
|
||||
if match is None:
|
||||
raise RuntimeError(f"Missing vLLM commit pin in {dockerfile}")
|
||||
expected_commit = match.group(1)
|
||||
raise RuntimeError(f"Missing vLLM release version in {dockerfile}")
|
||||
expected_version = match.group(1)
|
||||
|
||||
import torch
|
||||
import vllm
|
||||
|
||||
assert expected_commit[:8] in vllm.__version__, vllm.__version__
|
||||
assert vllm.__version__ == expected_version, vllm.__version__
|
||||
assert torch.cuda.is_available(), "vLLM runtime check requires a GPU worker"
|
||||
for module in ("flashinfer", "vllm._C_stable_libtorch"):
|
||||
importlib.import_module(module)
|
||||
print(
|
||||
f"Verified vLLM CUDA runtime: vllm={vllm.__version__} "
|
||||
f"commit={expected_commit} torch={torch.__version__} "
|
||||
f"expected={expected_version} torch={torch.__version__} "
|
||||
f"cuda={torch.version.cuda} device={torch.cuda.get_device_name()}"
|
||||
)
|
||||
|
||||
|
||||
+8
-10
@@ -1,11 +1,9 @@
|
||||
# Target an unreleased vLLM main commit. The official commit image carries
|
||||
# the matching CUDA/PyTorch/FlashInfer stack; do not overlay a nightly wheel
|
||||
# on the previous release image. Copilot updates this commit pin, which also
|
||||
# selects the image used by CI. The selected commit must have a published
|
||||
# nightly image as well as a cu130 wheel.
|
||||
ARG VLLM_PRECOMPILED_WHEEL_COMMIT=ac9126e58aa7bbab1856ba6593ba4d5003fea516
|
||||
ARG VLLM_BASE_IMAGE=vllm/vllm-openai
|
||||
ARG VLLM_BASE_TAG=nightly-${VLLM_PRECOMPILED_WHEEL_COMMIT}
|
||||
# Use the official release image with its matching CUDA/PyTorch stack.
|
||||
# The release images are available in upstream ECR before Docker Hub promotion.
|
||||
ARG VLLM_VERSION=0.31.0
|
||||
ARG VLLM_PRECOMPILED_WHEEL_COMMIT=db9527a46873454610df6dbedf79a36d6bf1a7f6
|
||||
ARG VLLM_BASE_IMAGE=public.ecr.aws/q9t5s3a7/vllm-release-repo
|
||||
ARG VLLM_BASE_TAG=${VLLM_PRECOMPILED_WHEEL_COMMIT}
|
||||
|
||||
# We use registry-based layer caching for the dependencies,
|
||||
# where the tag is determined based on the hash of the contents
|
||||
@@ -13,7 +11,7 @@ ARG VLLM_BASE_TAG=nightly-${VLLM_PRECOMPILED_WHEEL_COMMIT}
|
||||
# everything except the actual project dir, since that should not
|
||||
# change much across branches.
|
||||
FROM ${VLLM_BASE_IMAGE}:${VLLM_BASE_TAG} AS deps
|
||||
ARG VLLM_PRECOMPILED_WHEEL_COMMIT
|
||||
ARG VLLM_VERSION
|
||||
# Keep APP_DIR outside /workspace so k8s Buildkite workspace mounts cannot
|
||||
# shadow the editable install target (#5364). Docker WORKDIR creates /opt if
|
||||
# needed.
|
||||
@@ -47,7 +45,7 @@ RUN uv pip install --system -e ".[dev]"
|
||||
# Fail the image build if dependency resolution replaced the selected vLLM.
|
||||
# The CPU builder has no NVIDIA driver; CUDA imports are checked at the start
|
||||
# of each GPU test job by .buildkite/cuda/scripts/check_vllm_runtime.py.
|
||||
RUN python3 -c "import vllm; assert '${VLLM_PRECOMPILED_WHEEL_COMMIT}'[:8] in vllm.__version__, vllm.__version__"
|
||||
RUN python3 -c "import vllm; assert vllm.__version__ == '${VLLM_VERSION}', vllm.__version__"
|
||||
|
||||
# The final stage just copies the working dir on top of the
|
||||
# dependencies image. This uses --link so that we can skip
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
ARG BASE_IMAGE=vllm/vllm-openai:v0.30.0
|
||||
# Official vLLM v0.31.0 release image, before Docker Hub tag promotion.
|
||||
ARG BASE_IMAGE=public.ecr.aws/q9t5s3a7/vllm-release-repo:db9527a46873454610df6dbedf79a36d6bf1a7f6
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
ARG COMMON_WORKDIR=/app
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Keep the ROCm runtime aligned with the vLLM release targeted by
|
||||
# docker/Dockerfile.ci. A stale base image can build successfully while failing
|
||||
# at runtime when vLLM-Omni imports APIs added by the newer vLLM release.
|
||||
ARG BASE_IMAGE=vllm/vllm-openai-rocm:v0.30.0
|
||||
# Official vLLM v0.31.0 release image, before Docker Hub tag promotion.
|
||||
ARG BASE_IMAGE=public.ecr.aws/q9t5s3a7/vllm-release-repo:db9527a46873454610df6dbedf79a36d6bf1a7f6-rocm
|
||||
|
||||
# Keep the dependency-heavy portion independent from the source tree. The
|
||||
# registry cache is keyed on these inputs, while the final source copy can be
|
||||
@@ -12,11 +13,11 @@ FROM ${BASE_IMAGE} AS deps
|
||||
# BASE_IMAGE pins the default prebuilt runtime when USE_NIGHTLY_BUILD=0.
|
||||
# VLLM_VERSION_OR_COMMIT_HASH is consumed only by the opt-in source rebuild when
|
||||
# USE_NIGHTLY_BUILD=1. Keep both aligned with docker/Dockerfile.ci's
|
||||
# VLLM_BASE_TAG. This is enforced by tests/buildkite/test_rocm_dockerfile.py. An
|
||||
# release version. This is enforced by tests/buildkite/test_rocm_dockerfile.py. An
|
||||
# intentional custom source pin must update that regression in the same change,
|
||||
# and should return to the stable release as soon as one is available.
|
||||
ARG USE_NIGHTLY_BUILD=0
|
||||
ARG VLLM_VERSION_OR_COMMIT_HASH=v0.30.0
|
||||
ARG VLLM_VERSION_OR_COMMIT_HASH=v0.31.0
|
||||
ARG ARG_PYTORCH_ROCM_ARCH
|
||||
ENV PYTORCH_ROCM_ARCH=${ARG_PYTORCH_ROCM_ARCH:-${PYTORCH_ROCM_ARCH}}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# kernels==0.16.1 requires the LayerRepository version=/revision= integration
|
||||
# introduced in transformers 5.13. Keep the tested upper bound: 5.15 has
|
||||
# a reported model-construction regression; later versions need validation.
|
||||
# This range also satisfies vLLM 0.30.0's transformers>=5.10.4 requirement.
|
||||
# This range also satisfies vLLM 0.31.0's transformers>=5.10.4,<5.18.0 requirement.
|
||||
# MOSS-TTS-Nano's list/set weight-loading compatibility is handled by
|
||||
# transformers_keys_to_ignore_compat in model_executor/models/utils.py.
|
||||
transformers >= 5.13.0, < 5.15
|
||||
|
||||
@@ -11,6 +11,7 @@ REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
AMD_TEMPLATE = REPO_ROOT / ".buildkite/amd/test-template-amd-omni.j2"
|
||||
AMD_BUILD_SCRIPT = REPO_ROOT / ".buildkite/amd/scripts/build-ci-image.sh"
|
||||
CUDA_RELEASE_DOCKERFILE = REPO_ROOT / "docker/Dockerfile.cuda"
|
||||
CUDA_CI_DOCKERFILE = REPO_ROOT / "docker/Dockerfile.ci"
|
||||
ROCM_DOCKERFILE = REPO_ROOT / "docker/Dockerfile.rocm"
|
||||
ROCM_DOCKERIGNORE = REPO_ROOT / "docker/Dockerfile.rocm.dockerignore"
|
||||
|
||||
@@ -31,16 +32,15 @@ def _line_index(lines: list[str], prefix: str) -> int:
|
||||
|
||||
|
||||
def test_rocm_base_tracks_cuda_vllm_release() -> None:
|
||||
# CUDA CI can target a main-branch nightly independently of the stable
|
||||
# release images used by the CUDA and ROCm distribution Dockerfiles.
|
||||
cuda_base = _docker_arg(CUDA_RELEASE_DOCKERFILE, "BASE_IMAGE")
|
||||
_, _, cuda_release = cuda_base.rpartition(":")
|
||||
cuda_image, _, cuda_release = cuda_base.rpartition(":")
|
||||
rocm_base = _docker_arg(ROCM_DOCKERFILE, "BASE_IMAGE")
|
||||
|
||||
image_ref, separator, image_tag = rocm_base.rpartition(":")
|
||||
assert separator, f"expected a tagged ROCm base image, got {rocm_base}"
|
||||
assert image_ref.rsplit("/", 1)[-1] == "vllm-openai-rocm", image_ref
|
||||
assert image_tag == cuda_release
|
||||
assert image_ref == cuda_image
|
||||
assert image_tag == f"{cuda_release}-rocm"
|
||||
assert cuda_release == _docker_arg(CUDA_CI_DOCKERFILE, "VLLM_PRECOMPILED_WHEEL_COMMIT")
|
||||
|
||||
|
||||
def test_rocm_defaults_to_prebuilt_base_image() -> None:
|
||||
@@ -107,11 +107,10 @@ def test_rocm_build_context_excludes_git_history() -> None:
|
||||
|
||||
|
||||
def test_rocm_source_ref_tracks_cuda_vllm_release() -> None:
|
||||
cuda_base = _docker_arg(CUDA_RELEASE_DOCKERFILE, "BASE_IMAGE")
|
||||
_, _, cuda_release = cuda_base.rpartition(":")
|
||||
cuda_release = _docker_arg(CUDA_CI_DOCKERFILE, "VLLM_VERSION")
|
||||
rocm_source_ref = _docker_arg(ROCM_DOCKERFILE, "VLLM_VERSION_OR_COMMIT_HASH")
|
||||
|
||||
assert rocm_source_ref == cuda_release
|
||||
assert rocm_source_ref == f"v{cuda_release}"
|
||||
|
||||
|
||||
def test_rocm_dockerfile_contains_vllm_api_canary() -> None:
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
from importlib import import_module
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
from transformers import BatchFeature
|
||||
from vllm.config.multimodal import MultiModalDummyOptions
|
||||
from vllm.multimodal.parse import AudioProcessorItems, ImageProcessorItems, MultiModalDataItems
|
||||
from vllm.multimodal.processing import BaseMultiModalProcessor
|
||||
|
||||
from vllm_omni.inputs.mm_processor import OmniMultiModalProcessor
|
||||
from vllm_omni.inputs.mm_processor import OmniDummyInputsBuilder, OmniMultiModalProcessor
|
||||
|
||||
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
||||
|
||||
@@ -47,3 +50,77 @@ def test_custom_processor_bridge_preserves_prompt_kwargs_and_passthrough(counts,
|
||||
)
|
||||
assert dict(result) == ({"features": "processed", "embedding": "preserve"} if counts else {"features": "processed"})
|
||||
assert kwargs == before
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"module_name,builder_name,processor_name,expected_kwargs",
|
||||
[
|
||||
(
|
||||
"cosyvoice3",
|
||||
"CosyVoice3DummyInputsBuilder",
|
||||
"CosyVoice3MultiModalProcessor",
|
||||
{"prompt_text": "Testing my voices. Why should I not?"},
|
||||
),
|
||||
(
|
||||
"glm_tts",
|
||||
"GLMTTSDummyInputsBuilder",
|
||||
"GLMTTSMultiModalProcessor",
|
||||
{"prompt_text": "This is the reference voice."},
|
||||
),
|
||||
(
|
||||
"omnivoice",
|
||||
"OmniVoiceDummyInputsBuilder",
|
||||
"OmniVoiceMultiModalProcessor",
|
||||
{"ref_text": "Testing voice cloning."},
|
||||
),
|
||||
("mimo_audio", "MiMoAudioLLMDummyInputsBuilder", "MiMoAudioLLMMultiModalProcessor", {}),
|
||||
],
|
||||
)
|
||||
def test_dummy_budget_preserves_model_conditioning(module_name, builder_name, processor_name, expected_kwargs):
|
||||
"""The v0.31 budget path must reach each model's custom builder hook."""
|
||||
module = import_module(f"vllm_omni.model_executor.models.{module_name}.{module_name}")
|
||||
builder = object.__new__(getattr(module, builder_name))
|
||||
assert isinstance(builder, OmniDummyInputsBuilder)
|
||||
items = MultiModalDataItems({})
|
||||
builder.info = SimpleNamespace(ctx=SimpleNamespace(tokenizer=None), parse_mm_data=Mock(return_value=items))
|
||||
builder.get_dummy_mm_data = Mock(return_value={})
|
||||
processor = object.__new__(getattr(module, processor_name))
|
||||
processor.dummy_inputs = builder
|
||||
|
||||
inputs = processor.get_dummy_inputs(128, {"audio": 1}, MultiModalDummyOptions())
|
||||
|
||||
assert inputs.mm_data_items is items
|
||||
assert inputs.hf_processor_mm_kwargs == expected_kwargs
|
||||
assert inputs.prompt == ("<|empty|>" if module_name == "mimo_audio" else [])
|
||||
|
||||
|
||||
def test_dummy_budget_keeps_upstream_path_for_standard_builders(monkeypatch):
|
||||
class Processor(OmniMultiModalProcessor):
|
||||
def _get_mm_fields_config(self, *args):
|
||||
return {}
|
||||
|
||||
def _get_prompt_updates(self, *args):
|
||||
return []
|
||||
|
||||
processor = object.__new__(Processor)
|
||||
processor.dummy_inputs = SimpleNamespace()
|
||||
expected = object()
|
||||
upstream = Mock(return_value=expected)
|
||||
monkeypatch.setattr(BaseMultiModalProcessor, "get_dummy_inputs", upstream)
|
||||
options = MultiModalDummyOptions()
|
||||
|
||||
assert processor.get_dummy_inputs(128, {"audio": 1}, options) is expected
|
||||
upstream.assert_called_once_with(128, {"audio": 1}, options)
|
||||
|
||||
|
||||
def test_voxtral_dummy_budget_uses_audio_token_prompt():
|
||||
from vllm_omni.model_executor.models.voxtral_tts.voxtral_tts_audio_generation import VoxtralTTSMultiModalProcessor
|
||||
|
||||
processor = object.__new__(VoxtralTTSMultiModalProcessor)
|
||||
expected = SimpleNamespace(prompt=[1, 25, 24, 35])
|
||||
builder = SimpleNamespace(get_dummy_processor_inputs=Mock(return_value=expected))
|
||||
processor.dummy_inputs = builder
|
||||
options = MultiModalDummyOptions()
|
||||
|
||||
assert processor.get_dummy_inputs(128, {"audio": 1}, options) is expected
|
||||
builder.get_dummy_processor_inputs.assert_called_once_with(128, {"audio": 1}, options)
|
||||
@@ -986,6 +986,27 @@ def test_cosyvoice3_full_payload_replace_keys_present() -> None:
|
||||
)
|
||||
|
||||
|
||||
def test_cosyvoice3_conditioning_replaces_snapshot_while_audio_accumulates() -> None:
|
||||
from vllm_omni.model_executor.stage_input_processors.cosyvoice3 import _FULL_PAYLOAD_REPLACE_KEYS
|
||||
from vllm_omni.outputs.mm_outputs import MultimodalPayload
|
||||
from vllm_omni.outputs.output_modality import OutputModality
|
||||
|
||||
previous = {key: torch.ones(1, 174) for key in _FULL_PAYLOAD_REPLACE_KEYS}
|
||||
padded = {key: torch.zeros(1, 1500) for key in _FULL_PAYLOAD_REPLACE_KEYS}
|
||||
previous["embed.speech_token_len"] = torch.tensor([174])
|
||||
padded["embed.speech_token_len"] = torch.tensor([174])
|
||||
payload = MultimodalPayload.from_dict({**previous, "audio": torch.ones(2)})
|
||||
incoming = MultimodalPayload.from_dict({**padded, "audio": torch.ones(3)})
|
||||
assert payload is not None and incoming is not None
|
||||
|
||||
payload = payload.merged_with(incoming)
|
||||
payload.consolidate_tensors(OutputModality.AUDIO)
|
||||
|
||||
for key in _FULL_PAYLOAD_REPLACE_KEYS:
|
||||
assert torch.equal(payload[key], padded[key])
|
||||
assert torch.equal(payload["audio"], torch.ones(5))
|
||||
|
||||
|
||||
def test_ming_flash_omni_thinker2talker_token_only_smoke() -> None:
|
||||
"""Smoke: ming_flash_omni token-only carries voice metadata."""
|
||||
from vllm_omni.model_executor.stage_input_processors.ming_flash_omni import (
|
||||
|
||||
@@ -46,7 +46,6 @@ def _check_prefill():
|
||||
state = OmniModelState.__new__(OmniModelState)
|
||||
state.model_config = SimpleNamespace(max_model_len=256)
|
||||
state.vllm_config = c
|
||||
state.max_model_len = 256
|
||||
state.supports_mm_inputs = False
|
||||
with set_current_vllm_config(c):
|
||||
group = AttentionGroup(FlashAttentionBackend, ["attn"], spec, 0)
|
||||
|
||||
@@ -7,6 +7,7 @@ from collections.abc import Mapping
|
||||
from typing import TypeVar
|
||||
|
||||
from transformers import BatchFeature
|
||||
from vllm.config.multimodal import BaseDummyOptions, MultiModalDummyOptions
|
||||
from vllm.multimodal.parse import MultiModalDataItems
|
||||
from vllm.multimodal.processing import (
|
||||
BaseDummyInputsBuilder,
|
||||
@@ -26,18 +27,14 @@ class OmniDummyInputsBuilder(BaseDummyInputsBuilder[_I]):
|
||||
self,
|
||||
seq_len: int,
|
||||
mm_counts: Mapping[str, int],
|
||||
mm_options: Mapping[str, object],
|
||||
mm_options: Mapping[str, BaseDummyOptions] | None = None,
|
||||
) -> ProcessorInputs:
|
||||
dummy_text = self.get_dummy_text(mm_counts)
|
||||
dummy_mm_data = self.get_dummy_mm_data(seq_len, mm_counts, mm_options)
|
||||
dummy_mm_data = self.get_dummy_mm_data(seq_len, mm_counts, MultiModalDummyOptions(mm_options or {}))
|
||||
dummy_mm_items = self.info.parse_mm_data(dummy_mm_data, validate=False)
|
||||
|
||||
tokenizer = self.info.ctx.tokenizer
|
||||
dummy_prompt = (
|
||||
[]
|
||||
if tokenizer is None
|
||||
else cached_encode(tokenizer, dummy_text, truncation=False)
|
||||
)
|
||||
dummy_prompt = [] if tokenizer is None else cached_encode(tokenizer, dummy_text, truncation=False)
|
||||
return ProcessorInputs(prompt=dummy_prompt, mm_data_items=dummy_mm_items)
|
||||
|
||||
|
||||
@@ -55,12 +52,10 @@ class OmniMultiModalProcessor(BaseMultiModalProcessor[_I]):
|
||||
self,
|
||||
seq_len: int,
|
||||
mm_counts: Mapping[str, int],
|
||||
mm_options: Mapping[str, object],
|
||||
mm_options: MultiModalDummyOptions,
|
||||
) -> ProcessorInputs:
|
||||
if isinstance(self.dummy_inputs, OmniDummyInputsBuilder):
|
||||
return self.dummy_inputs.get_dummy_processor_inputs(
|
||||
seq_len, mm_counts, mm_options
|
||||
)
|
||||
return self.dummy_inputs.get_dummy_processor_inputs(seq_len, mm_counts, mm_options)
|
||||
return super().get_dummy_inputs(seq_len, mm_counts, mm_options)
|
||||
|
||||
def _apply_hf_processor_main(
|
||||
|
||||
@@ -28,7 +28,6 @@ from vllm.multimodal import MULTIMODAL_REGISTRY
|
||||
from vllm.multimodal.inputs import MultiModalFieldConfig, MultiModalKwargsItems
|
||||
from vllm.multimodal.parse import MultiModalDataItems, MultiModalDataParser
|
||||
from vllm.multimodal.processing import (
|
||||
BaseDummyInputsBuilder,
|
||||
BaseProcessingInfo,
|
||||
ProcessorInputs,
|
||||
PromptIndexTargets,
|
||||
|
||||
@@ -38,7 +38,6 @@ from vllm.multimodal import MULTIMODAL_REGISTRY
|
||||
from vllm.multimodal.inputs import MultiModalFieldConfig, MultiModalKwargsItems
|
||||
from vllm.multimodal.parse import MultiModalDataItems, MultiModalDataParser
|
||||
from vllm.multimodal.processing import (
|
||||
BaseDummyInputsBuilder,
|
||||
BaseProcessingInfo,
|
||||
ProcessorInputs,
|
||||
PromptIndexTargets,
|
||||
|
||||
@@ -29,7 +29,6 @@ from vllm.multimodal.inputs import (
|
||||
)
|
||||
from vllm.multimodal.parse import AudioProcessorItems, MultiModalDataItems, MultiModalDataParser
|
||||
from vllm.multimodal.processing import (
|
||||
BaseDummyInputsBuilder,
|
||||
BaseProcessingInfo,
|
||||
ProcessorInputs,
|
||||
PromptReplacement,
|
||||
|
||||
@@ -28,7 +28,6 @@ from vllm.multimodal.inputs import (
|
||||
)
|
||||
from vllm.multimodal.parse import MultiModalDataItems, MultiModalDataParser
|
||||
from vllm.multimodal.processing import (
|
||||
BaseDummyInputsBuilder,
|
||||
BaseProcessingInfo,
|
||||
ProcessorInputs,
|
||||
PromptIndexTargets,
|
||||
|
||||
Reference in new issue
Block a user