Compare commits

..
Author SHA1 Message Date
Roger WangandGitHub b98ddeaca4 Merge branch 'main' into feat-k2.5-support 2026-01-26 20:35:11 -08:00
Roger Wang 61a45f5a77 override doc
Signed-off-by: Roger Wang <hey@rogerw.io>
2026-01-26 20:34:54 -08:00
Isotr0py 01d3aa72b0 fix image embeds test
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-27 11:58:31 +08:00
Isotr0py bfd8e63566 clean mm tracker adding
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-27 11:33:15 +08:00
Isotr0py d19264ea95 fuse moe contiguous
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-27 11:22:55 +08:00
Isotr0py 3c8c7cae43 fix vit dtype
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-27 11:17:28 +08:00
Roger WangGitHubgemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
afd23eabb1 Update vllm/model_executor/models/kimi_k25.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: Roger Wang <hey@rogerw.io>
2026-01-26 18:12:03 -08:00
Roger Wang 3b43b31340 update
Signed-off-by: Roger Wang <hey@rogerw.io>
2026-01-26 18:08:50 -08:00
youkaichaoandGitHub d3fddd46c3 Update tests/models/registry.py
Signed-off-by: youkaichao <youkaichao@gmail.com>
2026-01-27 10:06:51 +08:00
youkaichaoandGitHub 33cf86c8e4 Update docs/models/supported_models.md
Signed-off-by: youkaichao <youkaichao@gmail.com>
2026-01-27 10:06:13 +08:00
Nick Hill d4aee89521 Merge remote-tracking branch 'origin/main' into feat-k2.5-support 2026-01-26 18:01:34 -08:00
Isotr0py fcb1983cd1 fix missing uuids
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-26 17:33:32 +08:00
Isotr0py e50f62cacb use vision chunk uuid validation through data parser
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-26 16:22:19 +08:00
Isotr0py 0ce7a6064a Merge remote-tracking branch 'vllm-kv/main' into k2.5-data-parser
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-26 15:58:26 +08:00
Isotr0py 69c8721a0e fix reason parser
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-25 20:49:07 +08:00
Isotr0py 0ed896dc14 fix
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-25 19:26:39 +08:00
Isotr0py 62be6ada0e fix vit tp mode
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-25 19:25:08 +08:00
Isotr0py f79ba642ae fix outdate
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-24 23:42:43 +08:00
Isotr0py d27e665bef fix legacy import
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-24 23:02:38 +08:00
Isotr0py d1553ada27 move video chunk rebuild to render
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-24 22:33:27 +08:00
Isotr0py 8570035de9 Merge remote-tracking branch 'upstream/main' into k2.5-render
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2026-01-24 22:26:16 +08:00
wanglinian 389aa5a69c refactor(kimi_k25_vit): use run_dp_sharded_mrope_vision_model for ViT DP
Replace manual sequential batching loop with vLLM's standard DP utility.
This enables true data parallelism across GPUs for vision features.

- Add run_dp_sharded_mrope_vision_model import
- Remove KIMIV_VT_INFER_MAX_PATCH_NUM constant
- Simplify vision_tower_forward to use DP sharding
- Add self.config to MoonViT3dPretrainedModel for DP compatibility

Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-13 09:36:55 +00:00
wanglinian 009dff45c7 refactor(kimi_k25): address code review feedback
- Move PIL.Image import out of TYPE_CHECKING in inputs.py
- Remove duplicate get_dummy_image, use parent _get_dummy_images instead
- Add get_expert_mapping method following DeepseekV2 pattern
- Use SharedFusedMoE for proper shared experts handling

Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-13 09:00:28 +00:00
wanglinian 1043ba3138 style: fix ruff format - remove extra blank lines
Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-13 06:27:51 +00:00
wanglinian a69f0d5a7e Address code review feedback for KimiK25 model
Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-12 04:10:51 +00:00
wanglinian 0bbbd388de perf(chat_utils): use .media instead of .original_bytes to avoid redundant bytes→PIL conversion
When processing vision_chunk items, pass the already-decoded PIL.Image
via .media instead of .original_bytes. This avoids an unnecessary
bytes→PIL.Image conversion in media_processor since the image was
already decoded in load_bytes().

Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-08 06:06:40 +00:00
wanglinian c2bfb1def1 docs: Update Kimi-K2.5 model name and remove video support marker
Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-07 08:59:10 +00:00
wanglinian 5f54da5e7e Rename K2VL to KimiK25
- Rename files: k2vl.py -> kimi_k25.py, k2vl_vit.py -> kimi_k25_vit.py
- Rename classes: K2VLConfig -> KimiK25Config, K2VLForConditionalGeneration -> KimiK25ForConditionalGeneration, etc.
- Update registry, configs/__init__.py, config.py mappings
- Update docs and comments to reference Kimi-K2.5 instead of K2VL
- Pass vision_config to KimiK25MultiModalProjector per reference diff

Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-07 08:53:22 +00:00
wanglinian 875d970dd0 refactor(k2vl): remove unused video-chunk config params
Remove temporal_merge_kernel_size, sample_fps, and timestamp_mode
from K2VLConfig as they are not used by vLLM.

