Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
77e1f38
Refactor INC quantization package
yiliu30 May 11, 2026
069881c
merge main
yiliu30 May 14, 2026
d461f02
adapt ark linear
yiliu30 May 14, 2026
757d3a8
fix
yiliu30 May 15, 2026
e62e16a
adapt gptq update
yiliu30 May 15, 2026
3fef0b9
Merge branch 'main' into inc-refactor
yiliu30 May 15, 2026
002e58d
Merge branch 'main' into inc-refactor
yiliu30 May 16, 2026
00ce39e
Merge branch 'main' into inc-refactor
yiliu30 May 19, 2026
db41ea3
add inc back (tmp)
yiliu30 May 19, 2026
85aa9a8
Fix false substring match in INCConfig.get_layer_config step 4
n1ck-guo May 12, 2026
849f486
Address review: use helper to check exact+regex match in step 4 guard
n1ck-guo May 12, 2026
c5d05f6
porting fix
yiliu30 May 19, 2026
da03e89
clean
yiliu30 May 19, 2026
4ac9b84
fix format
yiliu30 May 19, 2026
5b8faa2
Merge branch 'main' into inc-refactor
yiliu30 May 20, 2026
668d904
Merge branch 'main' into inc-refactor
yiliu30 May 20, 2026
0739fd4
rename resolve to parser
yiliu30 May 22, 2026
41c71f5
Merge branch 'main' into inc-refactor
yiliu30 May 22, 2026
e6c7317
update
yiliu30 May 22, 2026
41b1469
fix
yiliu30 May 22, 2026
d1eba07
fix format
yiliu30 May 22, 2026
8182975
Merge branch 'main' into inc-refactor
yiliu30 May 27, 2026
d16dedd
clean
yiliu30 May 27, 2026
03460a1
align naming
yiliu30 May 27, 2026
e337c6e
update
yiliu30 May 27, 2026
e063b35
Merge branch 'main' into inc-refactor
yiliu30 May 27, 2026
6c376de
Merge branch 'main' into inc-refactor
yiliu30 May 29, 2026
5da3ce5
Merge branch 'main' into inc-refactor
yiliu30 Jun 1, 2026
a4ed59a
add test to ci
yiliu30 Jun 1, 2026
ca4527f
add test
yiliu30 Jun 1, 2026
5fdca35
update
yiliu30 Jun 1, 2026
1068eda
Merge branch 'main' into inc-refactor
yiliu30 Jun 2, 2026
ba428ea
fix ut
yiliu30 Jun 2, 2026
b191396
Merge branch 'inc-refactor' of https://github.com/yiliu30/vllm-fork i…
yiliu30 Jun 2, 2026
70af126
fix
yiliu30 Jun 2, 2026
44edf8b
Merge branch 'main' into inc-refactor
yiliu30 Jun 2, 2026
6a09808
update ARK API
Zhenzhong1 Jun 9, 2026
bd23dcb
update ARK API
Zhenzhong1 Jun 9, 2026
cf44dd7
update ARK API
Zhenzhong1 Jun 9, 2026
06373cb
Merge branch 'main' into inc-refactor
yiliu30 Jun 9, 2026
59dd25e
Merge pull request #118 from yiliu30/inc-refactor-ARK-update
Zhenzhong1 Jun 10, 2026
669fe5b
Merge branch 'main' into inc-refactor
Zhenzhong1 Jun 10, 2026
af09bef
Merge branch 'main' into inc-refactor
yiliu30 Jun 10, 2026
ac3d90c
Merge branch 'main' into inc-refactor
yiliu30 Jun 10, 2026
d2e7511
adpat main
yiliu30 Jun 10, 2026
1afa4fc
fix
yiliu30 Jun 10, 2026
f971058
fix
yiliu30 Jun 10, 2026
a72f009
Merge branch 'main' into inc-refactor
yiliu30 Jun 11, 2026
35d8dd5
Merge branch 'main' into inc-refactor
yiliu30 Jun 11, 2026
906cb7d
Merge branch 'main' into inc-refactor
yiliu30 Jun 11, 2026
27996c4
upgrade auto-round-lib
yiliu30 Jun 12, 2026
b08de02
Merge branch 'main' into inc-refactor
yiliu30 Jun 12, 2026
2c6f51e
Merge branch 'main' into inc-refactor
yiliu30 Jun 15, 2026
2445297
Merge branch 'main' into inc-refactor
yiliu30 Jun 15, 2026
f57ad8e
Merge branch 'main' into inc-refactor
yiliu30 Jun 16, 2026
50d8a74
Merge branch 'main' into inc-refactor
yiliu30 Jun 16, 2026
c8cf10f
Merge branch 'main' into inc-refactor
yiliu30 Jun 17, 2026
0561f29
refine test
yiliu30 Jun 17, 2026
2c23264
Merge branch 'main' into inc-refactor
yiliu30 Jun 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
717 changes: 717 additions & 0 deletions tests/quantization/test_auto_round.py

