PyTorch Quantization:融合モジュールで量子化推論を高速化 - 「torch.ao.quantization.backend_config.BackendPatternConfig.set_fused_module」の使い方と代替方法
torch.ao.quantization.backend_config.BackendPatternConfig.set_fused_module()
は、PyTorch Quantizationにおいて、複数のモジュールを融合したカスタムモジュールを指定するためのメソッドです。このメソッドを使用することで、量子の推論効率を向上させることができます。
引数
fused_module
: 融合されたカスタムモジュールのクラス。このモジュールは、元のモジュールと同じ入出力と機能を持つ必要があります。
動作
BackendPatternConfig
オブジェクトは、特定のパターンの量子化方法を定義します。set_fused_module()
メソッドを呼び出すことで、このパターンにおける融合モジュールを指定できます。- PyTorch Quantizationは、推論時に、元のモジュールを融合モジュールに置き換えます。これにより、計算量とメモリ使用量を削減できます。
例
import torch
from torch.ao.quantization.backend_config import BackendPatternConfig, DTypeConfig, ObservationType
def fuse_conv2d_relu(is_qat, conv, relu):
return torch.nn.intrinsic.ConvReLU2d(conv, relu)
# 畳み込み2DとReLUを融合するパターンを定義
conv_relu_config = BackendPatternConfig((torch.nn.Conv2d, torch.nn.ReLU))
# 観察タイプを設定
conv_relu_config.set_observation_type(ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT)
# データ型設定
weighted_int8_dtype_config = DTypeConfig(
input_dtype=torch.quint8,
output_dtype=torch.quint8,
weight_dtype=torch.qint8,
bias_dtype=torch.float,
)
conv_relu_config.add_dtype_config(weighted_int8_dtype_config)
# 融合モジュールを設定
conv_relu_config.set_fused_module(torch.ao.nn.intrinsic.ConvReLU2d)
# 融合方法を設定
conv_relu_config.set_fuser_method(fuse_conv2d_relu)
上記の例では、conv2d
と relu
モジュールの融合を定義しています。fuse_conv2d_relu
関数は、融合されたカスタムモジュールを実装します。
利点
- モデルの保守性の向上
- コードの簡素化
- 量子の推論効率の向上
- すべてのバックエンドが融合をサポートしているわけではありません。
- 融合モジュールは、元のモジュールと同じ入出力と機能を持つ必要があります。
import torch
from torch.ao.quantization.backend_config import BackendPatternConfig, DTypeConfig, ObservationType
from torch.ao.quantization.quantizer import Quantizer
from torch.quantization import QuantStub, DeQuantStub
# モデルを定義
class MyModel(torch.nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.conv1 = torch.nn.Conv2d(1, 32, 3, 1, padding=1)
self.relu1 = torch.nn.ReLU()
self.conv2 = torch.nn.Conv2d(32, 64, 3, 1, padding=1)
self.relu2 = torch.nn.ReLU()
def forward(self, x):
x = self.conv1(x)
x = self.relu1(x)
x = self.conv2(x)
x = self.relu2(x)
return x
# 畳み込み2DとReLUを融合するパターンを定義
conv_relu_config = BackendPatternConfig((torch.nn.Conv2d, torch.nn.ReLU))
# 観察タイプを設定
conv_relu_config.set_observation_type(ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT)
# データ型設定
weighted_int8_dtype_config = DTypeConfig(
input_dtype=torch.quint8,
output_dtype=torch.quint8,
weight_dtype=torch.qint8,
bias_dtype=torch.float,
)
conv_relu_config.add_dtype_config(weighted_int8_dtype_config)
# 融合モジュールを設定
conv_relu_config.set_fused_module(torch.ao.nn.intrinsic.ConvReLU2d)
# 融合方法を設定
def fuse_conv2d_relu(is_qat, conv, relu):
return torch.nn.intrinsic.ConvReLU2d(conv, relu)
conv_relu_config.set_fuser_method(fuse_conv2d_relu)
# モデルを準備
model = MyModel()
qat_model = torch.quantization.quantize_dynamic(
model,
{torch.nn.Conv2d: QuantStub},
{torch.nn.ReLU: DeQuantStub},
backend_config=conv_relu_config,
)
# 量子化を行う
quantizer = Quantizer(qat_model)
quantizer.prepare()
quantizer.convert()
# 量子化モデルを評価
このコードでは、まず MyModel
クラスを定義します。このモデルには、2つの畳み込み2D層と2つのReLU層が含まれています。
次に、conv_relu_config
オブジェクトを作成して、畳み込み2DとReLUを融合するパターンを定義します。このオブジェクトには、観察タイプ、データ型、融合モジュール、融合方法などの設定が含まれます。
続いて、qat_model
を作成して、モデルを動的に量子化します。このモデルには、QuantStub
モジュールと DeQuantStub
モジュールが挿入されます。
最後に、quantizer
オブジェクトを作成して、モデルを量子化します。
- このコードは、PyTorch 1.12以降で動作します。
torch.quantization.QuantFusion を使用する
torch.quantization.QuantFusion
は、モデルの量子化時にモジュールを融合するための機能です。set_fused_module()
メソッドと比較して、以下の利点があります。
- より柔軟なモジュール融合
- より簡潔なコード
QuantFusion
を使用する例:
import torch
from torch.quantization import QuantFusion
# モデルを定義
class MyModel(torch.nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.conv1 = torch.nn.Conv2d(1, 32, 3, 1, padding=1)
self.relu1 = torch.nn.ReLU()
self.conv2 = torch.nn.Conv2d(32, 64, 3, 1, padding=1)
self.relu2 = torch.nn.ReLU()
def forward(self, x):
x = self.conv1(x)
x = self.relu1(x)
x = self.conv2(x)
x = self.relu2(x)
return x
# モデルを準備
model = MyModel()
# モデルを融合
fused_model = QuantFusion.fuse(model, [torch.nn.Conv2d, torch.nn.ReLU])
# 量子化を行う
quantizer = Quantizer(fused_model)
quantizer.prepare()
quantizer.convert()
# 量子化モデルを評価
torch.quantization.quantize_dynamic の add_pattern オプションを使用する
torch.quantization.quantize_dynamic
の add_pattern
オプションを使用して、融合パターンを定義することもできます。この方法は、QuantFusion
よりも詳細な制御を提供します。
add_pattern
を使用する例:
import torch
from torch.quantization import QuantStub, DeQuantStub, Quantizer
# モデルを定義
class MyModel(torch.nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.conv1 = torch.nn.Conv2d(1, 32, 3, 1, padding=1)
self.relu1 = torch.nn.ReLU()
self.conv2 = torch.nn.Conv2d(32, 64, 3, 1, padding=1)
self.relu2 = torch.nn.ReLU()
def forward(self, x):
x = self.conv1(x)
x = self.relu1(x)
x = self.conv2(x)
x = self.relu2(x)
return x
# モデルを準備
model = MyModel()
# 量子化を行う
quantizer = Quantizer(model)
# 融合パターンを定義
def fuse_conv2d_relu(is_qat, conv, relu):
return torch.nn.intrinsic.ConvReLU2d(conv, relu)
quantizer.add_pattern(torch.nn.Sequential(torch.nn.Conv2d, torch.nn.ReLU), fuse_conv2d_relu)
quantizer.prepare()
quantizer.convert()
# 量子化モデルを評価
手動でモジュールを融合する
最も詳細な制御が必要な場合は、手動でモジュールを融合することができます。この方法は、複雑なモデルやカスタムモジュールを使用する場合は役立ちます。
手動でモジュールを融合する例:
import torch
from torch.nn.intrinsic import ConvReLU2d
# モデルを定義
class MyModel(torch.nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.conv1 = torch.nn.Conv2d(1, 32, 3, 1, padding=1)
self.relu1 = torch.nn.ReLU()
self.conv2 = torch.nn.Conv