Files
wehub-resource-sync 2aaeece67c
Codestyle Check / Lint (push) Has been cancelled
Codestyle Check / Check bypass (push) Has been cancelled
Pipelines-Test / Pipelines-Test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:37:14 +08:00

234 lines
8.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Copyright (c) 2023 PaddlePaddle Authors. 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 copy
import json
from dataclasses import dataclass
quant_inference_mapping = {"avg": "abs_max", "abs_max_channel_wise": "abs_max_channel_wise", "abs_max": "abs_max"}
fp8_format_mapping = {
"hybrid": {"weight": "float8_e4m3fn", "activation": "float8_e4m3fn", "grad_output": "float8_e5m2"},
"e4m3": {"weight": "float8_e4m3fn", "activation": "float8_e4m3fn", "grad_output": "float8_e4m3fn"},
}
@dataclass
class QuantizationConfig:
"""
This is the configuration class to store quantization configuration.
Args:
weight_quantize_algo: Weight quantization algorithm.
quant_type: Quantization type applied to weight and activation, weight may still keep in float tensor.
shift: Whether the model applied the shift strategy.
smooth: Whether the model applied the smooth strategy.
shift_smooth_all_linears: Whether the model applied shift or smooth strategy for all linears.
quant_round_type: The quant round type, 0:-rounding to nearest ties to even 1: -rounding to nearest ties away from zero.
llm_int8_threshold: The threshold for llm.int8 quantization.
qlora_weight_double_quant: Whether quant weight scale.
qlora_weight_blocksize: Block size for weight quantization.
qlora_weight_double_quant_block_size: Block size for quant_scale of weight quant_scale.
weight_quant_method: The method for weight quantization.
act_quant_method: The method for activation quantization.
apply_online_actscale_step: Use online (per-step) activation scales for the first N steps. During these steps, activation scales are also collected to compute their mean for later use.
"""
def __init__(
self,
weight_quantize_algo=None,
quant_type=None,
shift=False,
smooth=False,
shift_smooth_all_linears=False,
quant_round_type=0,
llm_int8_threshold=6.0,
qlora_weight_double_quant=False,
qlora_weight_blocksize=64,
qlora_weight_double_quant_block_size=256,
weight_quant_method="abs_max_channel_wise",
act_quant_method="abs_max",
activation_scheme=None,
fmt=None,
quant_method=None,
weight_block_size=None,
dtype=None,
ignore_modules=None,
group_size=-1,
apply_hadamard=False,
hadamard_block_size=32,
quant_input_grad=False,
quant_weight_grad=False,
apply_online_actscale_step=200,
actscale_moving_rate=0.01,
fp8_format_type="hybrid",
scale_epsilon=1e-8,
**kwargs,
):
if weight_quantize_algo is not None:
if isinstance(weight_quantize_algo, dict):
if any(
algo
not in [
"weight_only_int8",
"weight_only_int4",
"llm.int8",
"a8w8",
"nf4",
"fp4",
"a8w8linear",
"a8w4linear",
"fp8linear",
]
for algo in weight_quantize_algo
):
raise ValueError(
f"weight_quantize_algo:{weight_quantize_algo.keys()} not in supported list ['weight_only_int8', 'weight_only_int4', 'llm.int8', 'a8w8', 'nf4', 'fp4']"
)
elif weight_quantize_algo not in [
"weight_only_int8",
"weight_only_int4",
"llm.int8",
"a8w8",
"nf4",
"fp4",
"a8w8linear",
"a8w4linear",
"fp8linear",
]:
raise ValueError(
f"weight_quantize_algo:{weight_quantize_algo} not in supported list ['weight_only_int8', 'weight_only_int4', 'llm.int8', 'a8w8', 'nf4', 'fp4']"
)
if quant_type is not None and quant_type not in [
"weight_only_int8",
"weight_only_int4",
"a8w8",
"a8w8c8",
"a8w8_fp8",
"a8w8c8_fp8",
]:
raise ValueError(
f"quant_type:{quant_type} not in supported list ['weight_only_int8', 'weight_only_int4', 'a8w8', 'a8w8c8', 'a8w8_fp8', 'a8w8c8_fp8']"
)
self.weight_quantize_algo = weight_quantize_algo
self.quant_type = quant_type
self.shift = shift
self.smooth = smooth
self.shift = shift
self.shift_smooth_all_linears = shift_smooth_all_linears
self.quant_round_type = quant_round_type
self.llm_int8_threshold = llm_int8_threshold
self.qlora_weight_double_quant = qlora_weight_double_quant
self.qlora_weight_blocksize = qlora_weight_blocksize
self.weight_quant_method = weight_quant_method
self.act_quant_method = quant_inference_mapping[act_quant_method]
self.qlora_weight_double_quant_block_size = qlora_weight_double_quant_block_size
self.activation_scheme = activation_scheme
self.fmt = fmt
self.quant_method = quant_method
self.weight_block_size = weight_block_size
self.dtype = dtype
self.ignore_modules = ignore_modules
self.group_size = group_size
self.apply_hadamard = apply_hadamard
self.hadamard_block_size = hadamard_block_size
self.quant_input_grad = quant_input_grad
self.quant_weight_grad = quant_weight_grad
self.apply_online_actscale_step = apply_online_actscale_step
self.actscale_moving_rate = actscale_moving_rate
self.fp8_format_type = fp8_format_type
self.scale_epsilon = scale_epsilon
@property
def fp8_format(self):
return fp8_format_mapping[self.fp8_format_type]
def is_weight_quantize(self):
if isinstance(self.weight_quantize_algo, dict):
return True
elif self.weight_quantize_algo in [
"weight_only_int8",
"weight_only_int4",
"llm.int8",
"nf4",
"fp4",
"a8w8",
"a8w8linear",
"a8w4linear",
"fp8linear",
]:
return True
else:
return False
def is_support_merge_tensor_parallel(self):
if self.weight_quantize_algo in ["weight_only_int8", "weight_only_int4", "llm.int8", "a8w8"]:
return False
else:
return True
@classmethod
def from_dict(cls, config_dict, return_unused_kwargs=False, **kwargs):
"""
Instantiates QuantizationConfig from dict
"""
config = cls(**config_dict)
to_remove = []
for key, value in kwargs.items():
if hasattr(config, key):
setattr(config, key, value)
to_remove.append(key)
for key in to_remove:
kwargs.pop(key, None)
if return_unused_kwargs:
return config, kwargs
else:
return config
def to_json_file(self, json_file_path):
"""
Save this instance to a JSON file.
"""
with open(json_file_path, "w", encoding="utf-8") as f:
f.write(json.dumps(self.to_dict(), indent=2, sort_keys=True) + "\n")
def to_dict(self):
return copy.deepcopy(self.__dict__)
def __repr__(self):
return f"{self.__class__.__name__} {self.to_json_string()}"
def to_json_string(self, use_diff=True):
if use_diff is True:
config_dict = self.to_diff_dict()
else:
config_dict = self.to_dict()
return json.dumps(config_dict, indent=2, sort_keys=True) + "\n"
def to_diff_dict(self):
config_dict = self.to_dict()
# get the default config dict
default_config_dict = QuantizationConfig().to_dict()
serializable_config_dict = {}
# only serialize values that differ from the default config
for key, value in config_dict.items():
if value != default_config_dict[key]:
serializable_config_dict[key] = value
return serializable_config_dict