人気急上昇PyTorchで学ぶディープラーニング入門【学習・予測編】

概要

今回はPyTorchを利用したモデルの作成と学習・予測の流れについてご紹介します。アヤメのデータセットを用いて実際にモデルの作成から予測を行います。

ディープラーニングの学習の流れ

まずはディープラーニングではどのように学習を行うか処理の流れを説明します。ディープラーニングの流れは以下となります。

  1. モデルに入力データを渡し、順伝播により予測値を計算します。
  2. 損失関数に予測値と教師データ(真値)を渡し、誤差を計算します。
  3. バックプロバゲーション(誤差逆伝播法)により出力層から入力層へ誤差を逆伝播し、全ての層の誤差を計算する
  4. オプティマイザを用いて損失関数がなるべく小さくなるように重みを最適化する。
  5. 上記を繰り返し実行する。

PyTorchによるモデルの実装

学習を行う前にまずは、学習対象となるデータセットを用意します。今回はアヤメの花のデータセットを利用します。データセットを以下のような構造となっております。

カラム名説明
sepal lengthガクの長さ
sepal widthガクの幅
petal length花弁の長さ
petal width花弁の幅
target花の種類

今回はガクの長さなどの情報を与え、花の種類を予測するモデルを実装することとなります。

最初に必要なライブラリをインポートします。

import torch
import torch.nn as nn
import torch.nn.functional as F
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

続いて、データセットを読み込みます。

# データのロード
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
# 花の種類(target)のカラムを作成
df['target'] = iris.target
df.head()

# sepal length (cm)	sepal width (cm)	petal length (cm)	petal width (cm)	target
# 0	5.1	3.5	1.4	0.2	0
# 1	4.9	3.0	1.4	0.2	0
# 2	4.7	3.2	1.3	0.2	0
# 3	4.6	3.1	1.5	0.2	0
# 4	5.0	3.6	1.4	0.2	0

データセットの準備ができたので、学習モデルを実装します。モデルの定義にはnn.Moduleを継承したクラスを定義します。そしてクラスに初期化関数__init__()forward()を定義します。

__init__()の説明

今回のモデルは4層のニューラルネットワークです。(入力層、隠れ層 x 2、出力層)

  • 入力層のノード:4個
  • 隠れ層1のノード:8個
  • 隠れ層2のノード:9個
  • 出力層のノード:3個
  1. fc1にnn.Linearのインスタンスを代入し、引数に入力層のノード数(4)と隠れ層1のノード数(8)を渡します。
  2. fc2にnn.Linearのインスタンスを代入し、引数に隠れ層1のノード数(8)と隠れ層2のノード数(9)を渡します。
  3. outにnn.Linearのインスタンスを代入し、引数に隠れ層2のノード数(9)と出力層2のノード数(3)を渡します。

foward()の説明

順伝播を行うためにforwadを定義します。forwardでは、initで定義した最初の層であるfc1に入力値であるxが代入され、出力値に対して活性化関数reluを適用した値がxに代入されます。その後も同様に2番目の層であるfc2にxが代入され、出力値に対して活性化関数reluを適用した値がxに代入されます。出力層では出力をそのまま使用するのでself.out(x)となります。

# 学習モデル
class Model(nn.Module):
    def __init__(self, in_features=4, h1=8, h2=9, out_features=3):
        super().__init__()
        self.fc1 = nn.Linear(in_features, h1)
        self.fc2 = nn.Linear(h1, h2)
        self.out = nn.Linear(h2, out_features)
        
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.out(x)
        return x

続いて、学習を行う前にデータを学習用のデータとテスト用のデータに分割し、それぞれをPyTorchのTensor型に変換しておきます。

# 説明変数と目的変数に分ける
X = df.drop('target', axis=1).values
y = df['target'].values

# 学習データと検証データに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=123)

# テンソルに変換
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train)
y_test = torch.tensor(y_test)

次に損失関数とオプティマイザを定義します。今回のタスクは多値分類になるので損失関数にはCrossEntropyLossを用います。また、オプティマイザには、Adamを利用します。Adamはもっともよく使われている最適化アルゴリズムの一つです。

torch.manual_seed(1)
model = Model()
# 損失関数
criterion = nn.CrossEntropyLoss()
# 最適化関数
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

それでは学習を行っていきましょう。今回はエポックを100として実行します。その際に10エポックごとに損失を出力して、損失がどのように収束するかを確認します。

  • y_pred = model.forward(X_train)では予測値を計算しています。
  • loss = criterion(y_pred, y_train)で損失を計算。
  • optimizer.zero_grad()勾配を初期化
  • loss.backward()逆伝播
  • optimizer.step()重みの更新
epochs = 100
loss_list = []

for epoch in range(epochs):
    # 予測
    y_pred = model.forward(X_train)
    # 損失の計算
    loss = criterion(y_pred, y_train)
    
    # 勾配の初期化
    optimizer.zero_grad()
    # バックプロバゲーション
    loss.backward()
    #  重みの更新
    optimizer.step()
    
    loss_list.append(loss)
    
    if (epoch + 1) % 10 == 0:
        print(f'epoch: {epoch + 1} -> loss: {loss.item():.4f}')

# epoch: 10 -> loss: 0.9545
# epoch: 20 -> loss: 0.7401
# epoch: 30 -> loss: 0.5219
# epoch: 40 -> loss: 0.3841
# epoch: 50 -> loss: 0.2752
# epoch: 60 -> loss: 0.1778
# epoch: 70 -> loss: 0.1133
# epoch: 80 -> loss: 0.0802
# epoch: 90 -> loss: 0.0640
# epoch: 100 -> loss: 0.0557

損失関数値が徐々に小さくなり正常に収束していることがわかります。実際にloss_listをプロットしてみます。

plt.plot(loss_list)

最後にテストデータで予測を行い、どの程度の精度が出るかを確認します。

# 精度計算
outputs = model.forward(X_test)
_, y_predicted = torch.max(outputs.data, 1)
accuracy = 100 * np.sum(y_predicted.numpy() == y_test.numpy()) / len(y_predicted)
print(f'accuracy: {accuracy:.1f}%')

# accuracy: 93.3%

約93%が正しく予測できているので、まずますの精度と言えます。

モデルの保存

最後にモデルの保存方法について説明しておきます。

# モデルの保存
torch.save(model.state_dict(), 'IrisClassification.pth')

まとめ

今回はPyTorchでのモデルの作成方法と学習、予測までの基本的な流れを紹介しました。今回の内容はPyTorchの扱い方の基本となります。次回以降より実践的な内容をご紹介します。