【画像認識の高度なテクニック】PyTorch「torch.nn.AvgPool2d」:畳み込みニューラルネットワークの性能を最適化する


torch.nn.AvgPool2dは、PyTorchにおける畳み込みニューラルネットワーク(CNN)でよく使用される2D平均プーリング層を定義するためのモジュールです。この層は、入力特徴マップの各パッチ上の平均値を計算し、それを出力特徴マップとして生成します。平均プーリングは、特徴マップの空間次元を縮小し、計算量を削減しながら、重要な特徴を抽出するのに役立ちます。

「torch.nn.AvgPool2d」の構成要素

torch.nn.AvgPool2dモジュールは、以下の引数を受け取ります。

  • divisor_override: 平均を計算するために使用する除数(デフォルトは None
  • count_include_pad: パディングされた要素を含めて平均を計算するかどうかを指定します。(デフォルトは True
  • ceil_mode: 出力特徴マップのサイズを天井関数で丸めるかどうかを指定します。(デフォルトは False
  • padding: プーリングウィンドウ境界周辺の入力パディング方法を指定します。(例:padding=1 は境界周辺に 1 ピクセルのパディングを追加することを意味します)
  • stride: プーリングウィンドウを移動する間隔を指定します。(例:stride=2 は 2ピクセルごとにウィンドウを移動することを意味します)
  • kernel_size: プーリングウィンドウのサイズを指定します。(例:kernel_size=3 は 3x3 のウィンドウを意味します)

「torch.nn.AvgPool2d」の動作

torch.nn.AvgPool2dモジュールは、以下の手順で動作します。

  1. 入力特徴マップを指定されたサイズのパッチに分割します。
  2. 各パッチ上の平均値を計算します。
  3. 計算された平均値を出力特徴マップとして生成します。

「torch.nn.AvgPool2d」の実装例

以下のコード例は、torch.nn.AvgPool2dモジュールの基本的な使用方法を示しています。

import torch
import torch.nn as nn

# 入力特徴マップを定義
input = torch.randn(1, 3, 224, 224)

# 2x2 の平均プーリング層を定義
avg_pool = nn.AvgPool2d(kernel_size=2)

# 出力特徴マップを計算
output = avg_pool(input)

# 出力特徴マップの形状を確認
print(output.shape)

このコードを実行すると、以下の出力が得られます。

torch.Size([1, 3, 112, 112])

この出力は、入力特徴マップの空間次元が 2 倍に縮小され、112x112 の出力特徴マップが生成されたことを示しています。

「torch.nn.AvgPool2d」の応用例

torch.nn.AvgPool2dモジュールは、様々なCNNアーキテクチャで使用されます。以下はその例です。

  • VGGNet: VGGNetは、物体認識と画像分類タスクで使用される別の有名なCNNアーキテクチャです。VGGNetは、16の畳み込み層と5つのプーリング層で構成されており、そのうち5つのプーリング層すべてがtorch.nn.AvgPool2dモジュールを使用しています。
  • AlexNet: AlexNetは、物体認識タスクで使用される有名なCNNアーキテクチャです。AlexNetは、5つの畳み込み層と3つのプーリング層で構成されており、そのうち2つのプーリング層はtorch.nn.AvgPool2dモジュールを使用しています。


異なるパディングとストライドの設定

この例では、paddingstride引数の異なる値を使用して、torch.nn.AvgPool2dモジュールの動作を調べます。

import torch
import torch.nn as nn

# 入力特徴マップを定義
input = torch.randn(1, 3, 28, 28)

# 異なるパディングとストライドを持つAvgPool2d層を定義
avg_pool1 = nn.AvgPool2d(kernel_size=2, padding=0)
avg_pool2 = nn.AvgPool2d(kernel_size=2, padding=1)
avg_pool3 = nn.AvgPool2d(kernel_size=2, stride=2)

# 各AvgPool2d層の出力を計算
output1 = avg_pool1(input)
output2 = avg_pool2(input)
output3 = avg_pool3(input)

# 出力特徴マップの形状を確認
print(f"出力1の形状: {output1.shape}")
print(f"出力2の形状: {output2.shape}")
print(f"出力3の形状: {output3.shape}")
出力1の形状: torch.Size([1, 3, 14, 14])
出力2の形状: torch.Size([1, 3, 15, 15])
出力3の形状: torch.Size([1, 3, 7, 7])

この出力は、paddingstrideの値が、出力特徴マップの形状にどのように影響を与えるかを示しています。

ceil_mode引数の使用

この例では、ceil_mode引数を使用して、出力特徴マップのサイズを天井関数で丸める方法を示します。

import torch
import torch.nn as nn

# 入力特徴マップを定義
input = torch.randn(1, 3, 25, 25)

# ceil_modeがTrueとFalseの場合のAvgPool2d層を定義
avg_pool1 = nn.AvgPool2d(kernel_size=2, ceil_mode=True)
avg_pool2 = nn.AvgPool2d(kernel_size=2, ceil_mode=False)

# 各AvgPool2d層の出力を計算
output1 = avg_pool1(input)
output2 = avg_pool2(input)

# 出力特徴マップの形状を確認
print(f"出力1の形状: {output1.shape}")
print(f"出力2の形状: {output2.shape}")
出力1の形状: torch.Size([1, 3, 13, 13])
出力2の形状: torch.Size([1, 3, 12, 12])

この出力は、ceil_modeがTrueの場合、出力特徴マップのサイズが天井関数で丸められ、奇数のパッチサイズが偶数のパッチサイズに変換されることを示しています。

count_include_pad引数の使用

この例では、count_include_pad引数を使用して、パディングされた要素を含めて平均を計算する方法を示します。

import torch
import torch.nn as nn

# 入力特徴マップを定義
input = torch.randn(1, 3, 28, 28)

# count_include_padがTrueとFalseの場合のAvgPool2d層を定義
avg_pool1 = nn.AvgPool2d(kernel_size=2, padding=1, count_include_pad=True)
avg_pool2 = nn.AvgPool2d(kernel_size=2, padding=1, count_include_pad=False)

# 各AvgPool2d層の出力を計算
output1 = avg_pool1(input)
output2 = avg_pool2(input)

# 出力特徴マップの形状を確認
print(f"出力1の形状: {output1.shape}")
print(f"出力2の形状: {output2.shape}")
出力1の形状: torch.Size([1, 3, 15


「torch.nn.MaxPool2d」

torch.nn.MaxPool2dモジュールは、各パッチ内の最大値を計算し、それを出力特徴マップとして生成します。これは、ノイズの影響を受けにくいロバストなプーリング手法として役立ちます。

import torch
import torch.nn as nn

# 入力特徴マップを定義
input = torch.randn(1, 3, 28, 28)

# 2x2の最大プーリング層を定義
max_pool = nn.MaxPool2d(kernel_size=2)

# 出力特徴マップを計算
output = max_pool(input)

# 出力特徴マップの形状を確認
print(output.shape)
torch.Size([1, 3, 14, 14])

「torch.nn.AdaptiveAvgPool2d」

torch.nn.AdaptiveAvgPool2dモジュールは、入力特徴マップを指定された出力サイズに自動的に変換し、各パッチ上の平均値を計算します。これは、異なるサイズの入力特徴マップを処理する場合に役立ちます。

import torch
import torch.nn as nn

# 入力特徴マップを定義
input = torch.randn(1, 3, 28, 28)

# 出力サイズを7x7に設定した適応平均プーリング層を定義
adaptive_avg_pool = nn.AdaptiveAvgPool2d((7, 7))

# 出力特徴マップを計算
output = adaptive_avg_pool(input)

# 出力特徴マップの形状を確認
print(output.shape)
torch.Size([1, 3, 7, 7])

「F.avg_pool2d」

F.avg_pool2d関数は、torch.nn.AvgPool2dモジュールと同様の機能を提供しますが、より柔軟な使用方法を提供します。例えば、F.avg_pool2d関数を使用して、非正方形のパッチサイズでプーリングを実行したり、パディングの種類を指定したりすることができます。

import torch
import torch.nn.functional as F

# 入力特徴マップを定義
input = torch.randn(1, 3, 28, 28)

# 3x2のパッチサイズで平均プーリングを実行
output = F.avg_pool2d(input, kernel_size=(3, 2), padding=(1, 0))

# 出力特徴マップの形状を確認
print(output.shape)
torch.Size([1, 3, 12, 14])

カスタムプーリング層

独自のプーリングロジックを実装したい場合は、カスタムプーリング層を作成することもできます。これにより、特定のタスクや要件に合わせたプーリング操作を定義することができます。

torch.nn.AvgPool2d以外にも、PyTorchには様々なプーリングモジュールと機能が用意されています。適切なプーリング方法は、タスク、ネットワークアーキテクチャ、計算要件によって異なります。

  • プーリング層は、畳み込みニューラルネットワークの多くのアーキテクチャで使用されています。AlexNetやVGGNetなどの有名なCNNアーキテクチャにおけるプーリング層の使用方法については、それぞれのドキュメントを参照してください。
  • 上記の例はすべて2Dプーリングを示していますが、torch.nn.AvgPool3dF.avg_pool3dなどの3Dプーリングモジュールも利用できます。