機械学習

【入門】PyTorchでCNNを構築し分類タスクを解いてみよう!Kerasとの違いも見ていこう!

PyTorch
記事内に商品プロモーションを含む場合があります
ウマたん
ウマたん
当サイト【スタビジ】の本記事では、ディープラーニングを実装するためのライブラリであるPyTorchについて解説していきます!TensorFlowやKerasとの違いをまとめつつ、最終的にPythonでPyTorchを使ってディープラーニングのモデルを構築していきます!

こんにちは!データサイエンティストのウマたん(@statistics1012)です!

この記事ではディープラーニングを簡単に誰でも実装できるPythonのライブラリPyTorchについて分かりやすく解説していきます!

ディープラーニングを実装するライブラリとしては他にもTensorFlowやKerasが有名ですが、最近ではPyTorchの人気が高まっています!

PyTorchとKerasとTensorFlowの違いとは

PyTorchはFacebook(現Meta)の人工知能研究グループであるAI Research labによって開発されたライブラリ。

冒頭にも述べたとおり、実はディープラーニングを実装するライブラリの中にはPyTorch以外にもKerasやTensorFlowなどが存在します。

そこでPyTorchの特徴を理解するために、他のライブラリと比較していきましょう!

最新のモデル

昨今はAIの進化が非常に早く、色々なモデルが日々登場しています。

大規模言語モデル
大規模言語モデル(LLM)の仕組みや種類について分かりやすく解説!当サイト【スタビジ】の本記事では、大規模言語モデル(LLM)の仕組みや種類について分かりやすく解説していきます。ChatGPTなどの大規模言語モデルの基本を理解してこのAI時代の流れに乗り遅れないようにしましょう!...

登場時点で最高レベルの精度を達成することをSOTA(State-of-the-Art)と言いますが、そんなSOTAを達成したような最新のモデルに関してはPyTorchで利用できる場合が多いです。

カスタマイズ性

また、PyTorchでは他のライブラリと比較して複雑なモデルを柔軟に作ることが可能です。

そのため学術研究の領域ではKerasやTensorFlowよりもPyTorchが好まれて使われるケースが多いです。

私自身もアカデミックの世界にいましたが、結局アカデミックでは手法を改良して精度向上を試みることになるので、カスタマイズ性が高くないと手法改良ができません。

研究開発の領域では、数式展開部分から改良してモデルとして実装できるかが肝になってくるんです!

後ほどPyTorchを使ってディープラーニングのモデルを実装していきますよ!

ウマたん
ウマたん
色々カスタマイズしたい場合はPyTorch!

処理速度

また、処理速度の観点ではPyTorchはTensorFlowと同程度、Kerasが他2つと比較して遅めです。

ウマたん
ウマたん
処理速度の面ではKerasは他2つに劣る!

コードの複雑さ

ここまでPyTorchの良さが際立っていましたが、その一方でコードの見やすさはKerasに軍配が上がります。

PyTorchは、カスタマイズ性が高い分Kerasと比較すると複雑で分かりにくいコードになりがちです。

例えば、KerasでCNNのモデルを構築し学習するコード(※全コードではなくモデル設計と学習部分のみピックアップ)は以下のようになるのですが、

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))

# モデルを構築
model.compile(optimizer=tf.optimizers.Adam(0.01), loss='categorical_crossentropy', metrics=['accuracy'])

# モデル学習
log = model.fit(train_x, train_y, epochs=3, batch_size=10, verbose=True,
                callbacks=[keras.callbacks.EarlyStopping(monitor='val_loss', 
                                                     min_delta=0, patience=10, 
                                                         verbose=1)],
                validation_data=(valid_x, valid_y))

これと同じような処理をPyTorchで記述すると以下のようになります。

# モデルの定義
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.conv3 = nn.Conv2d(64, 64, 3, 1)
        self.fc1 = nn.Linear(3*3*64, 64)
        self.fc2 = nn.Linear(64, 10)

    def forward(self, x):
        x = torch.relu(self.conv1(x))
        x = nn.MaxPool2d(2)(x)
        x = torch.relu(self.conv2(x))
        x = nn.MaxPool2d(2)(x)
        x = torch.relu(self.conv3(x))
        x = torch.flatten(x, 1)
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

