PyTorch torch.nn.Conv2d 関数
torch.nn.Conv2dは、PyTorch において 2 次元畳み込みに使用されるモジュールで、畳み込みニューラルネットワーク(CNN)の中心的な構成要素です。
それは入力テンソルに学習可能な畳み込みカーネルを適用することで空間特徴を抽出し、画像処理やコンピュータビジョンタスクで広く使用されています。
関数定義
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')
パラメータの説明:
in_channels(int): 入力チャネル数。例えばRGB画像は3です。out_channels(int): 出力チャネル数、つまり畳み込みカーネルの数です。kernel_size(int または tuple): 畳み込みカーネルのサイズ。整数(正方形)またはタプル(高さ x 幅)にできます。stride(int または tuple): 畳み込みカーネルが移動するストライド。デフォルトは1です。padding(int または tuple): 入力端のパディングサイズ。デフォルトは0です。dilation(int または tuple): 畳み込みカーネル要素間の間隔。デフォルトは1(標準畳み込み)です。groups(int): グループ畳み込みのグループ数。デフォルトは1(標準畳み込み)です。bias(bool): バイアス項を追加するかどうか。デフォルトはTrue。padding_mode(str): パディングモード。選択可能:'zeros'、'reflect'、'replicate'、'circular'。
属性:
weight(Tensor): 形状が (out_channels, in_channels/groups, kernel_sizebias(Tensor): 形状が (out_channels,) の学習可能なバイアス。
使用例
例1: 基本的な使い方
簡単な2次元畳み込み層を作成します:
例
import torch
import torch.nn as nn
# 畳み込み層を作成:入力3チャネル、出力32チャネル、カーネル3x3
conv = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3)
# 重みとバイアスの形状を出力
print("重みの形状:", conv.weight.shape) # torch.Size([32, 3, 3, 3])
print("バイアスの形状:", conv.bias.shape) # torch.Size([32])
# 入力テンソルを作成:batch=1、チャネル=3、高さ=32、幅=32
input_tensor = torch.randn(1, 3, 32, 32)
# 順伝播
output = conv(input_tensor)
print("入力の形状:", input_tensor.shape) # torch.Size([1, 3, 32, 32])
print("出力の形状:", output.shape) # torch.Size([1, 32, 30, 30])
import torch.nn as nn
# 畳み込み層を作成:入力3チャネル、出力32チャネル、カーネル3x3
conv = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3)
# 重みとバイアスの形状を出力
print("重みの形状:", conv.weight.shape) # torch.Size([32, 3, 3, 3])
print("バイアスの形状:", conv.bias.shape) # torch.Size([32])
# 入力テンソルを作成:batch=1、チャネル=3、高さ=32、幅=32
input_tensor = torch.randn(1, 3, 32, 32)
# 順伝播
output = conv(input_tensor)
print("入力の形状:", input_tensor.shape) # torch.Size([1, 3, 32, 32])
print("出力の形状:", output.shape) # torch.Size([1, 32, 30, 30])
出力結果は次のとおりです:
权重形状: torch.Size([32, 3, 3, 3]) 偏置形状: torch.Size([32]) 输入形状: torch.Size([1, 3, 32, 32]) 输出形状: torch.Size([1, 32, 30, 30])
デフォルトでは padding=0 のため、出力サイズは小さくなります。サイズを維持したい場合は padding を追加できます。
例2: paddingを使用してサイズを維持
paddingを追加することで入力と出力のサイズを一致させることができます:
例
import torch
import torch.nn as nn
# padding付き畳み込み層を作成:padding=1 でサイズを維持
conv_pad = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=1)
# 入力
input_tensor = torch.randn(1, 3, 32, 32)
# 順伝播
output = conv_pad(input_tensor)
print("入力の形状:", input_tensor.shape)
print("出力の形状:", output.shape) # 32x32を維持
import torch.nn as nn
# padding付き畳み込み層を作成:padding=1 でサイズを維持
conv_pad = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=1)
# 入力
input_tensor = torch.randn(1, 3, 32, 32)
# 順伝播
output = conv_pad(input_tensor)
print("入力の形状:", input_tensor.shape)
print("出力の形状:", output.shape) # 32x32を維持
出力結果は次のとおりです:
输入形状: torch.Size([1, 3, 32, 32]) 输出形状: torch.Size([1, 32, 32, 32])
例3: 異なるstrideとdilation
stride と dilation を調整すると、出力サイズと受容野を変更できます:
例
import torch
import torch.nn as nn
# ストライド畳み込み:stride=2 でサイズを縮小
conv_stride = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1)
input_tensor = torch.randn(1, 3, 32, 32)
output_stride = conv_stride(input_tensor)
print("Stride=2 -> 出力の形状:", output_stride.shape)
# 空洞畳み込み:dilation=2 で受容野を拡大
conv_dilation = nn.Conv2d(3, 32, kernel_size=3, dilation=2)
output_dilation = conv_dilation(input_tensor)
print("Dilation=2 -> 出力の形状:", output_dilation.shape)
import torch.nn as nn
# ストライド畳み込み:stride=2 でサイズを縮小
conv_stride = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1)
input_tensor = torch.randn(1, 3, 32, 32)
output_stride = conv_stride(input_tensor)
print("Stride=2 -> 出力の形状:", output_stride.shape)
# 空洞畳み込み:dilation=2 で受容野を拡大
conv_dilation = nn.Conv2d(3, 32, kernel_size=3, dilation=2)
output_dilation = conv_dilation(input_tensor)
print("Dilation=2 -> 出力の形状:", output_dilation.shape)
出力結果は次のとおりです:
Stride=2 -> 输出形状: torch.Size([1, 32, 16, 16]) Dilation=2 -> 输出形状: torch.Size([1, 32, 28, 28])
例4: グループ畳み込み
groups パラメータによりグループ畳み込みを実現でき、軽量なネットワークでよく使用されます:
例
import torch
import torch.nn as nn
# グループ畳み込み:groups=2 で入力を2つのグループに分割
conv_group = nn.Conv2d(in_channels=4, out_channels=8, kernel_size=3, groups=2)
# 入力は4チャネル
input_tensor = torch.randn(1, 4, 16, 16)
# 順伝播
output = conv_group(input_tensor)
print("入力の形状:", input_tensor.shape)
print("出力の形状:", output.shape)
print("重みの形状:", conv_group.weight.shape) # グループ化すると重みの形状が異なります
import torch.nn as nn
# グループ畳み込み:groups=2 で入力を2つのグループに分割
conv_group = nn.Conv2d(in_channels=4, out_channels=8, kernel_size=3, groups=2)
# 入力は4チャネル
input_tensor = torch.randn(1, 4, 16, 16)
# 順伝播
output = conv_group(input_tensor)
print("入力の形状:", input_tensor.shape)
print("出力の形状:", output.shape)
print("重みの形状:", conv_group.weight.shape) # グループ化すると重みの形状が異なります
出力結果は次のとおりです:
输入形状: torch.Size([1, 4, 16, 16]) 输出形状: torch.Size([1, 8, 14, 14]) 权重形状: torch.Size([8, 2, 3, 3])
例5: ニューラルネットワークでの使用
簡単な手書き数字認識ネットワークを構築します:
例
import torch
import torch.nn as nn
class SimpleCNN(nn.Module):
def __init__(self, num_classes=10):
super(SimpleCNN, self).__init__()
# 1つ目の畳み込みブロック
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)
self.bn1 = nn.BatchNorm2d(32)
self.relu1 = nn.ReLU()
# 2つ目の畳み込みブロック
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.bn2 = nn.BatchNorm2d(64)
self.relu2 = nn.ReLU()
# プーリング層
self.pool = nn.MaxPool2d(2, 2)
# 全結合層
self.fc = nn.Linear(64 * 7 * 7, num_classes)
def forward(self, x):
# 1つ目の畳み込みブロック
x = self.conv1(x)
x = self.bn1(x)
x = self.relu1(x)
x = self.pool(x)
# 2つ目の畳み込みブロック
x = self.conv2(x)
x = self.bn2(x)
x = self.relu2(x)
x = self.pool(x)
# フラット化して分類
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
# モデルを作成
model = SimpleCNN(num_classes=10)
# テスト入力:batch=4、グレースケール画像 28x28
input_image = torch.randn(4, 1, 28, 28)
output = model(input_image)
print("入力の形状:", input_image.shape)
print("出力の形状:", output.shape) # torch.Size([4, 10])
import torch.nn as nn
class SimpleCNN(nn.Module):
def __init__(self, num_classes=10):
super(SimpleCNN, self).__init__()
# 1つ目の畳み込みブロック
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)
self.bn1 = nn.BatchNorm2d(32)
self.relu1 = nn.ReLU()
# 2つ目の畳み込みブロック
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.bn2 = nn.BatchNorm2d(64)
self.relu2 = nn.ReLU()
# プーリング層
self.pool = nn.MaxPool2d(2, 2)
# 全結合層
self.fc = nn.Linear(64 * 7 * 7, num_classes)
def forward(self, x):
# 1つ目の畳み込みブロック
x = self.conv1(x)
x = self.bn1(x)
x = self.relu1(x)
x = self.pool(x)
# 2つ目の畳み込みブロック
x = self.conv2(x)
x = self.bn2(x)
x = self.relu2(x)
x = self.pool(x)
# フラット化して分類
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
# モデルを作成
model = SimpleCNN(num_classes=10)
# テスト入力:batch=4、グレースケール画像 28x28
input_image = torch.randn(4, 1, 28, 28)
output = model(input_image)
print("入力の形状:", input_image.shape)
print("出力の形状:", output.shape) # torch.Size([4, 10])
出力サイズの計算
畳み込み層の出力サイズの計算式:
H_out = floor((H_in + 2 * padding[0] - dilation[0] * (kernel_size[0] - 1) - 1) / stride[0]) + 1 W_out = floor((W_in + 2 * padding[1] - dilation[1] * (kernel_size[1] - 1) - 1) / stride[1]) + 1
よくある質問
Q1: 畳み込みカーネルサイズはどのように選びますか?
一般的な畳み込みカーネルサイズ:
1x1: チャネル数を変更し、非線形性を追加するために使用します3x3: 最も一般的で、パラメータ数と受容野のバランスが取れています5x5、7x7: 受容野は大きいですが、パラメータ数が多くなります
Q2: paddingとstrideはどのように選びますか?
- 特徴マップのサイズを維持するには padding を使用します
padding = (kernel_size - 1) / 2 - ダウンサンプリングには stride を使用します
stride > 1
使用シーン
nn.Conv2dは、コンピュータビジョンで最も重要な層の1つであり、主な適用シーンは次のとおりです:
- 画像分類: 画像の特徴を抽出します。例:VGG、ResNet など
- 物体検出: YOLO、Faster R-CNN など
- セマンティックセグメンテーション: U-Net、FCN など
- スタイル変換: 芸術的な画像を生成
ヒント:現代のCNNでは、3x3畳み込みが最も一般的であり、パラメータ数を小さく保ちながら十分な空間情報をカバーできます。
その他の拡張
PyTorch torch.nn リファレンスマニュアル