データ分析ガチ勉強アドベントカレンダー 19日目。
2日間、Kerasに触れてみましたが、最近はPyTorchがディープラーニング系ライブラリでは良いという話も聞きます。
とりあえずTutorialを触りながら使ってみて、自分が疑問に思ったことをまとめていくスタイルにします。
また、同じく有名ライブラリであるKerasやTensorFlowについての比較もしたいと思っています(Define and RunかDefine by Runか)
PyTorchとは
ざっくりまとめると
- 深層学習用ライブラリ
- chainerからフォークされて作られている。思想はChainerを引き継いでいる。
- GPUでの計算も楽に行える
- Define by Run
- コミュニティが活発で、後発にもかかわらず急速に発達
特にDefine by RunはTensorflowやKerasと大きく異なる特徴です(後述)
PyTorch入門
変数の扱い方
PyTorchでは、変数や関数をPyTorchオリジナルの型として扱う。大体はnumpyライクに扱えるので、ストレスは少ない
x = torch.Tensor(5,3)
y = torch.rand(5,3)
print(x.add_(y))
print(torch.add(x,y))
print(x+y)
print(y[:,1],y.mean(), y.std())
print(torch.ones(10))
print(torch.ones(10)+1)
import numpy as np
a = np.arange(4).reshape(2,2)
x = torch.from_numpy(a)
Autograd
torch.autograd
Function
とVariables
で定義すると、演算結果が保存されるので、
そのままさかのぼった微分が可能。
下記の式は、
より、
その結果を返す
より詳しい内容は公式
from torch.autograd import Variable
import numpy as np
x = Variable(torch.FloatTensor([1,2,3,4]), requires_grad=True)
y = x.float()**2 + 2
z = y**2
out = z.mean()
out.backward()
print(x.grad)
出力
<AddBackward0 object at 0x7f88d576ea90>
Variable containing:
3 12
33 72
[torch.FloatTensor of size 2x2]
学習の手順
- 学習ができるニューラルネットを定義する。
- データセットを繰り返し投げられるようにする。
- インプットに応じて、処理(計算)が走るようにする
- 誤差(損失)を計算する
- back propagationを実施する
- optimizerによってパラメータを更新する
この中でデータセットを繰り返し投げる以外の要素を説明していく。
ライブラリ構成
PyTorchのよく使うパッケージ
パッケージ |
説明 |
torch |
NumPyのような配列(テンソル)ライブラリ。GPUも簡単に使える |
torch.autograd |
自動微分ライブラリ。Torchで定義されたすべての関数に対して微分を可能にしている |
torch.nn |
ネットワークを構成する要素 |
torch.optim |
パラメータ更新時に使う最適化パッケージ |
torch.utils |
DataLoaderなど、その他のユーティリティ関数 |
torch.nn
ネットワークを構成する要素関連はここに入っている
Conv1d
,Conv2d
,MaxPool1d
, AvePool1d
, AdaptiveAvgPool1d
... : CNN向け
RNN
, LSTM
, GRU
.... : RNN向け
BatchNorm1d
,BachNorm2d
, InstanceNorm1d
,... : バッチ正規化
functional.hoge
: 活性化関数(SoftMax, ReLUなど)
- その他、dropout, sparse_embeddings,...
詳しくはpytorch:nn
すべてPyTorch内の関数で渡してやることができれば、autograd
により、back propagation時の微分演算などがスムーズ
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 6, 5)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
x = x.view(-1, self.num_flat_features(x))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def num_flat_features(self, x):
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s
return num_features
net = Net()
print(net)
出力 : ネットワーク構成が分かる
Net(
(conv1): Conv2d (1, 6, kernel_size=(5, 5), stride=(1, 1))
(conv2): Conv2d (6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear(in_features=400, out_features=120)
(fc2): Linear(in_features=120, out_features=84)
(fc3): Linear(in_features=84, out_features=10)
)
値を投げる
torch
の型にしたがってデータを構成し、投げる。
params = list(net.parameters())
input = Variable(torch.randn(1, 1, 32, 32))
out = net(input)
損失関数
誤差の算出のために、いろいろな関数が用意されている。シンプルなのはMean Squared Error。いろんな誤差を知りたい人は、機械学習で使う指標総まとめ(教師あり学習編)へ。
- MSELoss
- CrossEntropyLoss
- NLLLoss(negative log likelihood loss) (1d, 2d)
- Poisson NLL Loss
- KLDivLoss (Kullback-Leibler divergence)
- BCELoss (Binary Cross Entropy)
- ...
より詳しくは公式
output = net(input)
target = Variable(torch.arange(1, 11))
criterion = nn.MSELoss()
loss = criterion(output, target)
back propagation
損失が算出できたので。この損失からさかのぼっていく。PyTorchだと、backward
とだけ実行すれば、簡単にパラメータの微分値を算出できるようになっている。
net.zero_grad()
loss.backward()
重みのアップデート
学習には、torch.optim
を使う。下記のようなアルゴリズムがある。
- SGD, ASGD, Nesterov-SGD
- Adadelta, Adagrad, Adam, SparseAdam, Adamax
- LBFGS
- RMSProp, Rprop
また、torch.optim.lr_scheduler
で学習率の調整もできる。
import torch.optim as optim
optimizer = optim.SGD(net.parameters(), lr=0.01)
optimizer.zero_grad()
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()
これで一通り終了。最終的にはデータを繰り返し投げて、学習を進めていく。
Githubのday19では、最後にMNISTの分類をPyTorchでやっている。そちらも是非どうぞ。
主要フレームワークとの比較とDefine by Run
Define and RunとDefine by Run
ディープラーニングライブラリは上記の二種類の設計思想に大きく分かれる。
Chainerの血を受け継ぐPyTorchは、Define by Run。TensorflowやKerasとの最も大きな違い。
どのように違うのか。下図は、PyTorchとKerasで定義した、Mnistに投げるCNN。
PyTorchがデータを投げて実行しながらネットワークを定義するのに対して、Kerasはネットワーク構成をかっちりと決めてからデータを投げる。定義の時点でデータは考えない。
Define by Runのメリットとしては、
ということで、研究者界隈では、Define by Runが主流。
使いやすさのKeras, 柔軟性のPyTorch
とはいえ、Kerasはやはり圧倒的に使いやすい。
ネットワークを積み上げるだけで、簡単にディープラーニングができてしまう。
その一方で、ネットワークの詳細設計はしにくい。
通常のデータ分析業務ならば、Kerasの簡潔さが輝くだろうし、研究や難しいタスクならばPyTorchが優位なのかなという印象。
コミュニティの強いPyTorch
PyTorchの優位性は、コミュニティの強さにもある。
同じくdefine by runのChainerは、やはり日本が主流であって、海外での利用は少ない。
一方でPyTorchは、研究者が続々と採用していて、主要な論文が出るとすごいスピードで実装されるので、最新論文のアルゴリズムをすぐに試すことができる。the incredible pytorchなどが好例。
github.com
まとめ
PyTorchについて勉強してみた。
設計思想の違いなんかにも触れられたと思う。一長一短なので、両方とも使えるようになっていたら便利そうだなと思った。
明日もPyTorch系の話題。どうやらsklearnラッパーがあるようなので、試してみたいと思う。ではでは!