Large diffs are not rendered by default.

794 changes: 0 additions & 794 deletions vllm/model_executor/layers/quantization/inc.py

This file was deleted.

147 changes: 147 additions & 0 deletions vllm/model_executor/layers/quantization/inc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# INC Quantization Support

## High-Level Architecture and Call Flow

```bash
┌─────────────────────────────┐
│ HuggingFace Config │
│ (quantization_config.json) │
└──────────────┬──────────────┘
│ parsed by
▼
┌──────────────────────────────────────────────────────────────────────┐
│ INCConfig │
│ │
│ get_quant_method(layer, prefix): │
│ 1. resolver.resolve(layer, prefix) → INCLayerConfig │
│ 2. resolve_scheme(layer_config) → INCScheme │
│ 3. isinstance dispatch: │
│ LinearBase → scheme.get_linear_method() → INCLinearMethod │
│ FusedMoE → scheme.get_moe_method() → concrete MoE method│
│ Attention → scheme.get_kvcache_method() → (future) │
└───────────────────────────────┬──────────────────────────────────────┘
│
resolve_scheme(layer_config)
│
┌─────────────┼──────────────┐
▼ ▼ ▼
INCWna16Scheme INCFp8Scheme INCMxfp8Scheme
(current) (future) (future)
│
┌──────────┼──────────┐
▼ ▼ ▼
get_linear get_moe get_kvcache
_method() _method() _method()
│ │ │
▼ ▼ ▼
INCLinear concrete (future)
Method MoE method
(adapter) (no wrapper)
│ │
▼ ▼
INCLinear GPTQMarlin
Scheme MoEMethod
(impl) (direct)
```

### Dispatch flow (same 3 steps for all layer types)

```bash
resolve config → resolve scheme → scheme.get_xxx_method()
```

### Why Linear has an adapter but MoE doesn't

- **Linear**: `INCLinearScheme` defines a different lifecycle API (`create_weights`/`process_weights_after_loading`/`apply_weights`) than `LinearMethodBase`, so `INCLinearMethod` bridges them.
- **MoE**: Concrete methods already implement `FusedMoEMethodBase` directly. Wrapping would break class identity checks in vLLM's MoE layer.

## Package layout

```bash
inc/
├── inc.py # INCConfig (entry point + dispatch)
├── resolver.py # INCLayerConfig + INCConfigResolver
├── inc_linear.py # INCLinearMethod
└── schemes/
├── base.py # INCScheme ABC + INCLinearScheme ABC
├── factory.py # resolve_scheme() — ordered list
├── wna16.py # INCWna16Scheme (orchestrator)
├── wna16_linear.py # INCWNA16LinearScheme
└── xpu_w4a16_linear.py
Comment thread
yiliu30 marked this conversation as resolved.
Resolved
```

## Adding a new scheme

### Linear only (e.g., FP8)

```python
# schemes/fp8.py
class INCFp8Scheme(INCScheme):
@staticmethod
def can_handle(layer_config):
return layer_config.is_fp8

def get_linear_method(self, config, layer, prefix, layer_config):
return INCLinearMethod(INCFp8LinearScheme(layer_config))

# get_moe_method — inherits default NotImplementedError


class INCFp8LinearScheme(INCLinearScheme):
def __init__(self, layer_config):
self.kernel = init_fp8_linear_kernel() # vLLM picks best kernel per platform

def get_min_capability(cls) -> int:
return 89

def create_weights(self, layer, ...):
# Register FP8 weight + per-channel scale
layer.register_parameter("weight", ...)
layer.register_parameter("weight_scale", ...)

def process_weights_after_loading(self, layer):
self.kernel.process_weights_after_loading(layer)

def apply_weights(self, layer, x, bias=None):
return self.kernel.apply_weights(layer, x, bias)
```

### Adding MoE support

