プロクラシスト

今日の寄り道 明日の近道

【Day-19】『PyTorch入門』 使い方&Tensorflow, Keras等との違いとは?


スポンサーリンク

f:id:imslotter:20171219000627p:plain

データ分析ガチ勉強アドベントカレンダー 19日目。

2日間、Kerasに触れてみましたが、最近はPyTorchがディープラーニング系ライブラリでは良いという話も聞きます。

とりあえずTutorialを触りながら使ってみて、自分が疑問に思ったことをまとめていくスタイルにします。

また、同じく有名ライブラリであるKerasやTensorFlowについての比較もしたいと思っています(Define and RunかDefine by Runか)

PyTorchとは

f:id:imslotter:20171219043523p:plain

ざっくりまとめると

  • 深層学習用ライブラリ
  • 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 FunctionVariablesで定義すると、演算結果が保存されるので、 そのままさかのぼった微分が可能。

下記の式は、

  • {x=} [[1,2],[3,4]]
  • {y = x^{2} +2}
  • {z = y^{2} = (x^{2}+2)^{2}}

{out = \frac{1}{4} \sum_{i} z_{i} z_{i}  (x^{2}+2)^{2}} より、 {\frac{\partial out}{\partial x_{i}}=x_{i}(x_{i}^{2}+2)}

その結果を返す より詳しい内容は公式

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を使う。下記のようなアルゴリズムがある。

  • SGD, ASGD, Nesterov-SGD
  • Adadelta, Adagrad, Adam, SparseAdam, Adamax
  • LBFGS
  • RMSProp, Rprop

また、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のメリットとしては、

  • ネットワークを動的に変更できる。

ということで、研究者界隈では、Define by Runが主流。

使いやすさのKeras, 柔軟性のPyTorch

とはいえ、Kerasはやはり圧倒的に使いやすい。 ネットワークを積み上げるだけで、簡単にディープラーニングができてしまう。

その一方で、ネットワークの詳細設計はしにくい。

通常のデータ分析業務ならば、Kerasの簡潔さが輝くだろうし、研究や難しいタスクならばPyTorchが優位なのかなという印象。

コミュニティの強いPyTorch

PyTorchの優位性は、コミュニティの強さにもある。 同じくdefine by runのChainerは、やはり日本が主流であって、海外での利用は少ない。

一方でPyTorchは、研究者が続々と採用していて、主要な論文が出るとすごいスピードで実装されるので、最新論文のアルゴリズムをすぐに試すことができる。the incredible pytorchなどが好例。

github.com

まとめ

PyTorchについて勉強してみた。 設計思想の違いなんかにも触れられたと思う。一長一短なので、両方とも使えるようになっていたら便利そうだなと思った。

明日もPyTorch系の話題。どうやらsklearnラッパーがあるようなので、試してみたいと思う。ではでは!

詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~

詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~

Natural Language Processing With Pytorch: Build Intelligent Language Applications Using Deep Learning

Natural Language Processing With Pytorch: Build Intelligent Language Applications Using Deep Learning

PROCRASIST