PyTorchのインストールとニューラルネットワーク


pytorchのインストール

下のサイトにインストール方法が載っています。
一応、pytorchの公式サイトです。
https://pytorch.org/

私の環境では、Anacondaを使って、pytorchを入れました。
コマンドを書いときます。

conda install pytorch torchvision -c pytorch

PyTorchでGPUを使う

Windows10でGPU環境を整える
PythonでGPUを使うCUDA10

Pytorch

torch.nn

ニューラルネットワークを構築するための様々なデータ構造やレイヤーが定義されている。

torch.optim

確率的勾配降下法を中心とした最適化アルゴリズムが実装されている

torch.utils.data

SGDの繰り返し計算を回す際のミニバッチを作るためのユーティリティ関数が含まれている。

Tensor

Tensorとは、多次元配列を扱うためのデータ構造

自動微分

Tensorにはrequires_gradという属性があり、これをTrueにすることで自動微分を行なうフラグが有効になる。
ニューラルネットワークを扱う場合、パラメータやデータはすべてこのフラグがゆうこうになっている。
requires_gradが有効なTensorに対して様々な演算を積み重ねていくことで計算グラフが構築され、backwardメソッドを呼ぶと、その情報から自動微分される。

DatasetとDataLoader

ミニバッチ学習データのシャッフル、さらには並列処理を簡単に行える

TensorDatasetはDatasetを継承したクラスで特徴量XとラベルYをまとめるコンテナであり、このTensorDatasetをDataLoaderにわたすことで、forループでデータの一部のみを簡単に受け取れるようになっている

TensorDatasetにはTensorのみ渡すことができ、Variableは渡せない

Pytorchでニューラルネットワークを実装

学習データは、sklearn.datasets.load_digitsを使用します。

サンプルコード

import torch
from torch import nn
from torch import optim
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from torch.utils.data import TensorDataset, DataLoader


digits = load_digits()

X = digits.data
y = digits.target

#学習用データとテストデータに分ける
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.3)

X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.int64)
y_test = torch.tensor(y_test, dtype=torch.int64)

#ミニバッチ学習
ds = TensorDataset(X_train, y_train)
loader = DataLoader(ds, batch_size=32, shuffle=True)

#ネットワーク構築
net = nn.Sequential(
    nn.Linear(64, 32),
    nn.ReLU(),
    nn.Linear(32, 16),
    nn.ReLU(),
    nn.Linear(16, 10)
)

#損失関数
loss_fn = nn.CrossEntropyLoss()

#最適化
optimizer = optim.Adam(net.parameters())


train_losses = []
test_losses = []

train_accuracy = []
test_accuracy = []

#学習
for epoch in range(100):
    running_loss = 0.0
    for i, (XX, yy) in enumerate(loader):
        optimizer.zero_grad()
        y_pred = net(XX)
        loss = loss_fn(y_pred, yy)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
    train_losses.append(running_loss/i)
    y_pred = net(X_test)
    test_loss = loss_fn(y_pred, y_test)
    test_losses.append(test_loss.item())
    
    print("epoch{0}:train={1};test={2}".format(epoch+1,running_loss/i,test_loss.item()))
    
    _, y_pred = torch.max(net(X_train), 1)
    train_accuracy.append((y_pred == y_train).sum().item() / len(y_train))
    
    _, y_pred = torch.max(net(X_test), 1)
    test_accuracy.append((y_pred == y_test).sum().item() / len(y_test))


lossをグラフ化

matplotで一応lossのグラフ化をしようと思います。

%matplotlib inline
import matplotlib.pyplot as plt

plt.plot(train_losses, label="train")
plt.plot(test_losses, label="test", color="orange")
plt.legend()
plt.savefig('train_test_loss.png')
plt.show()

Accuracyの計算

plt.plot(train_accuracy, label="train", color="blue")
plt.plot(test_accuracy, label="test", color="orange")
plt.legend()
plt.savefig('train_test_accuracy.png')
plt.show()

DatasetとDataLoader

#ミニバッチ学習
ds = TensorDataset(X_train, y_train)
loader = DataLoader(ds, batch_size=32, shuffle=True)

#学習
for epoch in range(100):
    running_loss = 0.0
    for i, (XX, yy) in enumerate(loader):
        optimizer.zero_grad()
        y_pred = net(XX)
        loss = loss_fn(y_pred, yy)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
    train_losses.append(running_loss/i)
    y_pred = net(X_test)
    test_loss = loss_fn(y_pred, y_test)
    test_losses.append(test_loss.item())
    print("epoch{0}:train={1};test={2}".format(epoch+1,running_loss/i,test_loss.item()))

ネットワークのモジュール化

Pytorchで独自ネットワークを作るには、nn.Moduleを継承したクラスを定義します。
nn.Moduleは、nn.Linearなどのすべての層の基底クラスになっている。

カスタム層を作る際には、forwardメソッドを実装すれば、自動微分まで可能になる。

class MLP(nn.Module):
    def __init__(self, in_features, out_features, bias=True, p=0.5):
        super().__init__()
        self.linear = nn.Linear(in_features, out_features, bias)
        self.relu = nn.ReLU()
        self.drop = nn.Dropout(p)
        
    def __call__(self, x):
        t = self.linear(x)
        t = self.relu(t)
        t = self.drop(t)
        return t

使い方

mlp = MLP(64, 10)
mlp(X_train)

参考

sklearn.datasets.load_digits