These parameters are loaded from preprocessor_config.json via
media_processor and should not be duplicated in the model config.

Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-07 07:15:54 +00:00
wanglinian a0a0fb6075 [Model] Refactor K2VL ViT to use MMEncoderAttention
- Replace custom multihead_attention/eager_attention with MMEncoderAttention
- Add tensor parallel support using QKVParallelLinear and RowParallelLinear
- MLP2 now uses ColumnParallelLinear/RowParallelLinear with TP/DP support
- Pass multimodal_config through MoonViT3dPretrainedModel to encoder layers
- Rename vision_tower_forward_auto to vision_tower_forward

This aligns with PR #31738 pattern for unified multi-platform attention backends.

Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-07 03:36:23 +00:00
wanglinian bd5bb72eb0 docs: add K2VL model to registry and supported models
Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-06 05:13:15 +00:00
wanglinian ffb3ecf3b8 refactor: address code review feedback
- k2vl_vit.py: Use get_act_fn('gelu_pytorch_tanh') instead of PytorchGELUTanh
- k2vl_vit.py: Remove VisionTowerConfig and ProjectorConfig wrapper classes
- k2vl.py: Use TensorSchema (K2VLMediaPixelInputs) instead of BatchFeature
- chat_utils.py: Add assert isinstance(item, dict) for type narrowing

Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-06 03:58:35 +00:00
wanglinian dabbad7e04 Address code review feedback: refactor tpool_patch_merger and fix imports
Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-05 11:41:01 +00:00
wanglinian a6db17b442 fix: rename mm_projection_auto to mm_projector_forward
Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-05 05:47:11 +00:00
wanglinian 256bc095ad refactor: split K2VLConfig vision params into K2VLVisionConfig
Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-05 04:20:54 +00:00
4502ffce65 Update vllm/entrypoints/chat_utils.py
Co-authored-by: Zaida Zhou <58739961+zhouzaida@users.noreply.github.com>
Signed-off-by: wangln19 <96399074+wangln19@users.noreply.github.com>
2026-01-05 11:42:23 +08:00
26898aa7aa Update vllm/entrypoints/chat_utils.py
Co-authored-by: Zaida Zhou <58739961+zhouzaida@users.noreply.github.com>
Signed-off-by: wangln19 <96399074+wangln19@users.noreply.github.com>
2026-01-05 11:42:02 +08:00
f28234d4bf Update vllm/model_executor/models/k2vl_vit.py
Co-authored-by: Zaida Zhou <58739961+zhouzaida@users.noreply.github.com>
Signed-off-by: wangln19 <96399074+wangln19@users.noreply.github.com>
2026-01-05 11:41:51 +08:00
c9243a0482 Update vllm/model_executor/models/k2vl_vit.py
Co-authored-by: Zaida Zhou <58739961+zhouzaida@users.noreply.github.com>
Signed-off-by: wangln19 <96399074+wangln19@users.noreply.github.com>
2026-01-05 11:41:29 +08:00
wanglinian 120e059650 delete enable_thinking and training para
Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-05 03:37:40 +00:00
wanglinian c9d5ff0405 feat: support K2.5 model
Add support for K2.5 model (K2VL) in vllm.