```python
# schemes/fp8.py — add to existing scheme
class INCFp8Scheme(INCScheme):
...
def get_moe_method(self, config, layer, prefix, layer_config):
return INCFp8MoEMethod(layer.moe_config)


# schemes/fp8_moe.py — new file, implements FusedMoEMethodBase directly
class INCFp8MoEMethod(FusedMoEMethodBase):
"""Only 2 abstract methods to implement."""

def __init__(self, moe_config):
super().__init__(moe_config)

def create_weights(self, layer, num_experts, hidden_size,
intermediate_size_per_partition, params_dtype, **kw):
# Register FP8 MoE weights + scales
...

def get_fused_moe_quant_config(self, layer):
return FusedMoEQuantConfig(...)

# apply() has a working default — override only if needed
```

### Register (one line)

```python
# schemes/factory.py
_SCHEME_LIST.extend([
INCFp8Scheme, # ← add
INCWna16Scheme,
])
```

**That's it.** Two files touched: one new scheme file + one line in factory.
6 changes: 6 additions & 0 deletions vllm/model_executor/layers/quantization/inc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project

from .inc import INCConfig

__all__ = ["INCConfig"]
191 changes: 191 additions & 0 deletions vllm/model_executor/layers/quantization/inc/inc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project

from fractions import Fraction
from typing import TYPE_CHECKING, Any

import torch

from vllm.logger import init_logger
from vllm.model_executor.layers.fused_moe.layer import UnquantizedFusedMoEMethod
from vllm.model_executor.layers.linear import (
LinearBase,
UnquantizedLinearMethod,
)
from vllm.model_executor.layers.quantization import (
QuantizationConfig,
QuantizationMethods,
)
from vllm.model_executor.layers.vocab_parallel_embedding import ParallelLMHead

from .resolver import INCConfigResolver

if TYPE_CHECKING:
from vllm.model_executor.models.utils import WeightsMapper

logger = init_logger(__name__)


class INCConfig(QuantizationConfig):
"""Config class for Intel Neural Compressor (INC).
Repo: https://github.com/intel/neural-compressor
"""

SUPPORTED_BITS = {2, 3, 4, 8}
SUPPORTED_DTYPES = {"int"}
SUPPORTED_FORMATS = {"auto_round:auto_gptq", "auto_round:auto_awq"}
SUPPORTED_BACKENDS = {
"auto",
"gptq",
"gptq:marlin",
"awq",
"awq:marlin",
"marlin",
}

def __init__(
self,
weight_bits: int,
group_size: int,
sym: bool = True,
packing_format: str = "auto_round:auto_gptq",
block_name_to_quantize: str | list[str] | None = None,
extra_config: dict[str, Any] | None = None,
data_type: str = "int",
backend: str = "auto",
) -> None:
super().__init__()
if weight_bits not in self.SUPPORTED_BITS:
raise ValueError(
f"Unsupported weight_bits: {weight_bits}, "
f"currently only support {self.SUPPORTED_BITS}."
)
if data_type not in self.SUPPORTED_DTYPES:
raise ValueError(
f"Unsupported data_type: {data_type},"
f" currently only support {self.SUPPORTED_DTYPES}."
)
if packing_format not in self.SUPPORTED_FORMATS:
raise ValueError(
f"Unsupported packing_format: {packing_format}, "
f"currently only support {self.SUPPORTED_FORMATS}."
)
if backend not in self.SUPPORTED_BACKENDS:
raise ValueError(
f"Unsupported backend: {backend}, "
f"currently only support {self.SUPPORTED_BACKENDS}."
)

self.weight_bits = weight_bits
self.group_size = group_size
self.sym = sym
self.packing_format = packing_format
self.block_name_to_quantize = (
block_name_to_quantize.split(",")
if isinstance(block_name_to_quantize, str)
else block_name_to_quantize
)
self.extra_config = extra_config
self.data_type = data_type
self.backend = backend
self.pack_factor = Fraction(32, weight_bits)
self.resolver = INCConfigResolver(self)

def __repr__(self) -> str:
return (
f"INCConfig(weight_bits={self.weight_bits}, "
f"group_size={self.group_size}, sym={self.sym})"
)

@classmethod
def get_name(cls) -> QuantizationMethods:
return "inc"

@classmethod
def get_supported_act_dtypes(cls) -> list[torch.dtype]:
return [torch.half, torch.bfloat16]

@classmethod
def get_min_capability(cls) -> int:
return 60

@classmethod
def get_config_filenames(cls) -> list[str]:
return ["quantization_config.json"]

