Now Loading...

Now Loading...

本記事は「PyTorch チュートリアル Part2:2クラスデータセットの分類を体験」の続きです。今回は3クラスデータの分類に挑戦します。

本記事の構成は下記の通りです。

3クラスデータセットの生成とデータの確認

今回は3クラスデータセットの分類を行ってみます。使用するデータは、sklearnなどのフレームワークの機能を用いたりせずに作成します。各データは原点からの距離、角度の二つの数字を変化させることで、プロットすると螺旋状になるように作成します。

 

上の出力を見てわかる通り、3つのクラスが存在します。今回もモデルに学習させることで、試験用データをこのように上手く分類することが目標です。以降本記事では、データセットの中のデータを「データ」、データセットの中で各データが属するクラスを「ラベル」と呼びます。

では、生成したデータについてより詳しく見てみましょう。データX、ラベルYの形状及びYの中身を出力してみます。

 

1クラスあたり500個のデータ×3で1500個というデータ数です。クラスはクラス0、クラス1、クラス2の三種類存在しますが、今回はラベルをワンホットエンコーディングしているため、Yの形状は(1500,3)となっていることに注意してください。

以上より、このデータセットは以下のような構造となっています。

図1

ディープラーニング:モデルの学習による3クラス分類

使用するデータについては把握できたのではないかと思いますので、早速学習に移りたいと思います。一般的に、ディープラーニングの流れは以下のようになっています。

  1. 訓練用データセット、試験用データセットの用意
  2. モデルを用意
  3. 訓練用データセットでモデルに学習させる
  4. 試験用データセットで推論

訓練用データセット、試験用データセットの用意

まずは訓練用データセットと試験用データセットの用意ということで、生成したデータセットを訓練用データセット : 試験用データセット = 8 : 2 の割合で分割します。また、データをシャッフルしてから分割する必要がある点に注意しましょう。便利なことに、sklearnのtrain_test_splitクラスは、データをシャッフルしながら分割してくれます。

from sklearn.model_selection import train_test_split

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, test_size=0.2) #データを8:2に分割

分割した結果、データセットの構造は下の図のようになります。

図2

これらはnumpy.ndarrayなのでtorch.tensorに変換します。

#float32のtensorに変換
train_X = torch.FloatTensor(train_X)
train_Y = torch.FloatTensor(train_Y) 
test_X = torch.FloatTensor(test_X)
test_Y = torch.FloatTensor(test_Y)

さらに今回もデータローダーを作成するため、訓練用データセットはデータとラベルをまとめておきます。

from torch.utils.data import TensorDataset

train = TensorDataset(train_X, train_Y) #train_X、train_Yを一つにまとめる

torch.utils.dataのDataloaderクラスを用いてデータローダーを作成します。ミニバッチのサイズは10に設定しました。

from torch.utils.data import DataLoader

BATCH_SIZE = 10 #ミニバッチのサイズ

#訓練用データのDataloaderを作成
train_dataloader = DataLoader(
    train, 
    batch_size=BATCH_SIZE, 
    shuffle=True
)

これで訓練用、試験用のデータセットを用意できました。

モデルを用意

続いて、モデルを用意します。今回のモデルもnn.Moduleを継承したクラスとして定義します。モデルの出力層のサイズと活性化関数、及び損失関数に注意してください。今回は3クラス分類なので出力層のサイズは3で、活性化関数にはソフトマックス関数を用い、損失関数にクロスエントロピー誤差を用います。多クラス分類では活性化関数にソフトマックス関数を、損失関数にはクロスエントロピー誤差を用いることが多いということを思い出してください。また、PyTorchの仕様ではnn.CrossEntropyLoss()内でソフトマックス関数を同じ処理を行うようになっているため、以下のコードでは出力層の活性化関数を省略しています。

import torch
import torch.nn as nn
from torch.nn import functional as F

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(2, 8) 
        self.fc2 = nn.Linear(8, 3) #pytorchの仕様のため、出力層の活性化関数は省略
        
    # 順伝播
    def forward(self, x):
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        return x    

# インスタンス化
net = Net()

# 損失関数の設定(クロスエントロピー誤差)
criterion = nn.CrossEntropyLoss() #この中でソフトマックス関数と同じ処理をしている

# 最適化手法の選択(SGD)
optimizer = torch.optim.SGD(net.parameters(), lr=0.1)

層数は2クラス分類のときと同じく2層に設定しました。隠れ層におけるニューロンの数も2クラス分類のときと同じく、8つのままです。

訓練用データセットでモデルに学習させる

では、ここまでのまとめを兼ねて訓練用データセットで学習させてみましょう。

 

損失の減少があまり芳しくないですね。これは、データ数が前回よりも格段に多いためです。前回は500個でしたが今回は3倍の1500個のデータだったため、このモデルでは上手く学習できなかったのでしょう。あまり期待できませんが、このまま推論させてみましょう。