model = Net()

# 損失関数と最適化手法
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 学習プロセス
def train(model, train_loader, valid_loader, criterion, optimizer, epochs=3):
    for epoch in range(epochs):
        model.train()
        for data, target in train_loader:
            optimizer.zero_grad()
            output = model(data)
            loss = criterion(output, target)
            loss.backward()
            optimizer.step()
        
        model.eval()
        valid_loss = 0
        correct = 0
        with torch.no_grad():
            for data, target in valid_loader:
                output = model(data)
                valid_loss += criterion(output, target).item()
                pred = output.argmax(dim=1, keepdim=True)
                correct += pred.eq(target.view_as(pred)).sum().item()

        valid_loss /= len(valid_loader.dataset)
        print(f'Epoch: {epoch+1}, Validation loss: {valid_loss}, Accuracy: {100. * correct / len(valid_loader.dataset)}%')

# 学習の実行
train(model, train_loader, valid_loader, criterion, optimizer)

Kerasだとディープラーニングの層を重ねる部分も学習部分も非常にシンプルなのですが、PyTorchだと少々複雑で可読性が低いことが分かりますね!

とはいえ、コードのシンプルさとカスタマイズ性の高さはトレードオフなので目的によって使い分けるとよいでしょう!

ウマたん
ウマたん
コードのシンプルさではKerasに軍配が上がる!

PyTorchを使ってディープラーニングを実装

ここまででPyTorchの特徴を他のライブラリと比較しながら見てきましたが、PyTorchについて知るためにはとりあえず手を動かして触ってみることが大事!

ということで、早速PyTorchを使ってディープラーニングのモデルを構築していきましょう!

先ほど少しモデル構築部分を紹介したCNN(畳み込みニューラルネットワーク)のアーキテクチャを使ってMnistデータを分類していきましょう!

MnistはMixed National Institute of Standards and Technology databaseの略で、手書き数字画像60,000枚とテスト画像10,000枚を集めた、画像データセット。

0~9の手書き数字が教師ラベルとして各画像に与えられています。

全体のコードは以下のようになります。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from sklearn.model_selection import train_test_split
from torchvision import datasets, transforms

# データの前処理
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])

# MNISTデータセットのダウンロード
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)

# NumPy配列への変換
train_x = train_dataset.data.type(torch.FloatTensor)
train_y = train_dataset.targets
test_x = test_dataset.data.type(torch.FloatTensor)
test_y = test_dataset.targets

# Training set を学習データと検証データに8:2で分割する
train_x, valid_x, train_y, valid_y = train_test_split(train_x, train_y, test_size=0.2, random_state=0)

# データの整形と正規化
train_x = train_x.unsqueeze(1) / 255.0
valid_x = valid_x.unsqueeze(1) / 255.0
test_x = test_x.unsqueeze(1) / 255.0

# DataLoaderの作成
train_loader = DataLoader(TensorDataset(train_x, train_y), batch_size=10, shuffle=True)
valid_loader = DataLoader(TensorDataset(valid_x, valid_y), batch_size=10, shuffle=False)
test_loader = DataLoader(TensorDataset(test_x, test_y), batch_size=10, shuffle=False)

# モデルの定義
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.conv3 = nn.Conv2d(64, 64, 3, 1)
        self.fc1 = nn.Linear(3*3*64, 64)
        self.fc2 = nn.Linear(64, 10)

    def forward(self, x):
        x = torch.relu(self.conv1(x))
        x = nn.MaxPool2d(2)(x)
        x = torch.relu(self.conv2(x))
        x = nn.MaxPool2d(2)(x)
        x = torch.relu(self.conv3(x))
        x = torch.flatten(x, 1)
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

model = Net()