@classmethod
def from_config(cls, config: dict[str, Any]) -> "INCConfig":
return cls(
weight_bits=cls.get_from_keys(config, ["bits"]),
group_size=cls.get_from_keys(config, ["group_size"]),
sym=cls.get_from_keys(config, ["sym"]),
packing_format=cls.get_from_keys_or(
config, ["packing_format"], "auto_round:auto_gptq"
),
block_name_to_quantize=cls.get_from_keys_or(
config, ["block_name_to_quantize", "to_quant_block_names"], None
),
extra_config=cls.get_from_keys_or(config, ["extra_config"], None),
data_type=cls.get_from_keys_or(config, ["data_type"], "int"),
backend=cls.get_from_keys_or(config, ["backend", "vllm_backend"], "auto"),
)

def get_layer_config(self, layer, layer_name: str):
return self.resolver.get_layer_config(layer, layer_name)

def apply_vllm_mapper(self, hf_to_vllm_mapper: "WeightsMapper"):
if self.block_name_to_quantize is not None:
self.block_name_to_quantize = hf_to_vllm_mapper.apply_list(
self.block_name_to_quantize
)
if self.extra_config is not None:
self.extra_config = hf_to_vllm_mapper.apply_dict(self.extra_config)

def get_quant_method(self, layer: torch.nn.Module, prefix: str):
from vllm.model_executor.layers.fused_moe import FusedMoE

from .schemes.factory import resolve_scheme

# Match original: check model.-prefixed names for unquantized layers
if prefix and self.extra_config:
for layer_name in self.extra_config:
if (
layer_name == prefix or layer_name == f"model.{prefix}"
) and self.extra_config[layer_name].get("bits", 16) >= 16:
if isinstance(layer, FusedMoE):
return UnquantizedFusedMoEMethod(layer.moe_config)
return UnquantizedLinearMethod()
Comment thread
yiliu30 marked this conversation as resolved.
Resolved

layer_config = self.resolver.resolve(layer, prefix)
if not layer_config.quantized:
if isinstance(layer, (LinearBase, ParallelLMHead)):
return UnquantizedLinearMethod()
if isinstance(layer, FusedMoE):
return UnquantizedFusedMoEMethod(layer.moe_config)
return None
Comment thread
yiliu30 marked this conversation as resolved.
Resolved

logger.debug(
"[%s] Type: %s, Bits: %s, Group Size: %s, Sym: %s",
prefix,
layer.__class__.__name__,
layer_config.bits,
layer_config.group_size,
layer_config.sym,
)

scheme = resolve_scheme(layer_config)
if isinstance(layer, (LinearBase, ParallelLMHead)):
return scheme.get_linear_method(self, layer, prefix, layer_config)
if isinstance(layer, FusedMoE):
return scheme.get_moe_method(self, layer, prefix, layer_config)
return None

@classmethod
def override_quantization_method(
cls, hf_quant_cfg, user_quant, hf_config=None
) -> "QuantizationMethods | None":
"""Override the `auto-round` method to `inc`."""
is_auto_round_format = hf_quant_cfg.get("quant_method", None) == "auto-round"
if is_auto_round_format:
return cls.get_name()
return None
47 changes: 47 additions & 0 deletions vllm/model_executor/layers/quantization/inc/inc_linear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project

from typing import TYPE_CHECKING

import torch

from vllm.model_executor.layers.linear import LinearMethodBase

if TYPE_CHECKING:
from .schemes.base import INCLinearScheme


class INCLinearMethod(LinearMethodBase):
def __init__(self, scheme: "INCLinearScheme") -> None:
self.scheme = scheme

def create_weights(
self,
layer: torch.nn.Module,
input_size_per_partition: int,
output_partition_sizes: list[int],
input_size: int,
output_size: int,
params_dtype: torch.dtype,
**extra_weight_attrs,
):
return self.scheme.create_weights(
layer=layer,
input_size_per_partition=input_size_per_partition,
output_partition_sizes=output_partition_sizes,
input_size=input_size,
output_size=output_size,
params_dtype=params_dtype,
**extra_weight_attrs,
)

def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
return self.scheme.process_weights_after_loading(layer)

def apply(
self,
layer: torch.nn.Module,
x: torch.Tensor,
bias: torch.Tensor | None = None,
) -> torch.Tensor:
return self.scheme.apply_weights(layer, x, bias)
Loading
Loading