Skip to content

Commit 333e202

Browse files
committed
rework dataset processing
1 parent bf4080a commit 333e202

File tree

4 files changed

+74
-57
lines changed

4 files changed

+74
-57
lines changed

optimum/intel/openvino/configuration.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,9 @@ class OVWeightQuantizationConfig(QuantizationConfigMixin):
178178
- A path to a *directory* containing vocabulary files required by the tokenizer, for instance saved
179179
using the [`~PreTrainedTokenizer.save_pretrained`] method, e.g., `./my_model_directory/`.
180180
dataset (`str or List[str]`, *optional*):
181-
The dataset used for data-aware compression. You can provide your own dataset in a list of string or just use the
182-
the one from the list ['wikitext2','c4','c4-new','ptb','ptb-new'] for LLLMs or
183-
['conceptual_captions','laion/220k-GPT4Vision-captions-from-LIVIS','laion/filtered-wit'] for SD models.
181+
The dataset used for data-aware compression or quantization with NNCF. You can provide your own dataset
182+
in a list of string or just use the the one from the list ['wikitext2','c4','c4-new','ptb','ptb-new'] for LLLMs
183+
or ['conceptual_captions','laion/220k-GPT4Vision-captions-from-LIVIS','laion/filtered-wit'] for SD models.
184184
ratio (`float`, defaults to 1.0):
185185
The ratio between baseline and backup precisions (e.g. 0.9 means 90% of layers quantized to INT4_ASYM
186186
and the rest to INT8_ASYM).

optimum/intel/openvino/modeling_diffusion.py

+53-26
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
import importlib
1616
import logging
17-
import math
1817
import os
1918
import shutil
2019
from copy import deepcopy
@@ -59,7 +58,13 @@
5958
from .configuration import OVConfig, OVWeightQuantizationConfig
6059
from .loaders import OVTextualInversionLoaderMixin
6160
from .modeling_base import OVBaseModel
62-
from .utils import ONNX_WEIGHTS_NAME, OV_TO_NP_TYPE, OV_XML_FILE_NAME, _print_compiled_model_properties
61+
from .utils import (
62+
ONNX_WEIGHTS_NAME,
63+
OV_TO_NP_TYPE,
64+
OV_XML_FILE_NAME,
65+
PREDEFINED_SD_DATASETS,
66+
_print_compiled_model_properties,
67+
)
6368

6469

