VGGアーキテクチャの設計思想
AlexNetはLeNetに比べて深い構造を持ち、精度の向上を実現した。この流れを受けて、さらにネットワークを深く・大規模化する方法が模索された。計算コストを抑えつつ表現力を高めるために、VGGでは複数の小さな畳み込み層を積み重ねる戦略を採用している。
VGGブロックの構成
VGGの基本単位である「VGGブロック」は以下の要素で構成される:
- 3×3サイズの畳み込みカーネル(パディング=1)を複数段設置
- 各畳み込み後にReLU活性化関数を適用
- ブロック終了時に2×2の最大プーリング層(ストライド=2)を配置し、空間解像度を半減
3×3カーネルを採用する理由は、5×5よりも少ない計算量で同等以上の受容野を実現できるため。例えば、連続した2つの3×3畳み込みは、理論的に5×5と同程度の空間情報を扱える一方で、パラメータ数が削減され、学習が安定しやすい。
モジュール型ネットワークの実装
以下は、PyTorchを用いたVGGブロックの実装例である。再利用可能なブロックとして定義することで、アーキテクチャの変更が容易になる。
import torch
from torch import nn
def create_vgg_block(num_convs: int, input_channels: int, output_channels: int) -> nn.Sequential:
block_layers = []
for _ in range(num_convs):
block_layers.append(nn.Conv2d(input_channels, output_channels, kernel_size=3, padding=1))
block_layers.append(nn.ReLU())
input_channels = output_channels
block_layers.append(nn.MaxPool2d(kernel_size=2, stride=2))
return nn.Sequential(*block_layers)
全体ネットワークの構成
VGGは複数の上記ブロックを直列に接続し、その後に全結合層を配置する。代表的なVGG-11は次の構成を持つ:
- 5つの畳み込みブロック(それぞれ1, 1, 2, 2, 2層の畳み込み)
- 出力チャンネル数:64 → 128 → 256 → 512 → 512へと段階的に増加
- 最終的な特徴マップは7×7×512となり、これを4096次元の全結合層へ展開
以下は、設定からネットワークを動的に構築するコード例である。
# 各ブロックの構成:(畳み込み層数, 出力チャンネル数)
config = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))
def build_vgg_network(config: tuple) -> nn.Sequential:
blocks = []
in_channels = 3 # カラー画像入力の場合
for num_conv_layers, out_channels in config:
blocks.append(create_vgg_block(num_conv_layers, in_channels, out_channels))
in_channels = out_channels
return nn.Sequential(
*blocks,
nn.Flatten(),
nn.Linear(out_channels * 7 * 7, 4096),
nn.ReLU(), nn.Dropout(0.5),
nn.Linear(4096, 4096),
nn.ReLU(), nn.Dropout(0.5),
nn.Linear(4096, 10)
)
model = build_vgg_network(config)
中間層の出力形状の確認
入力サイズ224×224のデータを順伝播させながら、各層のテンソル形状を観察することで、設計の妥当性を検証できる。
sample_input = torch.randn(1, 3, 224, 224)
for layer in model:
sample_input = layer(sample_input)
print(f"{layer.__class__.__name__}: {sample_input.shape}")
軽量モデルでの学習実験
VGGは計算負荷が高いため、Fashion-MNISTのような小規模データセットではチャンネル数を削減した軽量化モデルを使用する。以下はチャンネル数を1/4に縮小する手法である。
reduced_config = [(layers, channels // 4) for layers, channels in config]
compact_model = build_vgg_network(reduced_config)
# データローダー(リサイズ付き)
train_loader, test_loader = d2l.load_data_fashion_mnist(batch_size=128, resize=224)
# GPU使用可能なら活用
device = d2l.try_gpu()
d2l.train_ch6(compact_model, train_loader, test_loader, num_epochs=10, lr=0.05, device=device)