Yuki’s blog

自身の成果物や好きなことを発信していきたいと思います。情報系のジャンルが多いです。

PytorchによるVGG-16実装

     

こんばんは。
今回はILSVRCという大規模な画像コンペティションで優秀な成績を収めたDeep LearningのCNNモデルであるVGG-16を実装したのでメモ的な意味で残しておきます。研究でも使っているPytorchで実装しました。

必要なライブラリのインポート

まず、Pytorchでネットワークモデルを作成するために必要なライブラリをインポートします。

import torch
import torch.nn as nn

ネットワークのクラスの作成

pytorchでネットワークモデルを作成する際にはいくつかルールがあります。

  • nn.Moduleを継承する
  • __init__を実装
  • forwardを実装

以下に実装例を載せておきます。これらはほぼおまじないみたいな感じで覚えていれば良いです。

class vgg(nn.Module):
    def __init__(self):
        super(vgg, self).__init__()

    def forward(self, input):
        pass

__init__の中身には構成したい畳み込み層、活性化関数やプーリング層を記述していきます。forwardの中身には__init__で構成したものを使ってデータがどのように流れていって出力されるのかについて記述します。では具体的な書き方について説明していきます。

ネットワークの構成

 ネットワークの構成ですが、下記の画像のような構成になっています。VGG-16 のネットワークは16個の畳み込み層を用いて実装されています。
【畳み込み層】→【活性化関数(ReLU)】→【プーリング層】が次々と重ねられています。

f:id:Yuki9892:20201010174501p:plain
VGGのネットワーク構成

 実装の方法ですが、nn.Sequential()を用いて実装します。これを用いて実装したほうがforward()に書く部分がスッキリするのでオススメです。

    def __init__(self):
        super(vgg_fcn, self).__init__()

        self.features = nn.Sequential(
            nn.Conv2d(
                in_channels=3,
                out_channels=64,
                kernel_size=(3, 3),
                stride=(1, 1),
                padding=(1, 1),
            ),
            nn.ReLU(inplace=True),
            nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(
                kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False
            ),
            nn.Conv2d(64, 128, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.Conv2d(128, 128, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, 2, 0, 1, False),
            nn.Conv2d(128, 256, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, 2, 0, 1, False),
            nn.Conv2d(256, 512, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, 2, 0, 1, False),
            nn.Conv2d(512, 512, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, (3, 3), (1, 1), (1, 1)),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, 2, 0, 1, False),
        )
        self.avgpool = nn.AdaptiveAvgPool2d(output_size=(7, 7))
        self.classifier = nn.Sequential(
            nn.Linear(in_features=25088, out_features=4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(in_features=4096, out_features=4096, bias=True),
            nn.ReLU(inplace=True),
            nn.Dropout(p=0.5, inplace=True),
            nn.Linear(in_features=4096, out_features=1000, bias=True),
        )

    def forward(self, input):
        output = self.features(input)
        output = self.avgpool(output)
        output = output.view(input.shape[0], -1)
        output = self.classifier(output)
        return output

以上がVGG-16の構成です。