Fix manual mapping registration and kimi_k2 layer name mapping (#7347)
### What this PR does / why we need it?
This PR fixes the layer name mapping logic in `AscendModelSlimConfig`
for quantization config loading.
1. **kimi_k2 model layer name mapping issue**: The `kimi_k2` model has a
unique layer naming convention that differs from the standard
`hf_to_vllm` mapping. One layer was defined in the mapper but was not
being correctly applied, causing quantization config lookup failures.
2. **Manual mapping registration timing issue**: The manual mapping
check in `apply_vllm_mapper` was executed before `vllm_config` was
initialized, causing `model_type` to be unavailable. This prevented some
models with manual mappings from being correctly registered.
### Does this PR introduce _any_ user-facing change?
NO
### How was this patch tested?
Tested with `kimi_k2` model to verify the special layer name mapping
works correctly. Also tested with other models that have manual mappings
defined in `QUANT_MODEL_PREFIX_MAPPINGS` to ensure the registration
timing fix works properly.
- vLLM version: v0.17.0
- vLLM main:
4034c3d32e
---------
Signed-off-by: Matrix_K <zhangke144@huawei.com>
Signed-off-by: Feng-xiaosuo <tengchang1@huawei.com>
Co-authored-by: Matrix_K <zhangke144@huawei.com>
Co-authored-by: Wang Kunpeng <1289706727@qq.com>
This commit is contained in:
@@ -50,7 +50,8 @@ MODELSLIM_CONFIG_FILENAME = "quant_model_description.json"
|
|||||||
logger = init_logger(__name__)
|
logger = init_logger(__name__)
|
||||||
|
|
||||||
# key: model_type
|
# key: model_type
|
||||||
# value: orig_to_new_prefix
|
# value: vLLM prefix -> HF prefix mapping (used to convert vLLM layer names to HF format
|
||||||
|
# for looking up keys in quant_model_description.json)
|
||||||
QUANT_MODEL_PREFIX_MAPPINGS: dict[str, dict[str, str]] = {
|
QUANT_MODEL_PREFIX_MAPPINGS: dict[str, dict[str, str]] = {
|
||||||
"qwen3_vl_moe": {
|
"qwen3_vl_moe": {
|
||||||
"visual.": "model.visual.",
|
"visual.": "model.visual.",
|
||||||
@@ -78,6 +79,8 @@ QUANT_MODEL_PREFIX_MAPPINGS: dict[str, dict[str, str]] = {
|
|||||||
},
|
},
|
||||||
"qwen2_5_omni_text": {
|
"qwen2_5_omni_text": {
|
||||||
"language_model.": "thinker.",
|
"language_model.": "thinker.",
|
||||||
|
"language_model.lm_head.": "thinker.lm_head.",
|
||||||
|
"language_model.model.": "thinker.model.",
|
||||||
},
|
},
|
||||||
"glm4v_moe": {
|
"glm4v_moe": {
|
||||||
"visual.": "model.visual.",
|
"visual.": "model.visual.",
|
||||||
@@ -89,15 +92,11 @@ QUANT_MODEL_PREFIX_MAPPINGS: dict[str, dict[str, str]] = {
|
|||||||
"language_model.lm_head.": "lm_head.",
|
"language_model.lm_head.": "lm_head.",
|
||||||
"language_model.model.": "model.language_model.",
|
"language_model.model.": "model.language_model.",
|
||||||
},
|
},
|
||||||
"qwen3_5": {
|
"kimi_k2": {
|
||||||
"visual.": "model.visual.",
|
"language_model.layers.": "language_model.model.layers.",
|
||||||
"language_model.lm_head.": "lm_head.",
|
# mm projector
|
||||||
"language_model.model.": "model.language_model.",
|
"mm_projector.proj.0": "mm_projector.linear_1",
|
||||||
},
|
"mm_projector.proj.2": "mm_projector.linear_2",
|
||||||
"qwen3_5_moe": {
|
|
||||||
"visual.": "model.visual.",
|
|
||||||
"language_model.lm_head.": "lm_head.",
|
|
||||||
"language_model.model.": "model.language_model.",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,6 +439,10 @@ class AscendModelSlimConfig(QuantizationConfig):
|
|||||||
new_k = k.replace("weight_packed", "weight")
|
new_k = k.replace("weight_packed", "weight")
|
||||||
extra_quant_dict[new_k] = self.quant_description[k]
|
extra_quant_dict[new_k] = self.quant_description[k]
|
||||||
self.quant_description.update(extra_quant_dict)
|
self.quant_description.update(extra_quant_dict)
|
||||||
|
# Initialize attributes for type checking
|
||||||
|
self.model_type: str | None = None
|
||||||
|
self.hf_to_vllm_mapper: WeightsMapper | None = None
|
||||||
|
self.vllm_to_hf_mapper: WeightsMapper | None = None
|
||||||
self._add_kvcache_quant_metadata()
|
self._add_kvcache_quant_metadata()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
@@ -478,12 +481,73 @@ class AscendModelSlimConfig(QuantizationConfig):
|
|||||||
return ASCEND_QUANTIZATION_METHOD
|
return ASCEND_QUANTIZATION_METHOD
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# TODO: Modify the key values in self.quant_description instead of flipping the hf_to_vllm_mapper
|
||||||
|
def apply_vllm_mapper(self, hf_to_vllm_mapper: "WeightsMapper"):
|
||||||
|
"""Apply the vLLM model-specific mapper to this quantization config.
|
||||||
|
|
||||||
|
This method is called by vLLM to apply the model-specific weight mapper
|
||||||
|
to the quantization configuration. It creates a reverse mapper to convert
|
||||||
|
vLLM prefixes back to HF format for looking up keys in quant_config.json.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
hf_to_vllm_mapper: The WeightsMapper instance provided by vLLM
|
||||||
|
that contains model-specific prefix mappings (HF to vLLM).
|
||||||
|
"""
|
||||||
|
# Check if we already have a valid vllm_to_hf_mapper for this hf_to_vllm_mapper
|
||||||
|
if hasattr(self, "hf_to_vllm_mapper") and self.hf_to_vllm_mapper is hf_to_vllm_mapper:
|
||||||
|
# Same mapper instance, no need to recreate
|
||||||
|
return
|
||||||
|
|
||||||
|
# Store the original mapper
|
||||||
|
self.hf_to_vllm_mapper = hf_to_vllm_mapper
|
||||||
|
|
||||||
|
# Try different ways to get the mapping based on WeightsMapper implementation
|
||||||
|
mapping_attrs = ["orig_to_new_prefix"]
|
||||||
|
orig_to_new_prefix = {}
|
||||||
|
|
||||||
|
for attr_name in mapping_attrs:
|
||||||
|
if hasattr(hf_to_vllm_mapper, attr_name):
|
||||||
|
orig_to_new_prefix = getattr(hf_to_vllm_mapper, attr_name)
|
||||||
|
break
|
||||||
|
|
||||||
|
# Create reverse mapping (vLLM -> HF), skipping empty values
|
||||||
|
vllm_to_hf_mapping = {}
|
||||||
|
for orig_prefix, new_prefix in orig_to_new_prefix.items():
|
||||||
|
# Skip empty values to avoid invalid keys in reverse mapping
|
||||||
|
if new_prefix:
|
||||||
|
vllm_to_hf_mapping[new_prefix] = orig_prefix
|
||||||
|
|
||||||
|
# Create and store the reverse WeightsMapper instance
|
||||||
|
if vllm_to_hf_mapping:
|
||||||
|
self.vllm_to_hf_mapper = WeightsMapper(orig_to_new_prefix=vllm_to_hf_mapping)
|
||||||
|
logger.debug(f"Created reverse mapping from hf_to_vllm_mapper: {vllm_to_hf_mapping}")
|
||||||
|
else:
|
||||||
|
logger.info("No valid reverse mapping found for WeightsMapper.")
|
||||||
|
|
||||||
def quant_prefix_mapper(self, model_type: str, prefix: str) -> str:
|
def quant_prefix_mapper(self, model_type: str, prefix: str) -> str:
|
||||||
# TODO (Levi-JQ): will be removed when QuantizationConfig.apply_vllm_mapper is implemented
|
# Store model_type for reference
|
||||||
|
self.model_type = model_type
|
||||||
|
|
||||||
|
# Check if manual mapping exists for this model type
|
||||||
|
# Manual mapping takes priority and is used exclusively to avoid conflicts
|
||||||
|
if model_type in QUANT_MODEL_PREFIX_MAPPINGS:
|
||||||
|
manual_mapping = QUANT_MODEL_PREFIX_MAPPINGS[model_type]
|
||||||
|
# Manual mapping is already in vLLM -> HF direction, use directly
|
||||||
|
mapper = WeightsMapper(orig_to_new_prefix=manual_mapping)
|
||||||
|
return mapper._map_name(prefix)
|
||||||
|
|
||||||
|
# Use the reverse mapper (vLLM to HF) if available
|
||||||
|
if hasattr(self, "vllm_to_hf_mapper") and self.vllm_to_hf_mapper:
|
||||||
|
return self.vllm_to_hf_mapper._map_name(prefix)
|
||||||
|
|
||||||
|
# Fall back to manual mapping for backward compatibility (simplified)
|
||||||
|
# This is only used if apply_vllm_mapper wasn't called or failed
|
||||||
prefix_mapping = QUANT_MODEL_PREFIX_MAPPINGS.get(model_type)
|
prefix_mapping = QUANT_MODEL_PREFIX_MAPPINGS.get(model_type)
|
||||||
if prefix_mapping:
|
if prefix_mapping:
|
||||||
hf_to_vllm_mapper = WeightsMapper(orig_to_new_prefix=prefix_mapping)
|
# Manual mapping is already in vLLM -> HF direction, use directly
|
||||||
return hf_to_vllm_mapper._map_name(prefix)
|
mapper = WeightsMapper(orig_to_new_prefix=prefix_mapping)
|
||||||
|
return mapper._map_name(prefix)
|
||||||
|
|
||||||
return prefix
|
return prefix
|
||||||
|
|
||||||
def get_quant_method(self, layer: torch.nn.Module, prefix: str) -> Optional["QuantizeMethodBase"]:
|
def get_quant_method(self, layer: torch.nn.Module, prefix: str) -> Optional["QuantizeMethodBase"]:
|
||||||
@@ -512,9 +576,6 @@ class AscendModelSlimConfig(QuantizationConfig):
|
|||||||
self.packed_modules_mapping = packed_modules_model_mapping[model_type]
|
self.packed_modules_mapping = packed_modules_model_mapping[model_type]
|
||||||
prefix = self.quant_prefix_mapper(model_type, prefix)
|
prefix = self.quant_prefix_mapper(model_type, prefix)
|
||||||
|
|
||||||
if model_type != "kimi_k2":
|
|
||||||
if prefix.startswith("language_model"):
|
|
||||||
prefix = prefix.split(".", 1)[-1]
|
|
||||||
if isinstance(layer, LinearBase):
|
if isinstance(layer, LinearBase):
|
||||||
if self.is_layer_skipped_ascend(prefix, self.packed_modules_mapping):
|
if self.is_layer_skipped_ascend(prefix, self.packed_modules_mapping):
|
||||||
# Delayed import to avoid circular import
|
# Delayed import to avoid circular import
|
||||||
|
|||||||
Reference in New Issue
Block a user