Compare commits

..
Author SHA1 Message Date
mgoin 71b081ff19 Use instanttensor == 0.1.8
Signed-off-by: mgoin <mgoin64@gmail.com>
2026-04-14 17:11:57 +00:00
mgoin 9577520f6b Lower buffer size
Signed-off-by: mgoin <mgoin64@gmail.com>
2026-04-13 22:48:41 +00:00
mgoin 56ed9c7bd6 Improve pbar units
Signed-off-by: mgoin <mgoin64@gmail.com>
2026-04-13 22:29:52 +00:00
mgoin f284ff6c8a Fix InstantTensor buffer overwrite
Signed-off-by: mgoin <mgoin64@gmail.com>
2026-04-13 21:34:28 +00:00
Michael GoinandGitHub 9294524301 Add function to check for instanttensor package
Signed-off-by: Michael Goin <mgoin64@gmail.com>
2026-04-13 16:00:08 -04:00
Michael GoinandGitHub 3dc9488e52 Add support for auto-detection of InstantTensor loader
Signed-off-by: Michael Goin <mgoin64@gmail.com>
2026-04-13 15:59:09 -04:00
Michael GoinandGitHub cfdf6b5024 Update default load format in LoadConfig
Change default load format from 'instanttensor' to 'auto'.

Signed-off-by: Michael Goin <mgoin64@gmail.com>
2026-04-13 15:58:22 -04:00
Michael GoinandGitHub 9a5945e9c2 Merge branch 'main' into claude/zen-banach
Signed-off-by: Michael Goin <mgoin64@gmail.com>
2026-04-13 15:25:36 -04:00
mgoinandClaude Opus 4.6 8a2da87213 Enable InstantTensor as default load format
Change the default load_format from "auto" to "instanttensor" to test
CI with the InstantTensor weight loader enabled by default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Signed-off-by: mgoin <mgoin64@gmail.com>
2026-03-17 11:00:11 -04:00
359 changed files with 3487 additions and 15009 deletions
+2 -2
View File
@@ -46,7 +46,7 @@ steps:
- tests/models/language/pooling/
commands:
- |
bash .buildkite/scripts/hardware_ci/run-cpu-test.sh 40m "
bash .buildkite/scripts/hardware_ci/run-cpu-test.sh 30m "
pytest -x -v -s tests/models/language/generation -m cpu_model
pytest -x -v -s tests/models/language/pooling -m cpu_model"
@@ -99,7 +99,7 @@ steps:
- |
bash .buildkite/scripts/hardware_ci/run-cpu-test.sh 45m "
pytest -x -v -s tests/models/multimodal/generation --ignore=tests/models/multimodal/generation/test_pixtral.py -m cpu_model --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
parallelism: 3
parallelism: 2
- label: "Arm CPU Test"
depends_on: []
@@ -1,68 +0,0 @@
#!/bin/bash
set -euo pipefail
# Build a vLLM test image with PyTorch nightly installed.
# Called by the pipeline generator's "vLLM Against PyTorch Nightly" group.
if [[ $# -lt 5 ]]; then
echo "Usage: $0 <registry> <repo> <commit> <branch> <image_tag>"
exit 1
fi
REGISTRY=$1
REPO=$2
BUILDKITE_COMMIT=$3
BRANCH=$4
IMAGE_TAG=$5
# --- Arguments ---
echo "--- :mag: Arguments"
echo "REGISTRY: ${REGISTRY}"
echo "REPO: ${REPO}"
echo "BUILDKITE_COMMIT: ${BUILDKITE_COMMIT}"
echo "BRANCH: ${BRANCH}"
echo "IMAGE_TAG: ${IMAGE_TAG}"
# --- ECR login ---
echo "--- :key: ECR login"
aws ecr-public get-login-password --region us-east-1 \
| docker login --username AWS --password-stdin "$REGISTRY"
aws ecr get-login-password --region us-east-1 \
| docker login --username AWS --password-stdin 936637512419.dkr.ecr.us-east-1.amazonaws.com
# --- Set up buildx ---
echo "--- :docker: Setting up buildx"
docker buildx create --name vllm-builder --driver docker-container --use || true
docker buildx inspect --bootstrap
docker buildx ls
# --- Skip if image already exists ---
echo "--- :mag: Checking if image already exists"
if docker manifest inspect "$IMAGE_TAG" >/dev/null 2>&1; then
echo "Image found: $IMAGE_TAG — skipping build"
exit 0
fi
echo "Image not found, proceeding with build..."
# --- CUDA 13.0 for nightly builds ---
# Nightly CI uses CUDA 13.0 while regular CI stays on CUDA 12.9
NIGHTLY_CUDA_VERSION="13.0.0"
NIGHTLY_BUILD_BASE_IMAGE="nvidia/cuda:${NIGHTLY_CUDA_VERSION}-devel-ubuntu22.04"
NIGHTLY_FINAL_BASE_IMAGE="nvidia/cuda:${NIGHTLY_CUDA_VERSION}-base-ubuntu22.04"
echo "--- :docker: Building torch nightly image (CUDA ${NIGHTLY_CUDA_VERSION})"
docker buildx build --file docker/Dockerfile \
--build-arg max_jobs=16 \
--build-arg buildkite_commit="$BUILDKITE_COMMIT" \
--build-arg USE_SCCACHE=1 \
--build-arg PYTORCH_NIGHTLY=1 \
--build-arg CUDA_VERSION="${NIGHTLY_CUDA_VERSION}" \
--build-arg BUILD_BASE_IMAGE="${NIGHTLY_BUILD_BASE_IMAGE}" \
--build-arg FINAL_BASE_IMAGE="${NIGHTLY_FINAL_BASE_IMAGE}" \
--build-arg torch_cuda_arch_list="8.0 8.9 9.0 10.0 12.0" \
--tag "$IMAGE_TAG" \
--push \
--target test \
--progress plain .
echo "--- :white_check_mark: Torch nightly image build complete: $IMAGE_TAG"
-9
View File
@@ -98,15 +98,8 @@ steps:
commands:
- "bash .buildkite/scripts/generate-and-upload-nightly-index.sh"
- block: "Unblock to build release Docker images"
depends_on: ~
key: block-build-release-images
if: build.env("NIGHTLY") != "1"
- group: "Build release Docker images"
key: "build-release-images"
depends_on: block-build-release-images
allow_dependency_failure: true
steps:
- label: "Build release image - x86_64 - CUDA 12.9"
depends_on: ~
@@ -624,8 +617,6 @@ steps:
- label: ":docker: Build release image - x86_64 - ROCm"
id: build-rocm-release-image
depends_on:
- step: block-build-release-images
allow_failure: true
- step: build-rocm-base-wheels
allow_failure: false
agents:
@@ -51,7 +51,6 @@ function cpu_tests() {
set -e
pytest -x -v -s tests/kernels/test_onednn.py
pytest -x -v -s tests/kernels/attention/test_cpu_attn.py
pytest -x -v -s tests/kernels/core/test_cpu_activation.py
pytest -x -v -s tests/kernels/moe/test_moe.py -k test_cpu_fused_moe_basic"
# basic online serving
@@ -16,5 +16,5 @@ echo "--- :docker: Building Docker image"
docker build --progress plain --tag "$IMAGE_NAME" --target vllm-test -f docker/Dockerfile.cpu .
# Run the image, setting --shm-size=4g for tensor parallel.
docker run --rm --cpuset-cpus="$CORE_RANGE" --cpuset-mems="$NUMA_NODE" -v ~/.cache/huggingface:/root/.cache/huggingface --privileged=true -e HF_TOKEN -e VLLM_CPU_KVCACHE_SPACE=16 -e VLLM_CPU_CI_ENV=1 -e VLLM_CPU_SIM_MULTI_NUMA=1 -e VLLM_CPU_ATTN_SPLIT_KV=0 --shm-size=4g "$IMAGE_NAME" \
docker run --rm --cpuset-cpus="$CORE_RANGE" --cpuset-mems="$NUMA_NODE" -v ~/.cache/huggingface:/root/.cache/huggingface --privileged=true -e HF_TOKEN -e VLLM_CPU_KVCACHE_SPACE=16 -e VLLM_CPU_CI_ENV=1 -e VLLM_CPU_SIM_MULTI_NUMA=1 --shm-size=4g "$IMAGE_NAME" \
timeout "$TIMEOUT_VAL" bash -c "set -euox pipefail; echo \"--- Print packages\"; pip list; echo \"--- Running tests\"; ${TEST_COMMAND}"
+1 -1
View File
@@ -769,7 +769,7 @@ steps:
- tests/kernels/helion/
- vllm/platforms/rocm.py
commands:
- pip install helion==1.0.0
- pip install helion==0.3.3
- pytest -v -s kernels/helion/
+3 -17
View File
@@ -155,7 +155,7 @@ steps:
- vllm/utils/import_utils.py
- tests/kernels/helion/
commands:
- pip install helion==1.0.0
- pip install helion==0.3.3
- pytest -v -s kernels/helion/
@@ -200,14 +200,7 @@ steps:
timeout_in_minutes: 90
device: h100
num_devices: 2
source_file_dependencies:
- csrc/quantization/cutlass_w8a8/moe/
- csrc/moe/
- tests/kernels/moe
- vllm/model_executor/layers/fused_moe/
- vllm/model_executor/layers/quantization/
- vllm/distributed/device_communicators/
- vllm/config
optional: true
commands:
- pytest -v -s kernels/moe/test_moe_layer.py
@@ -216,13 +209,6 @@ steps:
timeout_in_minutes: 90
device: b200
num_devices: 2
source_file_dependencies:
- csrc/quantization/cutlass_w8a8/moe/
- csrc/moe/
- tests/kernels/moe
- vllm/model_executor/layers/fused_moe/
- vllm/model_executor/layers/quantization/
- vllm/distributed/device_communicators/
- vllm/config
optional: true
commands:
- pytest -v -s kernels/moe/test_moe_layer.py
-10
View File
@@ -91,16 +91,6 @@ steps:
- pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=evals/gsm8k/configs/moe-refactor-dp-ep/config-b200.txt
- label: LM Eval TurboQuant KV Cache
timeout_in_minutes: 75
source_file_dependencies:
- vllm/model_executor/layers/quantization/turboquant/
- vllm/v1/attention/backends/turboquant_attn.py
- vllm/v1/attention/ops/triton_turboquant_decode.py
- vllm/v1/attention/ops/triton_turboquant_store.py
commands:
- pytest -s -v evals/gsm8k/test_gsm8k_correctness.py --config-list-file=evals/gsm8k/configs/models-turboquant.txt
- label: GPQA Eval (GPT-OSS) (H100)
timeout_in_minutes: 120
device: h100
-1
View File
@@ -224,7 +224,6 @@ steps:
- pytest -v -s v1/determinism/test_rms_norm_batch_invariant.py
- VLLM_TEST_MODEL=deepseek-ai/DeepSeek-V2-Lite-Chat pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[TRITON_MLA]
- VLLM_TEST_MODEL=Qwen/Qwen3-30B-A3B-Thinking-2507-FP8 pytest -v -s v1/determinism/test_batch_invariance.py::test_v1_generation_is_deterministic_across_batch_sizes_with_needle[FLASH_ATTN]
- pytest -v -s v1/determinism/test_nvfp4_batch_invariant.py
- label: Acceptance Length Test (Large Models) # optional
timeout_in_minutes: 25
+5 -22
View File
@@ -1,9 +1,10 @@
group: Models - Basic
depends_on:
depends_on:
- image-build
steps:
- label: Basic Models Tests (Initialization)
timeout_in_minutes: 45
device: h200_18gb
torch_nightly: true
source_file_dependencies:
- vllm/
@@ -12,11 +13,10 @@ steps:
commands:
# Run a subset of model initialization tests
- pytest -v -s models/test_initialization.py::test_can_initialize_small_subset
mirror:
torch_nightly: {}
- label: Basic Models Tests (Extra Initialization) %N
timeout_in_minutes: 45
torch_nightly: true
source_file_dependencies:
- vllm/model_executor/models/
- tests/models/test_initialization.py
@@ -27,8 +27,6 @@ steps:
# test.) Also run if model initialization test file is modified
- pytest -v -s models/test_initialization.py -k 'not test_can_initialize_small_subset' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB
parallelism: 2
mirror:
torch_nightly: {}
- label: Basic Models Tests (Other)
timeout_in_minutes: 45
@@ -44,10 +42,10 @@ steps:
device: mi325_1
depends_on:
- image-build-amd
- label: Basic Models Test (Other CPU) # 5min
depends_on:
depends_on:
- image-build-cpu
timeout_in_minutes: 10
source_file_dependencies:
@@ -72,18 +70,3 @@ steps:
- python3 examples/offline_inference/vision_language.py --model-type qwen2_5_vl
# Whisper needs spawn method to avoid deadlock
- VLLM_WORKER_MULTIPROC_METHOD=spawn python3 examples/offline_inference/audio_language.py --model-type whisper
- label: Transformers Backward Compatibility Models Test
working_dir: "/vllm-workspace/"
optional: true
soft_fail: true
commands:
- pip install transformers==4.57.5
- pytest -v -s tests/models/test_initialization.py
- pytest -v -s tests/models/test_transformers.py
- pytest -v -s tests/models/multimodal/processing/
- pytest -v -s tests/models/multimodal/test_mapping.py
- python3 examples/offline_inference/basic/chat.py
- python3 examples/offline_inference/vision_language.py --model-type qwen2_5_vl
# Whisper needs spawn method to avoid deadlock
- VLLM_WORKER_MULTIPROC_METHOD=spawn python3 examples/offline_inference/audio_language.py --model-type whisper
+5 -8
View File
@@ -1,9 +1,10 @@
group: Models - Language
depends_on:
depends_on:
- image-build
steps:
- label: Language Models Tests (Standard)
timeout_in_minutes: 25
torch_nightly: true
source_file_dependencies:
- vllm/
- tests/models/language
@@ -11,11 +12,10 @@ steps:
# Test standard language models, excluding a subset of slow tests
- pip freeze | grep -E 'torch'
- pytest -v -s models/language -m 'core_model and (not slow_test)'
mirror:
torch_nightly: {}
- label: Language Models Tests (Extra Standard) %N
timeout_in_minutes: 45
torch_nightly: true
source_file_dependencies:
- vllm/model_executor/models/
- tests/models/language/pooling/test_embedding.py
@@ -27,11 +27,10 @@ steps:
- pip freeze | grep -E 'torch'
- pytest -v -s models/language -m 'core_model and slow_test' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB
parallelism: 2
mirror:
torch_nightly: {}
- label: Language Models Tests (Hybrid) %N
timeout_in_minutes: 75
torch_nightly: true
source_file_dependencies:
- vllm/
- tests/models/language/generation
@@ -43,8 +42,6 @@ steps:
# Shard hybrid language model tests
- pytest -v -s models/language/generation -m hybrid_model --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB
parallelism: 2
mirror:
torch_nightly: {}
- label: Language Models Test (Extended Generation) # 80min
timeout_in_minutes: 110
@@ -65,7 +62,7 @@ steps:
- image-build-amd
commands:
- uv pip install --system --no-build-isolation 'git+https://github.com/AndreasKaratzas/mamba@fix-rocm-7.0-warp-size-constexpr'
- uv pip install --system --no-build-isolation 'git+https://github.com/Dao-AILab/causal-conv1d@v1.6.0'
- uv pip install --system --no-build-isolation 'git+https://github.com/Dao-AILab/causal-conv1d@v1.5.2'
- pytest -v -s models/language/generation -m '(not core_model) and (not hybrid_model)'
- label: Language Models Test (PPL)
-13
View File
@@ -42,16 +42,3 @@ steps:
- tests/v1/e2e/spec_decode/
commands:
- pytest -v -s v1/e2e/spec_decode -k "draft_model or no_sync or batch_inference"
- label: DFlash Speculators Correctness
timeout_in_minutes: 30
device: h100
optional: true
num_devices: 1
source_file_dependencies:
- vllm/v1/spec_decode/
- vllm/model_executor/models/qwen3_dflash.py
- tests/v1/spec_decode/test_speculators_dflash.py
commands:
- export VLLM_ALLOW_INSECURE_SERIALIZATION=1
- pytest -v -s v1/spec_decode/test_speculators_dflash.py -m slow_test
+1
View File
@@ -15,6 +15,7 @@ PLEASE FILL IN THE PR DESCRIPTION HERE ENSURING ALL CHECKLIST ITEMS (AT THE BOTT
- [ ] The test plan, such as providing test command.
- [ ] The test results, such as pasting the results comparison before and after, or e2e results
- [ ] (Optional) The necessary documentation update, such as updating `supported_models.md` and `examples` for a new model.
- [ ] (Optional) Release notes update. If your change is user facing, please update the release notes draft in the [Google Doc](https://docs.google.com/document/d/1YyVqrgX4gHTtrstbq8oWUImOyPCKSGnJ7xtTpmXzlRs/edit?tab=t.0).
</details>
**BEFORE SUBMITTING, PLEASE READ <https://docs.vllm.ai/en/latest/contributing>** (anything written below this line will be removed by GitHub Actions)
+1 -2
View File
@@ -264,7 +264,6 @@ pull_request_rules:
- files=\.buildkite/ci_config_intel.yaml
- files=vllm/model_executor/layers/fused_moe/xpu_fused_moe.py
- files=vllm/model_executor/kernels/linear/mixed_precision/xpu.py
- files=vllm/model_executor/kernels/linear/mxfp8/xpu.py
- files=vllm/model_executor/kernels/linear/scaled_mm/xpu.py
- files=vllm/distributed/device_communicators/xpu_communicator.py
- files=vllm/v1/attention/backends/mla/xpu_mla_sparse.py
@@ -272,7 +271,6 @@ pull_request_rules:
- files=vllm/v1/worker/xpu_worker.py
- files=vllm/v1/worker/xpu_model_runner.py
- files=vllm/_xpu_ops.py
- files=vllm/kernels/xpu_ops.py
- files~=^vllm/lora/ops/xpu_ops
- files=vllm/lora/punica_wrapper/punica_xpu.py
- files=vllm/platforms/xpu.py
@@ -280,6 +278,7 @@ pull_request_rules:
- title~=(?i)XPU
- title~=(?i)Intel
- title~=(?i)BMG
- title~=(?i)Arc
actions:
label:
add:
-1
View File
@@ -360,7 +360,6 @@ set(VLLM_EXT_SRC
if (ASIMD_FOUND AND NOT APPLE_SILICON_FOUND)
set(VLLM_EXT_SRC
"csrc/cpu/shm.cpp"
"csrc/cpu/activation_lut_bf16.cpp"
${VLLM_EXT_SRC})
endif()
-71
View File
@@ -1,71 +0,0 @@
#include "cpu_types.hpp"
#include <array>
#include <cstdint>
#include <mutex>
#include <string>
#include <ATen/ops/empty.h>
#include <ATen/ops/gelu.h>
#include <c10/util/BFloat16.h>
constexpr uint32_t ActivationLutSize = 1u << 16;
at::Tensor gelu_reference(const at::Tensor& x) { return at::gelu(x, "none"); }
void maybe_init_activation_lut_bf16(
uint16_t* lut, std::once_flag& once,
at::Tensor (*activation)(const at::Tensor&)) {
std::call_once(once, [&]() {
auto lut_input =
at::empty({static_cast<int64_t>(ActivationLutSize)},
at::TensorOptions().device(at::kCPU).dtype(at::kFloat));
auto* lut_input_ptr = lut_input.data_ptr<float>();
#pragma omp parallel for
for (uint32_t i = 0; i < ActivationLutSize; ++i) {
lut_input_ptr[i] = c10::detail::f32_from_bits(static_cast<uint16_t>(i));
}
auto lut_output = activation(lut_input);
const auto* lut_output_ptr = lut_output.data_ptr<float>();
#pragma omp parallel for
for (uint32_t i = 0; i < ActivationLutSize; ++i) {
lut[i] = c10::detail::round_to_nearest_even(lut_output_ptr[i]);
}
});
}
void activation_lut_bf16(torch::Tensor& out, torch::Tensor& input,
const uint16_t* lut, const char* op_name) {
TORCH_CHECK(input.scalar_type() == at::kBFloat16, op_name,
": input must be bfloat16");
TORCH_CHECK(out.scalar_type() == at::kBFloat16, op_name,
": out must be bfloat16");
TORCH_CHECK(input.is_contiguous(), op_name, ": input must be contiguous");
TORCH_CHECK(out.is_contiguous(), op_name, ": out must be contiguous");
const auto* src =
reinterpret_cast<const uint16_t*>(input.data_ptr<at::BFloat16>());
auto* dst = reinterpret_cast<uint16_t*>(out.data_ptr<at::BFloat16>());
const int64_t n = input.numel();
CPU_KERNEL_GUARD_IN(activation_lut_bf16_impl)
#pragma omp parallel for
for (int64_t i = 0; i < n; ++i) {
dst[i] = lut[src[i]];
}
CPU_KERNEL_GUARD_OUT(activation_lut_bf16_impl)
}
void activation_lut_bf16(torch::Tensor& out, torch::Tensor& input,
const std::string& activation) {
if (activation == "gelu") {
static std::array<uint16_t, ActivationLutSize> lut{};
static std::once_flag once;
maybe_init_activation_lut_bf16(lut.data(), once, gelu_reference);
activation_lut_bf16(out, input, lut.data(), "gelu_lut");
return;
}
TORCH_CHECK(false, "Unsupported activation: ", activation);
}
-3
View File
@@ -147,9 +147,6 @@ struct AttentionMetadata {
case ISA::NEON:
ss << "NEON, ";
break;
case ISA::VXE:
ss << "VXE, ";
break;
}
ss << "workitem_group_num: " << workitem_group_num
<< ", reduction_item_num: " << reduction_item_num
-12
View File
@@ -85,9 +85,6 @@ at::Tensor int4_scaled_mm_cpu(at::Tensor& x, at::Tensor& w, at::Tensor& w_zeros,
at::Tensor& w_scales,
std::optional<at::Tensor> bias);
void activation_lut_bf16(torch::Tensor& out, torch::Tensor& input,
const std::string& activation);
torch::Tensor get_scheduler_metadata(
const int64_t num_req, const int64_t num_heads_q,
const int64_t num_heads_kv, const int64_t head_dim,
@@ -234,15 +231,6 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
ops.def("gelu_quick(Tensor! out, Tensor input) -> ()");
ops.impl("gelu_quick", torch::kCPU, &gelu_quick);
#if (defined(__aarch64__) && !defined(__APPLE__))
ops.def(
"activation_lut_bf16(Tensor! out, Tensor input, str activation)"
" -> ()");
ops.impl("activation_lut_bf16", torch::kCPU, &activation_lut_bf16);
#endif // (defined(__aarch64__) && !defined(__APPLE__))
// Layernorm
// Apply Root Mean Square (RMS) Normalization to the input tensor.
ops.def(
-22
View File
@@ -54,34 +54,12 @@ struct Counter {
};
inline int64_t get_available_l2_size() {
#if defined(__s390x__)
static int64_t size = []() {
uint32_t l2_cache_size = 0;
auto caps = at::cpu::get_cpu_capabilities();
auto it = caps.find("l2_cache_size");
if (it != caps.end()) {
l2_cache_size = static_cast<uint32_t>(it->second.toInt());
}
if (l2_cache_size == 0) {
long sys_l2 = sysconf(_SC_LEVEL2_CACHE_SIZE);
if (sys_l2 > 0) {
l2_cache_size = static_cast<uint32_t>(sys_l2);
}
}
if (l2_cache_size == 0) {
l2_cache_size = 256 * 1024;
}
return static_cast<int64_t>(l2_cache_size) >> 1; // use 50% of L2 cache
}();
return size;
#else
static int64_t size = []() {
auto caps = at::cpu::get_cpu_capabilities();
const uint32_t l2_cache_size = caps.at("l2_cache_size").toInt();
return l2_cache_size >> 1; // use 50% of L2 cache
}();
return size;
#endif
}
template <int32_t alignment_v, typename T>
-1
View File
@@ -1,7 +1,6 @@
#pragma once
#include <optional>
#include <string>
#include <torch/library.h>
#include <tuple>
+4 -5
View File
@@ -642,7 +642,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
else \
BITSANDBYTES_VERSION="${BITSANDBYTES_VERSION_X86}"; \
fi; \
uv pip install --system accelerate modelscope \
uv pip install --system accelerate hf_transfer modelscope \
"bitsandbytes>=${BITSANDBYTES_VERSION}" "timm${TIMM_VERSION}" "runai-model-streamer[s3,gcs,azure]${RUNAI_MODEL_STREAMER_VERSION}"
# ============================================================
@@ -756,10 +756,9 @@ RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install --system -e tests/vllm_test_utils
# enable fast downloads from hf (for testing)
ENV HF_XET_HIGH_PERFORMANCE 1
# increase timeout for hf downloads (for testing)
ENV HF_HUB_DOWNLOAD_TIMEOUT 60
RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install --system hf_transfer
ENV HF_HUB_ENABLE_HF_TRANSFER 1
# Copy in the v1 package for testing (it isn't distributed yet)
COPY vllm/v1 /usr/local/lib/python${PYTHON_VERSION}/dist-packages/vllm/v1
-6
View File
@@ -197,12 +197,6 @@ ADD ./.buildkite/ ./.buildkite/
RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install -e tests/vllm_test_utils
# enable fast downloads from hf (for testing)
ENV HF_XET_HIGH_PERFORMANCE 1
# increase timeout for hf downloads (for testing)
ENV HF_HUB_DOWNLOAD_TIMEOUT 60
######################### RELEASE IMAGE #########################
FROM base AS vllm-openai
+3 -4
View File
@@ -272,10 +272,9 @@ RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install --system -e tests/vllm_test_utils
# enable fast downloads from hf (for testing)
ENV HF_XET_HIGH_PERFORMANCE 1
# increase timeout for hf downloads (for testing)
ENV HF_HUB_DOWNLOAD_TIMEOUT 60
RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install --system hf_transfer
ENV HF_HUB_ENABLE_HF_TRANSFER 1
RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install --system -r requirements/test/nightly-torch.txt
+3 -4
View File
@@ -365,10 +365,9 @@ RUN cd /vllm-workspace \
&& python3 -m pip install pytest-shard
# enable fast downloads from hf (for testing)
ENV HF_XET_HIGH_PERFORMANCE=1
# increase timeout for hf downloads (for testing)
ENV HF_HUB_DOWNLOAD_TIMEOUT 60
RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install --system hf_transfer
ENV HF_HUB_ENABLE_HF_TRANSFER=1
# install audio decode package `torchcodec` from source (required due to
# ROCm and torch version mismatch) for tests with datasets package
+34 -34
View File
@@ -42,7 +42,7 @@ FROM python-install AS pyarrow
# Build Apache Arrow
WORKDIR /tmp
RUN --mount=type=cache,target=/root/.cache/uv \
git clone https://github.com/apache/arrow.git -b maint-19.0.1 && \
git clone https://github.com/apache/arrow.git && \
cd arrow/cpp && \
mkdir release && cd release && \
cmake -DCMAKE_BUILD_TYPE=Release \
@@ -68,6 +68,19 @@ RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install -r requirements-build.txt && \
python setup.py build_ext --build-type=$ARROW_BUILD_TYPE --bundle-arrow-cpp bdist_wheel
FROM python-install AS numa-build
# Install numactl (needed for numa.h dependency)
WORKDIR /tmp
RUN curl -LO https://github.com/numactl/numactl/archive/refs/tags/v2.0.16.tar.gz && \
tar -xvzf v2.0.16.tar.gz && \
cd numactl-2.0.16 && \
./autogen.sh && \
./configure && \
make
# Set include path
ENV C_INCLUDE_PATH="/usr/local/include:$C_INCLUDE_PATH"
FROM python-install AS rust
ENV CARGO_HOME=/root/.cargo
ENV RUSTUP_HOME=/root/.rustup
@@ -78,18 +91,6 @@ RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \
rustup default stable && \
rustup show
FROM python-install AS numa-build
WORKDIR /tmp
RUN curl -LO https://github.com/numactl/numactl/archive/refs/tags/v2.0.19.tar.gz && \
tar -xvzf v2.0.19.tar.gz && \
cd numactl-2.0.19 && \
./autogen.sh && \
./configure && \
make
# Set include path
ENV C_INCLUDE_PATH="/usr/local/include:$C_INCLUDE_PATH"
FROM python-install AS torch-vision
# Install torchvision
ARG TORCH_VISION_VERSION=v0.26.0
@@ -132,7 +133,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
git clone --recursive https://github.com/numba/llvmlite.git -b v0.44.0 && \
git clone --recursive https://github.com/numba/numba.git -b ${NUMBA_VERSION} && \
cd llvm-project && mkdir build && cd build && \
uv pip install 'cmake<4' 'setuptools<70' numpy && \
uv pip install 'cmake<4' setuptools numpy && \
export PREFIX=/usr/local && CMAKE_ARGS="${CMAKE_ARGS} -DLLVM_ENABLE_PROJECTS=lld;libunwind;compiler-rt" \
CFLAGS="$(echo $CFLAGS | sed 's/-fno-plt //g')" \
CXXFLAGS="$(echo $CXXFLAGS | sed 's/-fno-plt //g')" \
@@ -192,22 +193,27 @@ RUN --mount=type=cache,target=/root/.cache/uv \
cd opencv-python && \
python -m build --wheel --installer=uv --outdir /tmp/opencv-python/dist
## Todo(r3hankhan123): Remove guidance-builder stage once vLLM upgrades to new version of llguidance that fixes s390x issues. See https://github.com/guidance-ai/llguidance/issues/330
FROM python-install AS guidance-builder
# Build Outlines Core
FROM python-install AS outlines-core-builder
WORKDIR /tmp
ENV CARGO_HOME=/root/.cargo
ENV RUSTUP_HOME=/root/.rustup
ENV PATH="$CARGO_HOME/bin:$RUSTUP_HOME/bin:$PATH"
COPY requirements/common.txt /tmp/requirements/common.txt
ARG OUTLINES_CORE_VERSION
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,from=rust,source=/root/.cargo,target=/root/.cargo,rw \
--mount=type=bind,from=rust,source=/root/.rustup,target=/root/.rustup,rw \
git clone https://github.com/guidance-ai/llguidance.git && \
cd llguidance && \
git checkout s390x-fix-v2 && \
OUTLINES_CORE_VERSION=${OUTLINES_CORE_VERSION:-$(grep -E '^outlines_core\s*==\s*[0-9.]+' /tmp/requirements/common.txt | grep -Eo '[0-9.]+')} && \
if [ -z "${OUTLINES_CORE_VERSION}" ]; then echo "ERROR: Could not determine outlines_core version"; exit 1; fi && \
git clone https://github.com/dottxt-ai/outlines-core.git && \
cd outlines-core && \
git checkout tags/${OUTLINES_CORE_VERSION} && \
sed -i "s/version = \"0.0.0\"/version = \"${OUTLINES_CORE_VERSION}\"/" Cargo.toml && \
uv pip install maturin && \
python -m maturin build --release --out dist --compatibility linux
python -m maturin build --release --out dist
# # Final build stage
# Final build stage
FROM python-install AS vllm-cpu
ARG PYTHON_VERSION
ARG PIP_EXTRA_INDEX_URL="https://download.pytorch.org/whl/cpu"
@@ -223,12 +229,10 @@ ENV PKG_CONFIG_PATH="/opt/rh/gcc-toolset-14/root/usr/lib64/pkgconfig:/usr/local/
ENV PATH="${VIRTUAL_ENV:+${VIRTUAL_ENV}/bin}:/opt/rh/gcc-toolset-14/root/usr/bin:/usr/local/bin:$CARGO_HOME/bin:$RUSTUP_HOME/bin:$PATH"
ENV PIP_EXTRA_INDEX_URL=${PIP_EXTRA_INDEX_URL}
ENV UV_EXTRA_INDEX_URL=${PIP_EXTRA_INDEX_URL}
# Force pure Python protobuf to avoid s390x C++ extension crashes
ENV PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
COPY . /workspace/vllm
WORKDIR /workspace/vllm
RUN --mount=type=bind,from=numa-build,src=/tmp/numactl-2.0.19,target=/numactl \
RUN --mount=type=bind,from=numa-build,src=/tmp/numactl-2.0.16,target=/numactl \
make -C /numactl install
# Install dependencies, including PyTorch and Apache Arrow
@@ -241,22 +245,22 @@ RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,from=numba-builder,source=/tmp/llvmlite/dist,target=/tmp/llvmlite-wheels/ \
--mount=type=bind,from=numba-builder,source=/tmp/numba/dist,target=/tmp/numba-wheels/ \
--mount=type=bind,from=opencv-builder,source=/tmp/opencv-python/dist,target=/tmp/opencv-wheels/ \
--mount=type=bind,from=guidance-builder,source=/tmp/llguidance/dist,target=/tmp/guidance-wheels/ \
ARROW_WHL_FILE=$(ls /tmp/arrow-wheels/*.whl) && \
--mount=type=bind,from=outlines-core-builder,source=/tmp/outlines-core/dist,target=/tmp/outlines-core/dist/ \
ARROW_WHL_FILE=$(ls /tmp/arrow-wheels/pyarrow-*.whl) && \
VISION_WHL_FILE=$(ls /tmp/vision-wheels/*.whl) && \
HF_XET_WHL_FILE=$(ls /tmp/hf-xet-wheels/*.whl) && \
LLVM_WHL_FILE=$(ls /tmp/llvmlite-wheels/*.whl) && \
NUMBA_WHL_FILE=$(ls /tmp/numba-wheels/*.whl) && \
OPENCV_WHL_FILE=$(ls /tmp/opencv-wheels/*.whl) && \
GUIDANCE_WHL_FILE=$(ls /tmp/guidance-wheels/*.whl) && \
uv pip install -v \
$ARROW_WHL_FILE \
OUTLINES_CORE_WHL_FILE=$(ls /tmp/outlines-core/dist/*.whl) && \
uv pip install -v \
$ARROW_WHL_FILE \
$VISION_WHL_FILE \
$HF_XET_WHL_FILE \
$LLVM_WHL_FILE \
$NUMBA_WHL_FILE \
$OPENCV_WHL_FILE \
$GUIDANCE_WHL_FILE \
$OUTLINES_CORE_WHL_FILE \
--index-strategy unsafe-best-match \
-r requirements/build/cpu.txt \
-r requirements/cpu.txt
@@ -267,10 +271,6 @@ RUN --mount=type=cache,target=/root/.cache/uv \
VLLM_TARGET_DEVICE=cpu VLLM_CPU_MOE_PREPACK=0 python setup.py bdist_wheel && \
uv pip install "$(echo dist/*.whl)[tensorizer]"
# Remove protobuf C++ extension that crashes on s390x
RUN rm -rf /opt/vllm/lib64/python${PYTHON_VERSION}/site-packages/google/_upb/*.so \
/opt/vllm/lib64/python${PYTHON_VERSION}/site-packages/google/protobuf/pyext/*.so 2>/dev/null || true
# setup non-root user for vllm
RUN umask 002 && \
/usr/sbin/useradd --uid 2000 --gid 0 vllm && \
-64
View File
@@ -37,7 +37,6 @@ th {
| HuggingFace-Blazedit | ✅ | ✅ | `vdaita/edit_5k_char`, `vdaita/edit_10k_char` |
| HuggingFace-ASR | ✅ | ✅ | `openslr/librispeech_asr`, `facebook/voxpopuli`, `LIUM/tedlium`, `edinburghcstr/ami`, `speechcolab/gigaspeech`, `kensho/spgispeech` |
| Spec Bench | ✅ | ✅ | `wget https://raw.githubusercontent.com/hemingkx/Spec-Bench/refs/heads/main/data/spec_bench/question.jsonl` |
| SPEED-Bench | ✅ | ✅ | `curl -LsSf https://raw.githubusercontent.com/NVIDIA-NeMo/Skills/refs/heads/main/nemo_skills/dataset/speed-bench/prepare.py \| python3 -` |
| Custom | ✅ | ✅ | Local file: `data.jsonl` |
| Custom MM | ✅ | ✅ | Local file: `mm_data.jsonl` |
@@ -240,69 +239,6 @@ vllm bench serve \
--spec-bench-category "summarization"
```
#### SPEED-Bench Benchmark with Speculative Decoding
[SPEED-Bench](https://huggingface.co/datasets/nvidia/SPEED-Bench) is a unified and diverse dataset for speculative decoding, supporting acceptance rate and length measurements using the Qualitative split and throughput measurements using the Throughput splits in 5 configuration of input sequence length (1k, 2k, 8k, 16k, 32k).
!!! note
This dataset is governed by the [NVIDIA Evaluation Dataset License Agreement](https://huggingface.co/datasets/nvidia/SPEED-Bench/blob/main/License.pdf). For each dataset a user elects to use, the user is responsible for checking if the dataset license is fit for the intended purpose. The `prepare.py` script automatically fetches data from all the source datasets.
First, download the dataset to a folder, using this one liner:
```bash
curl -LsSf https://raw.githubusercontent.com/NVIDIA-NeMo/Skills/refs/heads/main/nemo_skills/dataset/speed-bench/prepare.py \| python3 -
```
The command supports also the following arguments:
- `--config`: download only a subset of the dataset: `qualitative`, `throughput_1k`, `throughput_2k`, `throughput_8k`, `throughput_16k` and `throughput_32k`. By default, it will download all subsets.
- `--output_dir`: download to a specified folder. By default, it will download to the current directory.
Start a server with speculative decoding:
```bash
vllm serve meta-llama/Llama-3.3-70B-Instruct \
--speculative-config $'{"method": "eagle3",
"num_speculative_tokens": 3,
"model": "nvidia/Llama-3.3-70B-Instruct-Eagle3"}'
```
Run all categories in the Qualitative split:
```bash
vllm bench serve \
--model meta-llama/Llama-3.3-70B-Instruct \
--dataset-name speed_bench \
--dataset-path "<YOUR_DOWNLOADED_PATH>/data/speed_bench" \
--num-prompts -1
```
Available categories include `[writing, roleplay, reasoning, math, coding, stem, humanities, multilingual, summarization, qa, rag]`.
Run only a specific category like "multilingual":
```bash
vllm bench serve \
--model meta-llama/Llama-3.3-70B-Instruct \
--dataset-name speed_bench \
--dataset-path "<YOUR_DOWNLOADED_PATH>/data/speed_bench" \
--num-prompts -1
--speed-bench-category "multilingual"
```
Run all categories in the Throughput split (2k ISL):
```bash
vllm bench serve \
--model meta-llama/Llama-3.3-70B-Instruct \
--dataset-name speed_bench \
--speed-bench-dataset-subset throughput_2k
--dataset-path "<YOUR_DOWNLOADED_PATH>/data/speed_bench/" \
--num-prompts -1
```
Available categories include `[high_entropy, mixed, low_entropy]`, where high entropy data contains unstructued data such as creative writing while low entropy data contains more structured data such as coding, more details are in the dataset card.
#### Other HuggingFaceDataset Examples
```bash
-1
View File
@@ -178,7 +178,6 @@ Priority is **1 = highest** (tried first).
| `ROCM_ATTN` | | fp16, bf16, fp32 | `auto`, `float16`, `bfloat16`, `fp8`, `fp8_e4m3`, `fp8_e5m2` | %16 | 32, 64, 80, 96, 128, 160, 192, 224, 256 | ❌ | ✅ | ❌ | Decoder, Encoder, Encoder Only | N/A |
| `TREE_ATTN` | | fp16, bf16 | `auto`, `float16`, `bfloat16` | %16 | 32, 64, 96, 128, 160, 192, 224, 256 | ❌ | ❌ | ❌ | Decoder | Any |
| `TRITON_ATTN` | | fp16, bf16, fp32 | `auto`, `float16`, `bfloat16`, `fp8`, `fp8_e4m3`, `fp8_e5m2`, `int8_per_token_head`, `fp8_per_token_head` | %16 | Any | ✅ | ✅ | ❌ | All | Any |
| `TURBOQUANT` | | fp16, bf16 | `turboquant_k8v4`, `turboquant_4bit_nc`, `turboquant_k3v4_nc`, `turboquant_3bit_nc` | 16, 32, 64, 128 | Any | ❌ | ❌ | ❌ | Decoder | Any |
> **†** FlashInfer uses TRTLLM attention on Blackwell (SM100), which supports sinks. Disable via `--attention-config.use_trtllm_attention=0`.
>
+7 -66
View File
@@ -28,7 +28,6 @@ Multiple CUDA Graphs are pre-captured at different **token budget** levels (e.g.
class BudgetGraphMetadata:
token_budget: int
max_batch_size: int
max_frames_per_batch: int
graph: torch.cuda.CUDAGraph
input_buffer: torch.Tensor # e.g. pixel_values
metadata_buffers: dict[str, torch.Tensor] # e.g. embeddings, seq metadata
@@ -52,15 +51,6 @@ For each graph replay:
When `mm_encoder_tp_mode="data"`, the manager distributes images across TP ranks using load-balanced assignment via `get_load_balance_assignment`, executes locally on each rank, then gathers results back in the original order via `tensor_model_parallel_all_gather`.
### Video inference support (experimental)
Following <https://github.com/vllm-project/vllm/pull/35963> (ViT full CUDA graph support for image inference), <https://github.com/vllm-project/vllm/pull/38061> extends the encoder CUDA graph framework to support video inference for Qwen3-VL. Previously, the CUDA graph capture/replay path only handled image inputs (`pixel_values` + `image_grid_thw`). Video inputs use different keys (`pixel_values_videos` + `video_grid_thw`) and require larger `cu_seqlens` buffers because each video item contributes multiple frames (`T` attention sequences). This PR generalizes the protocol and manager to handle both modalities through a single shared graph manager.
!!! note
Video CUDA graphs are automatically disabled when EVS (Efficient Video Sampling) pruning is enabled, since EVS makes the token count data-dependent and incompatible with CUDA graph capture.
Currently, we only support image-only or video-only inputs when enabling CUDA graph, mixed inputs (image + video) are not supported yet (we will work on it in the near future). Thus, it's recommended to turn off the image modality by `--limit-mm-per-prompt '{"image": 0}'` for video-only inputs.
## Model integration via `SupportsEncoderCudaGraph`
Models opt-in to encoder CUDA Graphs by implementing the [SupportsEncoderCudaGraph][vllm.model_executor.models.interfaces.SupportsEncoderCudaGraph] protocol. This protocol encapsulates all model-specific logic so that the manager remains model-agnostic. The protocol defines the following methods:
@@ -75,17 +65,12 @@ Models opt-in to encoder CUDA Graphs by implementing the [SupportsEncoderCudaGra
* `prepare_encoder_cudagraph_replay_buffers(...)` — computes new buffer values from actual batch inputs before replay.
* `encoder_cudagraph_forward(...)` — forward pass using precomputed buffers (called during capture and replay).
* `encoder_eager_forward(...)` — fallback eager forward when no graph fits.
* `get_input_modality(...)` - return the modality of the inputs.
Currently supported: **Qwen3-VL** (see `vllm/model_executor/models/qwen3_vl.py`).
!!! note
The `SupportsEncoderCudaGraph` protocol is designed to be model-agnostic. New vision encoder models can opt-in by implementing the protocol methods without modifying the manager.
**Supported models:**
| Architecture | Models | CG for Image | CG for Video |
| ------------ | ------ | ------------ | ------------ |
| `Qwen3VLForConditionalGeneration` | `Qwen3-VL` | ✅︎ | ✅︎ |
!!! note
Encoder CUDA Graphs have currently been tested with `--mm-encoder-attn-backend=FLASH_ATTN` and `--mm-encoder-attn-backend=FLASHINFER` on Blackwell GPUs.
@@ -95,13 +80,10 @@ Three fields in `CompilationConfig` control encoder CUDA Graphs:
* `cudagraph_mm_encoder` (`bool`, default `False`) — enable CUDA Graph capture for multimodal encoder. When enabled, captures the full encoder forward as a CUDA Graph for each token budget level.
* `encoder_cudagraph_token_budgets` (`list[int]`, default `[]`) — token budget levels for capture. If empty (default), auto-inferred from model architecture as power-of-2 levels. User-provided values override auto-inference.
* `encoder_cudagraph_max_vision_items_per_batch` (`int`, default `0`) — maximum number of images/videos per batch during capture. If 0 (default), auto-inferred as `max_budget // min_budget`.
* `encoder_cudagraph_max_frames_per_batch` (`int`, default `0`) — maximum number of video frames per batch during capture. If 0 (default), auto-inferred as `encoder_cudagraph_max_vision_items_per_batch * 2` (to be optimized).
* `encoder_cudagraph_max_images_per_batch` (`int`, default `0`) — maximum number of images per batch during capture. If 0 (default), auto-inferred as `max_budget // min_budget`.
## Usage guide
### Image inference
Enable encoder CUDA Graphs via `compilation_config`:
```bash
@@ -113,7 +95,7 @@ With explicit budgets:
```bash
vllm serve Qwen/Qwen3-VL-32B \
--compilation-config '{"cudagraph_mm_encoder": true, "encoder_cudagraph_token_budgets": [2048, 4096, 8192, 13824], "encoder_cudagraph_max_vision_items_per_batch": 8}'
--compilation-config '{"cudagraph_mm_encoder": true, "encoder_cudagraph_token_budgets": [2048, 4096, 8192, 13824], "encoder_cudagraph_max_images_per_batch": 8}'
```
Python example:
@@ -125,7 +107,7 @@ compilation_config = {
"cudagraph_mm_encoder": True,
# Optional: override auto-inferred budgets
# "encoder_cudagraph_token_budgets": [2048, 4096, 8192, 13824],
# "encoder_cudagraph_max_vision_items_per_batch": 8,
# "encoder_cudagraph_max_images_per_batch": 8,
}
model = vllm.LLM(
@@ -136,44 +118,6 @@ model = vllm.LLM(
The manager tracks hit/miss statistics and logs them periodically. A "hit" means an image was processed via CUDA Graph replay; a "miss" means eager fallback (image exceeded all budgets).
### Video inference
Enable encoder CUDA Graphs via `compilation_config`:
```bash
vllm serve Qwen/Qwen3-VL-32B \
--limit-mm-per-prompt '{"image": 0}' \
--compilation-config '{"cudagraph_mm_encoder": true}'
```
With explicit budgets:
```bash
vllm serve Qwen/Qwen3-VL-32B \
--limit-mm-per-prompt '{"image": 0}' \
--compilation-config '{"cudagraph_mm_encoder": true, "encoder_cudagraph_token_budgets": [2048, 4096, 8192, 13824], "encoder_cudagraph_max_vision_items_per_batch": 8, "encoder_cudagraph_max_frames_per_batch": 64}'
```
Python example:
```python
import vllm
compilation_config = {
"cudagraph_mm_encoder": True,
# Optional: override auto-inferred budgets
# "encoder_cudagraph_token_budgets": [2048, 4096, 8192, 13824],
# "encoder_cudagraph_max_vision_items_per_batch": 8,
# "encoder_cudagraph_max_frames_per_batch": 64,
}
model = vllm.LLM(
model="Qwen/Qwen3-VL-32B",
limit_mm_per_prompt='{"image": 0}',
compilation_config=compilation_config,
)
```
## About the Performance
The following benchmarks were run on Blackwell GPUs (GB200) using `vllm bench mm-processor`. See [#35963](https://github.com/vllm-project/vllm/pull/35963) for full details.
@@ -196,7 +140,7 @@ vllm bench mm-processor \
--num-prompts 3000 --num-warmups 300 \
--max-model-len 32768 --seed 42 \
--mm-encoder-attn-backend FLASH_ATTN \
--compilation-config '{"cudagraph_mm_encoder": true, "encoder_cudagraph_token_budgets": [512, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 4864], "encoder_cudagraph_max_vision_items_per_batch": 8}'
--compilation-config '{"cudagraph_mm_encoder": true, "encoder_cudagraph_token_budgets": [512, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 4864], "encoder_cudagraph_max_images_per_batch": 8}'
```
### Multi-GPU (4x GB200, TP=4, DP=4)
@@ -221,8 +165,5 @@ vllm bench mm-processor \
--max-model-len 8192 --seed 42 \
--mm-encoder-attn-backend FLASHINFER \
--tensor-parallel-size 4 --mm-encoder-tp-mode data \
--compilation-config '{"cudagraph_mm_encoder": true, "encoder_cudagraph_token_budgets": [512, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 4864], "encoder_cudagraph_max_vision_items_per_batch": 8}'
--compilation-config '{"cudagraph_mm_encoder": true, "encoder_cudagraph_token_budgets": [512, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 4864], "encoder_cudagraph_max_images_per_batch": 8}'
```
!!! note
Find more details about benchmarks on GPUs (A100) for video inference at [#38061](https://github.com/vllm-project/vllm/pull/38061).
+1 -1
View File
@@ -86,7 +86,7 @@ To be used with a particular `FusedMoEPrepareAndFinalizeModular` subclass, MoE k
| cutlass_fp4 | standard,</br>batched | nvfp4 | A,T | silu | Y | Y | [`CutlassExpertsFp4`][vllm.model_executor.layers.fused_moe.cutlass_moe.CutlassExpertsFp4] |
| cutlass_fp8 | standard,</br>batched | fp8 | A,T | silu, gelu | Y | Y | [`CutlassExpertsFp8`][vllm.model_executor.layers.fused_moe.cutlass_moe.CutlassExpertsFp8],</br>[`CutlasBatchedExpertsFp8`][vllm.model_executor.layers.fused_moe.cutlass_moe.CutlassBatchedExpertsFp8] |
| flashinfer | standard | nvfp4,</br>fp8 | T | <sup>5</sup> | N | Y | [`FlashInferExperts`][vllm.model_executor.layers.fused_moe.flashinfer_cutlass_moe.FlashInferExperts] |
| gpt oss triton | standard | N/A | N/A | <sup>5</sup> | Y | Y | [`triton_kernel_fused_experts`][vllm.model_executor.layers.fused_moe.experts.gpt_oss_triton_kernels_moe.triton_kernel_fused_experts],</br>[`OAITritonExperts`][vllm.model_executor.layers.fused_moe.experts.gpt_oss_triton_kernels_moe.OAITritonExperts] |
| gpt oss triton | standard | N/A | N/A | <sup>5</sup> | Y | Y | [`triton_kernel_fused_experts`][vllm.model_executor.layers.fused_moe.gpt_oss_triton_kernels_moe.triton_kernel_fused_experts],</br>[`OAITritonExperts`][vllm.model_executor.layers.fused_moe.gpt_oss_triton_kernels_moe.OAITritonExperts] |
| marlin | standard,</br>batched | <sup>3</sup> / N/A | <sup>3</sup> / N/A | silu,</br>swigluoai | Y | Y | [`fused_marlin_moe`][vllm.model_executor.layers.fused_moe.fused_marlin_moe.fused_marlin_moe],</br>[`MarlinExperts`][vllm.model_executor.layers.fused_moe.fused_marlin_moe.MarlinExperts],</br>[`BatchedMarlinExperts`][vllm.model_executor.layers.fused_moe.fused_marlin_moe.BatchedMarlinExperts] |
| trtllm | standard | mxfp4,</br>nvfp4 | G(16),G(32) | <sup>5</sup> | N | Y | [`TrtLlmMxfp4ExpertsMonolithic`][vllm.model_executor.layers.fused_moe.experts.trtllm_mxfp4_moe.TrtLlmMxfp4ExpertsMonolithic],</br>[`TrtLlmMxfp4ExpertsModular`][vllm.model_executor.layers.fused_moe.experts.trtllm_mxfp4_moe.TrtLlmMxfp4ExpertsModular],</br>[`TrtLlmNvFp4ExpertsMonolithic`][vllm.model_executor.layers.fused_moe.experts.trtllm_nvfp4_moe.TrtLlmNvFp4ExpertsMonolithic],</br>[`TrtLlmNvfp4ExpertsModular`][vllm.model_executor.layers.fused_moe.experts.trtllm_nvfp4_moe.TrtLlmNvFp4ExpertsModular] |
| rocm aiter moe | standard | mxfp4,</br>fp8 | G(32),G(128),A,T | silu, gelu,</br>swigluoai | Y | N | `rocm_aiter_fused_experts`,</br>`AiterExperts` |
-1
View File
@@ -16,7 +16,6 @@ The following are the supported quantization formats for vLLM:
- [INT8 W8A8](int8.md)
- [FP8 W8A8](fp8.md)
- [NVIDIA Model Optimizer](modelopt.md)
- [Online Quantization](online.md)
- [AMD Quark](quark.md)
- [Quantized KV Cache](quantized_kvcache.md)
- [TorchAO](torchao.md)
-94
View File
@@ -1,94 +0,0 @@
# Online Quantization
Online quantization lets you take a BF16/FP16 model and quantize its Linear
and MoE weights to lower precision (such as FP8) at load time, without needing
a pre-quantized checkpoint or calibration data. Weights are converted during
model loading and activations are dynamically scaled during each forward pass.
## Quick Start
Pass a scheme name to the `quantization` parameter:
```python
from vllm import LLM
# Per-tensor FP8 quantization (one scale per weight tensor)
llm = LLM("meta-llama/Llama-3.1-8B", quantization="fp8_per_tensor")
# Per-block FP8 quantization (128x128 block scaling for weights and 1x128 block scaling for activations)
llm = LLM("meta-llama/Llama-3.1-8B", quantization="fp8_per_block")
```
Or with the CLI:
```bash
vllm serve meta-llama/Llama-3.1-8B --quantization fp8_per_tensor
vllm serve meta-llama/Llama-3.1-8B --quantization fp8_per_block
```
## Supported Schemes
| Scheme | Weight recipe | Activation recipe | Notes |
| ------ | ------------- | ------------------ | ----- |
| `fp8_per_tensor` | fp8_e4m3 data, fp32 per-tensor scale | fp8_e4m3 data, fp32 per-tensor scale | On some GPUs (Ada, Hopper) linear activations use per-token scaling for better performance |
| `fp8_per_block` | fp8_e4m3 data, fp32 per-128x128-block scale | fp8_e4m3 data, fp32 per-1x128-block scale | |
Support for additional schemes will be added in future versions of vllm.
## Advanced Configuration
For fine-grained control, use a `quantization_config` dictionary.
### Separate Schemes for Dense and MoE Layers
You can apply different quantization schemes to dense linear layers and MoE expert layers:
```python
from vllm import LLM
llm = LLM(
"ibm-granite/granite-3.0-1b-a400m-base",
quantization="fp8_per_tensor",
quantization_config={
"linear_scheme_override": "fp8_per_block",
},
)
```
Or,
```python
from vllm import LLM
llm = LLM(
"ibm-granite/granite-3.0-1b-a400m-base",
quantization="fp8_per_tensor",
quantization_config={
"moe_scheme_override": "fp8_per_block",
},
)
```
### Excluding Layers from Quantization
Use the `ignore` parameter to skip specific layers. It accepts exact layer names and regex patterns (prefixed with `re:`):
```python
from vllm import LLM
llm = LLM(
"ibm-granite/granite-3.0-1b-a400m-base",
quantization="fp8_per_tensor",
quantization_config={
"ignore": [
# exact layer name
"model.layers.1.self_attn.o_proj",
# regex: skip all QKV projections
"re:.*[qkv]_proj",
],
},
)
```
!!! note
For fused layers (e.g., `qkv_proj` which fuses `q_proj`, `k_proj`, `v_proj`), the ignore pattern must match the **unfused** shard names (`q_proj`, `k_proj`, `v_proj`), not the fused name.
@@ -3,15 +3,15 @@
vLLM has experimental support for s390x architecture on IBM Z platform. For now, users must build from source to natively run on IBM Z platform.
Currently, the CPU implementation for s390x architecture supports FP32, BF16 and FP16.
Currently, the CPU implementation for s390x architecture supports FP32 datatype only.
--8<-- [end:installation]
--8<-- [start:requirements]
- OS: `Linux`
- SDK: `gcc/g++ >= 14.0.0` or later with Command Line Tools
- SDK: `gcc/g++ >= 12.3.0` or later with Command Line Tools
- Instruction Set Architecture (ISA): VXE support is required. Works with Z14 and above.
- Build install python packages: `torchvision`, `llvmlite`, `numba`, `pyarrow (for testing)`, `opencv-headless`
- Build install python packages: `pyarrow`, `torch` and `torchvision`
--8<-- [end:requirements]
--8<-- [start:set-up-using-python]
@@ -24,14 +24,13 @@ Currently, there are no pre-built IBM Z CPU wheels.
--8<-- [end:pre-built-wheels]
--8<-- [start:build-wheel-from-source]
Install the following packages from the package manager before building the vLLM. For example on RHEL 9.6:
Install the following packages from the package manager before building the vLLM. For example on RHEL 9.4:
```bash
dnf install -y \
which procps findutils tar vim git gcc-toolset-14 gcc-toolset-14-binutils gcc-toolset-14-libatomic-devel zlib-devel \
which procps findutils tar vim git gcc g++ make patch make cython zlib-devel \
libjpeg-turbo-devel libtiff-devel libpng-devel libwebp-devel freetype-devel harfbuzz-devel \
openssl-devel openblas openblas-devel autoconf automake libtool cmake numpy libsndfile \
clang llvm-devel llvm-static clang-devel
openssl-devel openblas openblas-devel wget autoconf automake libtool cmake numactl-devel
```
Install rust>=1.80 which is needed for `outlines-core` and `uvloop` python packages installation.
@@ -44,13 +43,13 @@ curl https://sh.rustup.rs -sSf | sh -s -- -y && \
Execute the following commands to build and install vLLM from source.
!!! tip
Please build the following dependencies, `torchvision`, `llvmlite`, `numba`, `llguidance`, `pyarrow`, `opencv-headless` from source before building vLLM.
Please build the following dependencies, `torchvision`, `pyarrow` from source before building vLLM.
```bash
sed -i '/^torch/d' requirements/build/cuda.txt # remove torch from requirements/build/cuda.txt since we use nightly builds
uv pip install -v \
--extra-index-url https://download.pytorch.org/whl/cpu \
--torch-backend auto \
-r requirements/build/cpu.txt \
-r requirements/build/cuda.txt \
-r requirements/cpu.txt \
VLLM_TARGET_DEVICE=cpu python setup.py bdist_wheel && \
uv pip install dist/*.whl
@@ -58,9 +57,10 @@ Execute the following commands to build and install vLLM from source.
??? console "pip"
```bash
sed -i '/^torch/d' requirements/build/cuda.txt # remove torch from requirements/build/cuda.txt since we use nightly builds
pip install -v \
--extra-index-url https://download.pytorch.org/whl/cpu \
-r requirements/build/cpu.txt \
--extra-index-url https://download.pytorch.org/whl/nightly/cpu \
-r requirements/build/cuda.txt \
-r requirements/cpu.txt \
VLLM_TARGET_DEVICE=cpu python setup.py bdist_wheel && \
pip install dist/*.whl
@@ -240,7 +240,7 @@ uv pip install vllm==${VLLM_VERSION} \
# Install dependencies
pip install --upgrade numba \
scipy \
huggingface-hub[cli] \
huggingface-hub[cli,hf_transfer] \
setuptools_scm
pip install -r requirements/rocm.txt
-10
View File
@@ -59,16 +59,6 @@ please refer to [IO Processor Plugins](../../design/io_processor_plugins.md).
Within classification tasks, there is a specialized subcategory: Cross-encoder (aka reranker) models. These models
are a subset of classification models that accept two prompts as input and output num_labels equal to 1.
### Pooling Types
| Pooling Tasks | Granularity | Description |
|----------------|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `CLS` pooling | Sequence-wise | For BERTlike (bidirectional selfattention) models, CLS pooling is used by default. This means the last_hidden_states corresponding to the first token (the [CLS] token) is taken as the output. |
| `LAST` pooling | Sequence-wise | For GPTlike (causal selfattention) models, LAST pooling is used by default. This means the last_hidden_states corresponding to the last token is taken as the output. |
| `MEAN` pooling | Sequence-wise | Many studies have shown that averaging the last_hidden_states over all input tokens performs better on certain downstream tasks. Therefore, more and more models are using MEAN pooling. |
| `ALL` pooling | Token-wise | Outputs the last_hidden_states for all input tokens. |
| `STEP` pooling | Token-wise | Filters and outputs the last_hidden_states corresponding to the token IDs returned by returned_token_ids. |
### Score Types
The scoring models is designed to compute similarity scores between two input prompts. It supports three model types
-7
View File
@@ -45,7 +45,6 @@ You can compute pairwise similarity scores to build a similarity matrix using th
| `GritLM` | GritLM | `parasail-ai/GritLM-7B-vllm`. | ✅︎ | ✅︎ |
| `GteModel` | Arctic-Embed-2.0-M | `Snowflake/snowflake-arctic-embed-m-v2.0`. | | |
| `GteNewModel` | mGTE-TRM (see note) | `Alibaba-NLP/gte-multilingual-base`, etc. | | |
| `JinaEmbeddingsV5Model`<sup>C</sup> | Qwen3-based with task-specific LoRA adapters | `jinaai/jina-embeddings-v5-text-small` (see note) | ✅︎ | ✅︎ |
| `LlamaBidirectionalModel`<sup>C</sup> | Llama-based with bidirectional attention | `nvidia/llama-nemotron-embed-1b-v2`, etc. | ✅︎ | ✅︎ |
| `LlamaModel`<sup>C</sup>, `LlamaForCausalLM`<sup>C</sup>, `MistralModel`<sup>C</sup>, etc. | Llama-based | `intfloat/e5-mistral-7b-instruct`, etc. | ✅︎ | ✅︎ |
| `ModernBertModel` | ModernBERT-based | `Alibaba-NLP/gte-modernbert-base`, etc. | | |
@@ -74,12 +73,6 @@ You can compute pairwise similarity scores to build a similarity matrix using th
!!! note
`jinaai/jina-embeddings-v3` supports multiple tasks through LoRA, while vllm temporarily only supports text-matching tasks by merging LoRA weights.
!!! note
`jinaai/jina-embeddings-v5-text-small` ships with four task-specific LoRA adapters
(`retrieval`, `text-matching`, `classification`, `clustering`). vLLM merges the
selected adapter into the base weights at load time. Choose the task with
`--hf-overrides '{"jina_task": "<task>"}'`; the default is `retrieval`.
### Multimodal Models
!!! note
-4
View File
@@ -160,8 +160,6 @@ The following Score API parameters are supported:
--8<-- "vllm/entrypoints/pooling/base/protocol.py:pooling-common-params"
--8<-- "vllm/entrypoints/pooling/base/protocol.py:pooling-common-extra-params"
--8<-- "vllm/entrypoints/pooling/base/protocol.py:classify-extra-params"
--8<-- "vllm/entrypoints/pooling/scoring/protocol.py:scoring-common-params"
--8<-- "vllm/entrypoints/pooling/scoring/protocol.py:score-request-params"
```
#### Examples
@@ -372,8 +370,6 @@ The following rerank api parameters are supported:
--8<-- "vllm/entrypoints/pooling/base/protocol.py:pooling-common-params"
--8<-- "vllm/entrypoints/pooling/base/protocol.py:pooling-common-extra-params"
--8<-- "vllm/entrypoints/pooling/base/protocol.py:classify-extra-params"
--8<-- "vllm/entrypoints/pooling/scoring/protocol.py:scoring-common-params"
--8<-- "vllm/entrypoints/pooling/scoring/protocol.py:rerank-request-params"
```
#### Examples
+1 -1
View File
@@ -68,7 +68,7 @@ If your model is not in the above list, we will try to automatically convert the
Forced alignment usage requires `--hf-overrides '{"architectures": ["Qwen3ASRForcedAlignerForTokenClassification"]}'`.
Please refer to [examples/pooling/token_classify/forced_alignment_offline.py](../../../examples/pooling/token_classify/forced_alignment_offline.py).
### Reward Models
### As Reward Models
Using token classification models as reward models. For details on reward models, see [Reward Models](reward.md).
+18 -1
View File
@@ -467,11 +467,28 @@ It consists of two endpoints:
- `/tokenize` corresponds to calling `tokenizer.encode()`.
- `/detokenize` corresponds to calling `tokenizer.decode()`.
### Score API
#### Score Template
Some scoring models require a specific prompt format to work correctly. You can specify a custom score template using the `--chat-template` parameter (see [Chat Template](#chat-template)).
Score templates are supported for **cross-encoder** models only. If you are using an **embedding** model for scoring, vLLM does not apply a score template.
Like chat templates, the score template receives a `messages` list. For scoring, each message has a `role` attribute—either `"query"` or `"document"`. For the usual kind of point-wise cross-encoder, you can expect exactly two messages: one query and one document. To access the query and document content, use Jinja's `selectattr` filter:
- **Query**: `{{ (messages | selectattr("role", "eq", "query") | first).content }}`
- **Document**: `{{ (messages | selectattr("role", "eq", "document") | first).content }}`
This approach is more robust than index-based access (`messages[0]`, `messages[1]`) because it selects messages by their semantic role. It also avoids assumptions about message ordering if additional message types are added to `messages` in the future.
Example template file: [examples/pooling/score/template/nemotron-rerank.jinja](../../examples/pooling/score/template/nemotron-rerank.jinja)
### Generative Scoring API
The `/generative_scoring` endpoint uses a CausalLM model (e.g., Llama, Qwen, Mistral) to compute the probability of specified token IDs appearing as the next token. Each item (document) is concatenated with the query to form a prompt, and the model predicts how likely each label token is as the next token after that prompt. This lets you score items against a query — for example, asking "Is this the capital of France?" and scoring each city by how likely the model is to answer "Yes".
This endpoint is automatically available when the server is started with a generative model (task `"generate"`). It is separate from the pooling-based [Score API](../models/pooling_models/scoring.md#score-api), which uses cross-encoder, bi-encoder, or late-interaction models.
This endpoint is automatically available when the server is started with a generative model (task `"generate"`). It is separate from the pooling-based [Score API](#score-api), which uses cross-encoder, bi-encoder, or late-interaction models.
**Requirements:**
-3
View File
@@ -170,9 +170,6 @@ eles = "eles"
datas = "datas"
ser = "ser"
ure = "ure"
# Walsh-Hadamard Transform
wht = "wht"
WHT = "WHT"
[tool.uv]
no-build-isolation-package = ["torch"]
+3 -5
View File
@@ -7,7 +7,7 @@ requests >= 2.26.0
tqdm
blake3
py-cpuinfo
transformers >= 4.56.0, != 5.0.*, != 5.1.*, != 5.2.*, != 5.3.*, != 5.4.*, != 5.5.0
transformers >= 4.56.0, < 5
tokenizers >= 0.21.1 # Required for fast incremental detokenization.
protobuf >= 5.29.6, !=6.30.*, !=6.31.*, !=6.32.*, !=6.33.0.*, !=6.33.1.*, !=6.33.2.*, !=6.33.3.*, !=6.33.4.* # Required by LlamaTokenizer, gRPC. CVE-2026-0994
fastapi[standard] >= 0.115.0 # Required by FastAPI's form models in the OpenAI API server's audio transcriptions endpoint.
@@ -19,7 +19,7 @@ pillow # Required for image processing
prometheus-fastapi-instrumentator >= 7.0.0
tiktoken >= 0.6.0 # Required for DBRX tokenizer
lm-format-enforcer == 0.11.3
llguidance >= 1.3.0, < 1.4.0; platform_machine == "x86_64" or platform_machine == "arm64" or platform_machine == "aarch64" or platform_machine == "ppc64le"
llguidance >= 1.3.0, < 1.4.0; platform_machine == "x86_64" or platform_machine == "arm64" or platform_machine == "aarch64" or platform_machine == "s390x" or platform_machine == "ppc64le"
outlines_core == 0.2.11
# required for outlines backend disk cache
diskcache == 5.6.3
@@ -32,14 +32,12 @@ pyzmq >= 25.0.0
msgspec
gguf >= 0.17.0
mistral_common[image] >= 1.11.0
av # required for audio in video IO
opencv-python-headless >= 4.13.0 # required for video IO
soundfile # required for audio IO
pyyaml
six>=1.16.0; python_version > '3.11' # transitive dependency of pandas that needs to be the latest version for python 3.12
setuptools>=77.0.3,<81.0.0; python_version > '3.11' # Setuptools is used by triton, we need to ensure a modern version is installed for 3.12+ so that it does not try to import distutils, which was removed in 3.12
einops # Required for Qwen2-VL.
compressed-tensors == 0.15.0.1 # required for compressed-tensors
compressed-tensors == 0.14.0.1 # required for compressed-tensors
depyf==0.20.0 # required for profiling and debugging with compilation config
cloudpickle # allows pickling lambda functions in model_executor/models/registry.py
watchfiles # required for http server to monitor the updates of TLS files
+1 -3
View File
@@ -1,5 +1,3 @@
lmcache >= 0.3.9
nixl[cu13] >= 0.7.1, <= 0.10.1 # Required for disaggregated prefill
nixl-cu12 >= 0.7.1, <= 0.10.1
nixl-cu13 >= 0.7.1, <= 0.10.1
nixl[cu13] >= 0.7.1, < 0.10.0 # Required for disaggregated prefill
mooncake-transfer-engine >= 0.3.8
+5 -4
View File
@@ -18,9 +18,10 @@ httpx
librosa # required for audio tests
vector_quantize_pytorch # required for minicpmo_26 test
vocos # required for minicpmo_26 test
peft>=0.18.1 # required for phi-4-mm test
peft>=0.15.0 # required for phi-4-mm test
pqdm
ray[cgraph,default]>=2.48.0 # Ray Compiled Graph, required by pipeline parallelism tests
resampy # required for audio tests
sentence-transformers>=5.2.0 # required for embedding tests
soundfile # required for audio tests
jiwer # required for audio tests
@@ -38,8 +39,8 @@ opencv-python-headless >= 4.13.0 # required for video test
datamodel_code_generator # required for minicpm3 test
lm-eval[api]>=0.4.11 # required for model evaluation test
mteb[bm25s]>=2, <3 # required for mteb test
transformers==5.5.3
tokenizers==0.22.2
transformers==4.57.5
tokenizers==0.22.0
schemathesis>=3.39.15 # Required for openai schema test.
# quantization
bitsandbytes==0.49.2
@@ -58,7 +59,7 @@ numba == 0.61.2 # Required for N-gram speculative decoding
numpy
runai-model-streamer[s3,gcs,azure]==0.15.7
fastsafetensors>=0.2.2 # 0.2.2 contains important fixes for multi-GPU mem usage
instanttensor>=0.1.5
instanttensor==0.1.8
pydantic>=2.12 # 2.11 leads to error on python 3.13
decord==0.6.0; platform_machine == "x86_64"
terratorch >= 1.2.2 # Required for Prithvi tests
+15 -11
View File
@@ -4,7 +4,7 @@ absl-py==2.1.0
# via
# rouge-score
# tensorboard
accelerate==1.13.0
accelerate==1.0.1
# via peft
aenum==3.1.16
# via lightly
@@ -248,6 +248,7 @@ filelock==3.16.1
# huggingface-hub
# ray
# torch
# transformers
# virtualenv
fiona==1.10.1
# via torchgeo
@@ -330,7 +331,7 @@ h5py==3.13.0
# via terratorch
harfile==0.3.0
# via schemathesis
hf-xet==1.4.3
hf-xet==1.1.7
# via huggingface-hub
hiredis==3.0.0
# via tensorizer
@@ -344,10 +345,9 @@ httpx==0.27.2
# via
# -r requirements/test/cuda.in
# diffusers
# huggingface-hub
# perceptron
# schemathesis
huggingface-hub==1.10.2
huggingface-hub==0.36.2
# via
# accelerate
# datasets
@@ -401,7 +401,7 @@ inflect==5.6.2
# via datamodel-code-generator
iniconfig==2.0.0
# via pytest
instanttensor==0.1.5
instanttensor==0.1.8
# via -r requirements/test/cuda.in
isodate==0.7.2
# via azure-storage-blob
@@ -555,6 +555,7 @@ numba==0.61.2
# -c requirements/cuda.txt
# -r requirements/test/cuda.in
# librosa
# resampy
numpy==2.2.6
# via
# -r requirements/test/cuda.in
@@ -595,6 +596,7 @@ numpy==2.2.6
# pyogrio
# pywavelets
# rasterio
# resampy
# rioxarray
# rouge-score
# runai-model-streamer
@@ -754,7 +756,7 @@ pathvalidate==3.2.1
# via pytablewriter
patsy==1.0.1
# via statsmodels
peft==0.18.1
peft==0.16.0
# via -r requirements/test/cuda.in
perceptron==0.1.4
# via -r requirements/test/cuda.in
@@ -980,7 +982,7 @@ referencing==0.35.1
# via
# jsonschema
# jsonschema-specifications
regex==2026.2.28
regex==2024.9.11
# via
# diffusers
# nltk
@@ -1000,6 +1002,7 @@ requests==2.32.3
# google-api-core
# google-cloud-storage
# gpt-oss
# huggingface-hub
# lightly
# lm-eval
# mistral-common
@@ -1012,7 +1015,10 @@ requests==2.32.3
# starlette-testclient
# tacoreader
# tiktoken
# transformers
# wandb
resampy==0.4.3
# via -r requirements/test/cuda.in
responses==0.25.3
# via genai-perf
rfc3339-validator==0.1.4
@@ -1210,7 +1216,7 @@ timm==1.0.17
# segmentation-models-pytorch
# terratorch
# torchgeo
tokenizers==0.22.2
tokenizers==0.22.0
# via
# -c requirements/common.txt
# -r requirements/test/cuda.in
@@ -1289,7 +1295,7 @@ tqdm==4.67.3
# tacoreader
# terratorch
# transformers
transformers==5.5.3
transformers==4.57.5
# via
# -c requirements/common.txt
# -r requirements/test/cuda.in
@@ -1311,9 +1317,7 @@ typepy==1.3.2
typer==0.15.2
# via
# fastsafetensors
# huggingface-hub
# perceptron
# transformers
types-python-dateutil==2.9.0.20241206
# via arrow
typeshed-client==2.8.2
+3 -3
View File
@@ -29,8 +29,8 @@ opencv-python-headless >= 4.13.0 # required for video test
datamodel_code_generator # required for minicpm3 test
lm-eval[api]>=0.4.11 # required for model evaluation test
mteb[bm25s]>=2, <3 # required for mteb test
transformers==5.5.3
tokenizers==0.22.2
transformers==4.57.5
tokenizers==0.22.0
schemathesis>=3.39.15 # Required for openai schema test.
# quantization
bitsandbytes>=0.49.2
@@ -44,5 +44,5 @@ numba == 0.61.2 # Required for N-gram speculative decoding
numpy
runai-model-streamer[s3,gcs,azure]==0.15.7
fastsafetensors>=0.2.2
instanttensor>=0.1.5
instanttensor==0.1.8
pydantic>=2.12 # 2.11 leads to error on python 3.13
+5 -3
View File
@@ -23,6 +23,7 @@ vocos # required for minicpmo_26 test
peft>=0.15.0 # required for phi-4-mm test
pqdm
ray[cgraph,default]>=2.48.0 # Ray Compiled Graph, required by pipeline parallelism tests
resampy # required for audio tests
sentence-transformers>=5.2.0 # required for embedding tests
soundfile # required for audio tests
jiwer # required for audio tests
@@ -37,8 +38,8 @@ opencv-python-headless>=4.13.0 # required for video test
datamodel_code_generator # required for minicpm3 test
lm-eval[api]>=0.4.11 # required for model evaluation test
mteb[bm25s]>=2, <3 # required for mteb test
transformers==5.5.3
tokenizers==0.22.2
transformers==4.57.5
tokenizers==0.22.0
schemathesis>=3.39.15 # Required for openai schema test
# quantization
bitsandbytes==0.49.2
@@ -56,7 +57,7 @@ numba==0.61.2 # Required for N-gram speculative decoding
numpy
runai-model-streamer[s3,gcs,azure]==0.15.7
fastsafetensors>=0.2.2 # 0.2.2 contains important fixes for multi-GPU mem usage
instanttensor>=0.1.5
instanttensor==0.1.8
pydantic>=2.12 # 2.11 leads to error on python 3.13
decord==0.6.0
@@ -81,3 +82,4 @@ plotly # required for perf comparison html report
rapidfuzz
torchgeo==0.7.0
multiprocess==0.70.16
huggingface-hub==0.36.2
+22 -20
View File
@@ -39,7 +39,7 @@ annotated-doc==0.0.4
# typer
annotated-types==0.7.0
# via pydantic
anthropic==0.93.0
anthropic==0.89.0
# via
# -c requirements/common.txt
# -r requirements/test/../common.txt
@@ -76,9 +76,7 @@ attrs==26.1.0
audioread==3.0.1
# via librosa
av==16.1.0
# via
# -r requirements/test/../common.txt
# -r requirements/test/rocm.in
# via -r requirements/test/rocm.in
azure-core==1.39.0
# via
# azure-identity
@@ -174,7 +172,7 @@ colorful==0.5.8
# via ray
colorlog==6.10.1
# via optuna
compressed-tensors==0.15.0.1
compressed-tensors==0.14.0.1
# via
# -c requirements/common.txt
# -r requirements/test/../common.txt
@@ -271,9 +269,9 @@ fastapi==0.135.2
# model-hosting-container-standards
fastapi-cli==0.0.24
# via fastapi
fastapi-cloud-cli==0.16.1
fastapi-cloud-cli==0.15.1
# via fastapi-cli
fastar==0.10.0
fastar==0.9.0
# via fastapi-cloud-cli
fastparquet==2026.3.0
# via genai-perf
@@ -292,6 +290,7 @@ filelock==3.25.2
# python-discovery
# ray
# torch
# transformers
# virtualenv
fiona==1.10.1
# via torchgeo
@@ -385,7 +384,7 @@ h5py==3.16.0
# via terratorch
harfile==0.4.0
# via schemathesis
hf-xet==1.4.3
hf-xet==1.4.2
# via huggingface-hub
hiredis==3.3.1
# via tensorizer
@@ -404,7 +403,6 @@ httpx==0.27.2
# diffusers
# fastapi
# fastapi-cloud-cli
# huggingface-hub
# mcp
# model-hosting-container-standards
# openai
@@ -412,8 +410,9 @@ httpx==0.27.2
# schemathesis
httpx-sse==0.4.3
# via mcp
huggingface-hub==1.10.2
huggingface-hub==0.36.2
# via
# -r requirements/test/rocm.in
# accelerate
# datasets
# diffusers
@@ -468,7 +467,7 @@ inflect==7.5.0
# via datamodel-code-generator
iniconfig==2.3.0
# via pytest
instanttensor==0.1.6
instanttensor==0.1.8
# via -r requirements/test/rocm.in
interegular==0.3.3
# via lm-format-enforcer
@@ -485,7 +484,7 @@ jinja2==3.1.6
# genai-perf
# lm-eval
# torch
jiter==0.14.0
jiter==0.13.0
# via
# anthropic
# openai
@@ -632,7 +631,7 @@ msgpack==1.1.2
# via
# librosa
# ray
msgspec==0.21.0
msgspec==0.20.0
# via -r requirements/test/../common.txt
mteb==2.11.5
# via -r requirements/test/rocm.in
@@ -664,6 +663,7 @@ numba==0.61.2
# -c requirements/rocm.txt
# -r requirements/test/rocm.in
# librosa
# resampy
numkong==7.1.1
# via albucore
numpy==2.2.6
@@ -709,6 +709,7 @@ numpy==2.2.6
# pytrec-eval-terrier
# pywavelets
# rasterio
# resampy
# rioxarray
# rouge-score
# runai-model-streamer
@@ -741,7 +742,7 @@ omegaconf==2.3.0
# lightning
open-clip-torch==2.32.0
# via -r requirements/test/rocm.in
openai==2.31.0
openai==2.30.0
# via
# -c requirements/common.txt
# -r requirements/test/../common.txt
@@ -1092,7 +1093,7 @@ python-dotenv==1.2.2
# uvicorn
python-json-logger==4.1.0
# via -r requirements/test/../common.txt
python-multipart==0.0.26
python-multipart==0.0.22
# via
# fastapi
# mcp
@@ -1179,6 +1180,7 @@ requests==2.32.5
# google-api-core
# google-cloud-storage
# gpt-oss
# huggingface-hub
# lightly
# lm-eval
# mistral-common
@@ -1192,7 +1194,10 @@ requests==2.32.5
# starlette-testclient
# tacoreader
# tiktoken
# transformers
# wandb
resampy==0.4.3
# via -r requirements/test/rocm.in
responses==0.26.0
# via genai-perf
rfc3339-validator==0.1.4
@@ -1333,7 +1338,6 @@ sortedcontainers==2.4.0
# via hypothesis
soundfile==0.13.1
# via
# -r requirements/test/../common.txt
# -r requirements/test/rocm.in
# genai-perf
# librosa
@@ -1424,7 +1428,7 @@ timm==1.0.17
# segmentation-models-pytorch
# terratorch
# torchgeo
tokenizers==0.22.2
tokenizers==0.22.0
# via
# -c requirements/common.txt
# -r requirements/test/../common.txt
@@ -1467,7 +1471,7 @@ tqdm==4.67.3
# tacoreader
# terratorch
# transformers
transformers==5.5.3
transformers==4.57.5
# via
# -c requirements/common.txt
# -r requirements/test/../common.txt
@@ -1494,9 +1498,7 @@ typer==0.24.1
# fastapi-cli
# fastapi-cloud-cli
# fastsafetensors
# huggingface-hub
# perceptron
# transformers
typeshed-client==2.9.0
# via jsonargparse
typing-extensions==4.15.0
+1
View File
@@ -13,6 +13,7 @@ pytest-shard
absl-py
accelerate
arctic-inference
hf_transfer
lm_eval[api]
modelscope
+9 -15
View File
@@ -19,9 +19,7 @@ aiosignal==1.4.0
albumentations==1.4.6
# via -r requirements/test/xpu.in
annotated-doc==0.0.4
# via
# fastapi
# typer
# via fastapi
annotated-types==0.7.0
# via pydantic
anyio==4.13.0
@@ -66,7 +64,6 @@ click==8.3.1
# jiwer
# nltk
# schemathesis
# typer
# uvicorn
colorama==0.4.6
# via sacrebleu
@@ -115,6 +112,7 @@ filelock==3.25.2
# huggingface-hub
# modelscope
# torch
# transformers
frozenlist==1.8.0
# via
# aiohttp
@@ -135,7 +133,9 @@ h11==0.16.0
# uvicorn
harfile==0.4.0
# via schemathesis
hf-xet==1.4.3
hf-transfer==0.1.9
# via -r requirements/test/xpu.in
hf-xet==1.4.2
# via huggingface-hub
html2text==2025.4.15
# via gpt-oss
@@ -144,9 +144,8 @@ httpcore==1.0.9
httpx==0.28.1
# via
# datasets
# huggingface-hub
# schemathesis
huggingface-hub==1.10.2
huggingface-hub==0.36.2
# via
# accelerate
# datasets
@@ -516,6 +515,7 @@ requests==2.33.1
# docker
# evaluate
# gpt-oss
# huggingface-hub
# lm-eval
# mistral-common
# modelscope
@@ -524,11 +524,11 @@ requests==2.33.1
# schemathesis
# starlette-testclient
# tiktoken
# transformers
rich==14.3.3
# via
# mteb
# schemathesis
# typer
rouge-score==0.1.2
# via lm-eval
rpds-py==0.30.0
@@ -572,8 +572,6 @@ setuptools==80.10.2
# modelscope
# pytablewriter
# torch
shellingham==1.5.4
# via typer
six==1.17.0
# via
# -c requirements/common.txt
@@ -667,7 +665,7 @@ tqdm==4.67.3
# pqdm
# sentence-transformers
# transformers
transformers==5.5.3
transformers==4.57.6
# via
# -c requirements/common.txt
# sentence-transformers
@@ -678,10 +676,6 @@ typepy==1.3.4
# dataproperty
# pytablewriter
# tabledata
typer==0.24.1
# via
# huggingface-hub
# transformers
typing-extensions==4.15.0
# via
# -c requirements/common.txt
+6 -13
View File
@@ -693,12 +693,6 @@ class precompiled_wheel_utils:
flash_attn_regex = re.compile(
r"vllm/vllm_flash_attn/(?:[^/.][^/]*/)*(?!\.)[^/]*\.py"
)
# __init__.py and flash_attn_interface.py are source-controlled
# in vllm and should not be overwritten (matches cmake exclusions)
flash_attn_files_to_skip = {
"vllm/vllm_flash_attn/__init__.py",
"vllm/vllm_flash_attn/flash_attn_interface.py",
}
triton_kernels_regex = re.compile(
r"vllm/third_party/triton_kernels/(?:[^/.][^/]*/)*(?!\.)[^/]*\.py"
)
@@ -711,11 +705,7 @@ class precompiled_wheel_utils:
filter(lambda x: x.filename in files_to_copy, wheel.filelist)
)
file_members += list(
filter(
lambda x: flash_attn_regex.match(x.filename)
and x.filename not in flash_attn_files_to_skip,
wheel.filelist,
)
filter(lambda x: flash_attn_regex.match(x.filename), wheel.filelist)
)
file_members += list(
filter(
@@ -1089,10 +1079,13 @@ setup(
"bench": ["pandas", "matplotlib", "seaborn", "datasets", "scipy", "plotly"],
"tensorizer": ["tensorizer==2.10.1"],
"fastsafetensors": ["fastsafetensors >= 0.2.2"],
"instanttensor": ["instanttensor >= 0.1.5"],
"instanttensor": ["instanttensor == 0.1.8"],
"runai": ["runai-model-streamer[s3,gcs,azure] >= 0.15.7"],
"audio": [
"av",
"resampy",
"scipy",
"soundfile",
"mistral_common[audio]",
], # Required for audio processing
"video": [], # Kept for backwards compatibility
@@ -1101,7 +1094,7 @@ setup(
# NOTE: When updating helion version, also update CI files:
# - .buildkite/test_areas/kernels.yaml
# - .buildkite/test-amd.yaml
"helion": ["helion==1.0.0"],
"helion": ["helion==0.3.3"],
# Optional deps for gRPC server (vllm serve --grpc)
"grpc": ["smg-grpc-servicer[vllm] >= 0.5.0"],
# Optional deps for OpenTelemetry tracing
+8 -10
View File
@@ -13,8 +13,6 @@ from vllm.utils.mem_constants import GiB_bytes
from ..utils import create_new_process_for_each_test, requires_fp8
DEVICE_TYPE = current_platform.device_type
@create_new_process_for_each_test("fork" if not current_platform.is_rocm() else "spawn")
def test_python_error():
@@ -28,13 +26,13 @@ def test_python_error():
tensors = []
with allocator.use_memory_pool():
# allocate 70% of the total memory
x = torch.empty(alloc_bytes, dtype=torch.uint8, device=DEVICE_TYPE)
x = torch.empty(alloc_bytes, dtype=torch.uint8, device="cuda")
tensors.append(x)
# release the memory
allocator.sleep()
# allocate more memory than the total memory
y = torch.empty(alloc_bytes, dtype=torch.uint8, device=DEVICE_TYPE)
y = torch.empty(alloc_bytes, dtype=torch.uint8, device="cuda")
tensors.append(y)
with pytest.raises(RuntimeError):
# when the allocator is woken up, it should raise an error
@@ -46,17 +44,17 @@ def test_python_error():
def test_basic_cumem():
# some tensors from default memory pool
shape = (1024, 1024)
x = torch.empty(shape, device=DEVICE_TYPE)
x = torch.empty(shape, device="cuda")
x.zero_()
# some tensors from custom memory pool
allocator = CuMemAllocator.get_instance()
with allocator.use_memory_pool():
# custom memory pool
y = torch.empty(shape, device=DEVICE_TYPE)
y = torch.empty(shape, device="cuda")
y.zero_()
y += 1
z = torch.empty(shape, device=DEVICE_TYPE)
z = torch.empty(shape, device="cuda")
z.zero_()
z += 2
@@ -79,16 +77,16 @@ def test_basic_cumem():
def test_cumem_with_cudagraph():
allocator = CuMemAllocator.get_instance()
with allocator.use_memory_pool():
weight = torch.eye(1024, device=DEVICE_TYPE)
weight = torch.eye(1024, device="cuda")
with allocator.use_memory_pool(tag="discard"):
cache = torch.empty(1024, 1024, device=DEVICE_TYPE)
cache = torch.empty(1024, 1024, device="cuda")
def model(x):
out = x @ weight
cache[: out.size(0)].copy_(out)
return out + 1
x = torch.empty(128, 1024, device=DEVICE_TYPE)
x = torch.empty(128, 1024, device="cuda")
# warmup
model(x)
-258
View File
@@ -1,258 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import numpy as np
import pytest
from vllm.benchmarks.datasets.utils import get_sampling_params
from vllm.tokenizers import TokenizerLike
class _FakeTokenizer(TokenizerLike):
"""Minimal tokenizer implementing the TokenizerLike protocol
for testing get_sampling_params."""
def __init__(self, vocab_size: int = 1000, num_special_tokens: int = 0) -> None:
self._vocab_size = vocab_size
self._num_special_tokens = num_special_tokens
# -- Properties required by TokenizerLike --
@classmethod
def from_pretrained(cls, path_or_repo_id, *a, **kw): # type: ignore[override]
return cls()
@property
def vocab_size(self) -> int:
return self._vocab_size
@property
def all_special_tokens(self) -> list[str]:
return []
@property
def all_special_ids(self) -> list[int]:
return []
@property
def bos_token_id(self) -> int:
return 0
@property
def eos_token_id(self) -> int:
return 1
@property
def pad_token_id(self) -> int:
return 2
@property
def is_fast(self) -> bool:
return False
@property
def max_token_id(self) -> int:
return self._vocab_size - 1
@property
def max_chars_per_token(self) -> int:
return 4
@property
def truncation_side(self) -> str:
return "right"
def num_special_tokens_to_add(self) -> int:
return self._num_special_tokens
def __call__(self, text, text_pair=None, **kw): # type: ignore[override]
raise NotImplementedError
def get_vocab(self) -> dict[str, int]:
return {}
def get_added_vocab(self) -> dict[str, int]:
return {}
def encode(self, text, **kw) -> list[int]: # type: ignore[override]
raise NotImplementedError
def apply_chat_template(self, messages, **kw): # type: ignore[override]
raise NotImplementedError
def convert_tokens_to_ids(self, tokens): # type: ignore[override]
raise NotImplementedError
def convert_tokens_to_string(self, tokens: list[str]) -> str:
raise NotImplementedError
def decode(self, ids, skip_special_tokens: bool = False) -> str: # type: ignore[override]
raise NotImplementedError
def convert_ids_to_tokens( # type: ignore[override]
self, ids, skip_special_tokens: bool = False
) -> list[str]:
raise NotImplementedError
class TestGetSamplingParams:
"""Tests for ``get_sampling_params`` in ``vllm.benchmarks.datasets.shared``."""
# -- helpers --
@staticmethod
def _tok(vocab_size: int = 1000, num_special: int = 0) -> _FakeTokenizer:
return _FakeTokenizer(vocab_size=vocab_size, num_special_tokens=num_special)
# -- return shape / dtype --
def test_returns_three_arrays(self):
rng = np.random.default_rng(0)
result = get_sampling_params(rng, 5, 0.0, 100, 50, self._tok())
assert len(result) == 3
for arr in result:
assert isinstance(arr, np.ndarray)
@pytest.mark.parametrize("n", [1, 10, 100])
def test_output_length_matches_num_requests(self, n: int):
rng = np.random.default_rng(42)
input_lens, output_lens, offsets = get_sampling_params(
rng, n, 0.0, 64, 32, self._tok()
)
assert input_lens.shape == (n,)
assert output_lens.shape == (n,)
assert offsets.shape == (n,)
# -- fixed lengths (range_ratio = 0) --
def test_zero_range_ratio_gives_constant_lengths(self):
rng = np.random.default_rng(7)
input_lens, output_lens, _ = get_sampling_params(
rng, 20, 0.0, 128, 64, self._tok()
)
assert np.all(input_lens == 128)
assert np.all(output_lens == 64)
def test_special_tokens_subtracted_from_input_only(self):
rng = np.random.default_rng(7)
input_lens, output_lens, _ = get_sampling_params(
rng, 10, 0.0, 100, 50, self._tok(num_special=4)
)
# real_input_len = 100 - 4 = 96, range_ratio 0 → all 96
assert np.all(input_lens == 96)
# special tokens are not subtracted from output length
assert np.all(output_lens == 50)
# -- range ratios --
def test_input_range_bounds(self):
rng = np.random.default_rng(0)
ratio = 0.5
base = 200
input_lens, _, _ = get_sampling_params(
rng, 500, {"input": ratio, "output": 0.0}, base, 50, self._tok()
)
lo = int(np.floor(base * (1 - ratio)))
hi = int(np.ceil(base * (1 + ratio)))
assert np.all(input_lens >= lo)
assert np.all(input_lens <= hi)
def test_output_range_bounds(self):
rng = np.random.default_rng(0)
ratio = 0.3
base = 100
_, output_lens, _ = get_sampling_params(
rng, 500, {"input": 0.0, "output": ratio}, 50, base, self._tok()
)
lo = max(1, int(np.floor(base * (1 - ratio))))
hi = int(np.ceil(base * (1 + ratio)))
assert np.all(output_lens >= lo)
assert np.all(output_lens <= hi)
def test_output_low_clamped_to_one(self):
"""Even with a high ratio that would push output_low to 0,
the function clamps it to 1."""
rng = np.random.default_rng(0)
# output_len=1, ratio=0.99 → floor(1*0.01)=0, should clamp to 1
_, output_lens, _ = get_sampling_params(
rng, 50, {"input": 0.0, "output": 0.99}, 100, 1, self._tok()
)
assert np.all(output_lens >= 1)
# -- offsets bounded by vocab_size --
@pytest.mark.parametrize("vocab", [100, 32000, 128256])
def test_offsets_within_vocab(self, vocab: int):
rng = np.random.default_rng(0)
_, _, offsets = get_sampling_params(
rng, 200, 0.0, 64, 32, self._tok(vocab_size=vocab)
)
assert np.all(offsets >= 0)
assert np.all(offsets < vocab)
# -- reproducibility --
def test_same_seed_same_results(self):
tok = self._tok()
rr = {"input": 0.3, "output": 0.2}
a = get_sampling_params(np.random.default_rng(42), 50, rr, 256, 64, tok)
b = get_sampling_params(np.random.default_rng(42), 50, rr, 256, 64, tok)
for arr_a, arr_b in zip(a, b):
np.testing.assert_array_equal(arr_a, arr_b)
def test_different_seed_different_results(self):
tok = self._tok()
rr = {"input": 0.3, "output": 0.2}
a = get_sampling_params(np.random.default_rng(0), 50, rr, 256, 64, tok)
b = get_sampling_params(np.random.default_rng(1), 50, rr, 256, 64, tok)
# Extremely unlikely all three arrays match with different seeds
assert not all(np.array_equal(arr_a, arr_b) for arr_a, arr_b in zip(a, b))
# -- validation / error paths --
@pytest.mark.parametrize("bad_ratio", [-0.1, 1.0, 1.5])
def test_invalid_input_range_ratio(self, bad_ratio: float):
rng = np.random.default_rng(0)
with pytest.raises(ValueError, match="input_range_ratio"):
get_sampling_params(
rng, 10, {"input": bad_ratio, "output": 0.0}, 100, 50, self._tok()
)
@pytest.mark.parametrize("bad_ratio", [-0.1, 1.0, 1.5])
def test_invalid_output_range_ratio(self, bad_ratio: float):
rng = np.random.default_rng(0)
with pytest.raises(ValueError, match="output_range_ratio"):
get_sampling_params(
rng, 10, {"input": 0.0, "output": bad_ratio}, 100, 50, self._tok()
)
def test_invalid_dict_missing_keys(self):
rng = np.random.default_rng(0)
with pytest.raises(ValueError, match="input.*output"):
get_sampling_params(rng, 10, {"input": 0.1}, 100, 50, self._tok())
def test_input_len_zero_with_special_tokens(self):
"""input_len < num_special_tokens → real_input_len = 0, which is fine
(range [0, 0])."""
rng = np.random.default_rng(0)
input_lens, _, _ = get_sampling_params(
rng, 5, 0.0, 5, 50, self._tok(num_special=10)
)
# real_input_len = max(0, 5 - 10) = 0
assert np.all(input_lens == 0)
# -- edge cases --
def test_single_request(self):
rng = np.random.default_rng(0)
i, o, off = get_sampling_params(rng, 1, 0.0, 100, 50, self._tok())
assert i.shape == (1,)
assert o.shape == (1,)
assert off.shape == (1,)
def test_large_num_requests(self):
rng = np.random.default_rng(0)
i, o, off = get_sampling_params(rng, 10_000, 0.5, 512, 128, self._tok())
assert i.shape == (10_000,)
assert o.shape == (10_000,)
assert off.shape == (10_000,)
@@ -1,68 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import json
from pathlib import Path
import pytest
from transformers import AutoTokenizer, PreTrainedTokenizerBase
from vllm.benchmarks.datasets import CustomDataset
from vllm.benchmarks.datasets.create_txt_slices_dataset import create_txt_slices_jsonl
@pytest.fixture(scope="session")
def hf_tokenizer() -> PreTrainedTokenizerBase:
# Use a small, commonly available tokenizer
return AutoTokenizer.from_pretrained("gpt2")
text_content = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum.
"""
@pytest.mark.benchmark
def test_create_txt_slices_jsonl(
hf_tokenizer: PreTrainedTokenizerBase, tmp_path: Path
) -> None:
"""Test that create_txt_slices_jsonl produces valid JSONL for CustomDataset."""
txt_path = tmp_path / "input.txt"
jsonl_path = tmp_path / "input.txt.jsonl"
txt_path.write_text(text_content)
create_txt_slices_jsonl(
input_path=str(txt_path),
output_path=str(jsonl_path),
tokenizer_name="gpt2",
num_prompts=10,
input_len=10,
output_len=10,
)
# Verify the JSONL file is valid and has the expected structure
records = [json.loads(line) for line in jsonl_path.read_text().splitlines()]
assert len(records) == 10
for record in records:
assert "prompt" in record
assert "output_tokens" in record
assert isinstance(record["prompt"], str)
assert record["output_tokens"] == 10
# Verify the JSONL file can be loaded by CustomDataset
dataset = CustomDataset(dataset_path=str(jsonl_path))
samples = dataset.sample(
tokenizer=hf_tokenizer,
num_requests=10,
output_len=10,
skip_chat_template=True,
)
assert len(samples) == 10
assert all(sample.expected_output_len == 10 for sample in samples)
@@ -31,7 +31,6 @@ from vllm.platforms import current_platform
from vllm.utils.system_utils import update_environment_variables
from vllm.utils.torch_utils import set_random_seed
DEVICE_TYPE = current_platform.device_type
FP8_DTYPE = current_platform.fp8_dtype()
prompts = [
@@ -300,7 +299,7 @@ def async_tp_pass_on_test_model(
):
set_random_seed(0)
device = torch.device(f"{DEVICE_TYPE}:{local_rank}")
device = torch.device(f"cuda:{local_rank}")
torch.accelerator.set_device_index(device)
torch.set_default_device(device)
torch.set_default_dtype(dtype)
@@ -325,7 +324,7 @@ def async_tp_pass_on_test_model(
fuse_gemm_comms=True,
),
)
vllm_config.device_config = DeviceConfig(device=torch.device(DEVICE_TYPE))
vllm_config.device_config = DeviceConfig(device=torch.device("cuda"))
# this is a fake model name to construct the model config
# in the vllm_config, it's not really used.
@@ -37,8 +37,6 @@ from vllm.platforms import current_platform
from vllm.utils.system_utils import update_environment_variables
from vllm.utils.torch_utils import set_random_seed
DEVICE_TYPE = current_platform.device_type
class TestAllReduceRMSNormModel(torch.nn.Module):
def __init__(
@@ -270,7 +268,7 @@ def all_reduce_fusion_pass_on_test_model(
):
set_random_seed(0)
device = torch.device(f"{DEVICE_TYPE}:{local_rank}")
device = torch.device(f"cuda:{local_rank}")
torch.accelerator.set_device_index(device)
torch.set_default_device(device)
torch.set_default_dtype(dtype)
@@ -302,7 +300,7 @@ def all_reduce_fusion_pass_on_test_model(
vllm_config.compilation_config.pass_config = PassConfig(
fuse_allreduce_rms=True, eliminate_noops=True
)
vllm_config.device_config = DeviceConfig(device=torch.device(DEVICE_TYPE))
vllm_config.device_config = DeviceConfig(device=torch.device("cuda"))
vllm_config.parallel_config.rank = local_rank # Setup rank for debug path
# this is a fake model name to construct the model config
@@ -35,8 +35,6 @@ from vllm.platforms import current_platform
from vllm.utils.system_utils import update_environment_variables
from vllm.utils.torch_utils import set_random_seed
DEVICE_TYPE = current_platform.device_type
pytestmark = pytest.mark.skipif(not current_platform.is_cuda(), reason="Only test CUDA")
FP8_DTYPE = current_platform.fp8_dtype()
@@ -230,7 +228,7 @@ def sequence_parallelism_pass_on_test_model(
):
set_random_seed(0)
device = torch.device(f"{DEVICE_TYPE}:{local_rank}")
device = torch.device(f"cuda:{local_rank}")
torch.accelerator.set_device_index(device)
torch.set_default_device(device)
torch.set_default_dtype(dtype)
@@ -260,7 +258,7 @@ def sequence_parallelism_pass_on_test_model(
eliminate_noops=True,
),
) # NoOp needed for fusion
device_config = DeviceConfig(device=torch.device(DEVICE_TYPE))
device_config = DeviceConfig(device=torch.device("cuda"))
# this is a fake model name to construct the model config
# in the vllm_config, it's not really used.
+1 -2
View File
@@ -41,7 +41,6 @@ from vllm.v1.attention.backend import AttentionMetadata
from vllm.v1.attention.backends.registry import AttentionBackendEnum
from vllm.v1.kv_cache_interface import AttentionSpec, get_kv_quant_mode
DEVICE_TYPE = current_platform.device_type
FP8_DTYPE = current_platform.fp8_dtype()
FP4_DTYPE = torch.uint8
@@ -301,7 +300,7 @@ def test_attention_quant_pattern(
custom_ops_list = custom_ops.split(",") if custom_ops else []
device = torch.device(f"{DEVICE_TYPE}:0")
device = torch.device("cuda:0")
torch.set_default_dtype(dtype)
torch.manual_seed(42)
@@ -45,7 +45,6 @@ from vllm.v1.kv_cache_interface import MLAAttentionSpec
FP8_DTYPE = current_platform.fp8_dtype()
FP4_DTYPE = torch.uint8
DEVICE_TYPE = current_platform.device_type
class MLAAttentionQuantPatternModel(torch.nn.Module):
@@ -357,7 +356,7 @@ def test_mla_attention_quant_pattern(
custom_ops_list = custom_ops.split(",") if custom_ops else []
device = torch.device(f"{DEVICE_TYPE}:0")
device = torch.device("cuda:0")
torch.set_default_dtype(dtype)
torch.manual_seed(42)
@@ -8,9 +8,6 @@ import vllm
from tests.compile.backend import TestBackend
from vllm.compilation.passes.utility.noop_elimination import NoOpEliminationPass
from vllm.config import CompilationConfig, CompilationMode, PassConfig, VllmConfig
from vllm.platforms import current_platform
DEVICE_TYPE = current_platform.device_type
@pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16, torch.float32])
@@ -20,7 +17,7 @@ DEVICE_TYPE = current_platform.device_type
)
@pytest.mark.parametrize("hidden_size", [64, 4096])
def test_noop_elimination(dtype, num_tokens, hidden_size, buffer_size):
torch.set_default_device(DEVICE_TYPE)
torch.set_default_device("cuda")
torch.set_default_dtype(dtype)
torch.manual_seed(1)
@@ -91,7 +88,7 @@ def test_non_noop_slice_preserved():
Regression test for a bug where end=-1 was treated like an inferred
dimension (reshape semantics) leading to incorrect elimination.
"""
torch.set_default_device(DEVICE_TYPE)
torch.set_default_device("cuda")
x = torch.randn(16, 16)
class SliceModel(torch.nn.Module):
@@ -13,9 +13,6 @@ from vllm.compilation.passes.utility.scatter_split_replace import (
from vllm.compilation.passes.utility.split_coalescing import SplitCoalescingPass
from vllm.config import CompilationConfig, CompilationMode, VllmConfig
from vllm.model_executor.layers.rotary_embedding import RotaryEmbedding
from vllm.platforms import current_platform
DEVICE_TYPE = current_platform.device_type
class ScatterSplitReplacementModel(nn.Module):
@@ -64,7 +61,7 @@ class ScatterSplitReplacementModel(nn.Module):
@pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16])
def test_scatter_split_replace(dtype):
torch.set_default_device(DEVICE_TYPE)
torch.set_default_device("cuda")
torch.set_default_dtype(dtype)
torch.manual_seed(0)
@@ -8,9 +8,6 @@ import vllm
from tests.compile.backend import TestBackend
from vllm.compilation.passes.utility.split_coalescing import SplitCoalescingPass
from vllm.config import CompilationConfig, CompilationMode, PassConfig, VllmConfig
from vllm.platforms import current_platform
DEVICE_TYPE = current_platform.device_type
class SplitCoalescingModel(torch.nn.Module):
@@ -31,7 +28,7 @@ class SplitCoalescingModel(torch.nn.Module):
@pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16])
def test_split_coalescing(dtype):
torch.set_default_device(DEVICE_TYPE)
torch.set_default_device("cuda")
torch.set_default_dtype(dtype)
torch.manual_seed(0)
+2 -4
View File
@@ -31,8 +31,6 @@ from vllm.v1.cudagraph_dispatcher import CudagraphDispatcher
# This import automatically registers `torch.ops.silly.attention`
from . import silly_attention # noqa: F401
DEVICE_TYPE = current_platform.device_type
def test_version():
# Test the version comparison logic using the private function
@@ -458,7 +456,7 @@ def test_cached_compilation_config(default_vllm_config):
from vllm.model_executor.layers.quantization.utils.quant_utils import GroupShape
dtype = torch.bfloat16
device = torch.device(f"{DEVICE_TYPE}:0")
device = torch.device("cuda:0")
batch_size, num_qo_heads, head_size = 8, 16, 128
# access and cache default compilation config
@@ -480,7 +478,7 @@ def test_cached_compilation_config(default_vllm_config):
query_quant = QuantFP8(static=True, group_shape=GroupShape.PER_TENSOR)
query_quant = torch.compile(query_quant)
_q_scale = torch.tensor(1.0, dtype=torch.float32, device=DEVICE_TYPE)
_q_scale = torch.tensor(1.0, dtype=torch.float32, device="cuda")
query = torch.randn(
batch_size, num_qo_heads * head_size, dtype=dtype, device=device
)
@@ -222,47 +222,3 @@ def test_model_specialization_with_evaluate_guards(
torch.randn(1, 10).cuda(),
is_01_specialization=True,
)
@pytest.mark.skipif(not is_torch_equal_or_newer("2.10.0"), reason="requires torch 2.10")
def test_piecewise_backend_empty_sym_shape_indices():
"""Test that PiecewiseBackend handles empty sym_shape_indices correctly.
When all inputs have static shapes (no torch.SymInt), sym_shape_indices
will be empty. The fix in PiecewiseBackend.__call__ handles this case
by using the first compiled range_entry.
"""
gc.collect()
torch.accelerator.empty_cache()
torch.accelerator.synchronize()
# Use small max_model_len and max_num_batched_tokens to encourage
# static shape compilation with empty sym_shape_indices
llm = LLM(
model="Qwen/Qwen3-0.6B",
max_model_len=512,
max_num_batched_tokens=1,
compilation_config={
"mode": CompilationMode.VLLM_COMPILE,
"dynamic_shapes_config": {
"type": DynamicShapesType.BACKED.value,
},
},
)
sampling_params = SamplingParams(temperature=0, top_p=0.95, max_tokens=10)
# Generate with static shape inputs
output = llm.generate("Hello, my name is", sampling_params=sampling_params)
result = output[0].outputs[0].text
assert len(result) > 0, "Should generate non-empty output"
# Generate again to verify compilation works with empty sym_shape_indices
output = llm.generate("The capital of France is", sampling_params=sampling_params)
result = output[0].outputs[0].text
assert len(result) > 0, "Should generate non-empty output on second run"
del llm
gc.collect()
torch.accelerator.empty_cache()
torch.accelerator.synchronize()
+2 -5
View File
@@ -15,13 +15,10 @@ from vllm.compilation.backends import (
split_graph,
)
from vllm.compilation.passes.fx_utils import find_op_nodes
from vllm.platforms import current_platform
# This import automatically registers `torch.ops.silly.attention`
from . import silly_attention # noqa: F401
DEVICE_TYPE = current_platform.device_type
def test_getitem_moved_to_producer_subgraph():
"""
@@ -154,7 +151,7 @@ def test_consecutive_ops_in_split():
final_result = torch.sigmoid(attn_inout)
return final_result
torch.set_default_device(DEVICE_TYPE)
torch.set_default_device("cuda")
# Create the traced FX graph for the model
x = torch.randn(8, 4)
@@ -332,7 +329,7 @@ def test_builtin_empty_only_partition_is_merged():
"Expected two builtin empty_like nodes in merged non-splitting subgraph"
)
x = torch.randn(2, 3, device=DEVICE_TYPE)
x = torch.randn(2, 3, device="cuda")
output_original = gm(x)
output_split = split_gm(x)
assert torch.allclose(output_original, output_split), "Output mismatch after split"
@@ -16,8 +16,6 @@ from vllm.config.compilation import CompilationMode, CUDAGraphMode
from vllm.model_executor.layers.rotary_embedding import get_rope
from vllm.platforms import current_platform
DEVICE_TYPE = current_platform.device_type
@support_torch_compile
class RotaryEmbeddingCompileModule(torch.nn.Module):
@@ -47,7 +45,7 @@ def test_rotary_embedding_torch_compile_with_custom_op(monkeypatch):
monkeypatch.setenv("VLLM_USE_BYTECODE_HOOK", "1")
monkeypatch.setenv("VLLM_USE_AOT_COMPILE", "0")
device = DEVICE_TYPE
device = "cuda"
positions = torch.arange(16, device=device)
query = torch.randn(16, 32, device=device, dtype=torch.bfloat16)
key = torch.randn(16, 32, device=device, dtype=torch.bfloat16)
+1 -3
View File
@@ -17,10 +17,8 @@ from vllm.config.compilation import (
)
from vllm.config.scheduler import SchedulerConfig
from vllm.forward_context import set_forward_context
from vllm.platforms import current_platform
MLP_SIZE = 64
DEVICE_TYPE = current_platform.device_type
@support_torch_compile
@@ -73,7 +71,7 @@ class TraceStructuredCapture:
@pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA required")
def test_vllm_structured_logging_artifacts(use_fresh_inductor_cache):
"""Test that all expected vLLM artifacts are logged during compilation."""
torch.set_default_device(DEVICE_TYPE)
torch.set_default_device("cuda")
capture = TraceStructuredCapture()
@@ -356,23 +356,6 @@
"is_multimodal_model": false,
"dtype": "torch.float32"
},
"stepfun-ai/Step-3.5-Flash": {
"architectures": [
"Step3p5ForCausalLM"
],
"model_type": "step3p5",
"text_model_type": "step3p5",
"hidden_size": 4096,
"total_num_hidden_layers": 45,
"total_num_attention_heads": 64,
"head_size": 128,
"vocab_size": 128896,
"total_num_kv_heads": 8,
"num_experts": 288,
"is_deepseek_mla": false,
"is_multimodal_model": false,
"dtype": "torch.bfloat16"
},
"nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16": {
"architectures": [
"NemotronHForCausalLM"
-1
View File
@@ -16,7 +16,6 @@ BASE_TRUST_REMOTE_CODE_MODELS = {
"nvidia/Llama-3_3-Nemotron-Super-49B-v1",
"nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16",
"XiaomiMiMo/MiMo-7B-RL",
"stepfun-ai/Step-3.5-Flash",
# Excluded: Not available online right now
# "FreedomIntelligence/openPangu-Ultra-MoE-718B-V1.1",
"meituan-longcat/LongCat-Flash-Chat",
-15
View File
@@ -364,7 +364,6 @@ class HfRunner:
model_name: str,
dtype: str = "auto",
*,
revision: str | None = None,
model_kwargs: dict[str, Any] | None = None,
trust_remote_code: bool = True,
is_sentence_transformer: bool = False,
@@ -384,7 +383,6 @@ class HfRunner:
self._init(
model_name=model_name,
dtype=dtype,
revision=revision,
model_kwargs=model_kwargs,
trust_remote_code=trust_remote_code,
is_sentence_transformer=is_sentence_transformer,
@@ -398,7 +396,6 @@ class HfRunner:
model_name: str,
dtype: str = "auto",
*,
revision: str | None = None,
model_kwargs: dict[str, Any] | None = None,
trust_remote_code: bool = True,
is_sentence_transformer: bool = False,
@@ -413,15 +410,6 @@ class HfRunner:
model_name,
trust_remote_code=trust_remote_code,
)
# HF runner should use the HF config so that it's consistent with the HF model
if self.config.__module__.startswith("vllm.transformers_utils.configs"):
from transformers.models.auto.configuration_auto import CONFIG_MAPPING
del CONFIG_MAPPING._extra_content[self.config.model_type]
self.config = AutoConfig.from_pretrained(
model_name,
trust_remote_code=trust_remote_code,
)
self.device = self.get_default_device()
self.dtype = dtype = _get_and_verify_dtype(
self.model_name,
@@ -440,7 +428,6 @@ class HfRunner:
self.model = SentenceTransformer(
model_name,
revision=revision,
device=self.device,
model_kwargs=model_kwargs,
trust_remote_code=trust_remote_code,
@@ -451,7 +438,6 @@ class HfRunner:
self.model = CrossEncoder(
model_name,
revision=revision,
device=self.device,
automodel_args=model_kwargs,
trust_remote_code=trust_remote_code,
@@ -461,7 +447,6 @@ class HfRunner:
nn.Module,
auto_cls.from_pretrained(
model_name,
revision=revision,
trust_remote_code=trust_remote_code,
**model_kwargs,
),
-6
View File
@@ -91,12 +91,6 @@ def test_multiple_priority(llm: LLM):
outputs = llm.generate(PROMPTS, sampling_params=None, priority=[])
def test_single_prompt_priority(llm: LLM):
# Single string prompts should be normalized to one request.
outputs = llm.generate(PROMPTS[0], sampling_params=None, priority=[0])
assert len(outputs) == 1
def test_max_model_len():
max_model_len = 20
llm = LLM(
@@ -249,74 +249,40 @@ async def test_function_calling_with_streaming_expected_arguments(
"additionalProperties": False,
},
"strict": True,
},
{
"type": "function",
"name": "get_time",
"description": "Get current local time for provided location.",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"},
},
"required": ["location"],
"additionalProperties": False,
},
"strict": True,
},
}
]
stream_response = await client.responses.create(
model=model_name,
input=(
"Use tools only. Call get_weather for Berlin and get_time for Tokyo. "
"Do not answer directly."
),
input="Can you tell me what the current weather is in Berlin?",
tools=tools,
stream=True,
)
tool_call_items = {}
arguments_done_events = {}
completed_events = {}
tool_call_item = None
completed_event = None
async for event in stream_response:
if (
event.type == "response.output_item.added"
and event.item.type == "function_call"
):
tool_call_items[event.output_index] = event.item
elif event.type == "response.function_call_arguments.delta":
tool_call_item = tool_call_items[event.output_index]
tool_call_item = event.item
elif event.type == "response.function_call_arguments.delta" and tool_call_item:
tool_call_item.arguments += event.delta
elif event.type == "response.function_call_arguments.done":
arguments_done_events[event.output_index] = event
elif (
event.type == "response.output_item.done"
and event.item.type == "function_call"
):
completed_events[event.output_index] = event
assert len(tool_call_items) >= 2
assert len(arguments_done_events) >= 2
assert len(completed_events) >= 2
tool_calls_by_name = {
event.item.name: (
tool_call_items[output_index],
arguments_done_events[output_index],
event.item,
)
for output_index, event in completed_events.items()
}
assert {"get_weather", "get_time"}.issubset(tool_calls_by_name)
for added_item, arguments_done_event, completed_item in tool_calls_by_name.values():
assert added_item.type == "function_call"
assert added_item.arguments == arguments_done_event.arguments
assert added_item.arguments == completed_item.arguments
assert added_item.name == arguments_done_event.name
assert added_item.name == completed_item.name
args = json.loads(added_item.arguments)
assert "location" in args
assert args["location"] is not None
completed_event = event
assert tool_call_item is not None
assert tool_call_item.type == "function_call"
assert tool_call_item.name == "get_weather"
assert completed_event is not None
assert tool_call_item.arguments == completed_event.item.arguments
assert tool_call_item.name == completed_event.item.name
args = json.loads(tool_call_item.arguments)
assert "location" in args
assert args["location"] is not None
@pytest.mark.asyncio
@@ -27,9 +27,7 @@ from openai.types.responses.tool import (
import vllm.envs as envs
from vllm.entrypoints.mcp.tool_server import ToolServer
from vllm.entrypoints.openai.engine.protocol import (
DeltaFunctionCall,
DeltaMessage,
DeltaToolCall,
ErrorResponse,
RequestResponseMetadata,
)
@@ -930,197 +928,3 @@ class TestStreamingReasoningToContentTransition:
]
assert len(item_done_events) == 1
assert isinstance(item_done_events[0].item, ResponseReasoningItem)
class TestAutoToolStreaming:
@staticmethod
async def _collect_events(delta_sequence: list[DeltaMessage]):
serving = _make_serving_instance_with_reasoning()
_mock_parser_with_reasoning(serving, delta_sequence)
contexts = [
_make_simple_context_with_output("chunk", [i])
for i in range(len(delta_sequence))
]
async def result_generator():
for ctx in contexts:
yield ctx
request = ResponsesRequest(
input="hi",
tools=[
{
"type": "function",
"name": "get_weather",
"description": "Get weather.",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string"}},
"required": ["location"],
"additionalProperties": False,
},
}
],
tool_choice="auto",
stream=True,
)
sampling_params = SamplingParams(max_tokens=64)
metadata = RequestResponseMetadata(request_id="req")
_identity_increment._counter = 0 # type: ignore
events = []
async for event in serving._process_simple_streaming_events(
request=request,
sampling_params=sampling_params,
result_generator=result_generator(),
context=SimpleContext(),
model_name="test-model",
tokenizer=MagicMock(),
request_metadata=metadata,
created_time=0,
_increment_sequence_number_and_return=_identity_increment,
):
events.append(event)
return events
@pytest.mark.skip_global_cleanup
@pytest.mark.asyncio
async def test_auto_multi_tool_streaming_opens_one_item_per_tool(self, monkeypatch):
monkeypatch.setattr(envs, "VLLM_USE_EXPERIMENTAL_PARSER_CONTEXT", False)
delta_sequence = [
DeltaMessage(
tool_calls=[
DeltaToolCall(
id="call_vienna",
type="function",
index=0,
function=DeltaFunctionCall(
name="get_weather",
arguments="",
),
)
]
),
DeltaMessage(
tool_calls=[
DeltaToolCall(
index=0,
function=DeltaFunctionCall(
arguments='{"location":"Vienna"}',
),
)
]
),
DeltaMessage(
tool_calls=[
DeltaToolCall(
id="call_berlin",
type="function",
index=1,
function=DeltaFunctionCall(
name="get_weather",
arguments='{"location":"Berlin"}',
),
)
]
),
]
events = await self._collect_events(delta_sequence)
function_items = [
event
for event in events
if event.type == "response.output_item.added"
and getattr(event.item, "type", None) == "function_call"
]
assert len(function_items) == 2
assert [event.item.name for event in function_items] == [
"get_weather",
"get_weather",
]
assert [event.output_index for event in function_items] == [0, 1]
argument_deltas = [
event.delta
for event in events
if event.type == "response.function_call_arguments.delta"
]
assert argument_deltas == [
'{"location":"Vienna"}',
'{"location":"Berlin"}',
]
argument_done = [
event
for event in events
if event.type == "response.function_call_arguments.done"
]
assert [event.arguments for event in argument_done] == [
'{"location":"Vienna"}',
'{"location":"Berlin"}',
]
assert [event.output_index for event in argument_done] == [0, 1]
function_done = [
event
for event in events
if event.type == "response.output_item.done"
and getattr(event.item, "type", None) == "function_call"
]
assert [event.item.arguments for event in function_done] == [
'{"location":"Vienna"}',
'{"location":"Berlin"}',
]
assert [event.output_index for event in function_done] == [0, 1]
@pytest.mark.skip_global_cleanup
@pytest.mark.asyncio
async def test_auto_tool_choice_first_delta_tool_call_does_not_duplicate_item(
self, monkeypatch
):
monkeypatch.setattr(envs, "VLLM_USE_EXPERIMENTAL_PARSER_CONTEXT", False)
delta_sequence = [
DeltaMessage(
tool_calls=[
DeltaToolCall(
id="call_test",
type="function",
index=0,
function=DeltaFunctionCall(
name="get_weather",
arguments="",
),
)
]
),
DeltaMessage(
tool_calls=[
DeltaToolCall(
index=0,
function=DeltaFunctionCall(
arguments='{"location":"Berlin"}',
),
)
]
),
]
events = await self._collect_events(delta_sequence)
function_items = [
event
for event in events
if event.type == "response.output_item.added"
and getattr(event.item, "type", None) == "function_call"
]
assert len(function_items) == 1
assert function_items[0].item.name == "get_weather"
argument_deltas = [
event.delta
for event in events
if event.type == "response.function_call_arguments.delta"
]
assert "".join(argument_deltas) == '{"location":"Berlin"}'
@@ -1,150 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Unit tests for tool_calls Iterable → list materialisation.
Regression tests for https://github.com/vllm-project/vllm/issues/34792.
Setting VLLM_LOGGING_LEVEL=debug caused tool calling to break for Mistral
models because:
1. The OpenAI Python SDK types tool_calls as Iterable[...] in
ChatCompletionAssistantMessageParam.
2. Pydantic v2, when validating from Python objects (not from raw JSON),
wraps Iterable fields in a one-shot lazy iterator.
3. Debug logging called model_dump_json() which consumed that iterator.
4. The Mistral tokenizer then saw empty tool_calls and raised
"ValueError: Unexpected tool call id ...".
"""
import pytest
from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionRequest
def _make_tool_call(tc_id: str, name: str, args: str) -> dict:
return {
"id": tc_id,
"type": "function",
"function": {"name": name, "arguments": args},
}
def _make_request(messages: list) -> ChatCompletionRequest:
return ChatCompletionRequest(
model="test-model",
messages=messages,
)
def test_tool_calls_list_preserved_after_model_dump():
"""tool_calls in assistant messages must be readable after model_dump_json.
When the request is built from Python dicts (as in the Anthropic OpenAI
conversion path), Pydantic v2 previously wrapped the Iterable tool_calls
in a one-shot iterator. model_dump_json() consumed it, leaving subsequent
readers (e.g. the Mistral tokenizer) with an empty sequence.
"""
tool_call = _make_tool_call("call_abc123", "get_weather", '{"city": "Paris"}')
messages = [
{"role": "user", "content": "What is the weather in Paris?"},
{"role": "assistant", "content": None, "tool_calls": [tool_call]},
{
"role": "tool",
"tool_call_id": "call_abc123",
"content": '{"temperature": 20}',
},
]
req = _make_request(messages)
# Simulate debug logging: serialize the model (this was the trigger)
_ = req.model_dump_json()
# The assistant message must still have accessible tool_calls afterwards
assistant_msg = req.messages[1]
assert isinstance(assistant_msg, dict)
tool_calls = assistant_msg.get("tool_calls")
assert tool_calls is not None, "tool_calls must not be None after model_dump_json"
assert isinstance(tool_calls, list), "tool_calls must be a list"
assert len(tool_calls) > 0, "tool_calls must not be empty after model_dump_json"
def test_tool_calls_from_generator_are_materialised():
"""tool_calls passed as a generator must be converted to list on validation."""
tool_call = _make_tool_call("call_gen1", "search", '{"query": "vllm"}')
def tool_calls_gen():
yield tool_call
messages = [
{"role": "user", "content": "Search for vllm"},
{
"role": "assistant",
"content": None,
"tool_calls": tool_calls_gen(), # one-shot generator
},
]
req = _make_request(messages)
assistant_msg = req.messages[1]
assert isinstance(assistant_msg, dict)
# Iterate twice — must not raise or return empty on second pass
tool_calls_first = list(assistant_msg.get("tool_calls", []))
tool_calls_second = list(assistant_msg.get("tool_calls", []))
assert len(tool_calls_first) == 1, "First read must return the tool call"
assert len(tool_calls_second) == 1, "Second read must also return the tool call"
def test_tool_calls_list_passthrough():
"""tool_calls already provided as a list must remain a list."""
tool_call = _make_tool_call("call_list1", "calculate", '{"expr": "2+2"}')
messages = [
{"role": "user", "content": "Calculate 2+2"},
{"role": "assistant", "content": None, "tool_calls": [tool_call]},
]
req = _make_request(messages)
assistant_msg = req.messages[1]
assert isinstance(assistant_msg, dict)
assert isinstance(assistant_msg.get("tool_calls"), list)
def test_messages_without_tool_calls_unaffected():
"""Messages without tool_calls must be handled correctly."""
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"},
{"role": "assistant", "content": "Hi there!"},
]
req = _make_request(messages)
# None of the messages should have tool_calls injected
for msg in req.messages:
assert isinstance(msg, dict)
assert msg.get("tool_calls") is None or msg.get("tool_calls") == []
@pytest.mark.parametrize("num_tool_calls", [1, 3])
def test_multiple_tool_calls_materialised(num_tool_calls: int):
"""Multiple tool calls in a single message are all preserved."""
tool_calls = [
_make_tool_call(f"call_{i}", f"func_{i}", f'{{"arg": {i}}}')
for i in range(num_tool_calls)
]
messages = [
{"role": "user", "content": "Do things"},
{"role": "assistant", "content": None, "tool_calls": iter(tool_calls)},
]
req = _make_request(messages)
assistant_msg = req.messages[1]
assert isinstance(assistant_msg, dict)
result_tool_calls = assistant_msg.get("tool_calls")
assert isinstance(result_tool_calls, list)
assert len(result_tool_calls) == num_tool_calls
# Verify after model_dump_json too
_ = req.model_dump_json()
assert len(assistant_msg.get("tool_calls", [])) == num_tool_calls
@@ -4,7 +4,6 @@
import pytest
from vllm import PoolingParams
from vllm.entrypoints.pooling.embed.io_processor import EmbedIOProcessor
from vllm.entrypoints.pooling.embed.protocol import (
CohereEmbedContent,
@@ -219,7 +218,6 @@ class TestPreProcessCohereOnline:
def _make_context(**request_kwargs) -> PoolingServeContext[CohereEmbedRequest]:
return PoolingServeContext(
request=CohereEmbedRequest(model="test", **request_kwargs),
pooling_params=PoolingParams(),
model_name="test",
request_id="embd-test",
)
@@ -235,13 +233,13 @@ class TestPreProcessCohereOnline:
ctx = self._make_context(texts=["hello"])
calls: list[tuple[str, object]] = []
def preprocess_cmpl_online(request, prompt_input, prompt_embeds):
def preprocess_completion(request, prompt_input, prompt_embeds):
calls.append(("completion", prompt_input))
return ["completion"]
handler._get_task_instruction_prefix = lambda _input_type: None
handler._has_chat_template = lambda: False
handler._preprocess_cmpl_online = preprocess_cmpl_online
handler._preprocess_completion_online = preprocess_completion
handler._batch_render_chat = lambda *_args, **_kwargs: (
pytest.fail("text-only request should not require chat rendering")
)
@@ -256,7 +254,7 @@ class TestPreProcessCohereOnline:
ctx = self._make_context(texts=["hello"], input_type="query")
calls: list[tuple[str, object]] = []
def preprocess_cmpl(request, prompt_input, prompt_embeds):
def preprocess_completion(request, prompt_input, prompt_embeds):
calls.append(("completion", prompt_input))
return ["fallback"]
@@ -265,7 +263,7 @@ class TestPreProcessCohereOnline:
handler._batch_render_chat = lambda *_args, **_kwargs: (
pytest.fail("chat rendering should be skipped without a template")
)
handler._preprocess_cmpl_online = preprocess_cmpl
handler._preprocess_completion_online = preprocess_completion
handler._pre_process_cohere_online(ctx)
@@ -299,7 +297,7 @@ class TestPreProcessCohereOnline:
handler._get_task_instruction_prefix = lambda _input_type: "query: "
handler._has_chat_template = lambda: True
handler._batch_render_chat = batch_render_chat
handler._preprocess_cmpl_online = lambda *_args, **_kwargs: (
handler._preprocess_completion_online = lambda *_args, **_kwargs: (
pytest.fail("completion path should be skipped when a template exists")
)
@@ -182,7 +182,6 @@ async def test_metrics_counts(
EXPECTED_METRICS_V1 = [
"vllm:num_requests_running",
"vllm:num_requests_waiting",
"vllm:num_requests_waiting_by_reason",
"vllm:kv_cache_usage_perc",
"vllm:prefix_cache_queries",
"vllm:prefix_cache_hits",
@@ -8,5 +8,4 @@ server_args: >-
--max-model-len 4096
--tensor-parallel-size 8
--enable-expert-parallel
--mamba-backend flashinfer
--speculative-config '{"method":"mtp","num_speculative_tokens":5}'
@@ -8,5 +8,4 @@ server_args: >-
--max-model-len 4096
--tensor-parallel-size 2
--enable-expert-parallel
--mamba-backend flashinfer
--speculative-config '{"method":"mtp","num_speculative_tokens":5}'
@@ -1,5 +0,0 @@
model_name: "Qwen/Qwen3-4B"
accuracy_threshold: 0.78
num_questions: 1319
num_fewshot: 5
server_args: "--kv-cache-dtype turboquant_k3v4_nc --enforce-eager --max-model-len 4096"
@@ -1,5 +0,0 @@
model_name: "Qwen/Qwen3-4B"
accuracy_threshold: 0.80
num_questions: 1319
num_fewshot: 5
server_args: "--kv-cache-dtype turboquant_k8v4 --enforce-eager --max-model-len 4096"
@@ -1,5 +0,0 @@
model_name: "Qwen/Qwen3-4B"
accuracy_threshold: 0.75
num_questions: 1319
num_fewshot: 5
server_args: "--kv-cache-dtype turboquant_3bit_nc --enforce-eager --max-model-len 4096"
@@ -1,5 +0,0 @@
model_name: "Qwen/Qwen3-4B"
accuracy_threshold: 0.80
num_questions: 1319
num_fewshot: 5
server_args: "--kv-cache-dtype turboquant_4bit_nc --enforce-eager --max-model-len 4096"
@@ -1,4 +0,0 @@
Qwen3-4B-TQ-k8v4.yaml
Qwen3-4B-TQ-t4nc.yaml
Qwen3-4B-TQ-k3v4nc.yaml
Qwen3-4B-TQ-t3nc.yaml
-111
View File
@@ -1,111 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import pytest
import torch
from tests.kernels.allclose_default import get_default_atol, get_default_rtol
from tests.kernels.utils import opcheck
from vllm.platforms import CpuArchEnum, current_platform
from vllm.utils.torch_utils import set_random_seed
if not current_platform.is_cpu():
pytest.skip("skipping CPU-only tests", allow_module_level=True)
from vllm.model_executor.layers.activation import (
GELU,
FastGELU,
GeluAndMul,
NewGELU,
QuickGELU,
SiluAndMul,
)
DTYPES = [torch.bfloat16, torch.float32]
NUM_TOKENS = [7, 83]
D = [512, 2048]
SEEDS = [0]
@pytest.mark.parametrize(
("activation_cls", "fn"),
[
(SiluAndMul, torch.ops._C.silu_and_mul),
(GeluAndMul, torch.ops._C.gelu_and_mul),
(GeluAndMul, torch.ops._C.gelu_tanh_and_mul),
],
)
@pytest.mark.parametrize("num_tokens", NUM_TOKENS)
@pytest.mark.parametrize("d", D)
@pytest.mark.parametrize("dtype", DTYPES)
@pytest.mark.parametrize("seed", SEEDS)
@torch.inference_mode()
def test_cpu_act_and_mul(
default_vllm_config,
activation_cls: type[torch.nn.Module],
fn: object,
num_tokens: int,
d: int,
dtype: torch.dtype,
seed: int,
) -> None:
set_random_seed(seed)
x = torch.randn(num_tokens, 2 * d, dtype=dtype)
layer = activation_cls()
out = layer(x)
ref_out = layer.forward_native(x)
torch.testing.assert_close(
out, ref_out, atol=get_default_atol(out), rtol=get_default_rtol(out)
)
output_shape = x.shape[:-1] + (x.shape[-1] // 2,)
raw_out = torch.empty(output_shape, dtype=x.dtype, device=x.device)
opcheck(fn, (raw_out, x))
@pytest.mark.parametrize(
("activation_cls", "fn", "op_args"),
[
(NewGELU, torch.ops._C.gelu_new, ()),
(FastGELU, torch.ops._C.gelu_fast, ()),
(QuickGELU, torch.ops._C.gelu_quick, ()),
pytest.param(
GELU,
getattr(torch.ops._C, "activation_lut_bf16", None),
("gelu",),
marks=pytest.mark.skipif(
current_platform.get_cpu_architecture() != CpuArchEnum.ARM,
reason="activation_lut_bf16 is only built on Arm CPU",
),
),
],
)
@pytest.mark.parametrize("num_tokens", NUM_TOKENS)
@pytest.mark.parametrize("d", D)
@pytest.mark.parametrize("dtype", DTYPES)
@pytest.mark.parametrize("seed", SEEDS)
@torch.inference_mode()
def test_cpu_unary_activation(
default_vllm_config,
activation_cls: type[torch.nn.Module],
fn: object,
op_args: tuple[str, ...],
num_tokens: int,
d: int,
dtype: torch.dtype,
seed: int,
) -> None:
set_random_seed(seed)
x = torch.randn(num_tokens, d, dtype=dtype)
layer = activation_cls()
out = layer(x)
ref_out = layer.forward_native(x)
torch.testing.assert_close(
out, ref_out, atol=get_default_atol(out), rtol=get_default_rtol(out)
)
# gelu with activation_lut_bf16 only makes sense for BF16
if not (activation_cls is GELU and dtype != torch.bfloat16):
raw_out = torch.empty_like(x)
opcheck(fn, (raw_out, x, *op_args))
-48
View File
@@ -36,11 +36,9 @@ from vllm.kernels.helion.register import (
)
if _HOP_AVAILABLE:
from helion._compat import supports_torch_compile_fusion
from helion._compiler._dynamo.higher_order_ops import (
helion_kernel_wrapper_mutation,
)
from torch._inductor.utils import run_and_get_code
def _add_kernel(x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
@@ -1005,49 +1003,3 @@ class TestTorchCompileHOP:
"Compiled execution result doesn't match eager execution. "
f"Max difference: {torch.max(torch.abs(compiled_result - eager_result))}"
)
@pytest.mark.skipif(
not (_HOP_AVAILABLE and supports_torch_compile_fusion()),
reason="Requires PyTorch with Helion inductor fusion support",
)
def test_inductor_backend_compiles_helion_hop(self):
"""Test torch.compile with inductor backend and Helion fusion enabled."""
configs = {"default": helion.Config(block_sizes=[4, 4])}
with dummy_kernel_registry(configs=configs) as register:
add_helion_kernel = register(
op_name="test_inductor_add_kernel",
config_picker=lambda args, keys: "default",
helion_settings=helion.Settings(
torch_compile_fusion=True, static_shapes=False
),
)(_add_kernel)
def f(x, y):
x = x * 2.0
y = y + 1.0
out = add_helion_kernel(x, y)
return out.relu()
torch._dynamo.reset()
compiled_f = torch.compile(f, backend="inductor", fullgraph=True)
x = torch.randn(4, 4, device="cuda")
y = torch.randn(4, 4, device="cuda")
compiled_result, source_codes = run_and_get_code(compiled_f, x, y)
eager_result = f(x, y)
assert torch.allclose(compiled_result, eager_result, atol=1e-5, rtol=1e-5), (
"Inductor-compiled result doesn't match eager execution. "
f"Max difference: {torch.max(torch.abs(compiled_result - eager_result))}"
)
# With fusion enabled, prologue/epilogue ops should be fused into
# a single triton kernel rather than generating separate kernels.
kernel_count = sum(code.count("@triton.jit") for code in source_codes)
assert kernel_count == 1, (
f"Expected 1 fused triton kernel, got {kernel_count}. "
"Prologue/epilogue ops were not fused into the Helion kernel."
)
-92
View File
@@ -1,92 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import pytest
import torch
from vllm.config.mamba import MambaBackendEnum, MambaConfig
from vllm.model_executor.layers.mamba.ops.ssu_dispatch import (
FlashInferSSUBackend,
TritonSSUBackend,
get_mamba_ssu_backend,
initialize_mamba_ssu_backend,
selective_state_update,
)
from vllm.utils.torch_utils import set_random_seed
try:
import flashinfer.mamba # noqa: F401
HAS_FLASHINFER = True
except ImportError:
HAS_FLASHINFER = False
def test_default_backend_is_triton():
initialize_mamba_ssu_backend(MambaConfig())
backend = get_mamba_ssu_backend()
assert isinstance(backend, TritonSSUBackend)
assert backend.name == "triton"
def test_explicit_triton_backend():
initialize_mamba_ssu_backend(MambaConfig(backend=MambaBackendEnum.TRITON))
backend = get_mamba_ssu_backend()
assert isinstance(backend, TritonSSUBackend)
@pytest.mark.skipif(not HAS_FLASHINFER, reason="flashinfer not installed")
def test_flashinfer_backend_init():
initialize_mamba_ssu_backend(MambaConfig(backend=MambaBackendEnum.FLASHINFER))
backend = get_mamba_ssu_backend()
assert isinstance(backend, FlashInferSSUBackend)
assert backend.name == "flashinfer"
def test_uninitialized_backend_raises():
import vllm.model_executor.layers.mamba.ops.ssu_dispatch as mod
old = mod._mamba_ssu_backend
mod._mamba_ssu_backend = None
with pytest.raises(RuntimeError, match="not been initialized"):
get_mamba_ssu_backend()
mod._mamba_ssu_backend = old
@pytest.mark.skipif(HAS_FLASHINFER, reason="flashinfer is installed")
def test_flashinfer_import_error():
with pytest.raises(ImportError, match="FlashInfer is required"):
FlashInferSSUBackend(MambaConfig())
def test_triton_basic_call():
set_random_seed(0)
initialize_mamba_ssu_backend(MambaConfig(backend=MambaBackendEnum.TRITON))
device = "cuda"
batch_size = 2
dim = 64
dstate = 16
state = torch.randn(batch_size, dim, dstate, device=device)
x = torch.randn(batch_size, dim, device=device)
out = torch.empty_like(x)
dt = torch.randn(batch_size, dim, device=device)
dt_bias = torch.rand(dim, device=device) - 4.0
A = -torch.rand(dim, dstate, device=device)
B = torch.randn(batch_size, dstate, device=device)
C = torch.randn(batch_size, dstate, device=device)
D = torch.randn(dim, device=device)
selective_state_update(
state,
x,
dt,
A,
B,
C,
D=D,
dt_bias=dt_bias,
dt_softplus=True,
out=out,
)
assert not torch.isnan(out).any()
@@ -46,7 +46,6 @@ from vllm.utils.import_utils import (
has_deep_gemm,
has_mori,
)
from vllm.utils.math_utils import next_power_of_2
from .mk_objects import (
TestMoEQuantConfig,
@@ -605,6 +604,13 @@ def make_modular_kernel(
vllm_config: VllmConfig,
quant_config: FusedMoEQuantConfig,
) -> mk.FusedMoEKernel:
def next_power_of_2(x):
import math
if x == 0:
return 1
return 2 ** math.ceil(math.log2(x))
# make moe config
moe_parallel_config: FusedMoEParallelConfig = FusedMoEParallelConfig.make(
tp_size_=get_tensor_model_parallel_world_size(),
@@ -126,7 +126,7 @@ def parallel_launch_with_config(
world_size: int,
worker: Callable[Concatenate[ProcessGroupInfo, VllmConfig, Any, P], None],
vllm_config: VllmConfig,
env_dict: dict[Any, Any] | None,
env_dict: dict[Any, Any],
*args: P.args,
**kwargs: P.kwargs,
) -> None:
@@ -29,7 +29,6 @@ from vllm.utils.deep_gemm import (
is_deep_gemm_supported,
)
from vllm.utils.import_utils import has_deep_ep, has_deep_gemm
from vllm.utils.math_utils import next_power_of_2
from vllm.utils.torch_utils import set_random_seed
from vllm.v1.worker.workspace import init_workspace_manager
@@ -85,6 +84,14 @@ def with_dp_metadata(M: int, world_size: int):
yield
def next_power_of_2(x):
import math
if x == 0:
return 1
return 2 ** math.ceil(math.log2(x))
def make_block_quant_fp8_weights(
e: int,
n: int,
-3
View File
@@ -32,7 +32,6 @@ from vllm.model_executor.layers.quantization.utils.flashinfer_utils import (
from vllm.model_executor.layers.quantization.utils.fp8_utils import input_to_float8
from vllm.model_executor.models.llama4 import Llama4MoE
from vllm.platforms import current_platform
from vllm.utils.math_utils import next_power_of_2
from vllm.utils.torch_utils import set_random_seed
try:
@@ -175,7 +174,6 @@ class TestData:
routing_method=layer.routing_method_type,
activation=activation,
device=w13_quantized.device,
max_num_tokens=next_power_of_2(m),
)
return TestData(
@@ -350,7 +348,6 @@ def test_flashinfer_cutlass_moe_fp8_no_graph(
in_dtype=torch.bfloat16,
is_act_and_mul=activation.is_gated,
routing_method=RoutingMethodType.TopK,
max_num_tokens=next_power_of_2(m),
)
kernel = mk.FusedMoEKernel(
-2
View File
@@ -29,7 +29,6 @@ from vllm.model_executor.layers.fused_moe.flashinfer_cutlass_moe import (
from vllm.model_executor.layers.fused_moe.modular_kernel import FusedMoEKernel
from vllm.platforms import current_platform
from vllm.utils.flashinfer import has_flashinfer_cutlass_fused_moe
from vllm.utils.math_utils import next_power_of_2
from vllm.utils.torch_utils import set_random_seed
if not has_flashinfer_cutlass_fused_moe() or not current_platform.has_device_capability(
@@ -106,7 +105,6 @@ def test_flashinfer_fp4_moe_no_graph(
in_dtype=dtype,
is_act_and_mul=is_gated_act,
routing_method=RoutingMethodType.TopK,
max_num_tokens=next_power_of_2(m),
)
flashinfer_experts = FusedMoEKernel(
@@ -25,7 +25,7 @@ from triton_kernels.tensor_details import layout
from triton_kernels.testing import assert_close
from vllm.model_executor.layers.fused_moe.config import mxfp4_w4a16_moe_quant_config
from vllm.model_executor.layers.fused_moe.experts.gpt_oss_triton_kernels_moe import (
from vllm.model_executor.layers.fused_moe.gpt_oss_triton_kernels_moe import (
triton_kernel_moe_forward,
)
from vllm.utils.math_utils import round_up
@@ -29,7 +29,7 @@ from vllm.model_executor.layers.fused_moe.all2all_utils import (
maybe_make_prepare_finalize,
)
from vllm.model_executor.layers.fused_moe.config import mxfp4_w4a16_moe_quant_config
from vllm.model_executor.layers.fused_moe.experts.gpt_oss_triton_kernels_moe import (
from vllm.model_executor.layers.fused_moe.gpt_oss_triton_kernels_moe import (
OAITritonExperts,
UnfusedOAITritonExperts,
)
+1 -2
View File
@@ -59,7 +59,6 @@ from vllm.model_executor.layers.quantization.utils.quant_utils import quantize_w
from vllm.model_executor.models.mixtral import MixtralMoE
from vllm.platforms import current_platform
from vllm.scalar_type import ScalarType, scalar_types
from vllm.utils.math_utils import next_power_of_2
from vllm.utils.torch_utils import set_random_seed
from vllm.v1.worker.workspace import init_workspace_manager
@@ -1677,7 +1676,7 @@ def test_unquantized_bf16_flashinfer_trtllm_backend(
in_dtype=dtype,
is_act_and_mul=True,
routing_method=RoutingMethodType.Renormalize,
max_num_tokens=next_power_of_2(m),
max_num_tokens=m,
)
with set_current_vllm_config(vllm_config):
+10 -13
View File
@@ -26,7 +26,6 @@ from tests.kernels.moe.utils import TestMLP, make_test_weights, moe_quantize_wei
from vllm.config import (
CompilationConfig,
ParallelConfig,
SchedulerConfig,
VllmConfig,
set_current_vllm_config,
)
@@ -54,7 +53,7 @@ from vllm.utils.flashinfer import (
has_flashinfer_nvlink_two_sided,
)
from vllm.utils.import_utils import has_deep_ep, has_mori, has_nixl_ep
from vllm.utils.math_utils import cdiv, next_power_of_2
from vllm.utils.math_utils import cdiv
from vllm.utils.torch_utils import set_random_seed
from vllm.v1.worker.workspace import (
init_workspace_manager,
@@ -66,9 +65,8 @@ fp8_dtype = torch.float8_e4m3fn # current_platform.fp8_dtype
SHAPE_COMBOS = [
(1, 128, 256),
(32, 1024, 512),
(222, 2048, 2048),
(222, 2048, 2048), # should be big enough to exercise DP chunking
]
MAX_M = max([x[0] for x in SHAPE_COMBOS])
NUM_EXPERTS = [8, 64]
TOP_KS = [2, 6]
@@ -114,7 +112,7 @@ BACKEND_SUPPORTED_QUANTS: dict[str, set[str | None]] = {
"mori": {None, "fp8", "modelopt_fp8"},
"flashinfer_nvlink_two_sided": {None, "modelopt_fp8", "modelopt_fp4"},
"flashinfer_nvlink_one_sided": {None, "modelopt_fp8", "modelopt_fp4"},
"deepep_low_latency": {None, "modelopt_fp8", "modelopt_fp4"},
"deepep_low_latency": {None, "fp8", "modelopt_fp8", "modelopt_fp4"},
"deepep_high_throughput": {None, "fp8", "modelopt_fp8", "modelopt_fp4"},
"nixl_ep": {None, "fp8", "modelopt_fp8"},
}
@@ -365,9 +363,9 @@ def is_valid_config(config: MoETestConfig) -> tuple[bool, str | None]:
)
# routed_input_transform + quantization + high hidden dimensions
# TODO: Disable >= 2048 for now due to insane errors.
# TODO: Disable >= 2048 w/fp8 + deepep LL for now due to insane errors.
if (
config.use_routed_input_transform
(config.use_routed_input_transform or config.backend == "deepep_low_latency")
and config.quantization is not None
and config.k >= 2048
):
@@ -1665,6 +1663,9 @@ def test_moe_layer(
verbosity = pytestconfig.getoption("verbose")
test_env = dict()
test_env["VLLM_MOE_DP_CHUNK_SIZE"] = "128"
monkeypatch.setenv("VLLM_MOE_DP_CHUNK_SIZE", "128")
if os.environ.get("VLLM_LOGGING_LEVEL") is None:
monkeypatch.setenv("VLLM_LOGGING_LEVEL", "ERROR")
@@ -1689,11 +1690,7 @@ def test_moe_layer(
compilation_config.pass_config.fuse_allreduce_rms = False # for now
vllm_config = VllmConfig(
parallel_config=parallel_config,
compilation_config=compilation_config,
scheduler_config=SchedulerConfig.default_factory(
max_num_batched_tokens=next_power_of_2(MAX_M)
),
parallel_config=parallel_config, compilation_config=compilation_config
)
test_configs = generate_valid_test_configs(
@@ -1721,7 +1718,7 @@ def test_moe_layer(
world_size,
_parallel_worker,
vllm_config,
None,
test_env,
test_configs,
verbosity,
)
@@ -257,41 +257,6 @@ class TestWeightLoadingWithPaddedHiddenSize:
assert torch.equal(expert_data_full, loaded_weight)
def test_narrow_shard_dim(self):
"""Simulate loading w2 when both hidden_size and intermediate_size
are padded.
"""
padded_hidden = 3072
original_hidden = 2688
padded_intermediate = 1024
original_intermediate = 896
expert_data_full = torch.zeros(padded_hidden, padded_intermediate)
loaded_weight = torch.randn(original_hidden, original_intermediate)
shard_dim = 1
hidden_dim = FusedMoE._get_hidden_dim(shard_dim=shard_dim, ndim=2)
expert_data = FusedMoE._narrow_expert_data_for_padding(
expert_data_full,
loaded_weight,
hidden_dim=hidden_dim,
shard_dim=shard_dim,
)
expert_data.copy_(loaded_weight)
assert torch.equal(
expert_data_full[:original_hidden, :original_intermediate],
loaded_weight,
)
assert torch.equal(
expert_data_full[original_hidden:, :],
torch.zeros(padded_hidden - original_hidden, padded_intermediate),
)
assert torch.equal(
expert_data_full[:original_hidden, original_intermediate:],
torch.zeros(original_hidden, padded_intermediate - original_intermediate),
)
def test_bnb_shape_mismatch_raises(self):
"""BnB + padded hidden_size should raise via weight_loader."""
from unittest.mock import MagicMock
-282
View File
@@ -1,282 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Tests for FusedMoE with zero experts.
Verifies that:
- The ZeroExpertRouter is properly created and used as the layer router.
- A forward pass through FusedMoE with zero experts produces correct output.
- The output decomposes correctly into real expert + zero expert contributions.
Note: tests generated with Claude.
"""
import pytest
import torch
from vllm.config import VllmConfig, set_current_vllm_config
from vllm.forward_context import get_forward_context, set_forward_context
from vllm.model_executor.layers.fused_moe.layer import FusedMoE
from vllm.model_executor.layers.fused_moe.router.zero_expert_router import (
ZeroExpertRouter,
)
from vllm.v1.worker.workspace import init_workspace_manager
@pytest.fixture
def zero_expert_moe(dist_init, default_vllm_config):
"""Create a FusedMoE layer with zero experts."""
num_experts = 4
top_k = 2
# hidden_size must be >= 256 for the zero expert identity kernel to
# produce output (its BLOCK_SIZE=256 causes grid=0 when hidden_dim<256).
hidden_size = 256
intermediate_size = 512
zero_expert_num = 1
e_score_correction_bias = torch.zeros(
num_experts + zero_expert_num,
dtype=torch.float32,
device="cuda",
)
vllm_config = VllmConfig()
vllm_config.compilation_config.static_forward_context = dict()
with set_current_vllm_config(vllm_config), set_forward_context(None, vllm_config):
init_workspace_manager(torch.accelerator.current_device_index())
layer = FusedMoE(
zero_expert_type="identity",
e_score_correction_bias=e_score_correction_bias,
num_experts=num_experts,
top_k=top_k,
hidden_size=hidden_size,
intermediate_size=intermediate_size,
params_dtype=torch.bfloat16,
prefix="test_zero_expert_moe",
renormalize=False,
routed_scaling_factor=1.0,
scoring_func="softmax",
).cuda()
layer.quant_method.process_weights_after_loading(layer)
yield layer, vllm_config
@pytest.mark.parametrize("num_tokens", [1, 32])
def test_zero_expert_moe_router_is_zero_expert_router(zero_expert_moe, num_tokens):
"""Verify that FusedMoE with zero_expert_type creates a ZeroExpertRouter."""
layer, _ = zero_expert_moe
assert isinstance(layer.router, ZeroExpertRouter), (
f"Expected ZeroExpertRouter but got {type(layer.router).__name__}."
)
@pytest.mark.parametrize("num_tokens", [1, 32])
def test_zero_expert_moe_no_custom_routing_fn(zero_expert_moe, num_tokens):
"""Verify that custom_routing_function is not set (routing is handled
by ZeroExpertRouter, not a memoizing closure)."""
layer, _ = zero_expert_moe
assert layer.custom_routing_function is None
@pytest.mark.parametrize("num_tokens", [1, 32])
def test_zero_expert_moe_forward(zero_expert_moe, num_tokens):
"""Run a forward pass through FusedMoE with zero experts and verify output shape."""
layer, vllm_config = zero_expert_moe
hidden_size = layer.hidden_size
num_experts = 4
zero_expert_num = 1
total_experts = num_experts + zero_expert_num
hidden_states = torch.randn(
num_tokens, hidden_size, dtype=torch.bfloat16, device="cuda"
)
router_logits = torch.randn(
num_tokens, total_experts, dtype=torch.float32, device="cuda"
)
# Initialize weights to small random values to avoid NaN from
# uninitialized memory.
with torch.no_grad():
for param in layer.parameters():
if param.dtype.is_floating_point:
param.normal_(0, 0.01)
with set_current_vllm_config(vllm_config), set_forward_context(None, vllm_config):
get_forward_context().all_moe_layers = None
output = layer.forward(hidden_states, router_logits)
assert output.shape == hidden_states.shape, (
f"Expected output shape {hidden_states.shape}, got {output.shape}"
)
assert output.dtype == hidden_states.dtype
assert not torch.isnan(output).any(), "Output contains NaN values"
@pytest.mark.parametrize("num_tokens", [1, 32])
def test_zero_expert_moe_output_decomposition(zero_expert_moe, num_tokens):
"""Validate that the FusedMoE output equals a plain FusedMoE
output (real experts only) plus the zero expert contribution.
The key invariant is:
zero_layer.forward(h, r_full) == plain_layer.forward(h, r_real)
+ zero_expert_output
We create a plain FusedMoE layer with the same weights and real-expert-only
router logits, compute the zero expert output via the ZeroExpertRouter, and
verify the sum matches the FusedMoE output.
"""
layer, vllm_config = zero_expert_moe
num_experts = 4
zero_expert_num = 1
total_experts = num_experts + zero_expert_num
hidden_states = torch.randn(
num_tokens, layer.hidden_size, dtype=torch.bfloat16, device="cuda"
)
router_logits = torch.randn(
num_tokens, total_experts, dtype=torch.float32, device="cuda"
)
with torch.no_grad():
for param in layer.parameters():
if param.dtype.is_floating_point:
param.normal_(0, 0.01)
with set_current_vllm_config(vllm_config), set_forward_context(None, vllm_config):
get_forward_context().all_moe_layers = None
# Create a plain FusedMoE layer with the same config but no zero
# experts. Use a separate prefix to avoid collision.
plain_layer = FusedMoE(
num_experts=num_experts,
top_k=layer.top_k,
hidden_size=layer.hidden_size,
intermediate_size=layer.intermediate_size_per_partition,
params_dtype=torch.bfloat16,
prefix="test_zero_expert_moe_plain",
renormalize=False,
scoring_func="softmax",
e_score_correction_bias=layer.e_score_correction_bias,
).cuda()
# Share weights from the zero expert layer.
plain_layer.w13_weight.data.copy_(layer.w13_weight.data)
plain_layer.w2_weight.data.copy_(layer.w2_weight.data)
plain_layer.quant_method.process_weights_after_loading(plain_layer)
# Compute routing via the ZeroExpertRouter. This produces masked
# topk_weights/topk_ids (zero expert entries have weight=0, id=0)
# and stores zero_expert_output as a side effect.
topk_weights, topk_ids = layer.router.select_experts(
hidden_states, router_logits
)
zero_output = layer.router.zero_expert_output
# Compute real expert output using the plain layer with the masked
# routing from the ZeroExpertRouter.
real_output = plain_layer.quant_method.apply(
layer=plain_layer,
x=hidden_states,
topk_weights=topk_weights,
topk_ids=topk_ids,
shared_experts_input=None,
)
# Get the combined output from the zero expert layer.
full_output = layer.forward(hidden_states, router_logits)
assert zero_output is not None, "Zero expert output should not be None"
assert not torch.isnan(real_output).any(), "Real expert output has NaN"
assert not torch.isnan(zero_output).any(), "Zero expert output has NaN"
assert not torch.isnan(full_output).any(), "Full output has NaN"
expected = real_output + zero_output
torch.testing.assert_close(
full_output,
expected,
atol=0,
rtol=0,
msg="FusedMoE output should equal plain FusedMoE output "
"plus zero expert contribution",
)
@pytest.mark.parametrize("num_tokens", [1, 32])
def test_zero_expert_moe_zero_expert_is_identity(zero_expert_moe, num_tokens):
"""Validate zero expert identity behavior.
When routing strongly favors the zero expert, its contribution should
be a scaled version of hidden_states (identity operation). We verify
this by manually computing the expected zero expert output from the
routing weights and comparing against what the router produces.
"""
layer, vllm_config = zero_expert_moe
num_experts = 4
zero_expert_num = 1
total_experts = num_experts + zero_expert_num
hidden_states = torch.randn(
num_tokens, layer.hidden_size, dtype=torch.bfloat16, device="cuda"
)
# Strongly bias toward the zero expert (index 4).
router_logits = torch.full(
(num_tokens, total_experts), -10.0, dtype=torch.float32, device="cuda"
)
router_logits[:, num_experts] = 10.0 # zero expert gets high logit
with torch.no_grad():
for param in layer.parameters():
if param.dtype.is_floating_point:
param.normal_(0, 0.01)
with set_current_vllm_config(vllm_config), set_forward_context(None, vllm_config):
get_forward_context().all_moe_layers = None
# Run routing to get topk_weights/topk_ids before masking.
from vllm.model_executor.layers.fused_moe.router.fused_topk_bias_router import (
fused_topk_bias,
)
topk_weights, topk_ids = fused_topk_bias(
hidden_states=hidden_states,
gating_output=router_logits,
e_score_correction_bias=layer.router.e_score_correction_bias.data,
topk=layer.top_k,
renormalize=layer.router.renormalize,
scoring_func=layer.router.scoring_func,
)
# Manually compute expected zero expert identity output:
# For each token, sum routing weights assigned to zero expert slots,
# then multiply by hidden_states.
zero_mask = topk_ids >= num_experts
zero_weight_per_token = (topk_weights * zero_mask.float()).sum(
dim=-1, keepdim=True
)
expected_zero_output = (hidden_states.float() * zero_weight_per_token).to(
hidden_states.dtype
)
# Run routing directly to trigger zero expert computation
# without going through the runner (which consumes the output).
layer.router.select_experts(hidden_states, router_logits)
actual_zero_output = layer.router.zero_expert_output
assert actual_zero_output is not None
assert zero_mask.any(), (
"With high zero expert logit, at least some slots should route "
"to the zero expert"
)
torch.testing.assert_close(
actual_zero_output,
expected_zero_output,
atol=1e-3,
rtol=1e-3,
msg="Zero expert identity output should equal "
"hidden_states * sum(zero_expert_weights)",
)
-1
View File
@@ -69,7 +69,6 @@ def make_dummy_moe_config(
in_dtype=in_dtype,
device="cuda",
routing_method=RoutingMethodType.TopK,
max_num_tokens=512,
)
@@ -29,22 +29,18 @@ class TestTritonMoeForwardExpertMap:
torch.tensor([0, -1, 1, -1], device=device) if expert_map_present else None
)
from vllm.utils.import_utils import import_triton_kernels
import_triton_kernels()
with (
patch("triton_kernels.topk.topk") as mock_topk,
patch(
"vllm.model_executor.layers.fused_moe.experts."
"vllm.model_executor.layers.fused_moe."
"gpt_oss_triton_kernels_moe.make_routing_data"
) as mock_make_routing,
patch(
"vllm.model_executor.layers.fused_moe.experts."
"vllm.model_executor.layers.fused_moe."
"gpt_oss_triton_kernels_moe.triton_kernel_fused_experts"
) as mock_fused_experts,
):
from vllm.model_executor.layers.fused_moe.experts.gpt_oss_triton_kernels_moe import ( # noqa: E501
from vllm.model_executor.layers.fused_moe.gpt_oss_triton_kernels_moe import ( # noqa: E501
triton_kernel_moe_forward,
)
@@ -6,7 +6,6 @@ import pytest
import torch
from vllm.model_executor.layers.quantization.utils import fp8_utils, int8_utils
from vllm.platforms import current_platform
@pytest.mark.parametrize(
@@ -81,9 +80,7 @@ def test_per_token_group_quant_fp8(
],
)
@pytest.mark.parametrize("poisoned_scales", [False, True])
@pytest.mark.skipif(
not current_platform.is_cuda(), reason="DeepGEMM not available on this platform"
)
@pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA not available")
def test_per_token_group_quant_fp8_packed(
num_tokens, hidden_dim, group_size, poisoned_scales
):
-6
View File
@@ -3,7 +3,6 @@
import tempfile
from collections import OrderedDict
from importlib import reload
from unittest.mock import MagicMock
import pytest
@@ -48,11 +47,6 @@ def cleanup_fixture(should_do_global_cleanup_after_test: bool):
def maybe_enable_lora_dual_stream(monkeypatch: pytest.MonkeyPatch):
if current_platform.is_cuda():
monkeypatch.setenv("VLLM_LORA_ENABLE_DUAL_STREAM", "1")
import vllm.lora.layers.base_linear
if not hasattr(vllm.lora.layers.base_linear, "lora_linear_async"):
# Reload the module to ensure the environment variable takes effect.
reload(vllm.lora.layers.base_linear)
yield
-11
View File
@@ -1,10 +1,7 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
from importlib.metadata import version
import pytest
from packaging.version import Version
import vllm
from vllm.assets.image import ImageAsset
@@ -13,14 +10,6 @@ from vllm.platforms import current_platform
from ..utils import multi_gpu_test
pytestmark = pytest.mark.skipif(
Version("5.0") <= Version(version("transformers")),
reason=(
"MiniCPMV custom processor uses tokenizer.im_start_id which is not "
"available on TokenizersBackend in transformers v5.0+"
),
)
MODEL_PATH = "openbmb/MiniCPM-Llama3-V-2_5"
PROMPT_TEMPLATE = (

Some files were not shown because too many files have changed in this diff Show More