# 損失関数と最適化手法
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 学習プロセス
def train(model, train_loader, valid_loader, criterion, optimizer, epochs=3):
    for epoch in range(epochs):
        model.train()
        for data, target in train_loader:
            optimizer.zero_grad()
            output = model(data)
            loss = criterion(output, target)
            loss.backward()
            optimizer.step()
        
        model.eval()
        valid_loss = 0
        correct = 0
        with torch.no_grad():
            for data, target in valid_loader:
                output = model(data)
                valid_loss += criterion(output, target).item()
                pred = output.argmax(dim=1, keepdim=True)
                correct += pred.eq(target.view_as(pred)).sum().item()

        valid_loss /= len(valid_loader.dataset)
        print(f'Epoch: {epoch+1}, Validation loss: {valid_loss}, Accuracy: {100. * correct / len(valid_loader.dataset)}%')

# 学習の実行
train(model, train_loader, valid_loader, criterion, optimizer)

# テストデータでの評価
model.eval()
correct = 0
with torch.no_grad():
    for data, target in test_loader:
        output = model(data)
        pred = output.argmax(dim=1, keepdim=True)
        correct += pred.eq(target.view_as(pred)).sum().item()

accuracy = correct / len(test_loader.dataset)
print(f'Test accuracy: {accuracy * 100}%')

 

コードの処理について順を追って見ていきましょう!

まず必要なライブラリをインポートしています。

以下の処理では、まずToTensor()で画像をPyTorchテンソルに変換し、Normalize()で正規化しています。

transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])

PyTorchテンソルはPyTorchにおける基本的なデータ構造であり、多次元配列の形でデータを表します。

これは、データセットに含まれる画像データをPyTorchが扱える形式に変換するために必要なんです!

また、同時にToTensor()変換はピクセルの値を[0, 255]の範囲から[0.0, 1.0]の範囲に自動的にスケーリングします。

これは、ニューラルネットワークが[0, 1]範囲の値を扱いやすいため、効果的な学習を促進するために重要になります。

ウマたん
ウマたん
まぁとりあえずPyTorchのアーキテクチャに突っ込む前の準備ということだね!

続いてMnistデータセットをダウンロードして前処理をかけたり学習データ・検証データに分けたり前準備をしていますね。

続いて、以下の処理でモデルの定義をしています。

# モデルの定義
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.conv3 = nn.Conv2d(64, 64, 3, 1)
        self.fc1 = nn.Linear(3*3*64, 64)
        self.fc2 = nn.Linear(64, 10)

    def forward(self, x):
        x = torch.relu(self.conv1(x))
        x = nn.MaxPool2d(2)(x)
        x = torch.relu(self.conv2(x))
        x = nn.MaxPool2d(2)(x)
        x = torch.relu(self.conv3(x))
        x = torch.flatten(x, 1)
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

model = Net()

 

ちょっと分かりにくいのですが、def __init__(self)で畳み込み層であるConv2dや全結合層であるLinearのアーキテクチャを定義しています。

その上でdef forward(self, x)内で、実際に入力データxを層構造に通していく処理を作っています。

ここでは先ほど定義した畳み込み層や全結合層を使いながら活性関数であるRelu関数やプーリング層の設定などをしています。

続いて以下の処理で損失関数と最適化手法を定義しています。

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

ディープラーニングの学習で最適なパラメータを求める際に必要です。

そしてやっと以下の部分で学習の処理です!

# 学習プロセス
def train(model, train_loader, valid_loader, criterion, optimizer, epochs=3):
    for epoch in range(epochs):
        model.train()
        for data, target in train_loader:
            optimizer.zero_grad()
            output = model(data)
            loss = criterion(output, target)
            loss.backward()
            optimizer.step()
        
        model.eval()
        valid_loss = 0
        correct = 0
        with torch.no_grad():
            for data, target in valid_loader:
                output = model(data)
                valid_loss += criterion(output, target).item()
                pred = output.argmax(dim=1, keepdim=True)
                correct += pred.eq(target.view_as(pred)).sum().item()

        valid_loss /= len(valid_loader.dataset)
        print(f'Epoch: {epoch+1}, Validation loss: {valid_loss}, Accuracy: {100. * correct / len(valid_loader.dataset)}%')

