データ分析ガチ勉強アドベントカレンダー 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)) #torchの関数から print(x+y) #通常の演算もいける # numpy likeに扱える print(y[:,1],y.mean(), y.std()) #ある程度の関数はそろっている print(torch.ones(10)) print(torch.ones(10)+1) # numpyからの変換も可能 import numpy as np a = np.arange(4).reshape(2,2) x = torch.from_numpy(a)
Autograd
torch.autograd
Function
とVariables
で定義すると、演算結果が保存されるので、 そのままさかのぼった微分が可能。
下記の式は、
- [[1,2],[3,4]]
より、
その結果を返す より詳しい内容は公式
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]
チュートリアル:NeuralNetの構築
学習の手順
- 学習ができるニューラルネットを定義する。
- データセットを繰り返し投げられるようにする。
- インプットに応じて、処理(計算)が走るようにする
- 誤差(損失)を計算する
- 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__() # 1 input image channel, 6 output channels, 5x5 square convolution # kernel self.conv1 = nn.Conv2d(1, 6, 5) self.conv2 = nn.Conv2d(6, 16, 5) # an affine operation: y = Wx + b self.fc1 = nn.Linear(16 * 5 * 5, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) def forward(self, x): # Max pooling over a (2, 2) window x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # If the size is a square you can only specify a single number 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:] # all dimensions except the batch dimension 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)) # a dummy target, for example criterion = nn.MSELoss() loss = criterion(output, target)
back propagation
損失が算出できたので。この損失からさかのぼっていく。PyTorchだと、backward
とだけ実行すれば、簡単にパラメータの微分値を算出できるようになっている。
net.zero_grad() #とりあえず0で初期化
loss.backward()
重みのアップデート
学習には、torch.optim
を使う。下記のようなアルゴリズムがある。
また、torch.optim.lr_scheduler
で学習率の調整もできる。
import torch.optim as optim # create your optimizer optimizer = optim.SGD(net.parameters(), lr=0.01) # in your training loop: optimizer.zero_grad() # zero the gradient buffers output = net(input) loss = criterion(output, target) loss.backward() optimizer.step() # Does the update
これで一通り終了。最終的にはデータを繰り返し投げて、学習を進めていく。 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のメリットとしては、
- ネットワークを動的に変更できる。
- 柔軟な設計が可能。
- 1イテレーションごとに設計を変えられる
ということで、研究者界隈では、Define by Runが主流。
使いやすさのKeras, 柔軟性のPyTorch
とはいえ、Kerasはやはり圧倒的に使いやすい。 ネットワークを積み上げるだけで、簡単にディープラーニングができてしまう。
その一方で、ネットワークの詳細設計はしにくい。
通常のデータ分析業務ならば、Kerasの簡潔さが輝くだろうし、研究や難しいタスクならばPyTorchが優位なのかなという印象。
コミュニティの強いPyTorch
PyTorchの優位性は、コミュニティの強さにもある。 同じくdefine by runのChainerは、やはり日本が主流であって、海外での利用は少ない。
一方でPyTorchは、研究者が続々と採用していて、主要な論文が出るとすごいスピードで実装されるので、最新論文のアルゴリズムをすぐに試すことができる。the incredible pytorchなどが好例。
まとめ
PyTorchについて勉強してみた。 設計思想の違いなんかにも触れられたと思う。一長一短なので、両方とも使えるようになっていたら便利そうだなと思った。
明日もPyTorch系の話題。どうやらsklearnラッパーがあるようなので、試してみたいと思う。ではでは!
詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~
- 作者: 巣籠悠輔
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/05/30
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る
- 作者: Delip Rao,Goku Mohandas
- 出版社/メーカー: Oreilly & Associates Inc
- 発売日: 2018/07/25
- メディア: ペーパーバック
- この商品を含むブログを見る