データ分析ガチ勉強アドベントカレンダー 20日目。
Skorchとは
- PyTorchのsklearnラッパー
- sklearnのインターフェースでPyTorchを使える
自分が感じたメリット
インストール
git clone https://github.com/dnouri/skorch.git cd skorch # create and activate a virtual environment pip install -r requirements.txt # install pytorch version for your system (see below) python setup.py install
※私の環境(ubuntu14.04, python3.6.1)では、sklearn0.18.1では実行時エラーが出たので、sklearn0.19.1にアップグレードしました。
pip install -U sklearn
使い方
データ読み込みはsklearn
データの作り方などはday-7の記事を参照
%matplotlib inline import matplotlib.pyplot as plt import torch from torch import nn import torch.nn.functional as F torch.manual_seed(0); import numpy as np from sklearn.datasets import make_classification import sklearn X, y = make_classification(1000, 20, n_informative=10, random_state=0) X = X.astype(np.float32) X.shape, y.shape,y.mean()
学習ネットワークの構築はPyTorch
day19の記事のように、ネットワークの設計をdefine by runでしていきましょう。
class ClassifierModule(nn.Module): def __init__( self, num_units=10, nonlin=F.relu, dropout=0.5, ): super(ClassifierModule, self).__init__() self.num_units = num_units self.nonlin = nonlin self.dropout = dropout self.dense0 = nn.Linear(20, num_units) self.nonlin = nonlin self.dropout = nn.Dropout(dropout) self.dense1 = nn.Linear(num_units, 10) self.output = nn.Linear(10, 2) def forward(self, X, **kwargs): X = self.nonlin(self.dense0(X)) X = self.dropout(X) X = F.relu(self.dense1(X)) X = F.softmax(self.output(X), dim=-1) return X
skorchでwrap
skorch.net
用意されているのは2種類
関数 | 用途 |
---|---|
NeuralNetClassifier |
分類器をsklearn風に |
NeuralNetRegressor |
回帰をsklearn風に |
初期化の際に、学習の仕方を決める。パラメータは、PyTorchの関数を使用できる。
criterion
: 損失関数の設定optimizer
: 最適化関数の設定lr
: 学習率の決定
その他色々とパラメータはあるので、skorch.net
を参照。
PyTorchのパラメータに関しては『PyTorch入門』 使い方&Tensorflow, Keras等との違いとは?を参照
.fit
で、自動的にtorch.tensorに変換される- validationまでやってくれて嬉しい
from skorch.net import NeuralNetClassifier net = NeuralNetClassifier( module=ClassifierModule, max_epochs=20, lr=0.1, # use_cuda=True, # uncomment this to train with CUDA ) net.fit(X,y) y_pred = net.predict(X[:5]) y_proba = net.predict_proba(X[:5]) for pred, proba in zip(y_pred,y_proba): print("score {}: class {}".format(proba, pred))
sklearnとのその他連携
pipeline
- スケーリングなどsklearnの処理をデータの流れに組み込める
- 前処理の話は day-8
from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler # データの流れるPipelineを設計 pipe = Pipeline([ ("scale",StandardScaler()), ("neuralnet", net) ]) print(pipe.named_steps) pipe.fit(X,y) y_pred = pipe.predict(X[:5]) y_proba = pipe.predict_proba(X[:5]) for pred, proba in zip(y_pred,y_proba): print("score {}: class {}".format(proba, pred))
Grid search
- NeuralNetClassifier/NeuralNetRegressorで設定できるパラメータを調べることができる(
GridSearchCV
orRandomSearchCV
) - optimizerなども
torch.optim
のリストを使って網羅的に調べられる - クラス内変数も
module__hoge
(hogeはメンバ変数)と入力することで置き換えられる
from sklearn.model_selection import GridSearchCV params = { "lr":[i*0.01 for i in range(1,5)], "optimizer":[torch.optim.Adam, torch.optim.Adagrad, torch.optim.SGD], "module__num_units":[10,20], } gs = GridSearchCV(net, params, refit=False, cv=3, scoring="accuracy") gs.fit(X,y) import pandas as pd df = pd.DataFrame(gs.cv_results_) df_scored = df.sort_values(by=["rank_test_score"])[["params","mean_test_score","std_test_score","mean_fit_time"]] df_scored
MNIST
MNISTを実装してみる。sklearnで書けるところはsklearnで書いて、PyTorchで書くべきところはそちらで書く。使い分けがはっきりしていてかなりいい感じ。
# データの読み込み(sklearn) from skorch import NeuralNetClassifier from torch import nn from sklearn.datasets import fetch_mldata from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report mnist = fetch_mldata('MNIST original') X = mnist.data.astype('float32') y = mnist.target.astype('int64') X /= 255 XCnn = X.reshape(-1, 1, 28, 28) XCnn_train, XCnn_test, y_train, y_test = train_test_split(XCnn, y, test_size=0.25, random_state=42) # Networkの設計(PyTorch) class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 32, kernel_size=3) self.conv2 = nn.Conv2d(32, 64, kernel_size=3) self.conv2_drop = nn.Dropout2d() self.fc1 = nn.Linear(1600, 128) # 1600 = number channels * width * height self.fc2 = nn.Linear(128, 10) def forward(self, x): x = F.relu(F.max_pool2d(self.conv1(x), 2)) x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2)) x = x.view(-1, x.size(1) * x.size(2) * x.size(3)) # flatten over channel, height and width = 1600 x = F.relu(self.fc1(x)) x = F.dropout(x, training=self.training) x = self.fc2(x) x = F.softmax(x, dim=-1) return x # ラッパーを使う(skorch) net = NeuralNetClassifier( Net, max_epochs=10, lr=1, optimizer=torch.optim.Adadelta, # use_cuda=True, # uncomment this to train with CUDA ) # training net.fit(XCnn_train, y_train) # test y_pred = net.predict(XCnn_test) print(classification_report(y_test, y_pred))
結果
学習の様子
結果の表示
precision recall f1-score support 0 1.00 0.99 0.99 1677 1 0.99 0.99 0.99 1935 2 0.99 0.99 0.99 1767 3 0.99 0.99 0.99 1766 4 0.99 0.99 0.99 1691 5 0.99 0.99 0.99 1653 6 0.99 0.99 0.99 1754 7 0.99 0.99 0.99 1846 8 0.98 0.99 0.99 1702 9 0.99 0.98 0.99 1709 avg / total 0.99 0.99 0.99 17500
まとめ
sklearnとPyTorchをつなげられる便利なライブラリを紹介しました。 PyTorchの持つ柔軟性と、sklearnの利用しやすさが相まって最高ですね。
かなり使いやすいので、sklearnに慣れている人は、一回使ってみることをおすすめします!
明日はどうするかな、ベイズ的な変化点検知をする予定だが、果たして、、、ではでは!