Add Intel Quantization Support in SGLang (#18139)
Signed-off-by: Mengni Wang <mengni.wang@intel.com> Signed-off-by: WeiweiZhang1 <weiwei1.zhang@intel.com> Co-authored-by: Peng Zhang <aniz1905@gmail.com> Co-authored-by: Ma Mingfei <mingfei.ma@intel.com> Co-authored-by: Weiwei <weiwei1.zhang@intel.com>
This commit is contained in:
co-authored by
Peng Zhang
Ma Mingfei
Weiwei
parent
10ff3c1dcb
commit
cfc0a0e0e0
@@ -139,6 +139,7 @@ fastokens = [
|
||||
test = [
|
||||
"accelerate",
|
||||
"addict",
|
||||
"auto-round>=0.13.1",
|
||||
"bitsandbytes",
|
||||
"diff-cover",
|
||||
"expecttest",
|
||||
|
||||
@@ -91,6 +91,11 @@ class LoadConfig:
|
||||
# ModelOpt configuration object
|
||||
modelopt_config: Optional[ModelOptConfig] = None
|
||||
|
||||
# Inc-related loading options
|
||||
inc_save_path: Optional[str] = None
|
||||
inc_tuning_iters: Optional[int] = 0
|
||||
inc_disable_opt_rtn: Optional[bool] = None
|
||||
|
||||
# QuantizedRL-specific options (for FlashRL-style quantization)
|
||||
rl_quant_profile: Optional[str] = (
|
||||
None # Path to rollout quantization profile (e.g., /root/profile.7b.pt)
|
||||
|
||||
@@ -1187,9 +1187,12 @@ class ModelConfig:
|
||||
return True
|
||||
|
||||
# Check for HuggingFace quantization config
|
||||
from sglang.srt.utils import has_hf_quant_config
|
||||
quant_cfg = getattr(self.hf_config, "quantization_config", None)
|
||||
if quant_cfg is None:
|
||||
from sglang.srt.utils import has_hf_quant_config
|
||||
|
||||
return has_hf_quant_config(self.model_path)
|
||||
return has_hf_quant_config(self.model_path)
|
||||
return True
|
||||
|
||||
def _get_modelopt_quant_type(self) -> str:
|
||||
"""Extract ModelOpt quantization type from unified quantization flag."""
|
||||
@@ -1269,6 +1272,7 @@ class ModelConfig:
|
||||
"mxfp4",
|
||||
"mxfp8",
|
||||
"auto-round",
|
||||
"auto-round-int8",
|
||||
"quark_int4fp8_moe",
|
||||
"quark_mxfp4",
|
||||
]
|
||||
@@ -1304,6 +1308,7 @@ class ModelConfig:
|
||||
"petit_nvfp4": ["modelopt"],
|
||||
"w8a8_int8": ["compressed-tensors", "compressed_tensors"],
|
||||
"w8a8_fp8": ["compressed-tensors", "compressed_tensors"],
|
||||
"auto-round-int8": ["compressed-tensors", "compressed_tensors"],
|
||||
}
|
||||
if self.quantization is not None:
|
||||
self.quantization = self.quantization.lower()
|
||||
|
||||
@@ -95,6 +95,7 @@ BASE_QUANTIZATION_METHODS: Dict[str, Type[QuantizationConfig]] = {
|
||||
"quark": QuarkConfig,
|
||||
"quark_mxfp4": QuarkConfig,
|
||||
"auto-round": AutoRoundConfig,
|
||||
"auto-round-int8": W8A8Int8Config,
|
||||
"modelslim": ModelSlimConfig,
|
||||
"quark_int4fp8_moe": QuarkInt4Fp8Config,
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import math
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
from abc import ABC, abstractmethod
|
||||
@@ -2581,6 +2582,110 @@ def load_model_with_cpu_quantization(
|
||||
return model.eval()
|
||||
|
||||
|
||||
class IncModelLoader(DefaultModelLoader):
|
||||
"""
|
||||
Model loader that applies Intel AutoRound quantization
|
||||
"""
|
||||
|
||||
def __init__(self, load_config: LoadConfig):
|
||||
super().__init__(load_config)
|
||||
|
||||
def load_model(
|
||||
self,
|
||||
*,
|
||||
model_config: ModelConfig,
|
||||
device_config: DeviceConfig,
|
||||
) -> nn.Module:
|
||||
|
||||
logger.info("IncModelLoader: Loading model...")
|
||||
|
||||
# Check if model is already quantized
|
||||
if model_config._is_already_quantized():
|
||||
logger.info("Model is already quantized, loading directly...")
|
||||
# Use default loading for pre-quantized models
|
||||
return super().load_model(
|
||||
model_config=model_config, device_config=device_config
|
||||
)
|
||||
|
||||
quant_model = self._autoround_quantization_workflow(model_config, device_config)
|
||||
|
||||
target_device = torch.device(device_config.device)
|
||||
|
||||
# Return autoround model for offline quantization mode
|
||||
if self.load_config.inc_save_path is not None:
|
||||
quant_model.to(target_device)
|
||||
return quant_model.eval()
|
||||
|
||||
model_config.hf_config = quant_model.config
|
||||
quant_config = _get_quantization_config(model_config, self.load_config)
|
||||
|
||||
with set_default_torch_dtype(model_config.dtype):
|
||||
with target_device:
|
||||
model = _initialize_model(
|
||||
model_config,
|
||||
self.load_config,
|
||||
quant_config,
|
||||
)
|
||||
|
||||
self.load_weights_and_postprocess(
|
||||
model, iter(quant_model.state_dict().items()), target_device
|
||||
)
|
||||
return model.eval()
|
||||
|
||||
def _parse_quantization(self, quantization: str):
|
||||
"""Map quantization to AutoRound's scheme and format."""
|
||||
AR_QUANT_CFG_CHOICES = {
|
||||
"auto-round-int8": ("INT8", "llm_compressor"),
|
||||
}
|
||||
quant_cfg = AR_QUANT_CFG_CHOICES.get(quantization)
|
||||
if not quant_cfg:
|
||||
raise ValueError(
|
||||
f"Invalid quantization choice: '{quantization}'. "
|
||||
f"Available choices: {list(AR_QUANT_CFG_CHOICES.keys())}"
|
||||
)
|
||||
return quant_cfg
|
||||
|
||||
def _autoround_quantization_workflow(
|
||||
self, model_config: ModelConfig, device_config: DeviceConfig
|
||||
) -> nn.Module:
|
||||
"""Auto-round quantization workflow: quantize, save checkpoint, then return model."""
|
||||
try:
|
||||
from auto_round import AutoRound
|
||||
except ImportError:
|
||||
logger.error(
|
||||
"auto-round library not found. "
|
||||
"Please install it using `pip install auto-round` to use AutoRound quantization."
|
||||
)
|
||||
raise
|
||||
|
||||
scheme, format = self._parse_quantization(model_config.quantization)
|
||||
|
||||
try:
|
||||
autoround = AutoRound(
|
||||
model_config.model_path,
|
||||
scheme=scheme,
|
||||
iters=self.load_config.inc_tuning_iters,
|
||||
disable_opt_rtn=self.load_config.inc_disable_opt_rtn,
|
||||
low_cpu_mem_usage=False,
|
||||
)
|
||||
if self.load_config.inc_save_path is not None:
|
||||
logger.info("Offline quantization mode: Will quantize and save")
|
||||
model, _ = autoround.quantize_and_save(
|
||||
output_dir=self.load_config.inc_save_path, format=format
|
||||
)
|
||||
return model
|
||||
else:
|
||||
logger.info("Online quantization mode: Will quantize and skip saving")
|
||||
# Use a temporary directory and discard it so nothing is persisted in online mode.
|
||||
with tempfile.TemporaryDirectory() as tmp_save_dir:
|
||||
model, _ = autoround.quantize_and_save(
|
||||
output_dir=tmp_save_dir, format=format
|
||||
)
|
||||
return model
|
||||
except Exception as e:
|
||||
raise ValueError(f"AutoRound quantization failed: {e}")
|
||||
|
||||
|
||||
class ModelOptModelLoader(DefaultModelLoader):
|
||||
"""
|
||||
Model loader that applies NVIDIA Model Optimizer quantization
|
||||
@@ -3102,6 +3207,10 @@ def get_model_loader(
|
||||
if load_config.load_format == LoadFormat.DUMMY:
|
||||
return DummyModelLoader(load_config)
|
||||
|
||||
if model_config and model_config.quantization in ["auto-round-int8"]:
|
||||
logger.info("Using IncModelLoader due to AutoRound quantization config.")
|
||||
return IncModelLoader(load_config)
|
||||
|
||||
# ModelOptModelLoader's local-copy quantize-and-export workflow doesn't apply
|
||||
# to non-local loaders. These loaders own their weight transport path and still
|
||||
# initialize the model with ModelOpt quantization config where applicable.
|
||||
|
||||
@@ -163,6 +163,7 @@ QUANTIZATION_CHOICES = [
|
||||
"w4afp8",
|
||||
"mxfp4", # MOE-only.
|
||||
"auto-round",
|
||||
"auto-round-int8",
|
||||
"compressed-tensors", # for Ktransformers
|
||||
"modelslim", # for NPU
|
||||
"quark", # AMD Quark quantizer (FP8 / MXFP4 / Int4FP8 etc.)
|
||||
|
||||
Reference in New Issue
Block a user