# 学習の実行
train(model, train_loader, valid_loader, criterion, optimizer)

 

このモデル学習部分がKerasと比較してかなり複雑になってます。

まず、model.train()とmodel.eval()で学習モードと検証モードで分けて処理を行います。

最初にmodel.train()で、事前に設計したモデル定義をもとにデータを出力し損失関数によって損失を計算しています。

そしてloss.backward()でバックプロパゲーション(誤差逆伝播法)を使いモデルの重みを更新します。

その後model.eval()で検証データにおける精度を算出しています。

このコードの中では計算時間をおさえるためエポック数(試行回数)を3に設定しておりますのでアーリーストッピングを設定していませんが、エポック数が多い場合は検証モードにおいて精度が改善しない場合はエポックを止めるアーリーストッピングの処理を追加するとよいでしょう!

このコードを回した結果、分類精度は96.3%となりました!まずまずの精度でしょう!

このようにPyTorchはちょーっと複雑な部分もありますが、柔軟に様々なディープラーニングのモデルを構築することが可能です!

ぜひ色々試してみてください!

PyTorch まとめ

今回はPyTorchについて解説してきました。

PyTorchを使いこなしてディープラーニングを実装していきましょう!

ディープラーニングの様々なモデルを知りたい方は以下の記事を参考にしてみてください。

さらに詳しくAIやデータサイエンスの勉強がしたい!という方は当サイト「スタビジ」が提供するスタビジアカデミーというサービスで体系的に学ぶことが可能ですので是非参考にしてみてください!

AIデータサイエンス特化スクール「スタアカ」

スタアカトップ
【価格】ライトプラン:980円/月
プレミアムプラン:98,000円
【オススメ度】
【サポート体制】
【受講形式】オンライン形式
【学習範囲】データサイエンスを網羅的に学ぶ
実践的なビジネスフレームワークを学ぶ
SQLとPythonを組み合わせて実データを使った様々なワークを行う
マーケティングの実行プラン策定
マーケティングとデータ分析の掛け合わせで集客マネタイズ

データサイエンティストとしての自分の経験をふまえてエッセンスを詰め込んだのがこちらのスタビジアカデミー、略して「スタアカ」!!

当メディアが運営するスクールです。

24時間以内の質問対応と現役データサイエンティストによる複数回のメンタリングを実施します!

カリキュラム自体は、他のスクールと比較して圧倒的に良い自信があるのでぜひ受講してみてください!

他のスクールのカリキュラムはPythonでの機械学習実装だけに焦点が当たっているものが多く、実務に即した内容になっていないものが多いです。

そんな課題感に対して、実務で使うことの多いSQLや機械学習のビジネス導入プロセスの理解なども合わせて学べるボリューム満点のコースになっています!

Pythonが初めての人でも学べるようなカリキュラムしておりますので是非チェックしてみてください!

ウォルマートのデータを使って商品の予測分析をしたり、実務で使うことの多いGoogleプロダクトのBigQueryを使って投球分析をしたり、データサイエンティストに必要なビジネス・マーケティングの基礎を学んでマーケティングプランを作ってもらったり・Webサイト構築してデータ基盤構築してWebマーケ×データ分析実践してもらったりする盛りだくさんの内容になってます!

・BigQuery上でSQL、Google Colab上でPythonを使い野球の投球分析
・世界最大手小売企業のウォルマートの実データを用いた需要予測
・ビジネス・マーケティングの基礎を学んで実際の企業を題材にしたマーケティングプランの策定
・Webサイト構築してデータ基盤構築してWebマーケ×データ分析実践して稼ぐ

スタビジアカデミーでデータサイエンスをさらに深く学ぼう!

スタアカサービスバナースタビジのコンテンツをさらに深堀りしたコンテンツが動画と一緒に学べるスクールです。

プレミアムプランでは私がマンツーマンで伴走させていただきます!ご受講お待ちしております!

スタビジアカデミーはこちら