konchangakita

KPS IoT(旧Xi IoT)を一番楽しんでるブログ 会社の看板を背負いません 転載はご自由にどうぞ

PyTorchを使ったDeep Learningのお勉強 基礎編

f:id:konchangakita:20200418114302p:plain:w400

ディープラーニング界隈では流行っていると噂のPyTorchを使ってディープラーニングの実装をやってみる
Python機械学習ライブラリになるわけですが、ようやくここまで追いついてきたって感じ
それにしても、独学での道のりは長いな~~

PyTorch お勉強シリーズ
第1回 PyTorchを使ったDeep Learningのお勉強 基礎編(イマココ)
第2回 PyTorchを使ったDeep Learningのお勉強 PyTorch Lightning編
第3回 PyTorchを使ってDeep Learningのお勉強 TensorBoard編
第4回 PyTorchを使ったDeep Learningのお勉強 画像認識編(MNIST)
第5回 PyTorchを使ったDeep Learningのお勉強 画像認識編(CIFAR-10)


ということではじめてのPyTorch

PyTorch インストール

anaconda環境を使っている場合はインストールは至って簡単
anaconda上でPyTorch用にPythonの仮想環境を作って、検索してインストールするだけ
(なんとなく TesorFlow環境とは分けておきたかった)
f:id:konchangakita:20200419171148p:plain

Google Colab上では、デフォルトでPyTorchインストールされているので、超簡単にお試しができてよいですね
colab.research.google.com

バージョン確認
ちゃんとインストールできていればこんな感じでバージョンが出力されることでしょう

import torch
torch.__version__

>>> 出力:
 '1.4.0'

PyTorch とりあえずの基礎

PyTorchの行列

numpy.ndarrayと同等な感じで扱います

torch.zeros(2,4)

>>> 出力:
tensor([[0., 0., 0., 0.],
        [0., 0., 0., 0.]])
torch.randn(2,4)

>>> 出力:
tensor([[ 1.2333, -0.1832, -1.3140, -1.6894],
        [ 1.2525, -0.5545,  0.3019,  1.1295]])


層の定義

PyTorchでは、一気に層の重みとバイアスを定義してしまえる
こんな風に書くと

import torch.nn as nn

# 乱数シードの固定
torch.manual_seed(1)
# 全結合層の定義
fc = nn.Linear(3, 2) # 入力と出力の数

この重み(W)とバイアス(b)の初期値を一気に定義してくれます
f:id:konchangakita:20200409191210p:plain


中身を確認

print(fc.weight)
print(fc.bias)

>>> 出力:
Parameter containing:
tensor([[ 0.2975, -0.2548, -0.1119],
        [ 0.2710, -0.5435,  0.3462]], requires_grad=True)
Parameter containing:
tensor([-0.1188,  0.2937], requires_grad=True)


入力値の定義

次に入力にあたるXを3個定義してやります

# リストから PyTorch の Tensor に変換、データ型に注意
X = torch.tensor([[1,2,3]], dtype=torch.float32)
print(X.shape)
X.dtype

>>>出力:
torch.Size([1, 3])
torch.float32


線形変換

では、早速計算をしてやります
事前に定義した fc に X を与えてやるだけで

y = fc(X)
y
>>> 出力:
tensor([[ 0.9894, -2.0327]], grad_fn=<AddmmBackward>)

つまりこの計算を一行でやってくれてます、ラクチン
f:id:konchangakita:20200418130659p:plain:w300


非線形変換

次に活性化関数のReLuを試してみます(0以下を0に変換しちゃう関数)

#非線形変換
import torch.nn.functional as F

# ReLU 関数
z = F.relu(y)
z

>>> 出力:
tensor([[0.9894, 0.0000]], grad_fn=&lt;ReluBackward0&gt;)


多層化

階層をこんな感じで多層化する場合
f:id:konchangakita:20200418132233p:plain

定義も複数してやります

# 全結合層の定義
fc1 = nn.Linear(3, 2) #一層目を定義
fc2 = nn.Linear(2, 1) #二層目を定義
X = torch.tensor([[1,2,3]], dtype=torch.float32) #入力Xを定義

# 一層目の計算
h1 = fc1(x)
z1 = F.relu(h1) #ReLu

# 二層目の計算
u2 = fc2(z1)
u2



PyTorchのコスト関数(損失関数)

予測した数値と正解データの間の差を定量化したコスト関数(損失関数)ですが、
Pytorchであらかじめ定義してくれているので、これまたラクチン
計算式を都度都度思い出さなくてもよいのです

問題 PyTorch定義 損失関関数
回帰 nn.MSELoss 平均二乗誤差
多クラス分類 nn.CrossEntropyLoss ソフトマックス交差エントロピ誤差

nn.MSELoss - PyTorch 1.4
https://pytorch.org/docs/stable/nn.html#torch.nn.MSELoss

nn.CrossEntropyLoss - PyTorch 1.4
https://pytorch.org/docs/stable/nn.html#crossentropyloss


簡単に実装してみるとこんな感じ

import torch
import torch.nn as nn

# MSELoss 平均二乗誤差
x = torch.randn(4)
y = torch.randn(4)
print("x: ",x)
print("y: ",y)
criterion = nn.MSELoss()
loss = criterion(x, y)
print("MSELoss: ",loss)

# CrossEntropyLoss ソフトマックス交差エントロピ誤差
x = torch.randn(1, 4)
y = torch.LongTensor([1]).random_(4)
criterion = nn.CrossEntropyLoss()
loss = criterion(x, y)
print("CrossEntropyLoss: ",loss)

>>> 出力:

x:  tensor([0.7670, 0.6899, 0.3282, 0.5085])
y:  tensor([-0.0515, -0.6248,  0.2844, -0.9130])
MSELoss:  tensor(1.1053)
CrossEntropyLoss:  tensor(1.2331)

コードの中では、こんな風に使うみたいです

# コスト関数の設定
criterion = nn.CrossEntropyLoss()

# ロスの計算(y:計算結果、t:正解ラベル)
loss = criterion(y, t)

# 勾配の計算
loss.backward()


PyTorchの重みの更新(最適化)

コスト関数で導いたロスから、パラメータ(重みとバイアス)の学習する方法

どの最適化手法を使うかは、こんな感じで
あらかじめ用意されているので、計算式を覚えておく必要ないですね

import torch
import torch.optim as optim

# 最適化手法をどれか選択
optimizer = optim.SGD(net.parameters(), lr=0.1)
optimizer = optim.Adagrad(net.parameters())
optimizer = optim.RMSprop(net.parameters())
optimizer = optim.Adam(net.parameters(), lr=1e-1, betas=(0.9, 0.99), eps=1e-09)

パラメータ更新はロスの計算、勾配計算の後に実行

optimizer.step()



GPUを使った計算処理

PyTorchでGPUを使った処理をする場合

まずはGPUが使える環境なのかチェック

# GPU の設定状況に基づいたデバイスの選択
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
device

>>> 出力:
device(type='cuda', index=0)

GPUが使える環境であるならば、データGPUへ転送してやることで
GPUを使った計算が行えます

x = torch.randn(4)
x = x.to(device)

>>>出力:
tensor([-0.5593, -0.1197, -0.1635, -0.2505], device='cuda:0')

device='cuda:x'ってついてればOK



PyTorchを使った順伝播の実装

というわけで、早速PyTorchの実装実験してみる
scikit-learn に用意されている Iris という「アヤメの品種」を分類する問題を2層で定義して、学習から検証までを一つにまとめて書いてみた


とりあえずの基礎はここまで