LoginSignup
20

More than 3 years have passed since last update.

とりあえずPyTorchで遊んでみた

Last updated at Posted at 2017-10-28

はじめに

この記事ではWindowsでのPyTorchのインストールから、Irisの分類をざっくりやっていきます。

関連リンク

PyTorch v0.4 導入
PyTorch-NLPを使ってみる
skorch入門

環境

  • python 3.6.2
  • Anaconda 4.3.27
  • Windows10

PyTorch

ざっくり説明すると、Facebookが開発していてChainerの様にコードが書け、
Tensorflowとは異なり研究向けのディープラーニングライブラリです。

Install

※2018年7月12日追記
Windowsも公式からインストールができるようになりました。

Windowsは公式からはインストールできないので、Anaconda Cloudから、
コマンドプロンプトを開いて下のようにインストールします。

conda install -c peterjc123 pytorch

※追記
Bash on Windowsにインストールする方法
Bash on WindowsでPyTorchを使えるようにする。

Iris

ここからはPyTorchを使ったIrisデータセットの分類をざっくり書いていきます。

データセット

Irisデータセットとは150件の花のデータセットで、setosa, versicolor, virginicaという3つのクラスに分類されていて、それぞれがく片(Sepal)と花弁(Petal)の長さと幅の4つの特徴量をもっています。

データセットの準備

scikit-learnからデータを読み込んだあと正規化し、訓練データとテストデータに分けます。
後ほど説明しますが、誤差関数にはCrossEntropyLossを使います。CrossEntropyLossの入力の型はFloatTensor, 出力はLongTensorである必要があります。出力のtargetの型はnp.int32になっているので、targetの型をnp.int64に変換します。詳しいことはこちらを参考にしてください。
target(クラス)はone-hotではなくラベルで与えます。

# Load dataset...
iris_dataset = datasets.load_iris()

data = iris_dataset.data
# Normalization...
data = sp.stats.zscore(data, axis=0)
# 0 -> setosa
# 1 -> versicolor
# 2 -> virginica
target = iris_dataset.target

# np.int64 -> Longtensor
target = target.astype(np.int64)

# Split data into train and test set...
# Training size -> 120
# Test size -> 30
train_X, test_X, train_Y, test_Y = train_test_split(data, target, test_size=0.2)

モデル

入力層、隠れ層、出力層からなるニューラルネットワークです。
Chainerの様にモデルを書くことができます。


class NeuralNetwork(nn.Module):
    def __init__(self, n_in, n_units, n_out):
        super(NeuralNetwork, self).__init__()
        self.l1 = nn.Linear(n_in, n_units)
        self.l2 = nn.Linear(n_units, n_out)

    def forward(self, x):
        h = F.relu(self.l1(x))
        y = self.l2(h)
        return y

学習

訓練データを使ってミニバッチ学習をします。
学習部分もChainerの様に書けます。


# Training...
for epoch in range(epochs):
    train_X, train_Y = shuffle(train_X, train_Y)
    for i in range(n_batch):
        start = i * batch_size
        end = start + batch_size
        x = Variable(torch.FloatTensor(train_X[start:end]))
        t = Variable(torch.LongTensor(train_Y[start:end]))
        optimizer.zero_grad()
        y = model(x)
        loss = criterion(y, t)
        loss.backward()
        optimizer.step()

モデルのテスト

テストデータを使って学習したモデルのテストをします。
テストデータをFloatTensorにした後、Variableに変換します。
それをモデルに渡すことでモデルからの出力を得られます。
torch.maxを使うことにより一つの入力に対する出力の中で最も高い値のindexを得ることができ、それがモデルの予測したラベルとなります。詳しいことはこちらを参考してください。

# Test...
test_case = Variable(torch.FloatTensor(test_X), requires_grad=False)
result = model(test_case)
predicted = torch.max(result, 1)[1]
print("{:.2f}".format(sum(p == t for p, t in zip(predicted.data, test_Y)) / len(test_X)))

40epochで9割を超える正答率を得ることができました。

結果
0.93

全体のコード

import argparse
import torch
import numpy as np
import matplotlib.pyplot as plt
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as O
import scipy.stats as sp
from torch.autograd import Variable
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.utils import shuffle


class NeuralNetwork(nn.Module):
    def __init__(self, n_in, n_units, n_out):
        super(NeuralNetwork, self).__init__()
        self.l1 = nn.Linear(n_in, n_units)
        self.l2 = nn.Linear(n_units, n_out)

    def forward(self, x):
        h = F.relu(self.l1(x))
        y = self.l2(h)
        return y


parser = argparse.ArgumentParser()
parser.add_argument('--batchsize', '-b', type=int, default=20,
                    help="Number of minibatch size...")
parser.add_argument('--epochs', '-e', type=int, default=40,
                    help="Number of epochs...")
parser.add_argument('--learning_rate', '-lr', type=float, default=0.1,
                    help="Learning rate...")
args = parser.parse_args()
batch_size = args.batchsize
epochs = args.epochs
learning_rate = args.learning_rate

# Load dataset...
iris_dataset = datasets.load_iris()
# data type -> numpy.ndarray
data = iris_dataset.data
# Normalization...
data = sp.stats.zscore(data, axis=0)
# 0 -> setosa
# 1 -> versicolor
# 2 -> virginica
target = iris_dataset.target

# np.float32 -> FloatTensor
# np.int64 -> Longtensor
target = target.astype(np.int64)

# Split data into train and test set...
# Training size -> 120
# Test size -> 30
train_X, test_X, train_Y, test_Y = train_test_split(data, target, test_size=0.2)

n_in = len(data[0])
n_units = 5
n_out = len(iris_dataset.target_names)
n_batch = len(train_X) // batch_size
history = {"loss": []}

# Model + Loss + Optimizer
model = NeuralNetwork(n_in, n_units, n_out)
criterion = nn.CrossEntropyLoss()
optimizer = O.Adam(model.parameters(), lr=learning_rate)

# Training...
for epoch in range(epochs):
    train_X, train_Y = shuffle(train_X, train_Y)
    for i in range(n_batch):
        start = i * batch_size
        end = start + batch_size
        x = Variable(torch.FloatTensor(train_X[start:end]))
        t = Variable(torch.LongTensor(train_Y[start:end]))
        optimizer.zero_grad()
        y = model(x)
        loss = criterion(y, t)
        loss.backward()
        optimizer.step()
    history["loss"].append(loss.data[0])

#print(history["loss"][-1])
plt.title("loss")
plt.plot(range(epochs), history["loss"])
plt.show()


# Test...
test_case = Variable(torch.FloatTensor(test_X), requires_grad=False)
result = model(test_case)
predicted = torch.max(result, 1)[1]
print("{:.2f}".format(sum(p == t for p, t in zip(predicted.data, test_Y)) / len(test_X)))

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20