Repository navigation
[quant][autoround]Refactor INC quantization into package with INCScheme orchestrator #40601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
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 069881c
merge main
yiliu30 d461f02
adapt ark linear
yiliu30 757d3a8
fix
yiliu30 e62e16a
adapt gptq update
yiliu30 3fef0b9
Merge branch 'main' into inc-refactor
yiliu30 002e58d
Merge branch 'main' into inc-refactor
yiliu30 00ce39e
Merge branch 'main' into inc-refactor
yiliu30 db41ea3
add inc back (tmp)
yiliu30 85aa9a8
Fix false substring match in INCConfig.get_layer_config step 4
n1ck-guo 849f486
Address review: use helper to check exact+regex match in step 4 guard
n1ck-guo c5d05f6
porting fix
yiliu30 da03e89
clean
yiliu30 4ac9b84
fix format
yiliu30 5b8faa2
Merge branch 'main' into inc-refactor
yiliu30 668d904
Merge branch 'main' into inc-refactor
yiliu30 0739fd4
rename resolve to parser
yiliu30 41c71f5
Merge branch 'main' into inc-refactor
yiliu30 e6c7317
update
yiliu30 41b1469
fix
yiliu30 d1eba07
fix format
yiliu30 8182975
Merge branch 'main' into inc-refactor
yiliu30 d16dedd
clean
yiliu30 03460a1
align naming
yiliu30 e337c6e
update
yiliu30 e063b35
Merge branch 'main' into inc-refactor
yiliu30 6c376de
Merge branch 'main' into inc-refactor
yiliu30 5da3ce5
Merge branch 'main' into inc-refactor
yiliu30 a4ed59a
add test to ci
yiliu30 ca4527f
add test
yiliu30 5fdca35
update
yiliu30 1068eda
Merge branch 'main' into inc-refactor
yiliu30 ba428ea
fix ut
yiliu30 b191396
Merge branch 'inc-refactor' of https://github.com/yiliu30/vllm-fork i…
yiliu30 70af126
fix
yiliu30 44edf8b
Merge branch 'main' into inc-refactor
yiliu30 6a09808
update ARK API
Zhenzhong1 bd23dcb
update ARK API
Zhenzhong1 cf44dd7
update ARK API
Zhenzhong1 06373cb
Merge branch 'main' into inc-refactor
yiliu30 59dd25e
Merge pull request #118 from yiliu30/inc-refactor-ARK-update
Zhenzhong1 669fe5b
Merge branch 'main' into inc-refactor
Zhenzhong1 af09bef
Merge branch 'main' into inc-refactor
yiliu30 ac3d90c
Merge branch 'main' into inc-refactor
yiliu30 d2e7511
adpat main
yiliu30 1afa4fc
fix
yiliu30 f971058
fix
yiliu30 a72f009
Merge branch 'main' into inc-refactor
yiliu30 35d8dd5
Merge branch 'main' into inc-refactor
yiliu30 906cb7d
Merge branch 'main' into inc-refactor
yiliu30 27996c4
upgrade auto-round-lib
yiliu30 b08de02
Merge branch 'main' into inc-refactor
yiliu30 2c6f51e
Merge branch 'main' into inc-refactor
yiliu30 2445297
Merge branch 'main' into inc-refactor
yiliu30 f57ad8e
Merge branch 'main' into inc-refactor
yiliu30 50d8a74
Merge branch 'main' into inc-refactor
yiliu30 c8cf10f
Merge branch 'main' into inc-refactor
yiliu30 0561f29
refine test
yiliu30 2c23264
Merge branch 'main' into inc-refactor
yiliu30 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | ||
| ``` | ||
|
|
||
| ## 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. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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() | ||
|
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 | ||
|
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 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.