PyTorch QuantizationのConvertCustomConfigを使いこなす:詳細ガイドとサンプルコード


torch.ao.quantization.fx.custom_config.ConvertCustomConfig は、PyTorch Quantization の FX Graph Mode における変換処理をカスタマイズするための設定クラスです。このクラスを用いることで、以下のことが可能になります。

  • 保持する属性を指定する
  • 観察された属性から量子化属性へのマッピングを指定する

主な属性と機能

  • preserved_attributes: 保持する属性名のリスト。このリストに含まれる属性は、変換処理において量子化されずにそのまま保持されます。
  • observed_to_quantized_mapping: 観察された属性名と量子化属性名の辞書。この辞書を用いて、変換処理においてどの属性を量子化属性に置き換えるかを指定します。

使用方法

ConvertCustomConfig は、convert_fx() 関数に custom_config 引数として渡すことで使用できます。

import torch
import torch.nn as nn
import torch.quantization

# モデルを定義
class MyModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 20)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(20, 10)

# モデルを準備
model = MyModel()
quantized_model = torch.quantization.quantize_fx(model, qconfig_dict={'fc1': {'dtype': torch.qint8}, 'fc2': {'dtype': torch.qint8}})

# カスタム設定を定義
custom_config = ConvertCustomConfig(
    observed_to_quantized_mapping={'fc1.weight': 'fc1_weight_quantized'},
    preserved_attributes=['fc1.bias'],
)

# モデルを変換
quantized_model = quantized_model.convert(custom_config=custom_config)

上記の例では、fc1.weight 属性は fc1_weight_quantized 属性に量子化され、fc1.bias 属性は量子化されずに保持されます。

  • ConvertCustomConfig は、主に古いモデルの量子化との互換性を維持するために使用されます。新しいモデルを量子化する場合には、通常は set_observed_to_quantized_mapping()set_preserved_attributes() などのメソッドを用いる代わりに、qconfig_dict 引数を使用して量子化設定を直接指定することをお勧めします。


import torch
import torch.nn as nn
import torch.quantization

# モデルを定義
class MyModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 20)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(20, 10)

# モデルを準備
model = MyModel()
quantized_model = torch.quantization.quantize_fx(model, qconfig_dict={'fc1': {'dtype': torch.qint8}, 'fc2': {'dtype': torch.qint8}})

# カスタム設定を定義
custom_config = ConvertCustomConfig(
    observed_to_quantized_mapping={'fc1.weight': 'fc1_weight_quantized'},
)

# モデルを変換
quantized_model = quantized_model.convert(custom_config=custom_config)

この例では、fc1.weight 属性は fc1_weight_quantized 属性に量子化されます。

例 2: 保持する属性を指定する

import torch
import torch.nn as nn
import torch.quantization

# モデルを定義
class MyModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 20)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(20, 10)

# モデルを準備
model = MyModel()
quantized_model = torch.quantization.quantize_fx(model, qconfig_dict={'fc1': {'dtype': torch.qint8}, 'fc2': {'dtype': torch.qint8}})

# カスタム設定を定義
custom_config = ConvertCustomConfig(
    preserved_attributes=['fc1.bias'],
)

# モデルを変換
quantized_model = quantized_model.convert(custom_config=custom_config)

この例では、fc1.bias 属性は量子化されずに保持されます。

import torch
import torch.nn as nn
import torch.quantization

# モデルを定義
class MyModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 20)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(20, 10)

# モデルを準備
model = MyModel()
quantized_model = torch.quantization.quantize_fx(model, qconfig_dict={'fc1': {'dtype': torch.qint8}, 'fc2': {'dtype': torch.qint8}})

# カスタム設定を定義
custom_config = ConvertCustomConfig(
    observed_to_quantized_mapping={'fc1.weight': 'fc1_weight_quantized'},
    preserved_attributes=['fc1.bias'],
)

# モデルを変換
quantized_model = quantized_model.convert(custom_config=custom_config)
  • ConvertCustomConfig を使用する場合には、量子化処理の挙動が複雑になる可能性があることに注意する必要があります。
  • 上記の例はあくまで基本的な使用方法を示したものです。実際の使用例では、モデルや量子化設定に合わせて、適切に設定を調整する必要があります。


qconfig_dict を使用した属性名による個別の設定

従来の ConvertCustomConfig で使用していた observed_to_quantized_mappingpreserved_attributes の機能は、qconfig_dict を使用して属性名ごとに個別に設定することが可能です。

import torch
import torch.nn as nn
import torch.quantization

# モデルを定義
class MyModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 20)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(20, 10)

# モデルを準備
model = MyModel()

# qconfig_dict を使用して属性ごとの設定を定義
qconfig_dict = {
    'fc1': {
        'dtype': torch.qint8,
        'observed_to_quantized_mapping': {'weight': 'fc1_weight_quantized'},
        'preserved_attributes': ['bias'],
    },
    'fc2': {'dtype': torch.qint8},
}

# モデルを量子化
quantized_model = torch.quantization.quantize_fx(model, qconfig_dict=qconfig_dict)

get_quantized_config 関数による属性レベルの設定

get_quantized_config 関数を使用して、各属性レベルで量子化設定を個別に取得し、それを修正してから quantize_fx 関数に渡す方法もあります。

import torch
import torch.nn as nn
import torch.quantization

# モデルを定義
class MyModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 20)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(20, 10)

# モデルを準備
model = MyModel()

# get_quantized_config 関数を使用して量子化設定を取得
qconfig_dict = torch.quantization.get_quantized_config(model)

# fc1 レイヤーの設定を修正
qconfig_dict['fc1']['observed_to_quantized_mapping']['weight'] = 'fc1_weight_quantized'
qconfig_dict['fc1']['preserved_attributes'] = ['bias']

# モデルを量子化
quantized_model = torch.quantization.quantize_fx(model, qconfig_dict=qconfig_dict)

上記の例は、qconfig_dict を直接編集する方法とほぼ同じですが、get_quantized_config 関数を使用して既存の設定をベースに修正する点が異なります。

CustomQuantizer クラスを使用した高度なカスタマイズ

より高度なカスタマイズが必要な場合は、CustomQuantizer クラスを使用して独自の量子化ロジックを実装することができます。これは、複雑なモデルや特殊な量子化要件を持つ場合に役立ちます。