[Misc] Remove deprecated calculate_kv_scales runtime KV scale calculation (#49389)
Signed-off-by: wangxiyuan <wangxiyuan1007@gmail.com>
wangxiyuan committed
Aug 3, 2026 at 23:15 UTC
dd11df04f3b7046c40f13e586ac38a3725bc3c03
19 files changed
+16
-263
.buildkite/test-amd.yaml
+1
-1
@@ -636,7 +636,7 @@ steps:
636
- tests/compile
637
- vllm/platforms/rocm.py
638
commands:
639
- - pytest -v -s compile/fullgraph/test_full_graph.py -k 'not test_fp8_kv_scale_compile'
639
+ - pytest -v -s compile/fullgraph/test_full_graph.py
640
641
- label: Pytorch Nightly Dependency Override Check # TBD
642
timeout_in_minutes: 180
.buildkite/test_areas/compile.yaml
-3
@@ -90,9 +90,6 @@ steps:
90
- pytest -v -s tests/compile/passes/test_silu_mul_quant_fusion.py
91
# this runner has 2 GPUs available even though num_devices=2 is not set
92
- pytest -v -s tests/compile/passes/distributed/test_fusion_all_reduce.py
93
- # test_fp8_kv_scale_compile requires FlashAttention (not supported on default L4/L40)
94
- # TODO(luka) move to H100 once pass tests run on H100
95
- - pytest -v -s tests/compile/fullgraph/test_full_graph.py::test_fp8_kv_scale_compile
93
94
- label: Fusion E2E Quick (H100)
95
key: fusion-e2e-quick-h100
.buildkite/test_areas/pytorch.yaml
+1
-2
@@ -211,8 +211,7 @@ steps:
211
- vllm/v1/
212
- tests/compile
213
commands:
214
- # fp8 kv scales not supported on sm89, tested on Blackwell instead
215
- - pytest -v -s compile/fullgraph/test_full_graph.py -k 'not test_fp8_kv_scale_compile'
214
+ - pytest -v -s compile/fullgraph/test_full_graph.py
215
216
- label: Pytorch Nightly Dependency Override Check # 2min
217
key: pytorch-nightly-dependency-override-check
docs/design/metrics.md
+1
-1
@@ -367,7 +367,7 @@ We use this concept for the `vllm:cache_config_info` metric:
367
```text
368
# HELP vllm:cache_config_info Information of the LLMEngine CacheConfig
369
# TYPE vllm:cache_config_info gauge
370
-vllm:cache_config_info{block_size="16",cache_dtype="auto",calculate_kv_scales="False",cpu_offload_gb="0",enable_prefix_caching="False",gpu_memory_utilization="0.9",...} 1.0
370
+vllm:cache_config_info{block_size="16",cache_dtype="auto",cpu_offload_gb="0",enable_prefix_caching="False",gpu_memory_utilization="0.9",...} 1.0
371
```
372
373
However, `prometheus_client` has
docs/features/quantization/quantized_kvcache.md
+3
-33
@@ -27,18 +27,9 @@ You can configure how the quantization scales are computed in vLLM using three d
27
_Configure with:_
28
```python
29
kv_cache_dtype="fp8"
30
- calculate_kv_scales=False
30
```
31
33
-2. **Random token calibration (on-the-fly):**
34
- Scales are automatically estimated from a single batch of random tokens during warmup and then fixed.
35
- _Configure with:_
36
- ```python
37
- kv_cache_dtype="fp8"
38
- calculate_kv_scales=True
39
- ```
40
-
41
-3. **[Recommended] Calibration with a dataset (via llm-compressor):**
32
+2. **[Recommended] Calibration with a dataset (via llm-compressor):**
33
Scales are estimated using a curated calibration dataset for maximum accuracy.
34
This requires the [llm-compressor](https://github.com/vllm-project/llm-compressor) library.
35
_See example below!_
@@ -79,7 +70,7 @@ llm = LLM(
70
71
## Examples
72
82
-### 1. No Calibration (`kv_cache_dtype="fp8"`, `calculate_kv_scales=False`)
73
+### 1. No Calibration (`kv_cache_dtype="fp8"`)
74
75
All quantization scales are set to 1.0.
76
@@ -90,27 +81,6 @@ sampling_params = SamplingParams(temperature=0.7, top_p=0.8)
81
llm = LLM(
82
model="meta-llama/Llama-2-7b-chat-hf",
83
kv_cache_dtype="fp8",
93
- calculate_kv_scales=False,
94
-)
95
-prompt = "London is the capital of"
96
-out = llm.generate(prompt, sampling_params)[0].outputs[0].text
97
-print(out)
98
-```
99
-
100
----
101
-
102
-### 2. Random Token Calibration (`kv_cache_dtype="fp8"`, `calculate_kv_scales=True`)
103
-
104
-Scales are automatically estimated from a single batch of tokens during warmup.
105
-
106
-```python
107
-from vllm import LLM, SamplingParams
108
-
109
-sampling_params = SamplingParams(temperature=0.7, top_p=0.8)
110
-llm = LLM(
111
- model="meta-llama/Llama-2-7b-chat-hf",
112
- kv_cache_dtype="fp8",
113
- calculate_kv_scales=True,
84
)
85
prompt = "London is the capital of"
86
out = llm.generate(prompt, sampling_params)[0].outputs[0].text
@@ -119,7 +89,7 @@ print(out)
89
90
---
91
122
-### 3. **[Recommended] Calibration Using a Dataset (with `llm-compressor`)**
92
+### 2. **[Recommended] Calibration Using a Dataset (with `llm-compressor`)**
93
94
For the highest-quality quantization, we recommend calibrating against a dataset using `llm-compressor`. This enables advanced strategies such as per-attention-head quantization.
95
tests/compile/fullgraph/test_full_graph.py
-32
@@ -13,7 +13,6 @@ from vllm import LLM, SamplingParams
13
from vllm.config import CompilationConfig, CompilationMode, CUDAGraphMode, PassConfig
14
from vllm.platforms import current_platform
15
from vllm.utils.torch_utils import is_torch_equal_or_newer
16
-from vllm.v1.attention.backends.registry import AttentionBackendEnum
16
17
from ...utils import create_new_process_for_each_test
18
@@ -182,37 +181,6 @@ def test_custom_compile_config(
181
run_model(compilation_config, model, **model_kwargs)
182
183
185
-@pytest.mark.parametrize(
186
- "compilation_mode",
187
- [CompilationMode.NONE, CompilationMode.VLLM_COMPILE],
188
-)
189
-@pytest.mark.parametrize(
190
- "model, backend",
191
- [
192
- ("Qwen/Qwen2-0.5B", None), # Standard attention model
193
- (
194
- "deepseek-ai/DeepSeek-V2-Lite",
195
- AttentionBackendEnum.FLASHINFER_MLA,
196
- ), # MLA (Multi-head Latent Attention) model
197
- ],
198
-)
199
-def test_fp8_kv_scale_compile(
200
- compilation_mode: CompilationMode,
201
- model: str,
202
- backend: AttentionBackendEnum | None,
203
-):
204
- model_kwargs = {
205
- "quantization": "fp8",
206
- "kv_cache_dtype": "fp8_e4m3",
207
- "calculate_kv_scales": True,
208
- "max_model_len": 512,
209
- }
210
- if backend:
211
- model_kwargs["attention_config"] = {"backend": backend.name}
212
-
213
- run_model(compilation_mode, model, **model_kwargs)
214
-
215
-
184
def run_model(
185
compile_config: CompilationMode | CompilationConfig, model: str, **model_kwargs
186
):
tests/models/quantization/test_per_token_kv_cache.py
-4
@@ -52,9 +52,6 @@ def test_per_token_head_kv_cache_accuracy(
52
) -> None:
53
"""Compare logprobs between bf16 baseline and per-token-head quantized KV
54
cache.
55
-
56
- Uses calculate_kv_scales (dynamic scale computation) since there are
57
- no per-token-head calibrated checkpoints available yet.
55
"""
56
with monkeypatch.context() as m:
57
m.setenv("TOKENIZERS_PARALLELISM", "true")
@@ -80,7 +77,6 @@ def test_per_token_head_kv_cache_accuracy(
77
tensor_parallel_size=tensor_parallel_size,
78
enforce_eager=enforce_eager,
79
kv_cache_dtype=kv_cache_dtype,
83
- calculate_kv_scales=True,
80
attention_config={"backend": backend},
81
) as vllm_model:
82
test_outputs = vllm_model.generate_greedy_logprobs(
tests/quantization/test_fp8.py
+8
-20
@@ -18,7 +18,6 @@ from vllm.model_executor.kernels.linear.scaled_mm import (
18
MarlinFP8ScaledMMLinearKernel,
19
)
20
from vllm.model_executor.layers.attention.attention import (
21
- Attention,
21
set_default_quant_scales,
22
)
23
from vllm.model_executor.layers.fused_moe import FusedMoEFactory
@@ -433,8 +432,7 @@ def test_fp8_reloading(
432
method.process_weights_after_loading(layer)
433
434
436
-@pytest.mark.parametrize("source", ["checkpoint", "runtime_calc"])
437
-def test_kv_cache_scale_sync_to_host_copies(source):
435
+def test_kv_cache_scale_sync_to_host_copies():
436
"""Test device-to-host sync of the k/v quantization scales, for both the
437
checkpoint-load and runtime-calc paths that produce them.
438
"""
@@ -442,23 +440,13 @@ def test_kv_cache_scale_sync_to_host_copies(source):
440
set_default_quant_scales(layer, register_buffer=True)
441
layer.kv_cache_dtype = "fp8"
442
445
- if source == "checkpoint":
446
- # Scales come from the checkpoint, so runtime calc is disabled.
447
- layer.calculate_kv_scales = False
448
- method = BaseKVCacheMethod(quant_config=None)
449
- method.create_weights(layer)
450
- # 0.3 stays != 1.0 even after the fp8_fnuz x2 rescale.
451
- checkpoint_scale = torch.tensor(0.3, dtype=torch.float32)
452
- layer.k_scale.weight_loader(layer.k_scale, checkpoint_scale)
453
- layer.v_scale.weight_loader(layer.v_scale, checkpoint_scale)
454
- method.process_weights_after_loading(layer)
455
- else:
456
- # First forward computes distinct, non-unity scales from live k/v.
457
- layer.calculate_kv_scales = True
458
- query = torch.full((4, 8), 10.0)
459
- key = torch.full((4, 8), 60.0)
460
- value = torch.full((4, 8), 50.0)
461
- Attention.calc_kv_scales(layer, query, key, value)
443
+ method = BaseKVCacheMethod(quant_config=None)
444
+ method.create_weights(layer)
445
+ # 0.3 stays != 1.0 even after the fp8_fnuz x2 rescale.
446
+ checkpoint_scale = torch.tensor(0.3, dtype=torch.float32)
447
+ layer.k_scale.weight_loader(layer.k_scale, checkpoint_scale)
448
+ layer.v_scale.weight_loader(layer.v_scale, checkpoint_scale)
449
+ method.process_weights_after_loading(layer)
450
451
assert layer._k_scale_float != 1.0
452
assert layer._v_scale_float != 1.0
tests/quantization/test_per_token_kv_cache.py
-1
@@ -497,7 +497,6 @@ def test_process_weights_sets_placeholder_scales(kv_cache_dtype: str):
497
498
layer = MagicMock()
499
layer.kv_cache_dtype = kv_cache_dtype
500
- layer.calculate_kv_scales = False
500
layer.k_scale = torch.nn.Parameter(torch.tensor(-1.0), requires_grad=False)
501
layer.v_scale = torch.nn.Parameter(torch.tensor(-1.0), requires_grad=False)
502
layer.q_scale = torch.nn.Parameter(torch.tensor(-1.0), requires_grad=False)
vllm/config/cache.py
-17
@@ -108,11 +108,6 @@ class CacheConfig:
108
security risk tolerance against the performance benefits before turning this on.
109
- "xxhash_cbor" combines canonical CBOR serialization with xxHash for
110
reproducible hashing. Requires the optional ``xxhash`` package."""
111
- calculate_kv_scales: bool = False
112
- """Deprecated: This option is deprecated and will be removed in v0.19.
113
- It enables dynamic calculation of `k_scale` and `v_scale` when
114
- kv_cache_dtype is fp8. If `False`, the scales will be loaded from the model
115
- checkpoint if available. Otherwise, the scales will default to 1.0."""
111
kv_cache_dtype_skip_layers: list[str] = field(default_factory=list)
112
"""Layer patterns to skip KV cache quantization. Accepts layer indices
113
(e.g., '0', '2', '4') or attention type names (e.g., 'sliding_window')."""
@@ -270,18 +265,6 @@ class CacheConfig:
265
self.user_specified_mamba_block_size = True
266
return self
267
273
- @field_validator("calculate_kv_scales", mode="after")
274
- @classmethod
275
- def _warn_deprecated_calculate_kv_scales(cls, calculate_kv_scales: bool) -> bool:
276
- if calculate_kv_scales:
277
- logger.warning(
278
- "The `--calculate-kv-scales` option is deprecated and will "
279
- "be removed in v0.19. The scales will be loaded from the "
280
- "model checkpoint if available, otherwise they default to "
281
- "1.0."
282
- )
283
- return calculate_kv_scales
284
-
268
@field_validator("cache_dtype", mode="after")
269
@classmethod
270
def _validate_cache_dtype(cls, cache_dtype: CacheDType) -> CacheDType:
vllm/engine/arg_utils.py
-5
@@ -695,7 +695,6 @@ class EngineArgs:
695
override_attention_dtype: str | None = ModelConfig.override_attention_dtype
696
attention_backend: AttentionBackendEnum | None = AttentionConfig.backend
697
698
- calculate_kv_scales: bool = CacheConfig.calculate_kv_scales
698
kv_cache_dtype_skip_layers: list[str] = get_field(
699
CacheConfig, "kv_cache_dtype_skip_layers"
700
)
@@ -1210,9 +1209,6 @@ class EngineArgs:
1209
cache_group.add_argument(
1210
"--prefix-caching-hash-algo", **cache_kwargs["prefix_caching_hash_algo"]
1211
)
1213
- cache_group.add_argument(
1214
- "--calculate-kv-scales", **cache_kwargs["calculate_kv_scales"]
1215
- )
1212
cache_group.add_argument(
1213
"--kv-cache-dtype-skip-layers", **cache_kwargs["kv_cache_dtype_skip_layers"]
1214
)
@@ -1957,7 +1953,6 @@ class EngineArgs:
1953
sliding_window=sliding_window,
1954
enable_prefix_caching=self.enable_prefix_caching,
1955
prefix_caching_hash_algo=self.prefix_caching_hash_algo,
1960
- calculate_kv_scales=self.calculate_kv_scales,
1956
kv_cache_dtype_skip_layers=self.kv_cache_dtype_skip_layers,
1957
kv_sharing_fast_prefill=self.kv_sharing_fast_prefill,
1958
mamba_cache_dtype=self.mamba_cache_dtype,
vllm/envs.py
-6
@@ -1325,12 +1325,6 @@ environment_variables: dict[str, Callable[[], Any]] = {
1325
"VLLM_ROCM_QUICK_REDUCE_QUANTIZATION_MIN_SIZE_KB": lambda: maybe_convert_int(
1326
os.environ.get("VLLM_ROCM_QUICK_REDUCE_QUANTIZATION_MIN_SIZE_KB", None)
1327
),
1328
- # Divisor for dynamic query scale factor calculation for FP8 KV Cache
1329
- "Q_SCALE_CONSTANT": lambda: int(os.getenv("Q_SCALE_CONSTANT", "200")),
1330
- # Divisor for dynamic key scale factor calculation for FP8 KV Cache
1331
- "K_SCALE_CONSTANT": lambda: int(os.getenv("K_SCALE_CONSTANT", "200")),
1332
- # Divisor for dynamic value scale factor calculation for FP8 KV Cache
1333
- "V_SCALE_CONSTANT": lambda: int(os.getenv("V_SCALE_CONSTANT", "100")),
1328
# If set, enable multiprocessing in LLM for the V1 code path.
1329
"VLLM_ENABLE_V1_MULTIPROCESSING": lambda: bool(
1330
int(os.getenv("VLLM_ENABLE_V1_MULTIPROCESSING", "1"))
vllm/model_executor/layers/attention/attention.py
-62
@@ -144,11 +144,6 @@ def set_default_quant_scales(layer: nn.Module, register_buffer: bool = False) ->
144
layer._v_scale_cpu = torch.tensor(1.0, dtype=torch.float32)
145
layer._prob_scale_float = 1.0
146
147
- # Initialize q/k/v range constants used by calc_kv_scales
148
- layer.q_range = torch.tensor(envs.Q_SCALE_CONSTANT, dtype=torch.float32)
149
- layer.k_range = torch.tensor(envs.K_SCALE_CONSTANT, dtype=torch.float32)
150
- layer.v_range = torch.tensor(envs.V_SCALE_CONSTANT, dtype=torch.float32)
151
-
147
148
def _init_kv_cache_quant(
149
layer: nn.Module,
@@ -270,10 +265,8 @@ class Attention(nn.Module, AttentionLayerBase):
265
vllm_config = get_current_vllm_config()
266
if cache_config is not None:
267
kv_cache_dtype = cache_config.cache_dtype
273
- calculate_kv_scales = cache_config.calculate_kv_scales
268
else:
269
kv_cache_dtype = "auto"
276
- calculate_kv_scales = False
270
271
# llm-compressor models declare an FP8 KV-cache scheme in their
272
# checkpoint config. Honor it only when the user did not explicitly
@@ -284,10 +277,8 @@ class Attention(nn.Module, AttentionLayerBase):
277
kv_cache_scheme = getattr(quant_config, "kv_cache_scheme", None)
278
if kv_cache_scheme is not None and kv_cache_dtype == "auto":
279
kv_cache_dtype = "fp8"
287
- calculate_kv_scales = False
280
if cache_config is not None:
281
cache_config.cache_dtype = "fp8"
290
- cache_config.calculate_kv_scales = False
282
283
# Check if per-head quant scales are required based on kv_cache_scheme
284
use_per_head_quant_scales = (
@@ -312,7 +303,6 @@ class Attention(nn.Module, AttentionLayerBase):
303
skip = True
304
if skip:
305
kv_cache_dtype = "auto"
315
- calculate_kv_scales = False
306
logger.debug(
307
"Layer %s: kv_cache_dtype=%s, sliding_window=%s",
308
prefix,
@@ -324,7 +314,6 @@ class Attention(nn.Module, AttentionLayerBase):
314
kv_cache_dtype, vllm_config.model_config
315
)
316
self.kv_cache_dtype = kv_cache_dtype
327
- self.calculate_kv_scales = calculate_kv_scales
317
if num_kv_heads is None:
318
num_kv_heads = num_heads
319
assert num_heads % num_kv_heads == 0, (
@@ -505,10 +494,6 @@ class Attention(nn.Module, AttentionLayerBase):
494
context using
495
`vllm.forward_context.get_forward_context().attn_metadata`.
496
"""
508
- if self.calculate_kv_scales:
509
- torch.ops.vllm.maybe_calc_kv_scales(
510
- query, key, value, _encode_layer_name(self.layer_name)
511
- )
497
if output_dtype is None:
498
output_dtype = query.dtype
499
if self.query_quant is not None:
@@ -581,18 +566,6 @@ class Attention(nn.Module, AttentionLayerBase):
566
)
567
return output.view(-1, hidden_size)
568
584
- def calc_kv_scales(self, query, key, value):
585
- self._q_scale.copy_(torch.abs(query).max() / self.q_range)
586
- self._k_scale.copy_(torch.abs(key).max() / self.k_range)
587
- self._v_scale.copy_(torch.abs(value).max() / self.v_range)
588
- self._q_scale_float = self._q_scale.item()
589
- self._k_scale_float = self._k_scale.item()
590
- self._v_scale_float = self._v_scale.item()
591
- self._k_scale_cpu.fill_(self._k_scale_float)
592
- self._v_scale_cpu.fill_(self._v_scale_float)
593
- # We only calculate the scales once
594
- self.calculate_kv_scales = False
595
-
569
def extra_repr(self) -> str:
570
s = f"head_size={self.impl.head_size}" # type: ignore
571
s += f", num_heads={self.impl.num_heads}" # type: ignore
@@ -694,41 +667,6 @@ class Attention(nn.Module, AttentionLayerBase):
667
)
668
669
697
-def maybe_calc_kv_scales(
698
- query: torch.Tensor,
699
- key: torch.Tensor,
700
- value: torch.Tensor,
701
- layer_name: LayerNameType,
702
-) -> None:
703
- layer_name = _resolve_layer_name(layer_name)
704
- forward_context: ForwardContext = get_forward_context()
705
- self = forward_context.no_compile_layers[layer_name]
706
-
707
- # Only calculate if the layer's calculate_kv_scales flag is True
708
- # This flag gets set to False after the first forward pass
709
- if not self.calculate_kv_scales:
710
- return
711
-
712
- self.calc_kv_scales(query, key, value)
713
-
714
-
715
-def maybe_calc_kv_scales_fake(
716
- query: torch.Tensor,
717
- key: torch.Tensor,
718
- value: torch.Tensor,
719
- layer_name: LayerNameType,
720
-) -> None:
721
- return
722
-
723
-
724
-direct_register_custom_op(
725
- op_name="maybe_calc_kv_scales",
726
- op_func=maybe_calc_kv_scales,
727
- mutates_args=["query", "key", "value"],
728
- fake_impl=maybe_calc_kv_scales_fake,
729
-)
730
-
731
-
670
def get_attention_context(
671
layer_name: str,
672
) -> tuple[Any, "Attention | MLAAttention", torch.Tensor, torch.Tensor]:
vllm/model_executor/layers/attention/mla_attention.py
-41
@@ -399,10 +399,8 @@ class MLAAttention(nn.Module, AttentionLayerBase):
399
400
if cache_config is not None:
401
kv_cache_dtype: CacheDType = cache_config.cache_dtype
402
- calculate_kv_scales = cache_config.calculate_kv_scales
402
else:
403
kv_cache_dtype = "auto"
405
- calculate_kv_scales = False
404
self.quant_config = quant_config
405
406
if cache_config is not None and cache_config.kv_cache_dtype_skip_layers:
@@ -411,7 +409,6 @@ class MLAAttention(nn.Module, AttentionLayerBase):
409
layer_idx = extract_layer_index(prefix)
410
if str(layer_idx) in cache_config.kv_cache_dtype_skip_layers:
411
kv_cache_dtype = "auto"
414
- calculate_kv_scales = False
412
logger.debug(
413
"Layer %s: kv_cache_dtype=%s",
414
prefix,
@@ -460,7 +457,6 @@ class MLAAttention(nn.Module, AttentionLayerBase):
457
458
# Initialize KV cache quantization attributes
459
self.kv_cache_dtype = kv_cache_dtype
463
- self.calculate_kv_scales = calculate_kv_scales
460
_init_kv_cache_quant(self, quant_config, prefix)
461
462
if (
@@ -560,11 +556,6 @@ class MLAAttention(nn.Module, AttentionLayerBase):
556
and _vllm_config.parallel_config.dcp_comm_backend == "a2a"
557
)
558
563
- # Initialize q/k/v range constants.
564
- self.q_range = torch.tensor(envs.Q_SCALE_CONSTANT, dtype=torch.float32)
565
- self.k_range = torch.tensor(envs.K_SCALE_CONSTANT, dtype=torch.float32)
566
- self.v_range = torch.tensor(envs.V_SCALE_CONSTANT, dtype=torch.float32)
567
-
559
self.is_aiter_triton_fp8_bmm_enabled = rocm_aiter_ops.is_fp8bmm_enabled()
560
561
# If kv_b_proj_weight is unquantized, quantize it to mxfp4 if supported
@@ -606,14 +597,6 @@ class MLAAttention(nn.Module, AttentionLayerBase):
597
output_shape: torch.Size | None = None,
598
q_dcp_replicated: torch.Tensor | None = None,
599
) -> torch.Tensor:
609
- if self.calculate_kv_scales:
610
- torch.ops.vllm.maybe_calc_kv_scales(
611
- q,
612
- kv_c_normed,
613
- k_pe,
614
- _encode_layer_name(self.layer_name),
615
- )
616
-
600
if self.use_direct_call:
601
forward_context: ForwardContext = get_forward_context()
602
attn_metadata_raw = forward_context.attn_metadata
@@ -1110,30 +1093,6 @@ class MLAAttention(nn.Module, AttentionLayerBase):
1093
if not should_load_quant_weights(quant_method):
1094
set_default_quant_scales(self, register_buffer=False)
1095
1113
- def calc_kv_scales(
1114
- self, q: torch.Tensor, kv_c_normed: torch.Tensor, k_pe: torch.Tensor
1115
- ) -> None:
1116
- """Optional scale calculation for MLA inputs.
1117
-
1118
- Mirrors Attention.calc_kv_scales. Not all MLA backends require this
1119
- """
1120
- # Use safe defaults if ranges are not present
1121
- q_range = getattr(self, "q_range", torch.tensor(1.0))
1122
- k_range = getattr(self, "k_range", torch.tensor(1.0))
1123
- v_range = getattr(self, "v_range", torch.tensor(1.0))
1124
-
1125
- self._q_scale.copy_(torch.abs(q).max() / q_range)
1126
- # kv_c_normed is the compressed KV representation; use it for k/v
1127
- kv_abs_max = torch.abs(kv_c_normed).max()
1128
- self._k_scale.copy_(kv_abs_max / k_range)
1129
- self._v_scale.copy_(kv_abs_max / v_range)
1130
- self._q_scale_float = self._q_scale.item()
1131
- self._k_scale_float = self._k_scale.item()
1132
- self._v_scale_float = self._v_scale.item()
1133
- self._k_scale_cpu.fill_(self._k_scale_float)
1134
- self._v_scale_cpu.fill_(self._v_scale_float)
1135
- self.calculate_kv_scales = False
1136
-
1096
def get_attn_backend(self) -> type[AttentionBackend]:
1097
return self.attn_backend
1098
vllm/model_executor/layers/quantization/kv_cache.py
+2
-7
@@ -80,8 +80,7 @@ class BaseKVCacheMethod(QuantizeMethodBase):
80
return
81
82
# Per-token-head quantized KV cache: scales are computed dynamically
83
- # per (token, head) in the kernel at cache-write time. Checkpoint
84
- # scales are never used regardless of calculate_kv_scales.
83
+ # per (token, head) in the kernel at cache-write time.
84
if kv_cache_uses_per_token_head_scales(layer.kv_cache_dtype):
85
layer._k_scale.copy_(1.0)
86
layer._v_scale.copy_(1.0)
@@ -97,10 +96,7 @@ class BaseKVCacheMethod(QuantizeMethodBase):
96
# regardless whether the kv-scale is available in the checkpoint.
97
# No need to process kv scales after loading if we are going to
98
# calculate them on the fly.
100
- if (
101
- is_quantized_kv_cache(layer.kv_cache_dtype)
102
- and not layer.calculate_kv_scales
103
- ):
99
+ if is_quantized_kv_cache(layer.kv_cache_dtype):
100
if layer.k_scale > 0.0 and layer.v_scale > 0.0:
101
# We prefer to use separate k_scale and v_scale if present
102
k_scale = layer.k_scale.to("cpu").tolist()
@@ -158,7 +154,6 @@ class BaseKVCacheMethod(QuantizeMethodBase):
154
q_scale = layer.q_scale
155
if current_platform.is_fp8_fnuz():
156
q_scale *= 2
161
- layer.calculate_kv_scales = False
157
else:
158
q_scale = 1.0
159
if layer.prob_scale > 0.0:
vllm/model_executor/models/config.py
-17
@@ -445,23 +445,6 @@ class HybridAttentionMambaModelConfig(VerifyAndUpdateConfig):
445
Args:
446
vllm_config: vLLM Config
447
"""
448
- cache_config = vllm_config.cache_config
449
-
450
- # Disable calculate_kv_scales for hybrid models: uninitialized
451
- # recurrent state corrupts scales during the calibration pass.
452
- # See issue: https://github.com/vllm-project/vllm/issues/37554
453
-
454
- if cache_config.calculate_kv_scales:
455
- logger.warning(
456
- "Disabling calculate_kv_scales for hybrid model '%s'. "
457
- "Hybrid models with recurrent layers (GDN, Mamba, SSM) "
458
- "produce unreliable KV cache scales during the "
459
- "calibration pass because recurrent state is "
460
- "uninitialized. Using default scale of 1.0 instead.",
461
- vllm_config.model_config.model,
462
- )
463
- cache_config.calculate_kv_scales = False
464
-
448
# Enable FULL_AND_PIECEWISE by default
449
MambaModelConfig.verify_and_update_config(vllm_config)
450
vllm/models/minimax_m3/amd/model.py
-1
@@ -642,7 +642,6 @@ class MiniMaxM3SparseAttention(nn.Module, AttentionLayerBase):
642
# MiniMax-M3 sparse attention owns its KV-cache insert/read path instead
643
# of wrapping the generic Attention module. Keep the same runtime scale
644
# attributes so FP8 KV reads can honor vLLM's per-layer descale contract.
645
- self.calculate_kv_scales = False
645
set_default_quant_scales(self, register_buffer=True)
646
647
# Shared top-k buffer: the indexer writes the selected blocks into it and
vllm/models/minimax_m3/nvidia/model.py
-1
@@ -495,7 +495,6 @@ class MiniMaxM3SparseAttention(nn.Module, AttentionLayerBase):
495
# MiniMax-M3 sparse attention owns its KV-cache insert/read path instead
496
# of wrapping the generic Attention module. Keep the same runtime scale
497
# attributes so FP8 KV reads can honor vLLM's per-layer descale contract.
498
- self.calculate_kv_scales = False
498
set_default_quant_scales(self, register_buffer=True)
499
# Indexer side-cache dtype, mirroring --kv-cache-dtype for the main
500
# cache (--attention-config '{"indexer_kv_dtype": ...}').
vllm/v1/worker/gpu_model_runner.py
-9
@@ -499,7 +499,6 @@ class GPUModelRunner(
499
self.max_model_len = model_config.max_model_len
500
501
# Always set to false after the first forward pass
502
- self.calculate_kv_scales = self.cache_config.calculate_kv_scales
502
self.dcp_world_size = self.parallel_config.decode_context_parallel_size
503
self.dcp_rank = 0 if self.dcp_world_size <= 1 else get_dcp_group().rank_in_group
504
self.max_num_tokens = scheduler_config.max_num_batched_tokens
@@ -4402,14 +4401,6 @@ class GPUModelRunner(
4401
scheduler_output, num_tokens_padded, intermediate_tensors
4402
)
4403
4405
- # Set cudagraph mode to none if calc_kv_scales is true.
4406
- # KV scales calculation involves dynamic operations that are incompatible
4407
- # with CUDA graph capture.
4408
- if self.calculate_kv_scales:
4409
- cudagraph_mode = CUDAGraphMode.NONE
4410
- # Mark KV scales as calculated after the first forward pass
4411
- self.calculate_kv_scales = False
4412
-
4404
# Encoder-decoder models can only compile the pure decode steps where no
4405
# encoder inputs are present. Use eager for the first pass.
4406
num_encoder_reqs = len(scheduler_output.scheduled_encoder_inputs)