基本的な量子化フロー¶
はじめに¶
基本的な量子化フローは、8 ビット量子化をモデルに適用する最も簡単な方法です。OpenVINO、PyTorch、TensorFlow 2.x、および ONNX フレームワーク・モデルで利用できます。基本的な量子化フローは次の手順に基づいています。
環境をセットアップし、依存関係をインストールします。
例えば 300 サンプルのモデル内のアクティベーションの量子化パラメーターの推定に使用される代表的なキャリブレーション・データセットを準備します。
量子化 API を呼び出して、8 ビット量子化をモデルに適用します。
環境設定のセットアップ¶
NNCF で量子化するには、別に Python 環境をセットアップすることを推奨します。これには、次のコマンドを実行します。
python3 -m venv nncf_ptq_env
DL フレームワークなど、モデル・オブジェクトのインスタンス化に必要なすべてのパッケージをインストールします。その後、その環境に NNCF をインストールします。
pip install nncf
キャリブレーション・データセットを準備¶
このステップでは、キャリブレーション・データセットを表す nncf.Dataset
クラスのインスタンスを作成します。nncf.Dataset
クラスは、モデルのトレーニングや検証に使用されるフレームワーク・データセット・オブジェクトのラッパーにすることができます。クラス・コンストラクターは、データセット・オブジェクトとオプションの変換関数を受け取ります。
変換関数は、データセットからサンプルを取得し、推論のためにモデルに渡すことが可能なデータを返す関数です。例えば、この関数はデータテンソルとラベルテンソルのタプルを受け取り、後者を無視して前者を返すことができます。変換関数は、量子化 API との互換性のためデータセット・コードの変更を避けるのに使用されます。この関数は、推論のためモデルに渡す前に、データセットの各サンプルに適用されます。次のコードは、nncf.Dataset
クラスのインスタンスを作成する方法を示しています。
import nncf
import torch
calibration_loader = torch.utils.data.DataLoader(...)
def transform_fn(data_item):
images, _ = data_item
return images.numpy()
calibration_dataset = nncf.Dataset(calibration_loader, transform_fn)
import nncf
import torch
calibration_loader = torch.utils.data.DataLoader(...)
def transform_fn(data_item):
images, _ = data_item
return images
calibration_dataset = nncf.Dataset(calibration_loader, transform_fn)
import nncf
import torch
calibration_loader = torch.utils.data.DataLoader(...)
def transform_fn(data_item):
images, _ = data_item
return {input_name: images.numpy()} # input_name should be taken from the model,
# e.g. model.graph.input[0].name
calibration_dataset = nncf.Dataset(calibration_loader, transform_fn)
import nncf
import tensorflow_datasets as tfds
calibration_loader = tfds.load(...)
def transform_fn(data_item):
images, _ = data_item
return images
calibration_dataset = nncf.Dataset(calibration_loader, transform_fn)
フレームワーク・データセット・オブジェクトがない場合は、Python の Iterable
インターフェイス (画像のリストなど) を実装する独自のエンティティーを作成し、推論に適したデータサンプルを返すことができます。この場合、変換関数は必要ありません。
モデルの量子化¶
データセットの準備が整い、モデル・オブジェクトがインスタンス化されたら、8 ビット量子化を適用できます。各フレームワークの例については、このドキュメントの最後にある例のセクションを参照してください。
import openvino as ov
model = ov.Core().read_model("model_path")
quantized_model = nncf.quantize(model, calibration_dataset)
import torchvision
model = torchvision.models.resnet50(pretrained=True)
quantized_model = nncf.quantize(model, calibration_dataset)
import onnx
model = onnx.load("model_path")
quantized_model = nncf.quantize(model, calibration_dataset)
import tensorflow as tf
model = tf.saved_model.load("model_path")
quantized_model = nncf.quantize(model, calibration_dataset)
その後、必要に応じてモデルを OpenVINO 中間表現 (IR) に変換し、OpenVINO でコンパイルして実行できます。OpenVINO 開発ツールをまだインストールしていない場合は、pip install openvino-dev
を使用してインストールします。
# compile the model to transform quantized operations to int8
model_int8 = ov.compile_model(quantized_model)
input_fp32 = ... # FP32 model input
res = model_int8(input_fp32)
# save the model
ov.save_model(quantized_model, "quantized_model.xml")
import openvino as ov
input_fp32 = ... # FP32 model input
# convert PyTorch model to OpenVINO model
ov_quantized_model = ov.convert_model(quantized_model, example_input=input_fp32)
# compile the model to transform quantized operations to int8
model_int8 = ov.compile_model(ov_quantized_model)
res = model_int8(input_fp32)
# save the model
ov.save_model(ov_quantized_model, "quantized_model.xml")
import openvino as ov
# convert ONNX model to OpenVINO model
ov_quantized_model = ov.convert_model(quantized_model)
# compile the model to transform quantized operations to int8
model_int8 = ov.compile_model(ov_quantized_model)
input_fp32 = ... # FP32 model input
res = model_int8(input_fp32)
# save the model
ov.save_model(ov_quantized_model, "quantized_model.xml")
import openvino as ov
# convert TensorFlow model to OpenVINO model
ov_quantized_model = ov.convert_model(quantized_model)
# compile the model to transform quantized operations to int8
model_int8 = ov.compile_model(ov_quantized_model)
input_fp32 = ... # FP32 model input
res = model_int8(input_fp32)
# save the model
ov.save_model(ov_quantized_model, "quantized_model.xml")
量子化パラメーターのチューニング¶
nncf.quantize()
関数には、より正確なモデルを取得するため量子化プロセスを調整できるオプション・パラメーターがあります。以下にパラメーターのリストとその説明を示します。
-
model_type
- 特定のタイプのモデルに必要な量子化スキームを指定します。Transformer
は、トランスフォーマー・モデル (BERT、DistilBERT など) の量子化後に精度を維持するためにサポートされる唯一の量子化スキームです。None
がデフォルトです。つまり、特定のスキームは定義されていません。nncf.quantize(model, dataset, model_type=nncf.ModelType.Transformer)
-
preset
- モデルの量子化スキームを定義します。2 つのタイプのプリセットが利用できます。PERFORMANCE
(デフォルト) - 重みとアクティベーションの対称量子化を定義します-
MIXED
- 重みは対称量子化で量子化され、アクティベーションは非対称量子化で量子化されます。このプリセットは、非 ReLU および非対称アクティベーション関数を備えたモデル (ELU、PReLU、GELU など) に推奨されます。nncf.quantize(model, dataset, preset=nncf.QuantizationPreset.MIXED)
-
fast_bias_correction
-False
に設定すると、モデルの精度を向上させるより正確なバイアス (エラー) 補正アルゴリズムが有効になります。このパラメーターは、OpenVINO および ONNX 表現でのみ使用できます。True
はデフォルトであり、量子化時間を最小限に抑えます。nncf.quantize(model, dataset, fast_bias_correction=False)
-
subset_size
- アクティベーションの量子化パラメーターを推定するためキャリブレーション・データセットからのサンプル数を定義します。デフォルト値は 300 です。nncf.quantize(model, dataset, subset_size=1000)
-
ignored_scope
- このパラメーターは、モデルの精度を維持するため量子化プロセスから一部のレイヤーを除外します。例えば、モデルの最後のレイヤーを量子化から除外する場合などに使用します。以下に、このパラメーターの使用例をいくつか示します。-
レイヤー名で除外します。
names = ['layer_1', 'layer_2', 'layer_3'] nncf.quantize(model, dataset, ignored_scope=nncf.IgnoredScope(names=names))
-
レイヤータイプで除外します。
types = ['Conv2d', 'Linear'] nncf.quantize(model, dataset, ignored_scope=nncf.IgnoredScope(types=types))
-
正規表現で除外します。
regex = '.*layer_.*' nncf.quantize(model, dataset, ignored_scope=nncf.IgnoredScope(patterns=regex))
-
-
target_device
- ターゲットデバイスを定義します。最適化中にその特性が考慮されます。次のライブラリーが使用されます:ANY
(デフォルト)、CPU
、CPU_SPR
、GPU
、およびNPU
。nncf.quantize(model, dataset, target_device=nncf.TargetDevice.CPU)
advanced_parameters
- 量子化アルゴリズムを微調整する高度な量子化パラメーターを指定します。nncf.quantization.advanced_parameters NNCF サブモジュールによって定義されます。None
はデフォルトです。
量子化モデルの精度に満足できない場合は、精度を備えた量子化制御フローを試みることができます。