fix qwenvl compressed tensors quantization weight loader (#11914)
Signed-off-by: LHXuuu <xulianhao.xlh@antgroup.com> Co-authored-by: Peng Zhang <aniz1905@gmail.com>
This commit is contained in:
@@ -11,6 +11,7 @@ from torch import nn
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from sglang.srt.layers.moe.moe_runner import MoeRunnerConfig
|
from sglang.srt.layers.moe.moe_runner import MoeRunnerConfig
|
||||||
from sglang.srt.layers.moe.token_dispatcher import CombineInput, DispatchOutput
|
from sglang.srt.layers.moe.token_dispatcher import CombineInput, DispatchOutput
|
||||||
|
from sglang.srt.models.utils import WeightsMapper
|
||||||
|
|
||||||
|
|
||||||
class QuantizeMethodBase(ABC):
|
class QuantizeMethodBase(ABC):
|
||||||
@@ -229,6 +230,15 @@ class QuantizationConfig(ABC):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def apply_sglang_mapper(self, hf_to_sglang_mapper: "WeightsMapper"): # noqa: B027
|
||||||
|
"""
|
||||||
|
Interface for models to update module names referenced in
|
||||||
|
quantization configs in order to reflect the sglang model structure
|
||||||
|
:param hf_to_sglang_mapper: maps from hf model structure (the assumed
|
||||||
|
structure of the qconfig) to sglang model structure
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def method_has_implemented_embedding(method_class: Type[QuantizeMethodBase]) -> bool:
|
def method_has_implemented_embedding(method_class: Type[QuantizeMethodBase]) -> bool:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -4,7 +4,17 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from typing import Any, Dict, List, Literal, NamedTuple, Optional, Tuple, cast
|
from typing import (
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Any,
|
||||||
|
Dict,
|
||||||
|
List,
|
||||||
|
Literal,
|
||||||
|
NamedTuple,
|
||||||
|
Optional,
|
||||||
|
Tuple,
|
||||||
|
cast,
|
||||||
|
)
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
from compressed_tensors.config import (
|
from compressed_tensors.config import (
|
||||||
@@ -44,6 +54,9 @@ from sglang.srt.layers.quantization.compressed_tensors.utils import (
|
|||||||
from sglang.srt.layers.quantization.fp8 import Fp8LinearMethod
|
from sglang.srt.layers.quantization.fp8 import Fp8LinearMethod
|
||||||
from sglang.srt.layers.quantization.unquant import UnquantizedLinearMethod
|
from sglang.srt.layers.quantization.unquant import UnquantizedLinearMethod
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from sglang.srt.models.utils import WeightsMapper
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
__all__ = ["CompressedTensorsLinearMethod"]
|
__all__ = ["CompressedTensorsLinearMethod"]
|
||||||
@@ -110,6 +123,18 @@ class CompressedTensorsConfig(QuantizationConfig):
|
|||||||
def get_scaled_act_names(self) -> List[str]:
|
def get_scaled_act_names(self) -> List[str]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def apply_sglang_mapper(self, hf_to_sglang_mapper: "WeightsMapper"):
|
||||||
|
self.target_scheme_map = hf_to_sglang_mapper.apply_dict(self.target_scheme_map)
|
||||||
|
self.ignore = hf_to_sglang_mapper.apply_list(self.ignore)
|
||||||
|
self.sparsity_scheme_map = hf_to_sglang_mapper.apply_dict(
|
||||||
|
self.sparsity_scheme_map
|
||||||
|
)
|
||||||
|
self.sparsity_ignore_list = hf_to_sglang_mapper.apply_list(
|
||||||
|
self.sparsity_ignore_list
|
||||||
|
)
|
||||||
|
if self.kv_cache_scheme is not None:
|
||||||
|
self.kv_cache_scheme = hf_to_sglang_mapper.apply_dict(self.kv_cache_scheme)
|
||||||
|
|
||||||
def get_quant_method(
|
def get_quant_method(
|
||||||
self,
|
self,
|
||||||
layer: torch.nn.Module,
|
layer: torch.nn.Module,
|
||||||
|
|||||||
@@ -257,6 +257,10 @@ def _initialize_model(
|
|||||||
quant_config = _get_quantization_config(
|
quant_config = _get_quantization_config(
|
||||||
model_config, load_config, packed_modules_mapping, remap_prefix
|
model_config, load_config, packed_modules_mapping, remap_prefix
|
||||||
)
|
)
|
||||||
|
hf_to_sglang_mapper = getattr(model_class, "hf_to_sglang_mapper", None)
|
||||||
|
# pass mappings by reference to quant_config
|
||||||
|
if hf_to_sglang_mapper is not None and quant_config is not None:
|
||||||
|
quant_config.apply_sglang_mapper(hf_to_sglang_mapper)
|
||||||
|
|
||||||
# Build kwargs conditionally
|
# Build kwargs conditionally
|
||||||
kwargs = {
|
kwargs = {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ from sglang.srt.managers.schedule_batch import (
|
|||||||
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, PPProxyTensors
|
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, PPProxyTensors
|
||||||
from sglang.srt.model_loader.weight_utils import default_weight_loader
|
from sglang.srt.model_loader.weight_utils import default_weight_loader
|
||||||
from sglang.srt.models.qwen2 import Qwen2Model
|
from sglang.srt.models.qwen2 import Qwen2Model
|
||||||
from sglang.srt.models.utils import RotaryPosMixin, permute_inv
|
from sglang.srt.models.utils import RotaryPosMixin, WeightsMapper, permute_inv
|
||||||
from sglang.srt.multimodal.mm_utils import run_dp_sharded_mrope_vision_model
|
from sglang.srt.multimodal.mm_utils import run_dp_sharded_mrope_vision_model
|
||||||
from sglang.srt.multimodal.vit_cuda_graph_runner import ViTCudaGraphRunner
|
from sglang.srt.multimodal.vit_cuda_graph_runner import ViTCudaGraphRunner
|
||||||
from sglang.srt.server_args import get_global_server_args
|
from sglang.srt.server_args import get_global_server_args
|
||||||
@@ -547,6 +547,24 @@ class Qwen2_5_VLForConditionalGeneration(nn.Module):
|
|||||||
"up_proj": ("gate_up_proj", 1),
|
"up_proj": ("gate_up_proj", 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packed_modules_mapping = {
|
||||||
|
"gate_up_proj": ["gate_proj", "up_proj"],
|
||||||
|
}
|
||||||
|
# To ensure correct weight loading and mapping.
|
||||||
|
hf_to_sglang_mapper = WeightsMapper(
|
||||||
|
orig_to_new_substr={
|
||||||
|
"attn.qkv": "attn.qkv_proj",
|
||||||
|
},
|
||||||
|
orig_to_new_prefix={
|
||||||
|
# mapping for new names in checkpoint saved after transformers v4.52
|
||||||
|
"model.language_model.": "language_model.model.",
|
||||||
|
"model.visual.": "visual.",
|
||||||
|
# mapping for original checkpoint
|
||||||
|
"lm_head.": "language_model.lm_head.",
|
||||||
|
"model.": "language_model.model.",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
config: Qwen2_5_VLConfig,
|
config: Qwen2_5_VLConfig,
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ from sglang.srt.managers.schedule_batch import MultimodalDataItem, MultimodalInp
|
|||||||
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
|
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
|
||||||
from sglang.srt.model_loader.weight_utils import default_weight_loader
|
from sglang.srt.model_loader.weight_utils import default_weight_loader
|
||||||
from sglang.srt.models.qwen2 import Qwen2Model
|
from sglang.srt.models.qwen2 import Qwen2Model
|
||||||
from sglang.srt.models.utils import compute_cu_seqlens_from_grid_numpy
|
from sglang.srt.models.utils import WeightsMapper, compute_cu_seqlens_from_grid_numpy
|
||||||
from sglang.srt.utils import add_prefix
|
from sglang.srt.utils import add_prefix
|
||||||
from sglang.srt.utils.hf_transformers_utils import get_processor
|
from sglang.srt.utils.hf_transformers_utils import get_processor
|
||||||
|
|
||||||
@@ -426,6 +426,21 @@ class Qwen2VLForConditionalGeneration(nn.Module):
|
|||||||
"up_proj": ("gate_up_proj", 1),
|
"up_proj": ("gate_up_proj", 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# To ensure correct weight loading and mapping.
|
||||||
|
hf_to_sglang_mapper = WeightsMapper(
|
||||||
|
orig_to_new_substr={
|
||||||
|
"attn.qkv": "attn.qkv_proj",
|
||||||
|
},
|
||||||
|
orig_to_new_prefix={
|
||||||
|
# mapping for new names in checkpoint saved after transformers v4.52
|
||||||
|
"model.language_model.": "language_model.model.",
|
||||||
|
"model.visual.": "visual.",
|
||||||
|
# mapping for original checkpoint
|
||||||
|
"lm_head.": "language_model.lm_head.",
|
||||||
|
"model.": "language_model.model.",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
config: Qwen2VLConfig,
|
config: Qwen2VLConfig,
|
||||||
|
|||||||
@@ -53,7 +53,11 @@ from sglang.srt.managers.schedule_batch import (
|
|||||||
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, PPProxyTensors
|
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, PPProxyTensors
|
||||||
from sglang.srt.model_loader.weight_utils import default_weight_loader
|
from sglang.srt.model_loader.weight_utils import default_weight_loader
|
||||||
from sglang.srt.models.qwen3 import Qwen3Model
|
from sglang.srt.models.qwen3 import Qwen3Model
|
||||||
from sglang.srt.models.utils import RotaryPosMixin, compute_cu_seqlens_from_grid_numpy
|
from sglang.srt.models.utils import (
|
||||||
|
RotaryPosMixin,
|
||||||
|
WeightsMapper,
|
||||||
|
compute_cu_seqlens_from_grid_numpy,
|
||||||
|
)
|
||||||
from sglang.srt.multimodal.mm_utils import run_dp_sharded_mrope_vision_model
|
from sglang.srt.multimodal.mm_utils import run_dp_sharded_mrope_vision_model
|
||||||
from sglang.srt.server_args import get_global_server_args
|
from sglang.srt.server_args import get_global_server_args
|
||||||
from sglang.srt.utils import add_prefix, get_int_env_var
|
from sglang.srt.utils import add_prefix, get_int_env_var
|
||||||
@@ -594,6 +598,21 @@ class Qwen3LLMModel(Qwen3Model):
|
|||||||
|
|
||||||
|
|
||||||
class Qwen3VLForConditionalGeneration(nn.Module):
|
class Qwen3VLForConditionalGeneration(nn.Module):
|
||||||
|
# To ensure correct weight loading and mapping.
|
||||||
|
hf_to_sglang_mapper = WeightsMapper(
|
||||||
|
orig_to_new_substr={
|
||||||
|
"attn.qkv": "attn.qkv_proj",
|
||||||
|
},
|
||||||
|
orig_to_new_prefix={
|
||||||
|
# mapping for new names in checkpoint saved after transformers v4.52
|
||||||
|
"model.language_model.": "language_model.model.",
|
||||||
|
"model.visual.": "visual.",
|
||||||
|
# mapping for original checkpoint
|
||||||
|
"lm_head.": "language_model.lm_head.",
|
||||||
|
"model.": "language_model.model.",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
config: Qwen3VLConfig,
|
config: Qwen3VLConfig,
|
||||||
|
|||||||
@@ -12,7 +12,10 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
||||||
|
from collections.abc import Iterable, Mapping
|
||||||
|
from dataclasses import dataclass, field
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import torch
|
import torch
|
||||||
@@ -27,6 +30,74 @@ _is_cuda = is_cuda()
|
|||||||
if _is_cuda:
|
if _is_cuda:
|
||||||
from sgl_kernel import FusedSetKVBufferArg
|
from sgl_kernel import FusedSetKVBufferArg
|
||||||
|
|
||||||
|
WeightsMapping = Mapping[str, Optional[str]]
|
||||||
|
"""If a key maps to a value of `None`, the corresponding weight is ignored."""
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class WeightsMapper:
|
||||||
|
"""Maps the name of each weight if they match the following patterns."""
|
||||||
|
|
||||||
|
orig_to_new_substr: WeightsMapping = field(default_factory=dict)
|
||||||
|
orig_to_new_prefix: WeightsMapping = field(default_factory=dict)
|
||||||
|
orig_to_new_suffix: WeightsMapping = field(default_factory=dict)
|
||||||
|
|
||||||
|
def _map_name(self, key: str) -> Optional[str]:
|
||||||
|
for substr, new_key in sorted(
|
||||||
|
self.orig_to_new_substr.items(), key=lambda i: len(i[0]), reverse=True
|
||||||
|
):
|
||||||
|
if substr in key:
|
||||||
|
if new_key is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
key = key.replace(substr, new_key, 1)
|
||||||
|
break
|
||||||
|
|
||||||
|
for prefix, new_key in sorted(
|
||||||
|
self.orig_to_new_prefix.items(), key=lambda i: len(i[0]), reverse=True
|
||||||
|
):
|
||||||
|
if key.startswith(prefix):
|
||||||
|
if new_key is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
key = key.replace(prefix, new_key, 1)
|
||||||
|
break
|
||||||
|
|
||||||
|
for suffix, new_key in sorted(
|
||||||
|
self.orig_to_new_suffix.items(), key=lambda i: len(i[0]), reverse=True
|
||||||
|
):
|
||||||
|
if key.endswith(suffix):
|
||||||
|
if new_key is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
key = new_key.join(key.rsplit(suffix, 1))
|
||||||
|
break
|
||||||
|
|
||||||
|
return key
|
||||||
|
|
||||||
|
def apply(
|
||||||
|
self, weights: Iterable[tuple[str, torch.Tensor]]
|
||||||
|
) -> Iterable[tuple[str, torch.Tensor]]:
|
||||||
|
return (
|
||||||
|
(out_name, data)
|
||||||
|
for name, data in weights
|
||||||
|
if (out_name := self._map_name(name)) is not None
|
||||||
|
)
|
||||||
|
|
||||||
|
def apply_list(self, values: list[str]) -> list[str]:
|
||||||
|
return [
|
||||||
|
out_name
|
||||||
|
for name in values
|
||||||
|
if (out_name := self._map_name(name)) is not None
|
||||||
|
]
|
||||||
|
|
||||||
|
def apply_dict(self, values: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
out_name: value
|
||||||
|
for name, value in values.items()
|
||||||
|
if (out_name := self._map_name(name)) is not None
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def enable_fused_set_kv_buffer(forward_batch: ForwardBatch):
|
def enable_fused_set_kv_buffer(forward_batch: ForwardBatch):
|
||||||
"""Enable fused set_kv_buffer only on CUDA with bfloat16 KV cache."""
|
"""Enable fused set_kv_buffer only on CUDA with bfloat16 KV cache."""
|
||||||
|
|||||||
Reference in New Issue
Block a user