PyTorch Quantizationでモデルを軽量化,「torch.ao.nn.intrinsic.ConvBnReLU2d」が役立つ理由


  • 精度保持: 適切な量子化手法を用いることで、精度を犠牲にすることなくモデルを軽量化することができます。
  • 推論速度の向上: 融合されたモジュールは、個々の層を別々に実行するよりも効率的に実行できます。
  • モデルの軽量化: 複数の層を融合させることで、モデルのパラメータ数と計算量を削減できます。

torch.ao.nn.intrinsic.ConvBnReLU2d は、以下の属性を持つクラスとして定義されています。

class ConvBnReLU2d(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=False, eps=1e-5, momentum=0.1, affine=True, qconfig=None):
        super(ConvBnReLU2d, self).__init__()
        self.conv = Conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias=bias, qconfig=qconfig)
        self.bn = BatchNorm2d(out_channels, eps=eps, momentum=momentum, affine=affine, qconfig=qconfig)
        self.relu = ReLU(qconfig=qconfig)
        self.qconfig = qconfig

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x

このクラスの主な使用方法は以下の通りです。

import torch.nn.intrinsic.qat as qnn
model = qnn.ConvBnReLU2d(16, 32, 3)
input = torch.randn(10, 16, 28, 28)
output = model(input)
print(output.size())

このコードは、16個の入力チャネルと32個の出力チャネルを持つ、3x3の畳み込み層、バッチ正規化層、ReLU 層を融合させたモジュールを作成し、入力データに対して推論を実行します。

torch.ao.nn.intrinsic.ConvBnReLU2d モジュールは、以下の機能を提供します。

  • 静的な量子化: このモジュールは、静的な量子化で使用することができます。これは、モデルのパラメータとアクティベーションを事前に量子化することを意味します。
  • 動的な量子化: このモジュールは、動的な量子化で使用することができます。これは、推論時にモデルのパラメータとアクティベーションを動的に量子化することを意味します。
  • 量子の感知訓練: このモジュールは、量子の感知訓練で使用することができます。これは、モデルを量子化するために必要な情報を収集するために、浮動小数点精度でモデルをトレーニングすることを意味します。

torch.ao.nn.intrinsic.ConvBnReLU2d モジュールは、PyTorch の Quantization において、モデルの軽量化、推論速度の向上、精度保持に役立つ強力なツールです。



import torch
import torch.nn as nn
import torch.nn.intrinsic.qat as qnn
import torch.optim as optim
from torchvision import datasets, transforms

# モデル定義
class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.conv1 = qnn.ConvBnReLU2d(1, 16, 3)
        self.conv2 = qnn.ConvBnReLU2d(16, 32, 3)
        self.fc = nn.Linear(32 * 5 * 5, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = F.max_pool2d(x, 2)
        x = self.conv2(x)
        x = F.max_pool2d(x, 2)
        x = x.view(-1, 32 * 5 * 5)
        x = self.fc(x)
        return x

# モデルの量子化設定
qconfig = dict(activation=qnn.ReLUQuantizer.fake_quant_per_channel,
               static_quant=True)

# モデルの構築
model = MyModel().qconfig(qconfig)

# データセットとデータローダー
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transforms.ToTensor())
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)

test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transforms.ToTensor())
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False)

# 損失関数と最適化アルゴリズム
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters())

# 訓練
for epoch in range(10):
    for images, labels in train_loader:
        optimizer.zero_grad()
        output = model(images)
        loss = criterion(output, labels)
        loss.backward()
        optimizer.step()

# モデルの評価
model.eval()
with torch.no_grad():
    correct = 0
    total = 0
    for images, labels in test_loader:
        output = model(images)
        _, predicted = torch.max(output.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
    print('Accuracy of the network on the 10000 test images: {} %'.format(100 * correct / total))

# モデルの量子化
model.quant.convert(qconfig)

# 量子化モデルの評価
model.eval()
with torch.no_grad():
    correct = 0
    total = 0
    for images, labels in test_loader:
        output = model(images)
        _, predicted = torch.max(output.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
    print('Accuracy of the quantized network on the 10000 test images: {} %'.format(100 * correct / total))

このコードは、以下の内容を実行します。

  1. MyModel というモデルクラスを定義します。このモデルは、畳み込み層、バッチ正規化層、ReLU 層、全結合層で構成されています。
  2. qconfig という辞書を定義します。この辞書は、量子化設定を指定します。
  3. model というモデルインスタンスを作成します。このモデルは、qconfig で指定された量子化設定を使用して量子化されます。
  4. train_datasettest_dataset というデータセットを作成します。これらのデータセットは、MNIST データセットからロードされます。
  5. train_loadertest_loader というデータローダーを作成します。これらのデータローダーは、バッチ処理を使用してデータをモデルに供給します。 6


個別のモジュールを使用する

torch.ao.nn.intrinsic.ConvBnReLU2d の代わりに、個別のモジュールを使用することができます。これは、以下のコードのように行うことができます。

import torch.nn as nn

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.conv = nn.Conv2d(16, 32, 3)
        self.bn = nn.BatchNorm2d(32)
        self.relu = nn.ReLU()

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x

このコードは、torch.ao.nn.intrinsic.ConvBnReLU2d モジュールと同じ機能を持つモデルを構築します。ただし、この方法では、モデルのパラメータ数と計算量が増加します。

カスタムモジュールを使用する

import torch.nn as nn

class ConvBnReLU2d(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=False, eps=1e-5, momentum=0.1, affine=True):
        super(ConvBnReLU2d, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias=bias)
        self.bn = nn.BatchNorm2d(out_channels, eps=eps, momentum=momentum, affine=affine)
        self.relu = nn.ReLU()

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x

このコードは、torch.ao.nn.intrinsic.ConvBnReLU2d モジュールと同じ機能を持つカスタムモジュールを定義します。この方法では、モデルのパラメータ数と計算量を削減することができます。

QuantizedMobileNetV2 を使用する

torch.ao.nn.intrinsic.ConvBnReLU2d の代わりに、QuantizedMobileNetV2 を使用することができます。これは、以下のコードのように行うことができます。

from torchvision.models import quantized_mobilenet_v2

model = quantized_mobilenet_v2(pretrained=True)

このコードは、QuantizedMobileNetV2 モデルを作成します。このモデルは、torch.ao.nn.intrinsic.ConvBnReLU2d モジュールを使用して量子化されています。

TFLite を使用する

import torch.quantization

model = MyModel()
quantized_model = torch.quantization.quantize_dynamic(model, {torch.nn.Conv2d, torch.nn.BatchNorm2d, torch.nn.Linear}, dtype=torch.qint8)

このコードは、MyModel モデルを TFLite 形式に変換します。TFLite 形式のモデルは、torch.ao.nn.intrinsic.ConvBnReLU2d モジュールを使用するよりも軽量で効率的です。