PyTorch nn.MaxPool2d 関数
torch.nn.MaxPool2dは、PyTorchで2次元最大プーリングを行うためのモジュールです。
プーリング層は、特徴マップの空間サイズを縮小し、計算量を削減するとともに、ある程度の並進不変性を提供します。
関数定義
torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
パラメータの説明:
kernel_size(intまたはtuple): プーリングウィンドウのサイズ。stride(intまたはtuple): プーリングウィンドウが移動するストライド。デフォルトはkernel_size。padding(intまたはtuple): 入力端のパディングサイズ。デフォルトは0。dilation(intまたはtuple): ウィンドウ要素の間隔(dilation)。デフォルトは1。return_indices(bool): 最大値のインデックスを返すかどうか。MaxUnpool2dで使用されます。デフォルトはFalse。ceil_mode(bool): 出力サイズの計算にfloorではなくceilを使用するかどうか。デフォルトはFalse。
使用例
例1: 基本的な使い方
最大プーリング層を作成します:
実例
import torch
import torch.nn as nn
# 最大プーリング層を作成:ウィンドウ2x2、ストライド2
max_pool = nn.MaxPool2d(kernel_size=2, stride=2)
# 入力テンソルを作成
input_tensor = torch.randn(1, 1, 4, 4)
print("入力:n", input_tensor.squeeze().tolist())
# 順伝播
output = max_pool(input_tensor)
print("n出力:n", output.squeeze().tolist())
print("入力形状:", input_tensor.shape)
print("出力形状:", output.shape)
import torch.nn as nn
# 最大プーリング層を作成:ウィンドウ2x2、ストライド2
max_pool = nn.MaxPool2d(kernel_size=2, stride=2)
# 入力テンソルを作成
input_tensor = torch.randn(1, 1, 4, 4)
print("入力:n", input_tensor.squeeze().tolist())
# 順伝播
output = max_pool(input_tensor)
print("n出力:n", output.squeeze().tolist())
print("入力形状:", input_tensor.shape)
print("出力形状:", output.shape)
出力結果は次のとおりです:
输入: [[-0.4128, 0.2341, -0.9876, 0.4567], [ 0.1234, 0.8765, -0.2345, 0.6789], [-0.5678, 0.3456, 0.7890, -0.1234], [ 0.9012, -0.4567, 0.2345, 0.5678]] 输出: [[0.8765, 0.6789], [0.9012, 0.7890]] 输入形状: torch.Size([1, 1, 4, 4]) 输出形状: torch.Size([1, 1, 2, 2])
各2x2ウィンドウ内の最大値が保持されていることがわかります。
例2: 異なるkernel_sizeとstride
プーリングパラメータを調整します:
実例
import torch
import torch.nn as nn
# 3x3プーリング、ストライド1(オーバーラップなし)
pool3x3 = nn.MaxPool2d(kernel_size=3, stride=1)
# 非正方形プーリング
pool_rect = nn.MaxPool2d(kernel_size=(2, 3), stride=(2, 3))
input_tensor = torch.randn(1, 1, 6, 9)
print("入力形状:", input_tensor.shape)
print("3x3 プーリング出力:", pool3x3(input_tensor).shape)
print("矩形プーリング出力:", pool_rect(input_tensor).shape)
import torch.nn as nn
# 3x3プーリング、ストライド1(オーバーラップなし)
pool3x3 = nn.MaxPool2d(kernel_size=3, stride=1)
# 非正方形プーリング
pool_rect = nn.MaxPool2d(kernel_size=(2, 3), stride=(2, 3))
input_tensor = torch.randn(1, 1, 6, 9)
print("入力形状:", input_tensor.shape)
print("3x3 プーリング出力:", pool3x3(input_tensor).shape)
print("矩形プーリング出力:", pool_rect(input_tensor).shape)
例3: paddingを使用
エッジのパディングにより、ある程度エッジ情報を保持できます:
実例
import torch
import torch.nn as nn
# padding付きプーリング
pool_padding = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
input_tensor = torch.randn(1, 1, 4, 4)
output = pool_padding(input_tensor)
print("入力形状:", input_tensor.shape)
print("出力形状 (padding付き):", output.shape)
import torch.nn as nn
# padding付きプーリング
pool_padding = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
input_tensor = torch.randn(1, 1, 4, 4)
output = pool_padding(input_tensor)
print("入力形状:", input_tensor.shape)
print("出力形状 (padding付き):", output.shape)
例4: インデックスを返す
return_indicesを使用すると、デコーダーで位置を復元できます:
実例
import torch
import torch.nn as nn
# インデックスを返すプーリング層を作成
pool_indices = nn.MaxPool2d(kernel_size=2, stride=2, return_indices=True)
input_tensor = torch.randn(1, 1, 4, 4)
output, indices = pool_indices(input_tensor)
print("出力形状:", output.shape)
print("インデックス形状:", indices.shape)
print("インデックス値:", indices.squeeze().tolist())
import torch.nn as nn
# インデックスを返すプーリング層を作成
pool_indices = nn.MaxPool2d(kernel_size=2, stride=2, return_indices=True)
input_tensor = torch.randn(1, 1, 4, 4)
output, indices = pool_indices(input_tensor)
print("出力形状:", output.shape)
print("インデックス形状:", indices.shape)
print("インデックス値:", indices.squeeze().tolist())
例5: CNNでの使用
典型的なCNN構造におけるプーリング層の位置:
実例
import torch
import torch.nn as nn
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
# 畳み込み層
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.relu = nn.ReLU()
# プーリング層:通過するたびにサイズが半分になる
self.pool = nn.MaxPool2d(2, 2)
def forward(self, x):
x = self.relu(self.conv1(x)) # 32x32
x = self.pool(x) # 16x16
x = self.relu(self.conv2(x)) # 16x16
x = self.pool(x) # 8x8
return x
model = SimpleCNN()
input_image = torch.randn(1, 3, 32, 32)
output = model(input_image)
print("入力形状:", input_image.shape)
print("出力形状:", output.shape)
import torch.nn as nn
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
# 畳み込み層
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.relu = nn.ReLU()
# プーリング層:通過するたびにサイズが半分になる
self.pool = nn.MaxPool2d(2, 2)
def forward(self, x):
x = self.relu(self.conv1(x)) # 32x32
x = self.pool(x) # 16x16
x = self.relu(self.conv2(x)) # 16x16
x = self.pool(x) # 8x8
return x
model = SimpleCNN()
input_image = torch.randn(1, 3, 32, 32)
output = model(input_image)
print("入力形状:", input_image.shape)
print("出力形状:", output.shape)
最大プーリング vs 平均プーリング
| タイプ | 公式 | 特徴 | 適用シーン |
|---|---|---|---|
MaxPool2d |
max(領域) | 顕著な特徴を保持し、ノイズに対してよりロバスト | 画像分類、物体検出(よく使用) |
AvgPool2d |
mean(領域) | 特徴を平滑化し、背景情報を保持 | グローバル平均プーリング、特徴抽出 |
よくある質問
Q1: プーリング層は削除できますか?
ResNetやDenseNetなどの現代のネットワークは、プーリングの代わりに小さいstrideの畳み込みを使用する傾向がありますが、プーリングは高速なダウンサンプリングに今でもよく使用されます。
Q2: strideとkernel_sizeにはどのような関係がありますか?
stride = kernel_sizeの場合、プーリングウィンドウはオーバーラップしません。stride < kernel_sizeの場合、プーリングウィンドウはオーバーラップします。
使用シーン
nn.MaxPool2d主な適用シーンは以下のとおりです:
- 画像分類ネットワーク: 解像度を段階的に下げ、高次特徴を抽出
- 物体検出: 顕著な特徴の位置を保持
- 計算量の削減: 特徴マップのサイズを縮小
- 受容野の拡大: 後続の層がより広い範囲の特徴を捉えられるようにする
その他の拡張
PyTorch torch.nn リファレンスマニュアル