Key changes:
- Add K2VL model implementation and configuration.
- Add Kimi K2 reasoning parser.
- Update Chat API and multimodal inputs to support video chunks.
- Add K2.5 specific multimodal processing logic and parsing.
- Register K2VL model and configuration.

Signed-off-by: wanglinian <wanglinian@stu.pku.edu.cn>
2026-01-04 07:25:03 +00:00
8 changed files with 50 additions and 93 deletions
+7 -9
View File
@@ -24,12 +24,6 @@
typedef __hip_bfloat16 __nv_bfloat16;
#endif
#if defined(__gfx942__)
constexpr float kFp8ScaleDivisor = 224.f;
#else
constexpr float kFp8ScaleDivisor = 448.f;
#endif
void swap_blocks(torch::Tensor& src, torch::Tensor& dst,
int64_t block_size_in_bytes,
const torch::Tensor& block_mapping) {
@@ -407,7 +401,8 @@ __global__ void concat_and_cache_ds_mla_kernel(
}
// Compute the scale for the tile
float tile_scale = fmaxf(max_abs / kFp8ScaleDivisor, FLT_MIN);
float tile_scale = max_abs / 448.f;
tile_scale = fmaxf(tile_scale, FLT_MIN);
// The first lane of each half-warp writes the scale to kv_cache
if ((lane_idx == 0) || (lane_idx == 16)) {
@@ -476,8 +471,11 @@ __global__ void indexer_k_quant_and_cache_kernel(
#endif
}
float scale = fmaxf(amax, 1e-4) / kFp8ScaleDivisor;
#if defined(__gfx942__)
float scale = fmaxf(amax, 1e-4) / 224.0f;
#else
float scale = fmaxf(amax, 1e-4) / 448.0f;
#endif
if (use_ue8m0) {
scale = exp2f(ceilf(log2f(scale)));
}
@@ -1,8 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import random
import numpy as np
import pytest
import torch
from transformers import AutoModelForTokenClassification
@@ -11,20 +8,6 @@ from tests.models.utils import softmax
from vllm.platforms import current_platform
@pytest.fixture(autouse=True)
def seed_everything():
"""Seed all random number generators for reproducibility."""
seed = 0
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
if torch.cuda.is_available():
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
yield
@pytest.mark.parametrize("model", ["boltuix/NeuroBERT-NER"])
# The float32 is required for this tiny model to pass the test.
@pytest.mark.parametrize("dtype", ["float"])
@@ -68,7 +51,6 @@ def test_bert_models(
@pytest.mark.parametrize("model", ["disham993/electrical-ner-ModernBERT-base"])
@pytest.mark.parametrize("dtype", ["float"])
@pytest.mark.flaky(reruns=3)
@torch.inference_mode
def test_modernbert_models(
hf_runner,
@@ -77,15 +59,6 @@ def test_modernbert_models(
model: str,
dtype: str,
) -> None:
# NOTE: https://github.com/vllm-project/vllm/pull/32403
# `disham993/electrical-ner-ModernBERT-base` is a randomly initialized
# model, which can cause numerical precision variance and edge cases.
# We use @flaky(reruns=3) to mitigate intermittent failures.
print(
f"\n[NOTE] Testing {model} (randomly initialized weights) - "
"flaky tolerance enabled due to numerical precision variance."
)
with vllm_runner(model, max_model_len=None, dtype=dtype) as vllm_model:
vllm_outputs = vllm_model.token_classify(example_prompts)
@@ -68,7 +68,6 @@ from vllm.entrypoints.openai.parser.harmony_utils import (
from vllm.entrypoints.openai.utils import maybe_filter_parallel_tool_calls
from vllm.entrypoints.utils import get_max_tokens, should_include_usage
from vllm.inputs.data import TokensPrompt
from vllm.inputs.parse import get_prompt_components
from vllm.logger import init_logger
from vllm.logprobs import Logprob
from vllm.outputs import CompletionOutput, RequestOutput
@@ -375,18 +374,20 @@ class OpenAIServingChat(OpenAIServing):
generators: list[AsyncGenerator[RequestOutput, None]] = []
try:
for i, engine_prompt in enumerate(engine_prompts):
prompt_text, _, _ = get_prompt_components(engine_prompt)
prompt_text, _, _ = self._get_prompt_components(engine_prompt)
# If we are creating sub requests for multiple prompts, ensure that they
# have unique request ids.
sub_request_id = (
request_id if len(engine_prompts) == 1 else f"{request_id}_{i}"
)
if self.default_sampling_params is None:
self.default_sampling_params = {}
max_tokens = get_max_tokens(
max_model_len=self.max_model_len,
request=request,
prompt=engine_prompt,
input_length=len(engine_prompt["prompt_token_ids"]),
default_sampling_params=self.default_sampling_params,
)
+15 -3
View File
@@ -36,7 +36,6 @@ from vllm.entrypoints.renderer import RenderConfig
from vllm.entrypoints.utils import get_max_tokens, should_include_usage
from vllm.exceptions import VLLMValidationError
from vllm.inputs.data import EmbedsPrompt, TokensPrompt, is_embeds_prompt
from vllm.inputs.parse import get_prompt_components
from vllm.logger import init_logger
from vllm.logprobs import Logprob
from vllm.outputs import RequestOutput
@@ -163,12 +162,25 @@ class OpenAIServingCompletion(OpenAIServing):
generators: list[AsyncGenerator[RequestOutput, None]] = []
try:
for i, engine_prompt in enumerate(engine_prompts):
prompt_text, _, _ = get_prompt_components(engine_prompt)
prompt_text, prompt_token_ids, prompt_embeds = (
self._get_prompt_components(engine_prompt)
)
input_length = None
if prompt_token_ids is not None:
input_length = len(prompt_token_ids)
elif prompt_embeds is not None:
input_length = len(prompt_embeds)
else:
raise NotImplementedError
if self.default_sampling_params is None:
self.default_sampling_params = {}
max_tokens = get_max_tokens(
max_model_len=self.max_model_len,
request=request,
prompt=engine_prompt,
input_length=input_length,
default_sampling_params=self.default_sampling_params,
)
+15 -20
View File
@@ -94,14 +94,11 @@ from vllm.entrypoints.serve.tokenize.protocol import (
TokenizeCompletionRequest,
TokenizeResponse,
)
from vllm.entrypoints.utils import (
_validate_truncation_size,
get_max_tokens,
sanitize_message,
)
from vllm.entrypoints.utils import _validate_truncation_size, sanitize_message
from vllm.exceptions import VLLMValidationError
from vllm.inputs.data import PromptType, TokensPrompt
from vllm.inputs.parse import (
PromptComponents,
get_prompt_components,
is_explicit_encoder_decoder_prompt,
)
@@ -1290,7 +1287,7 @@ class OpenAIServing:
priority: int = 0,
**kwargs,
):
prompt_text, _, _ = get_prompt_components(engine_prompt)
prompt_text, _, _ = self._get_prompt_components(engine_prompt)
orig_priority = priority
sub_request = 0
@@ -1341,12 +1338,10 @@ class OpenAIServing:
# yield context
# Create inputs for the next turn.
# Render the next prompt token ids and update sampling_params.
# Render the next prompt token ids.
if isinstance(context, (HarmonyContext, StreamingHarmonyContext)):
token_ids = context.render_for_completion()
engine_prompt = TokensPrompt(prompt_token_ids=token_ids)
sampling_params.max_tokens = self.max_model_len - len(token_ids)
prompt_token_ids = context.render_for_completion()
engine_prompt = TokensPrompt(prompt_token_ids=prompt_token_ids)
elif isinstance(context, ParsableContext):
engine_prompts = await self._render_next_turn(
context.request,
@@ -1358,19 +1353,19 @@ class OpenAIServing:
context.chat_template_content_format,
)
engine_prompt = engine_prompts[0]
prompt_text, _, _ = get_prompt_components(engine_prompt)
sampling_params.max_tokens = get_max_tokens(
self.max_model_len,
context.request,
engine_prompt,
self.default_sampling_params, # type: ignore
)
prompt_text, _, _ = self._get_prompt_components(engine_prompt)
# Update the sampling params.
sampling_params.max_tokens = self.max_model_len - len(
engine_prompt["prompt_token_ids"]
)
# OPTIMIZATION
priority = orig_priority - 1
sub_request += 1
def _get_prompt_components(self, prompt: PromptType) -> PromptComponents:
return get_prompt_components(prompt)
def _log_inputs(
self,
request_id: str,
@@ -1381,7 +1376,7 @@ class OpenAIServing:
if self.request_logger is None:
return
prompt, prompt_token_ids, prompt_embeds = get_prompt_components(inputs)
prompt, prompt_token_ids, prompt_embeds = self._get_prompt_components(inputs)
self.request_logger.log_inputs(
request_id,
+2 -6
View File
@@ -116,7 +116,6 @@ from vllm.entrypoints.openai.responses.utils import (
extract_tool_types,
should_continue_final_message,
)
from vllm.entrypoints.utils import get_max_tokens
from vllm.exceptions import VLLMValidationError
from vllm.inputs.data import TokensPrompt
from vllm.logger import init_logger
@@ -436,11 +435,8 @@ class OpenAIServingResponses(OpenAIServing):
if maybe_error is not None:
return maybe_error
default_max_tokens = get_max_tokens(
self.max_model_len,
request,
engine_prompt,
self.default_sampling_params,
default_max_tokens = self.max_model_len - len(
engine_prompt["prompt_token_ids"]
)
sampling_params = request.to_sampling_params(
+3 -24
View File
@@ -17,10 +17,8 @@ from starlette.background import BackgroundTask, BackgroundTasks
from vllm import envs
from vllm.engine.arg_utils import EngineArgs
from vllm.inputs import EmbedsPrompt, TokensPrompt
from vllm.logger import current_formatter_type, init_logger
from vllm.platforms import current_platform
from vllm.utils import length_from_prompt_token_ids_or_embeds
from vllm.utils.argparse_utils import FlexibleArgumentParser
if TYPE_CHECKING:
@@ -34,15 +32,11 @@ if TYPE_CHECKING:
StreamOptions,
)
from vllm.entrypoints.openai.models.protocol import LoRAModulePath
from vllm.entrypoints.openai.responses.protocol import (
ResponsesRequest,
)
else:
ChatCompletionRequest = object
CompletionRequest = object
StreamOptions = object
LoRAModulePath = object
ResponsesRequest = object
logger = init_logger(__name__)
@@ -217,26 +211,11 @@ def _validate_truncation_size(
def get_max_tokens(
max_model_len: int,
request: "CompletionRequest | ChatCompletionRequest | ResponsesRequest",
prompt: TokensPrompt | EmbedsPrompt,
request: "ChatCompletionRequest | CompletionRequest",
input_length: int,
default_sampling_params: dict,
) -> int:
# NOTE: Avoid isinstance() for better efficiency
max_tokens: int | None = None
if max_tokens is None:
# ChatCompletionRequest
max_tokens = getattr(request, "max_completion_tokens", None)
if max_tokens is None:
# ResponsesRequest
max_tokens = getattr(request, "max_output_tokens", None)
if max_tokens is None:
# CompletionRequest (also a fallback for ChatCompletionRequest)
max_tokens = getattr(request, "max_tokens", None)
input_length = length_from_prompt_token_ids_or_embeds(
prompt.get("prompt_token_ids"), # type: ignore[arg-type]
prompt.get("prompt_embeds"), # type: ignore[arg-type]
)
max_tokens = getattr(request, "max_completion_tokens", None) or request.max_tokens
default_max_tokens = max_model_len - input_length
max_output_tokens = current_platform.get_max_output_tokens(input_length)
+3
View File
@@ -74,6 +74,9 @@ class StructuredOutputManager:
self.tokenizer = cached_tokenizer_from_config(
model_config=self.vllm_config.model_config
)
reasoning_parser = (
self.vllm_config.structured_outputs_config.reasoning_parser
)
reasoning_parser_plugin = (
self.vllm_config.structured_outputs_config.reasoning_parser_plugin
)