6570
core = Core()
@@ -276,13 +281,15 @@ def _from_pretrained(
276281
kwargs[name] = load_method(new_model_save_dir)
277282

278283
quantization_config = cls._prepare_weight_quantization_config(quantization_config, load_in_8bit)
279-
weight_quantization_config = deepcopy(quantization_config)
284+
285+
dataset = None
280286
unet_path = new_model_save_dir / DIFFUSION_MODEL_UNET_SUBFOLDER / unet_file_name
281-
if weight_quantization_config is not None and weight_quantization_config.dataset is not None:
287+
if quantization_config is not None and quantization_config.dataset is not None:
288+
dataset = quantization_config.dataset
282289
# load the UNet model uncompressed to apply hybrid quantization further
283290
unet = cls.load_model(unet_path)
284291
# Apply weights compression to other `components` without dataset
285-
weight_quantization_config.dataset = None
292+
quantization_config.dataset = None
286293
else:
287294
unet = cls.load_model(unet_path, quantization_config)
288295

@@ -294,12 +301,12 @@ def _from_pretrained(
294301
}
295302

296303
for key, value in components.items():
297-
components[key] = cls.load_model(value, weight_quantization_config) if value.is_file() else None
304+
components[key] = cls.load_model(value, quantization_config) if value.is_file() else None
298305

299306
if model_save_dir is None:
300307
model_save_dir = new_model_save_dir
301308

302-
if quantization_config and quantization_config.dataset is not None:
309+
if dataset is not None:
303310
sd_model = cls(unet=unet, config=config, model_save_dir=model_save_dir, **components, **kwargs)
304311

305312
supported_pipelines = (
@@ -310,24 +317,13 @@ def _from_pretrained(
310317
if not isinstance(sd_model, supported_pipelines):
311318
raise NotImplementedError(f"Quantization in hybrid mode is not supported for {cls.__name__}")
312319

313-
num_inference_steps = 4 if isinstance(sd_model, OVLatentConsistencyModelPipeline) else 50
314320
nsamples = quantization_config.num_samples if quantization_config.num_samples else 200
315-
dataset = deepcopy(quantization_config.dataset)
316-
317-
if isinstance(dataset, str):
318-
from .quantization import get_stable_diffusion_dataset
319-
320-
num_unet_runs = math.ceil(nsamples / num_inference_steps)
321-
dataset = get_stable_diffusion_dataset(dataset, num_unet_runs)
322-
323-
unet_inputs = sd_model._prepare_unet_inputs(dataset, nsamples, num_inference_steps)
321+
unet_inputs = sd_model._prepare_unet_inputs(dataset, nsamples)
324322

325323
from .quantization import _hybrid_quantization
326324

327-
hybrid_quantization_config = deepcopy(quantization_config)
328-
hybrid_quantization_config.dataset = unet_inputs
329-
hybrid_quantization_config.num_samples = nsamples
330-
unet = _hybrid_quantization(sd_model.unet.model, hybrid_quantization_config)
325+
unet = _hybrid_quantization(sd_model.unet.model, quantization_config, dataset=unet_inputs)
326+
quantization_config.dataset = dataset
331327

332328
return cls(
333329
unet=unet,
@@ -340,21 +336,52 @@ def _from_pretrained(
340336

341337
def _prepare_unet_inputs(
342338
self,
343-
dataset: List[str],
339+
dataset: Union[str, List[Any]],
344340
num_samples: int,
345-
num_inference_steps: int,
346341
height: Optional[int] = 512,
347342
width: Optional[int] = 512,
343+
seed: Optional[int] = 42,
348344
**kwargs,
349345
) -> Dict[str, Any]:
350346
self.compile()
351-
calibration_data = []
347+
348+
if isinstance(dataset, str):
349+
dataset = deepcopy(dataset)
350+
available_datasets = PREDEFINED_SD_DATASETS.keys()
351+
if dataset not in available_datasets:
352+
raise ValueError(
353+
f"""You have entered a string value for dataset. You can only choose between
354+
{list(available_datasets)}, but the {dataset} was found"""
355+
)
356+
357+
from datasets import load_dataset
358+
359+
dataset_metadata = PREDEFINED_SD_DATASETS[dataset]
360+
dataset = load_dataset(dataset, split=dataset_metadata["split"], streaming=True).shuffle(seed=seed)
361+
input_names = dataset_metadata["inputs"]
362+
dataset = dataset.select_columns(list(input_names.values()))
363+
364+
def transform_fn(data_item):
365+
return {inp_name: data_item[column] for inp_name, column in input_names.items()}
366+
367+
else:
368+
369+
def transform_fn(data_item):
370+
return data_item if isinstance(data_item, (list, dict)) else [data_item]
352371

353372
from .quantization import InferRequestWrapper
354373

374+
calibration_data = []
355375
self.unet.request = InferRequestWrapper(self.unet.request, calibration_data)
356-
for prompt in dataset:
357-
_ = self.__call__(prompt, num_inference_steps=num_inference_steps, height=height, width=width)
376+
377+
for inputs in dataset:
378+
inputs = transform_fn(inputs)
379+
if isinstance(inputs, dict):
380+
self.__call__(**inputs, height=height, width=width)
381+
else:
382+
self.__call__(*inputs, height=height, width=width)
383+
if len(calibration_data) > num_samples:
384+
break
358385

359386
self.unet.request = self.unet.request.request
360387
return calibration_data[:num_samples]

optimum/intel/openvino/quantization.py

+11-28
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,13 @@
1717
import logging
1818
import os
1919
from collections import deque
20-
from copy import deepcopy
2120
from pathlib import Path
22-
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union
21+
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple, Union
2322

2423
import nncf
2524
import openvino
2625
import torch
2726
import transformers
28-
from datasets import load_dataset
2927
from nncf import CompressWeightsMode, IgnoredScope, NNCFConfig, SensitivityMetric
3028
from nncf.quantization.advanced_parameters import AdvancedSmoothQuantParameters
3129
from nncf.torch import create_compressed_model, register_default_init_args, register_module
@@ -638,23 +636,8 @@ def _collect_ops_with_weights(model):
638636
return ops_with_weights
639637

640638

641-
def get_stable_diffusion_dataset(
642-
dataset_name: str, nsamples: int = 50, seed: int = 0, text_column: str = "caption"
643-
) -> List[str]:
644-
if dataset_name not in ["conceptual_captions", "laion/220k-GPT4Vision-captions-from-LIVIS", "laion/filtered-wit"]:
645-
raise ValueError(
646-
f"""You have entered a string value for dataset. You can only choose between
647-
['conceptual_captions','laion/220k-GPT4Vision-captions-from-LIVIS','laion/filtered-wit'],
648-
but we found {dataset_name}"""
649-
)
650-
651-
data = load_dataset(dataset_name, split="train", streaming=True).shuffle(seed=seed).take(nsamples)
652-
dataset = [batch[text_column] for batch in data]
653-
return dataset
654-
655-
656639
def _hybrid_quantization(
657-
model: openvino.runtime.Model, quantization_config: OVWeightQuantizationConfig
640+
model: openvino.runtime.Model, quantization_config: OVWeightQuantizationConfig, dataset: Dict[str, Any]
658641
) -> openvino.runtime.Model:
659642
"""
660643
Quantize a model in hybrid mode with NNCF which means that we quantize:
@@ -666,28 +649,28 @@ def _hybrid_quantization(
666649
The OpenVINO Runtime model for applying hybrid quantization.
667650
quantization_config (`OVWeightQuantizationConfig`):
668651
The configuration containing the parameters related to quantization.
652+
dataset (`Dict[str, Any]`):
653+
The dataset used for hybrid quantization.
669654
Returns:
670655
The OpenVINO Runtime model with applied hybrid quantization.
671656
"""
672-
ignored_scope = quantization_config.ignored_scope if quantization_config.ignored_scope is not None else {}
673-
674657
ops_to_compress = _collect_ops_with_weights(model)
675-
ptq_ignored_scope = deepcopy(ignored_scope)
676-
ptq_ignored_scope["names"] = ignored_scope.get("names", []) + ops_to_compress
677658

678-
wc_quantization_config = deepcopy(quantization_config)
659+
ignored_scope = quantization_config.ignored_scope if isinstance(quantization_config.ignored_scope, dict) else {}
660+
ptq_ignored_scope = nncf.IgnoredScope(**ignored_scope)
661+
ptq_ignored_scope.names += ops_to_compress
662+
663+
wc_quantization_config = copy.deepcopy(quantization_config)
679664
wc_quantization_config.ignored_scope = ignored_scope
680665
wc_quantization_config.ignored_scope["types"] = ignored_scope.get("types", []) + ["Convolution"]
681-
# Apply Weight Compression without dataset
682-
wc_quantization_config.dataset = None
683666
compressed_model = _weight_only_quantization(model, wc_quantization_config)
684667

685668
subset_size = quantization_config.num_samples if quantization_config.num_samples else 200
686669
quantized_model = nncf.quantize(
687670
model=compressed_model,
688-
calibration_dataset=nncf.Dataset(quantization_config.dataset),
671+
calibration_dataset=nncf.Dataset(dataset),
689672
model_type=nncf.ModelType.TRANSFORMER,
690-
ignored_scope=nncf.IgnoredScope(**ptq_ignored_scope),
673+
ignored_scope=ptq_ignored_scope,
691674
# The SQ algo should be disabled for MatMul nodes because their weights are already compressed
692675
advanced_parameters=nncf.AdvancedQuantizationParameters(AdvancedSmoothQuantParameters(matmul=-1)),
693676
subset_size=subset_size,

optimum/intel/openvino/utils.py

+7
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@
9999
}
100100

101101

102+
PREDEFINED_SD_DATASETS = {
103+
"conceptual_captions": {"split": "train", "inputs": {"prompt": "caption"}},
104+
"laion/220k-GPT4Vision-captions-from-LIVIS": {"split": "train", "inputs": {"prompt": "caption"}},
105+
"laion/filtered-wit": {"split": "train", "inputs": {"prompt": "caption"}},
106+
}
107+
108+
102109
def use_external_data_format(num_parameters: int) -> bool:
103110
"""
104111
Returns whether or not the model requires using external data format for the ONNX export

0 commit comments

Comments
 (0)