ゼロからネットワークを作成
既存のネットワークではなく、自分でゼロからネットワークを設定してみます。ネットワークのコードは以下を使って、実装方法を確認してみました。
ちなみに、このコードはMNISTという0~9の数字 (28×28ピクセルの画像) を分類するためのモデルとして設計されています。
Build the Neural Network – PyTorch Tutorials 1.12.0+cu102 documentation
ネットワークを構成するためのモジュール類はtorch.nnに入っています。
まずは、必要モジュールを一式インポートします。
import torch from torch import nn
ネットワークの定義
ネットワークの定義に必要な各要素はnn.Moduleのサブクラスに含まれているため、nn.Moduleを継承したクラスとして設定します。
設定するモデルは以下の2つの関数が含まれている必要があります。
- __init__ : 初期化
- forward : feed forward処理を実施
クラスの外部とやり取りをするのはこの2つだけですので、内部的な処理を行う関数は別途、任意で作成しても問題ありません。
上記リンクで定義されているネットワークは以下のシンプルなものです。全結合層とReLUから構成されていて、最終出力のlogitsを後処理でSoftmaxにかけることで、入力画像が0~9のそれぞれの数字である確率が求められることになります。
class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten() # 2次元画像を1次元に変換
# 3つの全結合層 (ReLUを間に含む) からなるネットワーク
self.linear_relu_stack = nn.Sequential(
nn.Linear(28*28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
)
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
model = NeuralNetwork()
定義後のモデルの中身はこんな感じです。
NeuralNetwork(
(flatten): Flatten(start_dim=1, end_dim=-1)
(linear_relu_stack): Sequential(
(0): Linear(in_features=784, out_features=512, bias=True)
(1): ReLU()
(2): Linear(in_features=512, out_features=512, bias=True)
(3): ReLU()
(4): Linear(in_features=512, out_features=10, bias=True)
)
)
nn.Sequential()モジュール
ここで、nn.Sequential()というものが出てきました。これは、処理順序を定義したコンテナです。nn.Sequential()にレイヤを入れていくことで、格納された順番に処理が進んでいくことになります。
上の例だと、nn.Linear(28*28, 512)のアウトプットが、nn.ReLU()のインプットとなる、というイメージです。
各レイヤはスライスで取得することができます。
print(model.linear_relu_stack[0]) # Linear(in_features=784, out_features=512, bias=True)
OrderedDict
順序付きの辞書であるOrderedDictを使うことで、スライスだけでなく、名前指定でもレイヤを取得できるようになります。
from collections import OrderedDict # OrderedDictをインポート
class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(OrderedDict([
('fc1', nn.Linear(28*28, 512)),
('relu1', nn.ReLU()),
('fc2', nn.Linear(512, 512)),
('relu2', nn.ReLU()),
('fc3', nn.Linear(512, 10)),
]))
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
model = NeuralNetwork()
こんな感じでレイヤに名前が付きました。
NeuralNetwork(
(flatten): Flatten(start_dim=1, end_dim=-1)
(linear_relu_stack): Sequential(
(fc1): Linear(in_features=784, out_features=512, bias=True)
(relu1): ReLU()
(fc2): Linear(in_features=512, out_features=512, bias=True)
(relu2): ReLU()
(fc3): Linear(in_features=512, out_features=10, bias=True)
)
)
OrderedDictを使って設定した場合、レイヤは以下の2パターンで呼び出せます。
print(model.linear_relu_stack[0]) # スライス指定 print(model.linear_relu_stack.fc1) # 名前指定 # どちらの場合も # Linear(in_features=784, out_features=512, bias=True)