multimodalart's picture
multimodalart HF Staff
Initial ABot-World interactive rollout demo
28404e6 verified
Raw
History Blame Contribute Delete
6.44 kB
# Copyright 2025 Tencent Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import gc
import re
from typing import List, Optional, Union
import torch
__all__ = [
"replace_module",
"cleanup_memory",
"should_quantize_layer",
"_compile_pattern",
"_ensure_deep_gemm",
"_ensure_sgl_kernel",
"QuantType",
]
class QuantType:
FP8_PER_TENSOR = "fp8-per-tensor"
FP8_PER_TOKEN = "fp8-per-token"
FP8_PER_BLOCK = "fp8-per-block"
FP8_PER_CHANNEL_VLLM = "fp8-per-channel-vllm"
FP8_PER_TENSOR_WEIGHT_ONLY = "fp8-per-tensor-weight-only"
FP8_PER_TOKEN_SGL = "fp8-per-token-sgl"
INT8 = "int8"
INT8_TORCHAO = "int8-torchao"
INT8_VLLM = "int8-vllm"
INT8_TRITON = "int8-triton"
INT8_SGL = "int8-sgl"
INT8_Q8F = "int8-q8f"
NVFP4 = "nvfp4"
MXFP4 = "mxfp4"
MXFP6 = "mxfp6"
MXFP8 = "mxfp8"
VALID_TYPES = [
FP8_PER_TENSOR,
FP8_PER_TOKEN,
FP8_PER_BLOCK,
FP8_PER_CHANNEL_VLLM,
FP8_PER_TENSOR_WEIGHT_ONLY,
FP8_PER_TOKEN_SGL,
INT8,
INT8_TORCHAO,
INT8_VLLM,
INT8_TRITON,
INT8_SGL,
INT8_Q8F,
NVFP4,
MXFP4,
MXFP6,
MXFP8,
]
@classmethod
def validate(cls, quant_type: str):
if quant_type not in cls.VALID_TYPES:
raise ValueError(f"Invalid quant_type: {quant_type}. Valid types: {cls.VALID_TYPES}")
def replace_module(model: torch.nn.Module, name: str, new_module: torch.nn.Module):
"""
Replace a submodule in the model with a new module by name.
"""
if "." in name:
parent_name = name.rsplit(".", 1)[0]
child_name = name[len(parent_name) + 1 :]
parent = model.get_submodule(parent_name)
else:
parent_name = ""
parent = model
child_name = name
setattr(parent, child_name, new_module)
def cleanup_memory():
"""
Run garbage collection and clear CUDA memory cache.
"""
gc.collect()
torch.cuda.empty_cache()
def _compile_pattern(pattern: Union[str, re.Pattern], case_sensitive: bool = False) -> re.Pattern:
"""
Compile a pattern (string or pre-compiled pattern) into a regex pattern object.
Args:
pattern: String pattern or already-compiled regex pattern.
case_sensitive: Whether the match is case sensitive.
Returns:
Compiled regex pattern object.
"""
if isinstance(pattern, str):
# If the string contains special regex characters, treat as regex.
if any(char in pattern for char in ".*+?^${}[]|()\\"):
flags = 0 if case_sensitive else re.IGNORECASE
return re.compile(pattern, flags)
else:
# Escape regular string so it matches literally.
escaped = re.escape(pattern)
flags = 0 if case_sensitive else re.IGNORECASE
return re.compile(escaped, flags)
else:
# Already a compiled pattern.
return pattern
def should_quantize_layer(
layer_name: str,
include_patterns: Optional[List[Union[str, re.Pattern]]] = None,
exclude_patterns: Optional[List[Union[str, re.Pattern]]] = None,
case_sensitive: bool = False,
) -> bool:
"""
Decide whether a layer should be quantized based on inclusion/exclusion patterns.
Args:
layer_name: Name of the layer.
include_patterns: List of patterns (str or regex) to include.
exclude_patterns: List of patterns (str or regex) to exclude.
case_sensitive: Whether patterns are matched case sensitively.
Returns:
bool: Whether this layer should be quantized.
Note:
String patterns are auto-detected as regex if they include special chars:
- If contains any . * + ? ^ $ { } [ ] | ( ) \\ -> treated as regex
- Otherwise, escaped and matched literally
"""
if include_patterns is None:
include_patterns = []
if exclude_patterns is None:
exclude_patterns = []
# Check exclusion patterns
for pattern in exclude_patterns:
compiled_pattern = _compile_pattern(pattern, case_sensitive)
if compiled_pattern.search(layer_name):
return False
# If no include patterns, default is to include all layers
if not include_patterns:
return True
# Check inclusion patterns
for pattern in include_patterns:
compiled_pattern = _compile_pattern(pattern, case_sensitive)
if compiled_pattern.search(layer_name):
return True
return False
_deep_gemm_cached = None
def _ensure_deep_gemm():
"""
Lazy, safe import of deep_gemm with process-level caching. Returns the module
if available, otherwise raises a clear error.
"""
global _deep_gemm_cached
if _deep_gemm_cached is not None:
return _deep_gemm_cached
try:
import deep_gemm
_deep_gemm_cached = deep_gemm
return _deep_gemm_cached
except ImportError as e:
raise ImportError(
(
"deep_gemm is required for 'fp8-per-block' quantization with "
"native_fp8_support, but was not found. Please install deep_gemm first."
)
) from e
_sgl_kernel_cached = None
def _ensure_sgl_kernel():
"""
Lazy, safe import of sgl_kernel with process-level caching. Returns the module
if available, otherwise raises a clear error.
"""
global _sgl_kernel_cached
if _sgl_kernel_cached is not None:
return _sgl_kernel_cached
try:
import sgl_kernel
_sgl_kernel_cached = sgl_kernel
return _sgl_kernel_cached
except ImportError as e:
raise ImportError(
(
"sgl_kernel is required for 'fp8-per-token-sgl' quantization with "
"native_fp8_support, but was not found. Please install sgl_kernel first"
)
) from e