-
Notifications
You must be signed in to change notification settings - Fork 124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[OV] Move data-driven quantization after model export for text-generation models #721
Changes from 26 commits
56878bb
013a0f6
c566ccc
0a8fba0
6dbb4fe
3722624
dee582d
a44c096
12dc672
bcc4665
40058da
0886f7e
ee9b1b7
cb57068
ee0b67f
cacbb36
814d96c
d8017ab
24272dc
40b0e29
f54aa40
96bed29
a6005ad
e311916
fc44214
709085b
a2084d9
e8cc0e9
6815773
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -128,6 +128,33 @@ def parse_args_openvino(parser: "ArgumentParser"): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"compression is applied, they are compressed to INT8." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
optional_group.add_argument( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"--awq", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
action="store_true", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
help=( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Whether to apply AWQ algorithm. AWQ improves generation quality of INT4-compressed LLMs, but requires " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"additional time for tuning weights on a calibration dataset. To run AWQ, please also provide a dataset " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"argument. Note: it's possible that there will be no matching patterns in the model to apply AWQ, in such " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"case it will be skipped." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
optional_group.add_argument( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"--sensitivity-metric", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type=str, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
help=( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"The sensitivity metric for assigning quantization precision to layers. Can be one of the following: " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"['weight_quantization_error', 'hessian_input_activation', 'mean_activation_variance', " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"'max_activation_variance', 'mean_activation_magnitude']." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
optional_group.add_argument( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"--num-samples", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type=int, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
help="The maximum number of samples to take from the dataset for quantization.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
optional_group.add_argument( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"--disable-stateful", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
action="store_true", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -180,7 +207,7 @@ def parse_args(parser: "ArgumentParser"): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return parse_args_openvino(parser) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def run(self): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from ...exporters.openvino.__main__ import main_export | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from ...exporters.openvino.__main__ import infer_task, main_export | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from ...intel.openvino.configuration import _DEFAULT_4BIT_CONFIGS, OVConfig | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if self.args.fp16: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -208,6 +235,10 @@ def run(self): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
and self.args.group_size is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
and self.args.sym is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
and self.args.all_layers is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
and self.args.dataset is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
and self.args.num_samples is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
and self.args.awq is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
and self.args.sensitivity_metric is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
and self.args.model in _DEFAULT_4BIT_CONFIGS | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
quantization_config = _DEFAULT_4BIT_CONFIGS[self.args.model] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -218,6 +249,10 @@ def run(self): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"sym": self.args.sym or False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"group_size": -1 if is_int8 else self.args.group_size, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"all_layers": None if is_int8 else self.args.all_layers, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"dataset": self.args.dataset, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"num_samples": self.args.num_samples, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"quant_method": "awq" if self.args.awq else None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"sensitivity_metric": self.args.sensitivity_metric, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if self.args.weight_format in {"int4_sym_g128", "int4_asym_g128", "int4_sym_g64", "int4_asym_g64"}: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -226,7 +261,6 @@ def run(self): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
quantization_config["sym"] = "asym" not in self.args.weight_format | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
quantization_config["group_size"] = 128 if "128" in self.args.weight_format else 64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
quantization_config["dataset"] = self.args.dataset | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ov_config = OVConfig(quantization_config=quantization_config) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
library_name = TasksManager.infer_library_from_model(self.args.model, library_name=self.args.library) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -240,12 +274,11 @@ def run(self): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if self.args.convert_tokenizer: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
logger.warning("`--convert-tokenizer` option is deprecated. Tokenizer will be converted by default.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
library_name == "diffusers" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
and ov_config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
and ov_config.quantization_config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
and ov_config.quantization_config.dataset is not None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
quantization_config = ov_config.quantization_config if ov_config else None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
quantize_with_dataset = quantization_config and getattr(quantization_config, "dataset", None) is not None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
task = infer_task(self.args.task, self.args.model) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if library_name == "diffusers" and quantize_with_dataset: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if not is_diffusers_available(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
raise ValueError(DIFFUSERS_IMPORT_ERROR.format("Export of diffusers models")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -270,9 +303,7 @@ def run(self): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
raise NotImplementedError(f"Quantization in hybrid mode isn't supported for class {class_name}.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
model = model_cls.from_pretrained( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
self.args.model, export=True, quantization_config=ov_config.quantization_config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
model = model_cls.from_pretrained(self.args.model, export=True, quantization_config=quantization_config) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
model.save_pretrained(self.args.output) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if self.args.disable_convert_tokenizer: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -281,14 +312,41 @@ def run(self): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# avoid import when using other exporters (IPEX, INC) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from ...exporters.openvino.convert import export_tokenizer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
output = Path(self.args.output) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tokenizer = getattr(model, "tokenizer", None) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if tokenizer is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export_tokenizer(tokenizer, output / "tokenizer") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export_tokenizer(tokenizer, self.args.output / "tokenizer") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tokenizer_2 = getattr(model, "tokenizer_2", None) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if tokenizer_2 is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export_tokenizer(tokenizer_2, output / "tokenizer_2") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export_tokenizer(tokenizer_2, self.args.output / "tokenizer_2") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
elif task.startswith("text-generation") and quantize_with_dataset: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from optimum.intel import OVModelForCausalLM | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# To quantize a text-generation model with a dataset, an instantiated OVModelForCausalLM is required | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
model = OVModelForCausalLM.from_pretrained( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
self.args.model, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
quantization_config=quantization_config, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
stateful=not self.args.disable_stateful, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
trust_remote_code=self.args.trust_remote_code, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
model.save_pretrained(self.args.output) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tokenizer = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from transformers import AutoTokenizer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tokenizer = AutoTokenizer.from_pretrained( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
self.args.model, trust_remote_code=self.args.trust_remote_code | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tokenizer.save_pretrained(self.args.output) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except Exception: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
logger.warning("Could not save tokenizer") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if tokenizer and not self.args.disable_convert_tokenizer: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from ...exporters.openvino.convert import export_tokenizer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export_tokenizer(tokenizer, self.args.output / "tokenizer") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Had to add such logic because otherwise tokenizer ends up being saved to a temporary directory. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to simplify the code a bit what do you think about calling directly
and to save the tokenizer we can also use
also we could create a function optimum-intel/optimum/exporters/openvino/__main__.py Lines 364 to 390 in 8dd2a89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! Done |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# TODO : add input shapes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
main_export( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if it should be
QuantizationMethod.AWQ
instead of "awq" or if the configuration takes care of thisoptimum-intel/optimum/intel/openvino/quantization.py
Line 822 in 52875b9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hesitated to do it this way because it would require to introduce dependency on
transformers
in this file in order to importQuantizationMethod
. But now I see thattransformers
is a general requirement ofoptimum
so it should be fine I guess.