[Bugfix][Quant] Raise actionable error instead of bare assert for group-size/TP mismatch (#46230) (#46236)
Signed-off-by: Arsalan Shakil <shakil.arsalan@yahoo.com>
Arsalan Shakil committed
Jun 30, 2026 at 17:57 UTC
00ebf19ccaa30d6a4c671baa29ec43ed8c933772
6 files changed
+37
-12
vllm/distributed/utils.py
+18
@@ -64,6 +64,24 @@ def divide(numerator, denominator):
64
return numerator // denominator
65
66
67
+def verify_group_size_divides_partition(
68
+ input_size_per_partition: int,
69
+ group_size: int,
70
+ layer_name: str | None = None,
71
+ extra_suggestion: str = "",
72
+) -> None:
73
+ """Validate that a TP-sharded layer holds a whole number of quant groups."""
74
+ if input_size_per_partition % group_size == 0:
75
+ return
76
+ location = f" for layer '{layer_name}'" if layer_name else ""
77
+ raise ValueError(
78
+ f"Weight {input_size_per_partition=}{location} is not divisible by "
79
+ f"{group_size=}. This happens when tensor_parallel_size splits the layer input "
80
+ "into shards that are not a whole number of quant groups. Consider reducing "
81
+ f"tensor_parallel_size{extra_suggestion}."
82
+ )
83
+
84
+
85
def is_weak_contiguous(inp: torch.Tensor) -> bool:
86
"""Check that *inp* occupies a single contiguous block of memory.
87
vllm/model_executor/layers/quantization/compressed_tensors/schemes/compressed_tensors_w4a8_fp8.py
+2
-1
@@ -6,6 +6,7 @@ from collections.abc import Callable
6
import torch
7
from compressed_tensors.quantization import ActivationOrdering
8
9
+from vllm.distributed.utils import verify_group_size_divides_partition
10
from vllm.logger import init_logger
11
from vllm.model_executor.kernels.linear import (
12
MPLinearLayerConfig,
@@ -112,7 +113,7 @@ class CompressedTensorsW4A8Fp8(CompressedTensorsScheme):
113
scales_and_zp_size = input_size // group_size
114
115
if partition_scales:
115
- assert input_size_per_partition % group_size == 0
116
+ verify_group_size_divides_partition(input_size_per_partition, group_size)
117
scales_and_zp_size = input_size_per_partition // group_size
118
119
weight = PackedvLLMParameter(
vllm/model_executor/layers/quantization/compressed_tensors/schemes/compressed_tensors_w4a8_int.py
+3
-3
@@ -5,6 +5,7 @@ from collections.abc import Callable
5
6
import torch
7
8
+from vllm.distributed.utils import verify_group_size_divides_partition
9
from vllm.logger import init_logger
10
from vllm.model_executor.kernels.linear import (
11
MPLinearLayerConfig,
@@ -79,9 +80,8 @@ class CompressedTensorsW4A8Int(CompressedTensorsScheme):
80
effective_group_size = self.group_size
81
82
# Ensure group_size divides input_size_per_partition
82
- assert input_size_per_partition % effective_group_size == 0, (
83
- f"input_size_per_partition {input_size_per_partition}"
84
- f" not divisible by group_size {effective_group_size}"
83
+ verify_group_size_divides_partition(
84
+ input_size_per_partition, effective_group_size
85
)
86
87
# Determine scale partitioning
vllm/model_executor/layers/quantization/compressed_tensors/schemes/compressed_tensors_wNa16.py
+4
-1
@@ -8,6 +8,7 @@ from fractions import Fraction
8
import torch
9
from compressed_tensors.quantization import ActivationOrdering
10
11
+from vllm.distributed.utils import verify_group_size_divides_partition
12
from vllm.logger import init_logger
13
from vllm.model_executor.kernels.linear import (
14
MarlinLinearKernel,
@@ -151,7 +152,9 @@ class CompressedTensorsWNA16(CompressedTensorsScheme):
152
scales_and_zp_size = input_size // group_size
153
154
if partition_scales:
154
- assert input_size_per_partition % group_size == 0
155
+ verify_group_size_divides_partition(
156
+ input_size_per_partition, group_size, self.layer_name
157
+ )
158
scales_and_zp_size = input_size_per_partition // group_size
159
160
packed_input_dim = math.ceil(input_size_per_partition * self.num_bits / 32)
vllm/model_executor/layers/quantization/compressed_tensors/schemes/compressed_tensors_wNa8o8.py
+4
-1
@@ -13,6 +13,7 @@ from collections.abc import Callable
13
import torch
14
from compressed_tensors.compressors.pack_quantized.helpers import pack_to_int32
15
16
+from vllm.distributed.utils import verify_group_size_divides_partition
17
from vllm.model_executor.kernels.linear import (
18
MPLinearLayerConfig,
19
choose_mp_linear_kernel,
@@ -171,7 +172,9 @@ class CompressedTensorsWNA8O8Int(CompressedTensorsScheme):
172
scales = (input_size_per_partition if partitioned else input_size) // group_size
173
scale_data = torch.empty(out, scales, dtype=params_dtype)
174
if partitioned:
174
- assert input_size_per_partition % group_size == 0
175
+ verify_group_size_divides_partition(
176
+ input_size_per_partition, group_size, self.layer_name
177
+ )
178
weight_scale = GroupQuantScaleParameter(
179
data=scale_data, output_dim=0, input_dim=1, weight_loader=weight_loader
180
)
vllm/model_executor/layers/quantization/utils/marlin_utils.py
+6
-6
@@ -9,6 +9,7 @@ import torch
9
10
import vllm.envs as envs
11
from vllm import _custom_ops as ops
12
+from vllm.distributed.utils import verify_group_size_divides_partition
13
from vllm.logger import init_logger
14
from vllm.model_executor.layers.fused_moe import RoutedExperts
15
from vllm.model_executor.layers.linear import LinearBase
@@ -193,12 +194,11 @@ def verify_marlin_supports_shape(
194
"with --quantization gptq."
195
)
196
196
- if group_size < input_size and input_size_per_partition % group_size != 0:
197
- raise ValueError(
198
- f"Weight input_size_per_partition = {input_size_per_partition}"
199
- f" is not divisible by group_size = {group_size}. "
200
- "Consider reducing tensor_parallel_size or running "
201
- "with --quantization gptq."
197
+ if group_size < input_size:
198
+ verify_group_size_divides_partition(
199
+ input_size_per_partition,
200
+ group_size,
201
+ extra_suggestion=" or running with --quantization gptq",
202
)
203
204