前回2クラス分類でワンホットエンコーディングによるラベル付けを行ったときと同様、あるデータを入力したときの3つの出力の内、最も値が大きいクラスにデータが分類されるようにします。

図3

この処理は、以下のように実装できます。

with torch.no_grad():# 試験用データでは勾配を計算しない
    pred_labels = [] # 各バッチごとの結果格納用

    for x in test_X:
            pred = net(x) #モデルの出力
            #argmax関数で出力における最大値のインデックスを取得し、ワンホットエンコーディングされたラベルに変換
            if torch.argmax(pred) == torch.tensor(0) : 
              pred_labels.append([1.,0.,0.])

            elif torch.argmax(pred) == torch.tensor(1):
              pred_labels.append([0.,1.,0.])

            else:
              pred_labels.append([0.,0.,1.])  
 
pred_labels = np.array(pred_labels) #numpy arrayに変換

試験用データセットで推論

では、推論させ、その結果を描画してみましょう。

 

ある程度上手く分類できているようですが、いくつかのデータは別の色に誤分類されてしまっているのがわかります。このように、データに対してモデルが単純すぎると、学習させてもバイアスと呼ばれる汎化誤差が高いままです。これはモデルのパラメータを調整したり、より複雑なモデルにすることで改善できます。

モデルの改善

分類の精度がいまいちだったので、モデルを少しだけ変更します。モデルには調整できるパラメータがたくさんあります。モデルの層数、隠れ層のニューロン数、用いる活性関数、用いる損失関数、オプティマイザ、学習率などです。今回はそれほど大きな変更をする必要はなさそうなので、簡単に隠れ層の数を増やしてみましょう。

import torch
import torch.nn as nn
from torch.nn import functional as F

class Net_2(nn.Module):
    def __init__(self):
        super(Net_2, self).__init__()
        self.fc1 = nn.Linear(2, 8) 
        self.fc2 = nn.Linear(8, 8) #新しく線形変換層を追加
        self.fc3 = nn.Linear(8, 3) 
        
    # 順伝播
    def forward(self, x):
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        x = F.relu(x)
        x = self.fc3(x)
        return x    

net2 = Net_2()

criterion_2 = nn.CrossEntropyLoss() 

optimizer_2 = torch.optim.SGD(net2.parameters(), lr=0.1)

学習させてみます。訓練データは同じものを用い、訓練ループにおける処理も同じです。ただ、このモデルだと200エポックも学習さなくても100エポック程度で十分だと思われるので100エポックだけ学習します。

 

上手く学習できているようです。では、推論させてみましょう。

 

層を増やさなかったときと異なり、かなり上手く分類できているように見えます。

まとめ

今回は3クラスデータセットの分類に挑戦しました。2クラス分類のときと比べて新しいことはほとんどやっていないので、よい復習になったのではないかと思います。このように、3クラス以上の多クラスを分類するときもPyTorchの機能を用いれば簡単に実装することができます。また、モデルは様々な改善を施すことで精度を上げることができます。自分でも改造に挑戦してみてはいかがでしょうか。

参考文献

  • Eli stevens, Luca Antiga, Thomas Viehmann 『Pytorch実践入門 ディープラーニングの基礎から実装へ』後藤勇輝, 小川雄太郎, 櫻井亮佑, 大串和正 訳. 株式会社マイナビ. 2021
  • PYTORCH DOCUMENTATION , https://pytorch.org/docs/stable/index.html

\ シェア /

E資格スピードパッケージ

E資格スピードパッケージ2023#2修了者合格率100%達成

zero to one E資格 jdla

zero to oneの「E資格」向け認定プログラム

日本ディープラーニング協会の実施するE資格の受験ならzero to oneの「E資格」向け認定プログラム (税込165,000円) をおすすめします。当講座は、東京大学大学院工学系研究科の松尾豊教授と東北大学大学院情報科学研究科の岡谷貴之教授が監修する実践的なプログラムとなっています。
厚生労働省の教育訓練給付制度対象のE資格認定プログラムの中では最安値※となり、実質負担額49,500円~(支給割合70%の場合)で受講可能です。※2023年弊社調べ zero to one E資格 jdla

人工知能基礎講座を提供中

人工知能の第一人者である東京大学の松尾豊教授が監修した人工知能基礎講座を受講してみませんか? 人工知能の歴史から自然言語処理、機械学習、深層学習といった最先端のトピックやAIに関わる法律問題まで網羅しているので全てのビジネスパーソン・AIの初学者におすすめです。

サンプル動画

人工知能基礎講座はこちら↓ zero to one G検定 人工知能基礎 jdla

AI初学者・ビジネスパーソン向けのG検定対策講座

G検定受験前にトレーニングしたい方向けの問題集「G検定実践トレーニング」も提供中です。 zero to one E資格 jdla