PyTorchをscikit-learn風に使えるライブラリskorchを使ってみました。
この記事ではirisの分類問題を通してskorchのTutorialをやってみます。
環境
私の環境です。
関連リンク
Github
Documentation
インストール
pip install skorch
そのほかのインストール方法はこちら。
Tutorial
前準備
skorchの使い方を理解するために、まずは簡単なirisの分類をやってみます。
はじめに、PyTorchをインポートします。
import torch
from torch import nn
import torch.nn.functional as F
torch.manual_seed(0)
scikit-learnで用意されているirisのデータセットを用意し、学習用とテスト用に分けています。
from sklearn import datasets
from sklearn.model_selection import train_test_split
iris = datasets.load_iris()
X = iris.data
Y = iris.target
train_x, test_x, train_t, test_t = train_test_split(X, Y, test_size=0.1)
次に、2層の隠れ層からなるシンプルなニューラルネットワークのモデルを作ります。irisの分類は入力が4、3つのクラスがあるので出力は3となります。今回は以下のようにしてみました。
class Classifier(nn.Module):
def __init__(self):
super(Classifier, self).__init__()
self.dense0 = nn.Linear(4, 6)
self.dense1 = nn.Linear(6, 6)
self.output = nn.Linear(6, 3)
def forward(self, x):
h = F.relu(self.dense0(x))
h = F.relu(self.dense1(h))
y = self.output(h)
return y
ここで、やっとskorchの出番が来ます。skorchのNeuralNetClassifierを使えばPyTorchにより定義されたモデルをscikit-learn風の分類器に渡し学習することができます。
from skorch import NeuralNetClassifier
clf = NeuralNetClassifier(
Classifier,
optimizer=torch.optim.Adam,
criterion=torch.nn.CrossEntropyLoss,
max_epochs=40,
lr=0.1,
iterator_train__batch_size=20,
iterator_train__shuffle=True
)
学習
学習を開始するにはscikit-learnと同じようにfitを使います。fitを使えばデータを勝手にtorch.Tensorに変換してくれます。
clf.fit(train_x, train_t)
エラーが出た
RuntimeError: Expected object of type torch.FloatTensor but found type torch.DoubleTensor for argument #4 'mat1'
これは要するに、torch.FloatTensorを求められているのにtorch.DoubleTensorが渡されていてエラーが起きたようです。
これを解決するにはこのページが参考になります。
irisのデータの型を見てみると、
print(iris.data.dtype)
torch.FloatTensorにするにはfloat32である必要があるので型を変換します。同様に出力の方もtorch.LongTensorでなければならないのでこちらも型を変換します。
データセットを用意する部分を以下のようにします。
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
iris = datasets.load_iris()
X = iris.data.astype(np.float32)
Y = iris.target.astype(np.int64)
train_x, test_x, train_t, test_t = train_test_split(X, Y, test_size=0.1)
これで学習することができました。
テスト
テストデータを予測するにはsciki-learnと同じようにpredictを使います。
predicted = clf.predict(test_x)
print("Accuracy {:.2f}".format(sum(x for x in test_t == predicted) / test_t.shape[0]))
import torch
from torch import nn
import torch.nn.functional as F
torch.manual_seed(0)
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
iris = datasets.load_iris()
X = iris.data.astype(np.float32)
Y = iris.target.astype(np.int64)
train_x, test_x, train_t, test_t = train_test_split(X, Y, test_size=0.1)
class Classifier(nn.Module):
def __init__(self):
super(Classifier, self).__init__()
self.dense0 = nn.Linear(4, 6)
self.dense1 = nn.Linear(6, 6)
self.output = nn.Linear(6, 3)
def forward(self, x):
h = F.relu(self.dense0(x))
h = F.relu(self.dense1(h))
y = self.output(h)
return y
from skorch import NeuralNetClassifier
clf = NeuralNetClassifier(
Classifier,
optimizer=torch.optim.Adam,
criterion=torch.nn.CrossEntropyLoss,
max_epochs=40,
lr=0.1,
iterator_train__batch_size=20,
iterator_train__shuffle=True
)
clf.fit(train_x, train_t)
predicted = clf.predict(test_x)
print("Accuracy {:.2f}".format(sum(x for x in test_t == predicted) / test_t.shape[0]))
おまけ
Pipeline
scikit-learnのPipelineが使えます。上のプログラムで作ったモデルを渡しています。
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
pipe = Pipeline([
('scale', StandardScaler()),
('clf', clf)
])
pipe.fit(train_x, train_t)
GridSearch
sckit-learnのGridSearchが使えます。
from sklearn.model_selection import GridSearchCV
params = {
'lr': [0.01, 0.1],
'max_epochs' : [20, 40]
}
gs = GridSearchCV(clf, params, refit=False, cv=3, scoring="accuracy")
gs.fit(train_x, train_t)
print(gs.best_score_, gs.best_params_)
Q&A
分類器を作る際に、オプションのdeviceにcudaを渡す。
clf = NeuralNetClassifier(Classifier, max_epochs=40, lr=0.1, device="cuda")
モデルを保存するには?
pickleを使います。
import pickle
方法①:モデル全体を保存
filename = "model.pkl"
with open(filename, "wb") as f:
pickle.dump(clf, f)
方法②:モデルのパラメータだけを保存
このやり方ではlrやmax_epochsといったハイパーパラメータは保存されない。
filename = "model_params.pkl"
clf.save_params(filename)
モデルを読み込むには?
モデルを方法①で保存した場合
with open(filename, "rb") as f:
new_clf = pickle.load(f)
モデルを方法②で保存した場合
モデルを初期化した後に読み込む
new_clf = NeuralNetClassifier(
Classifier,
optimizer=torch.optim.Adam,
criterion=torch.nn.CrossEntropyLoss,
max_epochs=40,
lr=0.1,
iterator_train__batch_size=20,
iterator_train__shuffle=True
).initialize()
new_clf.load_params(filename)