forked from Karylab-cklius/vllm
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e766ef514 |
@@ -942,10 +942,9 @@ static void launchFullCacheKernel(
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// Torch op wrapper
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
void fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert_out(
|
||||
torch::stable::Tensor fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert(
|
||||
torch::stable::Tensor const& q_in, // [N, num_heads_q, 512] bf16
|
||||
torch::stable::Tensor const& kv, // [N, 512] bf16 (read-only)
|
||||
torch::stable::Tensor& q_out, // [N, q_head_padded, 512]
|
||||
torch::stable::Tensor& k_cache, // [num_blocks, block_bytes] uint8
|
||||
torch::stable::Tensor const& slot_mapping, // [N] int64
|
||||
torch::stable::Tensor const& position_ids, // [N] int64
|
||||
@@ -971,16 +970,8 @@ void fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert_out(
|
||||
STD_TORCH_CHECK(kv.dim() == 2 && kv.size(1) == 512, "kv shape [N, 512]");
|
||||
STD_TORCH_CHECK(q_in.scalar_type() == kv.scalar_type(),
|
||||
"q_in and kv dtype must match");
|
||||
STD_TORCH_CHECK(q_out.device() == q_in.device() && q_out.is_contiguous(),
|
||||
"q_out must be contiguous and on the same device as q_in");
|
||||
STD_TORCH_CHECK(q_out.scalar_type() == q_in.scalar_type(),
|
||||
"q_out dtype must match q_in");
|
||||
STD_TORCH_CHECK(q_head_padded >= q_in.size(1),
|
||||
"q_head_padded must be >= q_in.size(1) (num_heads_q)");
|
||||
STD_TORCH_CHECK(q_out.dim() == 3 && q_out.size(0) == q_in.size(0) &&
|
||||
q_out.size(1) == q_head_padded &&
|
||||
q_out.size(2) == q_in.size(2),
|
||||
"q_out shape [N, q_head_padded, 512]");
|
||||
STD_TORCH_CHECK(k_cache.scalar_type() == torch::headeronly::ScalarType::Byte,
|
||||
"k_cache must be uint8");
|
||||
STD_TORCH_CHECK(cos_sin_cache.dim() == 2 && cos_sin_cache.size(1) == 64,
|
||||
@@ -1008,6 +999,11 @@ void fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert_out(
|
||||
q_in.get_device_index());
|
||||
const cudaStream_t stream = get_current_cuda_stream(q_in.get_device_index());
|
||||
|
||||
// Allocate the padded q output. The kernel writes every element (live
|
||||
// region gets RMSNorm+RoPE; pad region gets zeros), so `empty` is safe.
|
||||
auto q_out = torch::stable::new_empty(
|
||||
q_in, {q_in.size(0), q_head_padded, q_in.size(2)}, q_in.scalar_type());
|
||||
|
||||
VLLM_STABLE_DISPATCH_HALF_TYPES(
|
||||
q_in.scalar_type(), "fused_deepseek_v4_qnorm_rope_kv_insert", [&] {
|
||||
using qkv_scalar_t = scalar_t;
|
||||
@@ -1024,20 +1020,6 @@ void fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert_out(
|
||||
num_heads_q_padded, cache_block_size_i, kv_block_stride,
|
||||
stream);
|
||||
});
|
||||
}
|
||||
|
||||
torch::stable::Tensor fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert(
|
||||
torch::stable::Tensor const& q_in, torch::stable::Tensor const& kv,
|
||||
torch::stable::Tensor& k_cache,
|
||||
torch::stable::Tensor const& slot_mapping,
|
||||
torch::stable::Tensor const& position_ids,
|
||||
torch::stable::Tensor const& cos_sin_cache, int64_t q_head_padded,
|
||||
double eps, int64_t cache_block_size) {
|
||||
auto q_out = torch::stable::new_empty(
|
||||
q_in, {q_in.size(0), q_head_padded, q_in.size(2)}, q_in.scalar_type());
|
||||
fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert_out(
|
||||
q_in, kv, q_out, k_cache, slot_mapping, position_ids, cos_sin_cache,
|
||||
q_head_padded, eps, cache_block_size);
|
||||
return q_out;
|
||||
}
|
||||
|
||||
|
||||
@@ -269,14 +269,6 @@ torch::stable::Tensor fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert(
|
||||
torch::stable::Tensor const& cos_sin_cache, int64_t q_head_padded,
|
||||
double eps, int64_t cache_block_size);
|
||||
|
||||
void fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert_out(
|
||||
torch::stable::Tensor const& q_in, torch::stable::Tensor const& kv,
|
||||
torch::stable::Tensor& q_out, torch::stable::Tensor& k_cache,
|
||||
torch::stable::Tensor const& slot_mapping,
|
||||
torch::stable::Tensor const& position_ids,
|
||||
torch::stable::Tensor const& cos_sin_cache, int64_t q_head_padded,
|
||||
double eps, int64_t cache_block_size);
|
||||
|
||||
void fused_deepseek_v4_qnorm_rope_kv_rope_full_cache_bf16_insert(
|
||||
torch::stable::Tensor& q, torch::stable::Tensor const& kv,
|
||||
torch::stable::Tensor& k_cache, torch::stable::Tensor const& slot_mapping,
|
||||
|
||||
@@ -433,11 +433,6 @@ STABLE_TORCH_LIBRARY_FRAGMENT(_C, ops) {
|
||||
"Tensor q_in, Tensor kv, Tensor! k_cache, "
|
||||
"Tensor slot_mapping, Tensor position_ids, Tensor cos_sin_cache, "
|
||||
"int q_head_padded, float eps, int cache_block_size) -> Tensor");
|
||||
ops.def(
|
||||
"fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert_out("
|
||||
"Tensor q_in, Tensor kv, Tensor! q_out, Tensor! k_cache, "
|
||||
"Tensor slot_mapping, Tensor position_ids, Tensor cos_sin_cache, "
|
||||
"int q_head_padded, float eps, int cache_block_size) -> ()");
|
||||
|
||||
// FlashInfer V4 full-cache variants: write Q in place (bf16) or to a separate
|
||||
// FP8 tensor, and KV into a contiguous 512-wide token-strided cache.
|
||||
@@ -756,8 +751,6 @@ STABLE_TORCH_LIBRARY_IMPL(_C, CUDA, ops) {
|
||||
ops.impl("fused_qk_norm_rope", TORCH_BOX(&fused_qk_norm_rope));
|
||||
ops.impl("fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert",
|
||||
TORCH_BOX(&fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert));
|
||||
ops.impl("fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert_out",
|
||||
TORCH_BOX(&fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert_out));
|
||||
ops.impl(
|
||||
"fused_deepseek_v4_qnorm_rope_kv_rope_full_cache_bf16_insert",
|
||||
TORCH_BOX(&fused_deepseek_v4_qnorm_rope_kv_rope_full_cache_bf16_insert));
|
||||
|
||||
@@ -20,7 +20,6 @@ import torch
|
||||
|
||||
from vllm import _custom_ops as ops
|
||||
from vllm.models.deepseek_v4.common.ops import (
|
||||
compute_global_topk_indices_and_lens,
|
||||
dequantize_and_gather_k_cache,
|
||||
quantize_and_insert_k_cache,
|
||||
)
|
||||
@@ -35,23 +34,6 @@ from vllm.platforms import current_platform
|
||||
from .test_fused_indexer_q_rope_quant import quantize_to_mxfp4
|
||||
|
||||
|
||||
def test_compute_global_topk_reuses_output_buffers():
|
||||
device = "cuda"
|
||||
topk_indices = torch.tensor(
|
||||
[[0, 3, -1], [1, 2, -1]], dtype=torch.int32, device=device
|
||||
)
|
||||
token_to_req = torch.tensor([0, 1], dtype=torch.int32, device=device)
|
||||
block_table = torch.tensor([[5, 7], [11, 13]], dtype=torch.int32, device=device)
|
||||
is_valid = torch.tensor([True, False], device=device)
|
||||
args = (topk_indices, token_to_req, block_table, 2, is_valid)
|
||||
expected = compute_global_topk_indices_and_lens(*args)
|
||||
outputs = tuple(torch.empty_like(tensor) for tensor in expected)
|
||||
actual = compute_global_topk_indices_and_lens(*args, output_buffers=outputs)
|
||||
for result, output, reference in zip(actual, outputs, expected):
|
||||
assert result.data_ptr() == output.data_ptr()
|
||||
torch.testing.assert_close(result, reference)
|
||||
|
||||
|
||||
def _ue8m0_reference(x: torch.Tensor, block_size: int, fp8_max: float):
|
||||
"""PyTorch reference for UE8M0 FP8 quantization (per-block, power-of-2 scale).
|
||||
|
||||
|
||||
@@ -257,18 +257,8 @@ def test_q_path_matches_reference(num_tokens: int, n_heads: int, padded_heads: i
|
||||
num_blocks, bs, HEAD_BYTES, dtype=torch.uint8, device=device
|
||||
).view(num_blocks, -1)
|
||||
slot_mapping = torch.full((num_tokens,), -1, dtype=torch.int64, device=device)
|
||||
q_out = torch.empty(num_tokens, padded_heads, HEAD_DIM, dtype=dtype, device=device)
|
||||
torch.ops._C.fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert_out(
|
||||
q,
|
||||
kv,
|
||||
q_out,
|
||||
k_cache,
|
||||
slot_mapping,
|
||||
positions,
|
||||
cos_sin_cache,
|
||||
padded_heads,
|
||||
eps,
|
||||
bs,
|
||||
q_out = _call_fused(
|
||||
q, padded_heads, kv, k_cache, slot_mapping, positions, cos_sin_cache, eps, bs
|
||||
)
|
||||
|
||||
torch.testing.assert_close(q_out[:, :n_heads], q_ref, rtol=1e-2, atol=1e-2)
|
||||
|
||||
@@ -150,23 +150,6 @@ def test_fused_indexer_q_rope_quant_matches_unfused(
|
||||
q_quant_ref, weights_ref = _reference(
|
||||
positions, q, cos_sin_cache, weights, softmax_scale, head_scale, use_fp4
|
||||
)
|
||||
output_buffers: tuple[torch.Tensor, ...] | None = None
|
||||
OUTPUT_BUFFER_TEST_NUM_TOKENS = 7
|
||||
if num_tokens == OUTPUT_BUFFER_TEST_NUM_TOKENS and cache_dtype == torch.float32:
|
||||
if use_fp4:
|
||||
q_ref, q_scale_ref = q_quant_ref
|
||||
output_buffers = (
|
||||
torch.empty_like(q_ref),
|
||||
torch.empty_like(q_scale_ref)
|
||||
.view(torch.uint8)
|
||||
.reshape(num_tokens, N_HEAD, -1),
|
||||
torch.empty_like(weights_ref),
|
||||
)
|
||||
else:
|
||||
output_buffers = (
|
||||
torch.empty_like(q_quant_ref),
|
||||
torch.empty_like(weights_ref),
|
||||
)
|
||||
# use_cutedsl=False: force the triton path even when cutedsl is installed
|
||||
# by patching the dispatcher's has_cutedsl() binding to return False.
|
||||
cutedsl_patch = (
|
||||
@@ -186,17 +169,8 @@ def test_fused_indexer_q_rope_quant_matches_unfused(
|
||||
softmax_scale,
|
||||
head_scale,
|
||||
use_fp4,
|
||||
output_buffers=output_buffers,
|
||||
)
|
||||
|
||||
if output_buffers is not None:
|
||||
if use_fp4:
|
||||
assert q_quant_fused[0].data_ptr() == output_buffers[0].data_ptr()
|
||||
assert q_quant_fused[1].data_ptr() == output_buffers[1].data_ptr()
|
||||
else:
|
||||
assert q_quant_fused.data_ptr() == output_buffers[0].data_ptr()
|
||||
assert weights_fused.data_ptr() == output_buffers[-1].data_ptr()
|
||||
|
||||
if use_fp4:
|
||||
q_quant_ref, q_scale_ref = q_quant_ref
|
||||
q_quant_fused, q_scale_fused = q_quant_fused
|
||||
|
||||
@@ -14,10 +14,6 @@ def is_func(node: fx.Node, target: Target) -> bool:
|
||||
return bool(node.op == "call_function" and node.target == target)
|
||||
|
||||
|
||||
def is_auto_func(node: fx.Node, op: OpOverload) -> bool:
|
||||
return is_func(node, auto_functionalized) and node.args[0] == op
|
||||
|
||||
|
||||
# Returns the first auto_functionalized node with the given op (if it exists)
|
||||
def find_auto_fn_maybe(nodes: Iterable[fx.Node], op: OpOverload) -> fx.Node | None:
|
||||
for node in nodes:
|
||||
@@ -42,13 +38,6 @@ def find_getitem_maybe(node: fx.Node, idx: int) -> fx.Node | None:
|
||||
return None
|
||||
|
||||
|
||||
# Returns the getitem node that extracts the idx-th element from node
|
||||
def find_getitem(node: fx.Node, idx: int) -> fx.Node:
|
||||
ret = find_getitem_maybe(node, idx)
|
||||
assert ret is not None, f"Could not find getitem {idx} in node {node}"
|
||||
return ret
|
||||
|
||||
|
||||
# An auto-functionalization-aware utility for finding nodes with a specific op
|
||||
# Also handles op overload packets and finds all overloads
|
||||
def find_op_nodes(
|
||||
@@ -67,11 +56,3 @@ def find_op_nodes(
|
||||
for n in graph.find_nodes(op="call_function", target=auto_functionalized):
|
||||
if n.args[0] == op:
|
||||
yield n
|
||||
|
||||
|
||||
# Asserts that the node only has one user and returns it
|
||||
# Even if a node has only 1 user, it might share storage with another node,
|
||||
# which might need to be taken into account.
|
||||
def get_only_user(node: fx.Node) -> fx.Node:
|
||||
assert len(node.users) == 1
|
||||
return next(iter(node.users))
|
||||
|
||||
@@ -333,12 +333,3 @@ class VllmFusionPatternMatcherPass(VllmPatternMatcherPass):
|
||||
def __call__(self, graph: torch.fx.Graph) -> None:
|
||||
self.matched_count = self.pm_pass.apply(graph)
|
||||
VllmPatternMatcherPass.match_table[self.pass_name] += self.matched_count
|
||||
|
||||
|
||||
class PrinterInductorPass(VllmInductorPass):
|
||||
def __init__(self, name: str, config: VllmConfig) -> None:
|
||||
super().__init__(config)
|
||||
self.name = name
|
||||
|
||||
def __call__(self, graph: torch.fx.Graph) -> None:
|
||||
self.dump_graph(graph, self.name)
|
||||
|
||||
@@ -415,31 +415,6 @@ class Range:
|
||||
return self.__str__()
|
||||
|
||||
|
||||
def handle_deprecated(
|
||||
config: ConfigT,
|
||||
old_name: str,
|
||||
new_name_or_names: str | list[str],
|
||||
removal_version: str,
|
||||
) -> None:
|
||||
old_val = getattr(config, old_name)
|
||||
if old_val is None:
|
||||
return
|
||||
|
||||
if isinstance(new_name_or_names, str):
|
||||
new_names = [new_name_or_names]
|
||||
else:
|
||||
new_names = new_name_or_names
|
||||
|
||||
msg = (
|
||||
f"{old_name} is deprecated and will be removed in {removal_version}. "
|
||||
f"Use {', '.join(new_names)} instead."
|
||||
)
|
||||
logger.warning(msg)
|
||||
|
||||
for new_name in new_names:
|
||||
setattr(config, new_name, old_val)
|
||||
|
||||
|
||||
def get_from_deprecated_env_if_set(
|
||||
env_name: str,
|
||||
removal_version: str,
|
||||
|
||||
@@ -2081,9 +2081,6 @@ def model_parallel_is_initialized():
|
||||
return _TP is not None and _PP is not None
|
||||
|
||||
|
||||
_TP_STATE_PATCHED = False
|
||||
|
||||
|
||||
def get_tensor_model_parallel_world_size() -> int:
|
||||
"""Return world size for the tensor model parallel group."""
|
||||
return get_tp_group().world_size
|
||||
|
||||
@@ -2015,15 +2015,6 @@ async def parse_chat_messages_async(
|
||||
return conversation, mm_data, mm_uuids
|
||||
|
||||
|
||||
def get_history_tool_calls_cnt(conversation: list[ConversationMessage]):
|
||||
idx = 0
|
||||
for msg in conversation:
|
||||
if msg["role"] == "assistant":
|
||||
tool_calls = msg.get("tool_calls")
|
||||
idx += len(list(tool_calls)) if tool_calls is not None else 0 # noqa
|
||||
return idx
|
||||
|
||||
|
||||
_KIMI_MODEL_TYPES = ("kimi_k2", "kimi_k25", "kimi_k3")
|
||||
|
||||
|
||||
|
||||
@@ -8,14 +8,8 @@ import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
|
||||
from vllm.distributed import (
|
||||
divide,
|
||||
get_tensor_model_parallel_rank,
|
||||
get_tensor_model_parallel_world_size,
|
||||
)
|
||||
from vllm.logger import init_logger
|
||||
from vllm.model_executor.custom_op import CustomOp
|
||||
from vllm.model_executor.utils import set_weight_attrs
|
||||
from vllm.platforms import CpuArchEnum, current_platform
|
||||
from vllm.triton_utils import tl, triton
|
||||
from vllm.utils.collection_utils import LazyDict
|
||||
@@ -788,48 +782,6 @@ class XIELU(CustomOp):
|
||||
return self.forward_native(input)
|
||||
|
||||
|
||||
class ScaledActivation(nn.Module):
|
||||
"""An activation function with post-scale parameters.
|
||||
|
||||
This is used for some quantization methods like AWQ.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
act_module: nn.Module,
|
||||
intermediate_size: int,
|
||||
input_is_parallel: bool = True,
|
||||
params_dtype: torch.dtype | None = None,
|
||||
):
|
||||
super().__init__()
|
||||
self.act = act_module
|
||||
self.input_is_parallel = input_is_parallel
|
||||
if input_is_parallel:
|
||||
tp_size = get_tensor_model_parallel_world_size()
|
||||
intermediate_size_per_partition = divide(intermediate_size, tp_size)
|
||||
else:
|
||||
intermediate_size_per_partition = intermediate_size
|
||||
if params_dtype is None:
|
||||
params_dtype = torch.get_default_dtype()
|
||||
self.scales = nn.Parameter(
|
||||
torch.empty(intermediate_size_per_partition, dtype=params_dtype)
|
||||
)
|
||||
set_weight_attrs(self.scales, {"weight_loader": self.weight_loader})
|
||||
|
||||
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
||||
return self.act(x) / self.scales
|
||||
|
||||
def weight_loader(self, param: nn.Parameter, loaded_weight: torch.Tensor):
|
||||
param_data = param.data
|
||||
if self.input_is_parallel:
|
||||
tp_rank = get_tensor_model_parallel_rank()
|
||||
shard_size = param_data.shape[0]
|
||||
start_idx = tp_rank * shard_size
|
||||
loaded_weight = loaded_weight.narrow(0, start_idx, shard_size)
|
||||
assert param_data.shape == loaded_weight.shape
|
||||
param_data.copy_(loaded_weight)
|
||||
|
||||
|
||||
_ACTIVATION_REGISTRY = LazyDict(
|
||||
{
|
||||
"gelu": lambda: GELU(),
|
||||
|
||||
@@ -155,58 +155,6 @@ class Conv2dLayer(ConvLayerBase):
|
||||
return self._forward_conv(x)
|
||||
|
||||
|
||||
class CausalConv2dLayer(Conv2dLayer):
|
||||
"""
|
||||
A causal version of nn.Conv2d where each location in the 2D matrix would
|
||||
have no access to locations on its right or down
|
||||
All arguments are the same as nn.Conv2d except padding which should be
|
||||
set as None
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
in_channels: int,
|
||||
out_channels: int,
|
||||
kernel_size: int,
|
||||
stride: int,
|
||||
padding: int = 0,
|
||||
dilation: int = 1,
|
||||
groups: int = 1,
|
||||
bias: bool = True,
|
||||
padding_mode: str = "zeros",
|
||||
*,
|
||||
params_dtype: torch.dtype | None = None,
|
||||
) -> None:
|
||||
if padding is not None:
|
||||
raise ValueError(
|
||||
"Argument padding should be set to None for CausalConv2dLayer."
|
||||
)
|
||||
self._left_padding: int = kernel_size - 1
|
||||
self._right_padding: int = stride - 1
|
||||
padding = 0
|
||||
|
||||
super().__init__(
|
||||
in_channels,
|
||||
out_channels,
|
||||
kernel_size,
|
||||
stride,
|
||||
padding,
|
||||
dilation,
|
||||
groups,
|
||||
bias,
|
||||
padding_mode,
|
||||
params_dtype=params_dtype,
|
||||
)
|
||||
|
||||
def forward(
|
||||
self,
|
||||
x: torch.Tensor,
|
||||
) -> torch.Tensor:
|
||||
x = F.pad(x, pad=(self._left_padding, self._right_padding, 0, 0))
|
||||
x = super().forward(x)
|
||||
return x
|
||||
|
||||
|
||||
# --8<-- [start:conv3d]
|
||||
@CustomOp.register("conv3d")
|
||||
class Conv3dLayer(ConvLayerBase):
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
import torch
|
||||
from torch.utils._python_dispatch import TorchDispatchMode
|
||||
|
||||
import vllm.envs as envs
|
||||
import vllm.model_executor.layers.fused_moe.modular_kernel as mk
|
||||
@@ -234,26 +233,6 @@ class Fp8Config(QuantizationConfig):
|
||||
return cache_scale_mapper | QuantizationConfig.get_cache_scale_mapper()
|
||||
|
||||
|
||||
class CopyNumelCounter(TorchDispatchMode):
|
||||
"""
|
||||
Tracks total number of elements modified with `copy_`. Useful for keeping
|
||||
track of weight loading where underlying weights can be arbitrarily
|
||||
transformed (such as with `narrow`) before calling copy.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.copied_numel = 0
|
||||
|
||||
def __torch_dispatch__(self, func, types, args=(), kwargs=None):
|
||||
if kwargs is None:
|
||||
kwargs = {}
|
||||
out = func(*args, **kwargs)
|
||||
if func == torch.ops.aten.copy_.default:
|
||||
self.copied_numel += args[0].numel()
|
||||
return out
|
||||
|
||||
|
||||
class Fp8LinearMethod(LinearMethodBase):
|
||||
"""Linear method for FP8.
|
||||
Supports loading FP8 checkpoints with static weight scale and
|
||||
|
||||
@@ -25,12 +25,6 @@ MOE_LAYER_ROUTER_GATE_SUFFIXES = {
|
||||
}
|
||||
|
||||
|
||||
def is_layer_moe_router_gate(prefix: str) -> bool:
|
||||
if not prefix:
|
||||
return False
|
||||
return prefix.rsplit(".", 1)[-1] in MOE_LAYER_ROUTER_GATE_SUFFIXES
|
||||
|
||||
|
||||
def get_token_bin_counts_and_mask(
|
||||
tokens: torch.Tensor,
|
||||
vocab_size: int,
|
||||
|
||||
@@ -242,10 +242,6 @@ class GlmOcrVisionBlock(Glm4vVisionBlock):
|
||||
)
|
||||
|
||||
|
||||
class GlmOcrVisionPatchEmbed(Glm4vVisionPatchEmbed):
|
||||
pass
|
||||
|
||||
|
||||
class GlmOcrPatchMerger(Glm4vPatchMerger):
|
||||
pass
|
||||
|
||||
|
||||
@@ -103,41 +103,6 @@ class Idefics3ProcessingInfo(BaseProcessingInfo):
|
||||
def get_supported_mm_limits(self) -> Mapping[str, int | None]:
|
||||
return {"image": None}
|
||||
|
||||
def _resize_output_size(
|
||||
self,
|
||||
*,
|
||||
height: int,
|
||||
width: int,
|
||||
max_len: int | None = None,
|
||||
min_len: int = 1,
|
||||
max_size: int | None = None,
|
||||
) -> tuple[int, int]:
|
||||
# Set default value for max_len if not provided
|
||||
max_len = max(height, width) if max_len is None else max_len
|
||||
aspect_ratio = width / height
|
||||
|
||||
# Handle the maximum size constraint
|
||||
if max_size is not None:
|
||||
max_len = min(max_len, max_size)
|
||||
|
||||
# Adjust dimensions according to the aspect ratio
|
||||
if width >= height:
|
||||
width = max_len
|
||||
height = int(width / aspect_ratio)
|
||||
else:
|
||||
height = max_len
|
||||
width = int(height * aspect_ratio)
|
||||
|
||||
# Ensure both width and height are even (if needed)
|
||||
height += height % 2
|
||||
width += width % 2
|
||||
|
||||
# Ensure dimensions are not smaller than the minimum length
|
||||
height = max(height, min_len)
|
||||
width = max(width, min_len)
|
||||
|
||||
return height, width
|
||||
|
||||
def _get_image_feature_grid_size(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -1531,13 +1531,6 @@ class LlavaOnevision2MultiModalDataParser(MultiModalDataParser):
|
||||
class LlavaOnevision2MultiModalProcessor(
|
||||
BaseMultiModalProcessor[LlavaOnevision2ProcessingInfo]
|
||||
):
|
||||
def _get_data_parser(self) -> MultiModalDataParser:
|
||||
# Retained for symmetry; vLLM actually fetches the parser via
|
||||
# info.get_data_parser() (see ProcessingInfo override above).
|
||||
return LlavaOnevision2MultiModalDataParser(
|
||||
self.info.get_hf_config().vision_config.spatial_merge_size
|
||||
)
|
||||
|
||||
def _call_hf_processor(
|
||||
self,
|
||||
prompt: str,
|
||||
|
||||
@@ -77,24 +77,6 @@ class BartScaledWordEmbedding(VocabParallelEmbedding):
|
||||
return super().forward(input_ids) * self.embed_scale
|
||||
|
||||
|
||||
class BartParallelLMHead(ParallelLMHead):
|
||||
"""
|
||||
This module overrides ParallelLMHead's
|
||||
forward by dividing by embeddings scale,
|
||||
yielding effectively the inverse of
|
||||
BartScaledWordEmbedding
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, num_embeddings: int, embedding_dim: int, embed_scale: float = 1.0
|
||||
):
|
||||
super().__init__(num_embeddings, embedding_dim)
|
||||
self.embed_scale = embed_scale
|
||||
|
||||
def forward(self, input_ids: torch.Tensor) -> torch.Tensor:
|
||||
return super().forward(input_ids) / self.embed_scale
|
||||
|
||||
|
||||
class BartDecoderLayer(nn.Module):
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -521,32 +521,6 @@ class Phi4MMAudioEmbeddingInputs(TensorSchema):
|
||||
Phi4MMAudioInputs: TypeAlias = Phi4MMAudioFeatureInputs | Phi4MMAudioEmbeddingInputs
|
||||
|
||||
|
||||
def cat_with_pad(tensors, dim, padding_value=0):
|
||||
"""
|
||||
cat along dim, while pad to max for all other dims
|
||||
"""
|
||||
ndim = tensors[0].dim()
|
||||
assert all(t.dim() == ndim for t in tensors[1:]), (
|
||||
"All tensors must have the same number of dimensions"
|
||||
)
|
||||
|
||||
out_size = [max(t.shape[i] for t in tensors) for i in range(ndim)]
|
||||
out_size[dim] = sum(t.shape[dim] for t in tensors)
|
||||
output = tensors[0].new_full(out_size, padding_value)
|
||||
|
||||
index = 0
|
||||
for t in tensors:
|
||||
# Create a slice list where every dimension except dim is full slice
|
||||
slices = [slice(0, t.shape[d]) for d in range(ndim)]
|
||||
# Update only the concat dimension slice
|
||||
slices[dim] = slice(index, index + t.shape[dim])
|
||||
|
||||
output[slices] = t
|
||||
index += t.shape[dim]
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def stack_with_pad(
|
||||
tensors: torch.Tensor | list[torch.Tensor],
|
||||
padding_value: int | float = 0,
|
||||
|
||||
@@ -1595,14 +1595,6 @@ class AttModule(nn.Module):
|
||||
return x, memory, pos_emb, att_mask
|
||||
|
||||
|
||||
class AttBlock(BlockBase, AttModule):
|
||||
"""Attention Block module to support both Attention and Block module."""
|
||||
|
||||
def memory_dims(self, max_len: bool = False) -> tuple[int, int]:
|
||||
"""memory dimensions"""
|
||||
return (1, self.input_size)
|
||||
|
||||
|
||||
def masked_softmax(
|
||||
scores: Tensor,
|
||||
mask: Tensor | None,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# Copyright (c) 2025 Skywork
|
||||
# Licensed under The MIT License [see LICENSE for details]
|
||||
# --------------------------------------------------------
|
||||
from collections.abc import Iterable, Mapping
|
||||
from collections.abc import Iterable
|
||||
from typing import Annotated, Literal, TypeAlias
|
||||
|
||||
import torch
|
||||
@@ -15,8 +15,6 @@ import torch.nn as nn
|
||||
from transformers import PretrainedConfig
|
||||
|
||||
from vllm.config import VllmConfig
|
||||
from vllm.config.multimodal import BaseDummyOptions
|
||||
from vllm.inputs import MultiModalDataDict
|
||||
from vllm.model_executor.layers.linear import ReplicatedLinear
|
||||
from vllm.model_executor.layers.quantization import QuantizationConfig
|
||||
from vllm.model_executor.layers.quantization.auto_awq import AutoAWQConfig
|
||||
@@ -24,7 +22,6 @@ from vllm.model_executor.models.intern_vit import (
|
||||
InternVisionModel,
|
||||
)
|
||||
from vllm.multimodal import MULTIMODAL_REGISTRY
|
||||
from vllm.multimodal.processing import BaseDummyInputsBuilder
|
||||
from vllm.sequence import IntermediateTensors
|
||||
from vllm.transformers_utils.processors.internvl import (
|
||||
InternVLImageProcessor,
|
||||
@@ -117,33 +114,6 @@ class SkyworkR1VProcessingInfo(BaseInternVLProcessingInfo):
|
||||
)
|
||||
|
||||
|
||||
class SkyworkR1VDummyInputsBuilder(BaseDummyInputsBuilder[SkyworkR1VProcessingInfo]):
|
||||
def get_dummy_text(self, mm_counts: Mapping[str, int]) -> str:
|
||||
num_images = mm_counts.get("image", 0)
|
||||
|
||||
return "<image>" * num_images
|
||||
|
||||
def get_dummy_mm_data(
|
||||
self,
|
||||
seq_len: int,
|
||||
mm_counts: Mapping[str, int],
|
||||
mm_options: Mapping[str, BaseDummyOptions],
|
||||
) -> MultiModalDataDict:
|
||||
target_width, target_height = self.info.get_image_size_with_most_features()
|
||||
num_images = mm_counts.get("image", 0)
|
||||
|
||||
image_overrides = mm_options.get("image")
|
||||
|
||||
return {
|
||||
"image": self._get_dummy_images(
|
||||
width=target_width,
|
||||
height=target_height,
|
||||
num_images=num_images,
|
||||
overrides=image_overrides,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@MULTIMODAL_REGISTRY.register_processor(
|
||||
BaseInternVLMultiModalProcessor,
|
||||
info=SkyworkR1VProcessingInfo,
|
||||
|
||||
@@ -27,7 +27,6 @@ from vllm.multimodal import NestedTensors
|
||||
from vllm.sequence import IntermediateTensors
|
||||
from vllm.utils.math_utils import cdiv
|
||||
from vllm.utils.torch_utils import (
|
||||
async_tensor_h2d,
|
||||
direct_register_custom_op,
|
||||
)
|
||||
|
||||
@@ -673,17 +672,6 @@ def _merge_multimodal_embeddings(
|
||||
return inputs_embeds
|
||||
|
||||
|
||||
def isin_list(
|
||||
elements: torch.Tensor,
|
||||
test_elements_list: list[int],
|
||||
) -> torch.Tensor:
|
||||
test_elements = async_tensor_h2d(
|
||||
test_elements_list, dtype=torch.int64, device=elements.device
|
||||
)
|
||||
|
||||
return torch.isin(elements, test_elements)
|
||||
|
||||
|
||||
class StageMissingLayer(nn.Module):
|
||||
def __init__(self, stage_name: str, module: nn.Module | None = None) -> None:
|
||||
super().__init__()
|
||||
|
||||
@@ -580,40 +580,3 @@ def run_dp_sharded_mrope_vision_model(
|
||||
"Found unassigned embeddings"
|
||||
)
|
||||
return out_embeddings
|
||||
|
||||
|
||||
def get_llm_pos_ids_for_vision(
|
||||
start_idx: int,
|
||||
vision_idx: int,
|
||||
spatial_merge_size: int,
|
||||
t_index: list[int],
|
||||
grid_hs: torch.Tensor,
|
||||
grid_ws: torch.Tensor,
|
||||
) -> torch.Tensor:
|
||||
llm_pos_ids_list = []
|
||||
llm_grid_h = grid_hs[vision_idx] // spatial_merge_size
|
||||
llm_grid_w = grid_ws[vision_idx] // spatial_merge_size
|
||||
h_index = (
|
||||
torch.arange(llm_grid_h)
|
||||
.view(1, -1, 1)
|
||||
.expand(len(t_index), -1, llm_grid_w)
|
||||
.flatten()
|
||||
)
|
||||
w_index = (
|
||||
torch.arange(llm_grid_w)
|
||||
.view(1, 1, -1)
|
||||
.expand(len(t_index), llm_grid_h, -1)
|
||||
.flatten()
|
||||
)
|
||||
t_index_tensor = (
|
||||
torch.Tensor(t_index)
|
||||
.to(llm_grid_h.device)
|
||||
.view(-1, 1)
|
||||
.expand(-1, llm_grid_h * llm_grid_w)
|
||||
.long()
|
||||
.flatten()
|
||||
)
|
||||
_llm_pos_ids = torch.stack([t_index_tensor, h_index, w_index])
|
||||
llm_pos_ids_list.append(_llm_pos_ids + start_idx)
|
||||
llm_pos_ids = torch.cat(llm_pos_ids_list, dim=1)
|
||||
return llm_pos_ids
|
||||
|
||||
@@ -29,7 +29,6 @@ from vllm.models.deepseek_v4.common.ops import (
|
||||
from vllm.models.deepseek_v4.common.ops.fused_indexer_q import MXFP4_BLOCK_SIZE
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from vllm.models.deepseek_v4.eager_scratch import DeepseekV4EagerScratchPool
|
||||
from vllm.v1.attention.backends.mla.sparse_swa import (
|
||||
DeepseekSparseSWAMetadata,
|
||||
)
|
||||
@@ -182,7 +181,6 @@ class DeepseekV4Attention(nn.Module, AttentionLayerBase, ABC):
|
||||
prefix: str,
|
||||
topk_indices_buffer: torch.Tensor | None = None,
|
||||
aux_stream_list: list[torch.cuda.Stream] | None = None,
|
||||
eager_scratch_pool: "DeepseekV4EagerScratchPool | None" = None,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
config = vllm_config.model_config.hf_config
|
||||
@@ -271,7 +269,6 @@ class DeepseekV4Attention(nn.Module, AttentionLayerBase, ABC):
|
||||
)
|
||||
self.indexer_rotary_emb = self.rotary_emb
|
||||
self.topk_indices_buffer = topk_indices_buffer
|
||||
self.eager_scratch_pool = eager_scratch_pool
|
||||
|
||||
self.indexer = None
|
||||
if self.compress_ratio == 4:
|
||||
@@ -293,7 +290,6 @@ class DeepseekV4Attention(nn.Module, AttentionLayerBase, ABC):
|
||||
compress_ratio=self.compress_ratio,
|
||||
prefix=f"{prefix}.indexer",
|
||||
aux_stream=indexer_aux_stream,
|
||||
eager_scratch_pool=eager_scratch_pool,
|
||||
)
|
||||
|
||||
# Will be None on ROCm for now.
|
||||
@@ -344,7 +340,6 @@ class DeepseekV4Attention(nn.Module, AttentionLayerBase, ABC):
|
||||
rotate=True,
|
||||
prefix=f"{prefix}.compressor",
|
||||
k_cache_prefix=self.prefix,
|
||||
eager_scratch_pool=eager_scratch_pool,
|
||||
)
|
||||
|
||||
def forward(
|
||||
@@ -573,24 +568,10 @@ class DeepseekV4Attention(nn.Module, AttentionLayerBase, ABC):
|
||||
if cache_dtype == torch.uint8:
|
||||
# fp8_ds_mla UE8M0 paged path. Horizontally fused:
|
||||
# Q side: per-head RMSNorm (no weight) + GPT-J RoPE, zero-filling
|
||||
# the padding head slots.
|
||||
# the padding head slots; the kernel allocates and returns
|
||||
# the padded q tensor.
|
||||
# KV side: GPT-J RoPE + UE8M0 FP8 quant + paged cache insert.
|
||||
swa_kv_cache_2d = swa_kv_cache.view(swa_kv_cache.shape[0], -1)
|
||||
if self.eager_scratch_pool is not None:
|
||||
q_out = self.eager_scratch_pool.q_out(q.shape[0])
|
||||
torch.ops._C.fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert_out(
|
||||
q,
|
||||
kv,
|
||||
q_out,
|
||||
swa_kv_cache_2d,
|
||||
swa_metadata.slot_mapping,
|
||||
positions,
|
||||
cos_sin_cache,
|
||||
self.padded_heads,
|
||||
self.eps,
|
||||
swa_metadata.block_size,
|
||||
)
|
||||
return q_out
|
||||
return torch.ops._C.fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert(
|
||||
q,
|
||||
kv,
|
||||
@@ -639,13 +620,6 @@ class DeepseekV4Attention(nn.Module, AttentionLayerBase, ABC):
|
||||
)
|
||||
return q_fp8
|
||||
|
||||
def _global_topk_output_buffers(
|
||||
self, topk_indices: torch.Tensor
|
||||
) -> tuple[torch.Tensor, torch.Tensor] | None:
|
||||
if self.compress_ratio != 4 or self.eager_scratch_pool is None:
|
||||
return None
|
||||
return self.eager_scratch_pool.global_topk_outputs(topk_indices)
|
||||
|
||||
def get_attn_backend(self) -> type[AttentionBackend]:
|
||||
return self.backend_cls
|
||||
|
||||
@@ -725,7 +699,6 @@ class DeepseekV4Indexer(nn.Module):
|
||||
compress_ratio: int = 1,
|
||||
prefix: str = "",
|
||||
aux_stream: torch.cuda.Stream | None = None,
|
||||
eager_scratch_pool: "DeepseekV4EagerScratchPool | None" = None,
|
||||
):
|
||||
super().__init__()
|
||||
self.vllm_config = vllm_config
|
||||
@@ -738,7 +711,6 @@ class DeepseekV4Indexer(nn.Module):
|
||||
self.rope_dim = config.qk_rope_head_dim # 64
|
||||
self.q_lora_rank = q_lora_rank # 1536
|
||||
self.compress_ratio = compress_ratio
|
||||
self.eager_scratch_pool = eager_scratch_pool
|
||||
self.use_fp4_kv = self.vllm_config.attention_config.use_fp4_indexer_cache
|
||||
logger.info_once(
|
||||
"Using %s indexer cache for Lightning Indexer.",
|
||||
@@ -802,7 +774,6 @@ class DeepseekV4Indexer(nn.Module):
|
||||
prefix=f"{prefix}.compressor",
|
||||
k_cache_prefix=self.k_cache.prefix,
|
||||
use_fp4_cache=self.use_fp4_kv,
|
||||
eager_scratch_pool=eager_scratch_pool,
|
||||
)
|
||||
|
||||
self.indexer_op = SparseAttnIndexer(
|
||||
@@ -863,9 +834,6 @@ class DeepseekV4Indexer(nn.Module):
|
||||
# ReplicatedLinear returns (output, bias); bias is None.
|
||||
q, _ = self.wq_b(qr)
|
||||
q = q.view(-1, self.n_head, self.head_dim)
|
||||
outputs = None
|
||||
if self.eager_scratch_pool is not None and self.use_fp4_kv:
|
||||
outputs = self.eager_scratch_pool.indexer_q_outputs(q.shape[0])
|
||||
return fused_indexer_q_rope_quant(
|
||||
positions,
|
||||
q,
|
||||
@@ -874,7 +842,6 @@ class DeepseekV4Indexer(nn.Module):
|
||||
self.softmax_scale,
|
||||
self.n_head**-0.5,
|
||||
use_fp4=self.use_fp4_kv,
|
||||
output_buffers=outputs,
|
||||
)
|
||||
|
||||
# compressor returns None and writes K to the indexer KV cache; the
|
||||
|
||||
@@ -438,7 +438,6 @@ def compute_global_topk_indices_and_lens(
|
||||
block_table: torch.Tensor,
|
||||
block_size: int,
|
||||
is_valid_token: torch.Tensor,
|
||||
output_buffers: tuple[torch.Tensor, torch.Tensor] | None = None,
|
||||
) -> tuple[torch.Tensor, torch.Tensor]:
|
||||
"""Map local topk indices to global KV cache slots and count valid entries.
|
||||
|
||||
@@ -448,15 +447,8 @@ def compute_global_topk_indices_and_lens(
|
||||
3. Masking padding tokens to length 0
|
||||
"""
|
||||
num_tokens = topk_indices.shape[0]
|
||||
if output_buffers is None:
|
||||
global_topk_indices = torch.empty_like(topk_indices)
|
||||
topk_lens = torch.empty(
|
||||
num_tokens, dtype=torch.int32, device=topk_indices.device
|
||||
)
|
||||
else:
|
||||
global_topk_indices, topk_lens = output_buffers
|
||||
assert global_topk_indices.shape == topk_indices.shape
|
||||
assert topk_lens.shape == (num_tokens,)
|
||||
global_topk_indices = torch.empty_like(topk_indices)
|
||||
topk_lens = torch.empty(num_tokens, dtype=torch.int32, device=topk_indices.device)
|
||||
_compute_global_topk_indices_and_lens_kernel[(num_tokens,)](
|
||||
global_topk_indices,
|
||||
global_topk_indices.stride(0),
|
||||
|
||||
@@ -295,7 +295,6 @@ def fused_indexer_q_rope_quant(
|
||||
index_weights_softmax_scale: float,
|
||||
index_weights_head_scale: float,
|
||||
use_fp4: bool = False,
|
||||
output_buffers: tuple[torch.Tensor, ...] | None = None,
|
||||
) -> tuple[
|
||||
torch.Tensor | tuple[torch.Tensor, torch.Tensor],
|
||||
torch.Tensor,
|
||||
@@ -333,13 +332,7 @@ def fused_indexer_q_rope_quant(
|
||||
num_index_q_heads = index_q.shape[1]
|
||||
index_q_head_dim = index_q.shape[2]
|
||||
|
||||
if output_buffers is None:
|
||||
index_weights_out = torch.empty_like(index_weights, dtype=torch.float32)
|
||||
else:
|
||||
expected_num_buffers = 3 if use_fp4 else 2
|
||||
assert len(output_buffers) == expected_num_buffers
|
||||
index_weights_out = output_buffers[-1]
|
||||
assert index_weights_out.shape == index_weights.shape
|
||||
index_weights_out = torch.empty_like(index_weights, dtype=torch.float32)
|
||||
|
||||
if use_fp4:
|
||||
assert index_q_head_dim % MXFP4_BLOCK_SIZE == 0, (
|
||||
@@ -347,23 +340,16 @@ def fused_indexer_q_rope_quant(
|
||||
f"size {MXFP4_BLOCK_SIZE}"
|
||||
)
|
||||
num_scale_blocks = index_q_head_dim // MXFP4_BLOCK_SIZE
|
||||
packed_shape = (num_tokens, num_index_q_heads, index_q_head_dim // 2)
|
||||
scale_shape = (num_tokens, num_index_q_heads, num_scale_blocks)
|
||||
if output_buffers is None:
|
||||
index_q_packed = torch.empty(
|
||||
packed_shape,
|
||||
dtype=torch.uint8,
|
||||
device=index_q.device,
|
||||
)
|
||||
index_q_scale = torch.empty(
|
||||
scale_shape,
|
||||
dtype=torch.uint8,
|
||||
device=index_q.device,
|
||||
)
|
||||
else:
|
||||
index_q_packed, index_q_scale, _ = output_buffers
|
||||
assert index_q_packed.shape == packed_shape
|
||||
assert index_q_scale.shape == scale_shape
|
||||
index_q_packed = torch.empty(
|
||||
(num_tokens, num_index_q_heads, index_q_head_dim // 2),
|
||||
dtype=torch.uint8,
|
||||
device=index_q.device,
|
||||
)
|
||||
index_q_scale = torch.empty(
|
||||
(num_tokens, num_index_q_heads, num_scale_blocks),
|
||||
dtype=torch.uint8,
|
||||
device=index_q.device,
|
||||
)
|
||||
if has_cutedsl():
|
||||
# lazily import, otherwise some tests fail due to CUDA driver init failure.
|
||||
from vllm.models.deepseek_v4.nvidia.ops.fused_indexer_q_cutedsl import (
|
||||
@@ -432,11 +418,7 @@ def fused_indexer_q_rope_quant(
|
||||
fp8_dtype = current_platform.fp8_dtype()
|
||||
use_fnuz = fp8_dtype == torch.float8_e4m3fnuz
|
||||
fp8_max = 224.0 if use_fnuz else 448.0
|
||||
if output_buffers is None:
|
||||
index_q_fp8 = torch.empty_like(index_q, dtype=fp8_dtype)
|
||||
else:
|
||||
index_q_fp8, _ = output_buffers
|
||||
assert index_q_fp8.shape == index_q.shape
|
||||
index_q_fp8 = torch.empty_like(index_q, dtype=fp8_dtype)
|
||||
if has_cutedsl():
|
||||
# lazily import, otherwise some tests fail due to CUDA driver init failure.
|
||||
from vllm.models.deepseek_v4.nvidia.ops.fused_indexer_q_cutedsl import (
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, cast
|
||||
from typing import Any, ClassVar, cast
|
||||
|
||||
import torch
|
||||
from torch import nn
|
||||
@@ -35,9 +35,6 @@ from vllm.v1.kv_cache_interface import (
|
||||
SlidingWindowMLASpec,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from vllm.models.deepseek_v4.eager_scratch import DeepseekV4EagerScratchPool
|
||||
|
||||
|
||||
def _prefer_two_stage_compressor() -> bool:
|
||||
# Platforms that favor the triton variant of two-stage compressor split.
|
||||
@@ -229,7 +226,6 @@ class DeepseekCompressor(nn.Module):
|
||||
prefix: str = "",
|
||||
k_cache_prefix="",
|
||||
use_fp4_cache: bool = False,
|
||||
eager_scratch_pool: "DeepseekV4EagerScratchPool | None" = None,
|
||||
):
|
||||
super().__init__()
|
||||
self.compress_ratio = compress_ratio
|
||||
@@ -239,7 +235,6 @@ class DeepseekCompressor(nn.Module):
|
||||
self.prefix = prefix
|
||||
self.k_cache_prefix = k_cache_prefix
|
||||
self.use_fp4_cache = use_fp4_cache
|
||||
self.eager_scratch_pool = eager_scratch_pool
|
||||
|
||||
config = vllm_config.model_config.hf_config
|
||||
self.rope_head_dim = config.qk_rope_head_dim
|
||||
@@ -433,10 +428,6 @@ class DeepseekCompressor(nn.Module):
|
||||
store_full_fp8=store_full_fp8,
|
||||
fp8_scale=fp8_scale,
|
||||
)
|
||||
if not self.overlap and self.eager_scratch_pool is not None:
|
||||
extra_kwargs["compress_scratch"] = (
|
||||
self.eager_scratch_pool.compressor_scratch(num_actual)
|
||||
)
|
||||
elif self._use_two_stage_fused_compressor:
|
||||
# head=512 cr>=128 (no overlap): two-pass split compressor on the
|
||||
# prefill suffix, single-pass on the decode prefix.
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
|
||||
from math import prod
|
||||
|
||||
import torch
|
||||
|
||||
from vllm.models.deepseek_v4.common.ops.fused_indexer_q import MXFP4_BLOCK_SIZE
|
||||
from vllm.utils.math_utils import round_up
|
||||
|
||||
|
||||
class DeepseekV4EagerScratchPool:
|
||||
"""Model-wide outputs and scratch used inside the attention eager break."""
|
||||
|
||||
_ALIGNMENT = 256
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
max_num_tokens: int,
|
||||
padded_q_heads: int,
|
||||
q_head_dim: int,
|
||||
index_q_heads: int,
|
||||
index_q_head_dim: int,
|
||||
index_topk: int,
|
||||
device: torch.device | str,
|
||||
) -> None:
|
||||
self.max_num_tokens = max_num_tokens
|
||||
self.index_topk = index_topk
|
||||
self._q = torch.empty(
|
||||
(max_num_tokens, padded_q_heads, q_head_dim),
|
||||
dtype=torch.bfloat16,
|
||||
device=device,
|
||||
)
|
||||
|
||||
fp4_specs = (
|
||||
((max_num_tokens, index_q_heads, index_q_head_dim // 2), torch.uint8),
|
||||
(
|
||||
(
|
||||
max_num_tokens,
|
||||
index_q_heads,
|
||||
index_q_head_dim // MXFP4_BLOCK_SIZE,
|
||||
),
|
||||
torch.uint8,
|
||||
),
|
||||
((max_num_tokens, index_q_heads), torch.float32),
|
||||
)
|
||||
global_specs = (
|
||||
((max_num_tokens, index_topk), torch.int32),
|
||||
((max_num_tokens,), torch.int32),
|
||||
)
|
||||
compressor_specs = (((max_num_tokens, q_head_dim), torch.float32),)
|
||||
# FP4 indexer is C4 only, global mapping after FP4 indexer
|
||||
# compressor scratch is C128 only
|
||||
# so here we use max instead of sum
|
||||
aux_bytes = max(
|
||||
self._packed_size(specs)
|
||||
for specs in (fp4_specs, global_specs, compressor_specs)
|
||||
)
|
||||
storage = torch.empty(aux_bytes, dtype=torch.uint8, device=device)
|
||||
|
||||
self._q_outputs: dict[int, torch.Tensor] = {}
|
||||
fp4_values, fp4_scales, fp4_weights = self._views(storage, fp4_specs)
|
||||
self._fp4_template = (fp4_values, fp4_scales, fp4_weights)
|
||||
self._fp4_outputs: dict[
|
||||
int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]
|
||||
] = {}
|
||||
global_indices, global_lens = self._views(storage, global_specs)
|
||||
self._global_template = (global_indices, global_lens)
|
||||
self._global_outputs: dict[int, tuple[torch.Tensor, torch.Tensor]] = {}
|
||||
self._compressor_template = self._views(storage, compressor_specs)[0]
|
||||
self._compressor_outputs: dict[int, torch.Tensor] = {}
|
||||
self._storage = storage
|
||||
|
||||
@classmethod
|
||||
def _packed_size(
|
||||
cls, specs: tuple[tuple[tuple[int, ...], torch.dtype], ...]
|
||||
) -> int:
|
||||
offset = 0
|
||||
for shape, dtype in specs:
|
||||
offset = round_up(offset, cls._ALIGNMENT) + prod(shape) * dtype.itemsize
|
||||
return round_up(offset, cls._ALIGNMENT)
|
||||
|
||||
@classmethod
|
||||
def _views(
|
||||
cls,
|
||||
storage: torch.Tensor,
|
||||
specs: tuple[tuple[tuple[int, ...], torch.dtype], ...],
|
||||
) -> list[torch.Tensor]:
|
||||
offset = 0
|
||||
views = []
|
||||
for shape, dtype in specs:
|
||||
offset = round_up(offset, cls._ALIGNMENT)
|
||||
num_bytes = prod(shape) * dtype.itemsize
|
||||
views.append(storage[offset : offset + num_bytes].view(dtype).view(shape))
|
||||
offset += num_bytes
|
||||
return views
|
||||
|
||||
def q_out(self, num_tokens: int) -> torch.Tensor:
|
||||
output = self._q_outputs.get(num_tokens)
|
||||
if output is None:
|
||||
output = self._q[:num_tokens]
|
||||
self._q_outputs[num_tokens] = output
|
||||
return output
|
||||
|
||||
def compressor_scratch(self, num_tokens: int) -> torch.Tensor:
|
||||
output = self._compressor_outputs.get(num_tokens)
|
||||
if output is None:
|
||||
output = self._compressor_template[:num_tokens]
|
||||
self._compressor_outputs[num_tokens] = output
|
||||
return output
|
||||
|
||||
def indexer_q_outputs(
|
||||
self,
|
||||
num_tokens: int,
|
||||
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
||||
output = self._fp4_outputs.get(num_tokens)
|
||||
if output is None:
|
||||
values, scales, weights = self._fp4_template
|
||||
output = (
|
||||
values[:num_tokens],
|
||||
scales[:num_tokens],
|
||||
weights[:num_tokens],
|
||||
)
|
||||
self._fp4_outputs[num_tokens] = output
|
||||
return output
|
||||
|
||||
def global_topk_outputs(
|
||||
self, topk_indices: torch.Tensor
|
||||
) -> tuple[torch.Tensor, torch.Tensor]:
|
||||
num_tokens, topk = topk_indices.shape
|
||||
assert topk == self.index_topk
|
||||
output = self._global_outputs.get(num_tokens)
|
||||
if output is None:
|
||||
indices, lens = self._global_template
|
||||
output = (indices[:num_tokens], lens[:num_tokens])
|
||||
self._global_outputs[num_tokens] = output
|
||||
return output
|
||||
@@ -748,9 +748,6 @@ class DeepseekV4FlashInferSM120Attention(DeepseekV4Attention):
|
||||
attn_metadata.block_table[:num_decodes],
|
||||
block_size,
|
||||
is_valid,
|
||||
output_buffers=self._global_topk_output_buffers(
|
||||
self.topk_indices_buffer[:num_decode_tokens]
|
||||
),
|
||||
)
|
||||
)
|
||||
extra_sparse_indices = global_indices.view(num_decode_tokens, 1, -1)
|
||||
@@ -840,7 +837,6 @@ class DeepseekV4FlashInferSM120Attention(DeepseekV4Attention):
|
||||
attn_metadata.block_table,
|
||||
block_size,
|
||||
swa_metadata.is_valid_token[prefill_token_slice],
|
||||
output_buffers=self._global_topk_output_buffers(local_topk_indices),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -170,9 +170,6 @@ class DeepseekV4FlashMLAAttention(DeepseekV4Attention):
|
||||
attn_metadata.block_table[:num_decodes],
|
||||
block_size,
|
||||
is_valid,
|
||||
output_buffers=self._global_topk_output_buffers(
|
||||
self.topk_indices_buffer[:num_decode_tokens]
|
||||
),
|
||||
)
|
||||
topk_indices = global_indices.view(num_decode_tokens, 1, -1)
|
||||
else:
|
||||
|
||||
@@ -66,7 +66,6 @@ from vllm.model_executor.models.utils import (
|
||||
)
|
||||
from vllm.model_executor.utils import set_weight_attrs
|
||||
from vllm.models.deepseek_v4.attention import DeepseekV4Attention
|
||||
from vllm.models.deepseek_v4.eager_scratch import DeepseekV4EagerScratchPool
|
||||
from vllm.models.deepseek_v4.nvidia.flashinfer_sparse import (
|
||||
DeepseekV4FlashInferMLAAttention,
|
||||
DeepseekV4FlashInferSM120Attention,
|
||||
@@ -799,7 +798,6 @@ class DeepseekV4DecoderLayer(nn.Module):
|
||||
prefix,
|
||||
topk_indices_buffer: torch.Tensor | None = None,
|
||||
aux_stream_list: list[torch.cuda.Stream] | None = None,
|
||||
eager_scratch_pool: DeepseekV4EagerScratchPool | None = None,
|
||||
):
|
||||
super().__init__()
|
||||
|
||||
@@ -812,7 +810,6 @@ class DeepseekV4DecoderLayer(nn.Module):
|
||||
prefix=f"{prefix}.attn",
|
||||
topk_indices_buffer=topk_indices_buffer,
|
||||
aux_stream_list=aux_stream_list,
|
||||
eager_scratch_pool=eager_scratch_pool,
|
||||
)
|
||||
self.ffn = DeepseekV4MoE(vllm_config, prefix=f"{prefix}.ffn")
|
||||
|
||||
@@ -989,22 +986,6 @@ class DeepseekV4Model(nn.Module, EagleModelMixin):
|
||||
# (compressor kv_score, indexer.weights_proj, indexer.compressor
|
||||
# kv_score). fused_wqa_wkv stays on the default stream.
|
||||
aux_stream_list = [torch.cuda.Stream() for _ in range(3)]
|
||||
padded_heads = _select_dsv4_attn_cls(vllm_config).get_padded_num_q_heads(
|
||||
config.num_attention_heads // get_tensor_model_parallel_world_size()
|
||||
)
|
||||
self.eager_scratch_pool: DeepseekV4EagerScratchPool | None = None
|
||||
if not vllm_config.parallel_config.use_ubatching:
|
||||
# TODO: support dbo if needed
|
||||
# this requires the buffer to have ubatch dim
|
||||
self.eager_scratch_pool = DeepseekV4EagerScratchPool(
|
||||
vllm_config.scheduler_config.max_num_batched_tokens,
|
||||
padded_heads,
|
||||
config.head_dim,
|
||||
config.index_n_heads,
|
||||
config.index_head_dim,
|
||||
config.index_topk,
|
||||
current_platform.device_type,
|
||||
)
|
||||
|
||||
# Reserved topk indices buffer for all Indexer layers to reuse.
|
||||
self.topk_indices_buffer = torch.empty(
|
||||
@@ -1030,7 +1011,6 @@ class DeepseekV4Model(nn.Module, EagleModelMixin):
|
||||
prefix=prefix,
|
||||
topk_indices_buffer=self.topk_indices_buffer,
|
||||
aux_stream_list=aux_stream_list,
|
||||
eager_scratch_pool=self.eager_scratch_pool,
|
||||
),
|
||||
prefix=f"{prefix}.layers",
|
||||
)
|
||||
|
||||
@@ -2097,7 +2097,6 @@ def compress_norm_rope_store_cutedsl(
|
||||
store_full_kv: bool = False,
|
||||
store_full_fp8: bool = False,
|
||||
fp8_scale: torch.Tensor | None = None,
|
||||
compress_scratch: torch.Tensor | None = None,
|
||||
) -> None:
|
||||
if compress_ratio == 4:
|
||||
# For C4A, the single fused kernel is faster than the two-kernel version.
|
||||
@@ -2130,15 +2129,11 @@ def compress_norm_rope_store_cutedsl(
|
||||
)
|
||||
else:
|
||||
# For C128, the two-kernel version is faster than the single fused kernel.
|
||||
if compress_scratch is None:
|
||||
compressed_kv = torch.empty(
|
||||
(num_actual, head_dim),
|
||||
dtype=torch.float32,
|
||||
device=state_cache.device,
|
||||
)
|
||||
else:
|
||||
assert compress_scratch.shape == (num_actual, head_dim)
|
||||
compressed_kv = compress_scratch
|
||||
compressed_kv = torch.empty(
|
||||
(num_actual, head_dim),
|
||||
dtype=torch.float32,
|
||||
device=state_cache.device,
|
||||
)
|
||||
split_kv_compress_norm_rope_insert_sparse_attn_cutedsl(
|
||||
state_cache,
|
||||
token_to_req_indices,
|
||||
|
||||
@@ -12,15 +12,6 @@ from torch._C._profiler import _EventType, _ProfilerEvent, _TensorMetadata
|
||||
#
|
||||
|
||||
|
||||
def trim_string_front(string: str, width: int) -> str:
|
||||
if len(string) > width:
|
||||
offset = len(string) - width + 3
|
||||
string = string[offset:]
|
||||
if len(string) > 3:
|
||||
string = "..." + string[3:]
|
||||
return string
|
||||
|
||||
|
||||
def trim_string_back(string: str, width: int) -> str:
|
||||
if len(string) > width:
|
||||
offset = len(string) - width + 3
|
||||
|
||||
@@ -182,10 +182,6 @@ class LRUCache(cachetools.LRUCache[_K, _V]):
|
||||
|
||||
self.popitem(remove_pinned=remove_pinned)
|
||||
|
||||
def _remove_old_if_needed(self) -> None:
|
||||
while self.currsize > self.capacity:
|
||||
self.remove_oldest()
|
||||
|
||||
def popitem(self, remove_pinned: bool = False):
|
||||
"""Remove and return the `(key, value)` pair least recently used."""
|
||||
if not remove_pinned:
|
||||
|
||||
@@ -8,10 +8,6 @@ from typing import Any
|
||||
import torch
|
||||
|
||||
|
||||
class AuxStreamType(Enum):
|
||||
Attention = 1
|
||||
|
||||
|
||||
class EventType(Enum):
|
||||
Main = 0
|
||||
Attention = 1
|
||||
|
||||
@@ -427,26 +427,6 @@ class FreeKVCacheBlockQueue:
|
||||
curr_block = curr_block.next_free_block
|
||||
|
||||
|
||||
def need_extra_keys(request: Request) -> bool:
|
||||
"""Check whether the blocks allocated to this request need extra hash keys.
|
||||
|
||||
Args:
|
||||
request (Request): The request.
|
||||
|
||||
Returns:
|
||||
bool: Whether blocks allocated to this request need extra hash keys.
|
||||
"""
|
||||
|
||||
# Multimodal requests need to include the MM hash.
|
||||
# LoRA requests need to include the LoRA name.
|
||||
# Request with provided cache salt need to include the salt.
|
||||
return (
|
||||
bool(request.mm_features)
|
||||
or (request.lora_request is not None)
|
||||
or (request.cache_salt is not None)
|
||||
)
|
||||
|
||||
|
||||
def _gen_mm_extra_hash_keys(
|
||||
request: Request, start_token_idx: int, end_token_idx: int, start_mm_idx: int
|
||||
) -> tuple[list[Any], int]:
|
||||
@@ -1053,20 +1033,6 @@ def _get_kv_cache_groups_uniform_type(
|
||||
return [KVCacheGroupSpec(list(spec.kv_cache_specs.keys()), spec)]
|
||||
|
||||
|
||||
def is_kv_cache_page_size_uniform(kv_cache_spec: dict[str, KVCacheSpec]) -> bool:
|
||||
"""
|
||||
Whether all layers in the given KVCacheSpec have the same page size.
|
||||
Args:
|
||||
kv_cache_spec: The KVCacheSpec of each attention layer in the model
|
||||
|
||||
Returns:
|
||||
True if all layers have the same page size, False otherwise.
|
||||
"""
|
||||
|
||||
page_sizes = {layer.page_size_bytes for layer in kv_cache_spec.values()}
|
||||
return len(page_sizes) == 1
|
||||
|
||||
|
||||
def unify_kv_cache_spec_page_size(
|
||||
kv_cache_spec: dict[str, KVCacheSpec],
|
||||
) -> dict[str, KVCacheSpec]:
|
||||
|
||||
Reference in New Issue
Block a user