Python

【入門】PyTorchの使い方をMNISTデータセットで学ぶ(15分)

【入門】PyTorchの使い方をMNISTデータセットで学ぶ(15分)

 

 

  • PyTorchってなんだ??
  • PyTorchでディープラーニングを実装してみたい
  • PyTorchが難しくてよくわからない…

本記事では、その悩みを解決していきます。

本記事は以下の二通りの読者に対応しています。

  • とりあえず機械学習を実装してPyTorchの実装の流れを掴みたい(所要時間15分)
  • 初心者だけど、PyTorchを丁寧に体系的に学びたい(所要時間30〜45分)

(PyTorchを丁寧に学びたい方へ): 各見出しごとに詳細ページへのリンクが貼られているので、より深く知りたいと思ったアクセスしてください!

 

本記事の内容

  1. PyTorchを使用するための準備
  2. PyTorchを利用してMNISTデータを読み込む
  3. PyTorchでネットワークを定義
  4. 定義したネットワークを学習
  5. 学習結果を確認

本記事を読むメリット

  1. PyTorchでディープラーニングを構築する基本が学べる

 

 

PyTorchを使用するための準備

 

Anaconda等を使用する場合は、下記のコードでPytorchを事前にインストールしてください。

$ pip3 install torch torchvision

 

Google Colaboratoryを使用する場合は、PyTorchは最初からインストールされているので問題はありません。

PyTorchを使用する場合は、GPUを無料で提供している『Google Colaboratory』がおすすめです。

 

Google Colaboratoryのインストールは下記を参考にしてください!!

 

【10分で完了】Google Colabのインストール法・使い方Google Colabは、GPUを使用できるため、低コストかつ高速で機械学習の実装を行う際に必要不可欠なツールです。本記事では、Google Colabのインストール方法と注意事項を10〜15分程度でまとめました。...

 

 

必要なライブラリをインストール

 

多層パーセプトロンを実装するのに必要なライブラリをインポートしましょう。

具体的には、以下を実行しましょう。

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

# グラフのスタイルを指定
plt.style.use('seaborn-darkgrid')

 

ざっくりとインポートしたパッケージを紹介します。

torch Pytorchの配列を扱う
torch.nn ネットワークが構築する
torch.nn.functional さまざまな関数を使用する
torch.optim 最適化アルゴリズムを使用する
torchvision 画像処理に関する操作を利用する
torchvision.transform 画像変換機能を利用する

 

この段階で覚える必要はありません、「こういうパッケージを使用するのか..」という感じで雰囲気のみつかんでおけば大丈夫です。

また、numpymatplotlibは、誤差関数の可視化等に使用します。

plt.style.use('seaborn-darkgrid')はグラフのスタイルを変更するために使用しました(これは私の好みの問題です…)

numpymatplotlibを初めて聞いたという方は下記を参考に学んでください!

 

PyTorchのTensorについて

 

Pytorchで機械学習を実行する場合、Pytorch独特の配列(Tensor)を利用します。

Numpyの配列と同様に、以下のようにTensorを作ることができます。

tensor = torch.Tensor([1, 2, 3])
tensor

 

<出力>

tensor([1., 2., 3.])

 

基本的には、Numpyの配列と同じように要素を取り出したりできます。

Tensorの操作をより詳しく知りたい方は下記を参考にしてください。

 

【Pytorch】tensor型とは|知らないとまずいものをまとめてみたPyTorchのTensorに関してまとめてみました。この中で紹介しているTensorの関数やメソッドは、どれもPytorchで深層学習を実装する際に必要不可欠なものばかりです。15分程度で読み終わるので一読して頭を整理させましょう。...

 

 

PyTorchを用いてMNISTデータセットを読み込む

 

PyTorchで学習を行う場合、データをDataset, DataLoderという形で読み込みます。

イメージ的には、各データを一つのデータベース的なものに格納するのが『Dataset』です。

そして、その『Dataset』を『DataLoder』に渡すことで、ミニバッチ単位でデータを簡単に取り出すことができます。

DatasetとDataLoaderの関係

  1. Dataset : データを一つのデータベースにまとめる
  2. DataLoader : データをミニバッチ単位で取り出す 

詳しく解説していきます。

 

Dataset : 各データを一つのデータベースにまとめる

 

今回は、MNISTデータセットをインポートして、データセットに格納していきます。

具体的には、下記のコードでインポートして、データセットを作成することができます。

train_dataset = torchvision.datasets.MNIST(root='./data',
                                           train=True,
                                           transform=transforms.ToTensor(),
                                           download=True)

test_dataset = torchvision.datasets.MNIST(root='./data',
                                           train=False,
                                           transform=transforms.ToTensor(),
                                           download=True)

 

train_dataset, test_datasetには、データの入力と出力が一つのデータベースにまとまって保管されています。

また、引数のtransform=transforms.ToTensor()でデータをTensor型に変換しています。

とりあえず、PyTorchを利用して流れを掴みたいという方は、コードの詳細というよりは、『Datasetというデータベースに一度まとめる必要があるんだな』と思って先に進んでください!!

 

『Dataset』の詳細を学んでみたい方は下記を参考にしてください。

 

PytorchのDatasetを徹底解説(自作データセットも作れる)PyTorchのDataset作成方法を徹底的に解説しました。本記事を読むことで、Numpy, PandasからDatasetを作成したり、自作のDatasetを作成しモジュール化する作業を初心者の方でも理解できるように徹底的に解説しました。...

 

本記事では、使用しませんが、引数transformに画像の前処理を指定することができます。

transformについて詳しく知りたい方は下記を参考にしてください。

 

PyTorchのTransformを使い方|自作Transformの作成方法も解説『PytorchのTransformsパッケージが何をやっているかよくわからん...』という方のために本記事を作成しました。本記事では、transformsを体系的に(複数の処理を行う、自作Transform)を解説しました。...

 

 

DataLoader : dataをミニバッチに適した形に変換

 

DataLoaderは、Datasetを入力としてミニバッチごとにデータを取り出すことができます。

今回は、ミニバッチデータサイズを256としてDataLoaderを作成します。

具体的には、下記のコードで実装することができます。

batch_size = 256


train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
                                           batch_size=batch_size,
                                           shuffle=True)

test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
                                           batch_size=batch_size,
                                           shuffle=False)

 

これで、PyTorchによるデータの読み込みは終了です。

同様に、とりあえずPytorchを使用して機械学習を実装してみたいという方はこのまま進んでください!

『DataLoader』の動作を確認してから先に進みたいという方は下記を参考にしてください。

 

【徹底解説】PytorchのDataLoaderの使い方PytorchのDataLoaderを具体的な例を使って解説しました。『DataLoaderが実はよくわからない...』という方は、具体的な動作を徹底解説したので、本記事を参考にしてください。...

 

次章では、使用するネットワーク(多層パーセプトロン)を構築していきましょう。

 

PyTorchでネットワークを定義

 

Pytorchには、主にネットワークを定義する方法が二つあります。

今回はカスタマイズ性の高い方法を用いてネットワークを定義します。

GPUを使用する方のために、ネットワークをGPUに転送するプロセスも詳しく紹介します!

  1. ネットワークを定義
  2. ネットワークをGPUに転送する

*GPUを使用できない方も対処法を②で詳しく説明するので安心してください。

 

ネットワークを定義

 

今回は、『nn.Module(ネットワークのモジュールのクラス)』を引き継ぐ方法でネットワークを定義します。

num_classes = 10

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(28*28, 1024)
        self.fc2 = nn.Linear(1024, 512)
        self.fc3 = nn.Linear(512, num_classes)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

 

num_classesで出力の数を指定しています。

__init__ 部分には、ネットワークの構造を指定します。

そして、forwardメソッドに順伝搬を記入します。

 

ネットワークの定義方法をより詳しく理解したいという方は下記を参考にしてください。

 

Pytorchのネットワークの書き方を徹底解説(カスタムレイヤー作成も説明)Pytorchのネットワークの書き方を二つ説明しました。一つ目はSequentialを使用する方法で、二つ目はネットワークを自作モジュール化する方法を説明しました。また、二つのメリット・デメリットを具体例を通じて理解できるように工夫しました。...

 

 

ネットワークをGPUに転送する

 

以下のコードで、ネットワークをGPUに転送することができます。

device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = Net().to(device)

 

  • 1行目 : GPUが利用できる場合はGPUを利用し、そうでない場合は、CPUを利用するように設定
  • 2行目:ネットワークをGPUに転送

 

以下のように入力することでネットワーク構造を確認することができます。

print(model)

 

<出力>

Net(
  (fc1): Linear(in_features=784, out_features=1024, bias=True)
  (fc2): Linear(in_features=1024, out_features=512, bias=True)
  (fc3): Linear(in_features=512, out_features=10, bias=True)
)

 

また、『net.parameters()』でパラメータの情報を取得することができます。

下記を入力して確かめてみてください。

list(model.parameters())

 

次はいよいよネットワークを学習させます!

 

ネットワークを学習

 

PyTorchでは以下のようにネットワークを学習することができます。

  1. 損失関数と最適化手法を設定
  2. 1エポックの訓練実行する関数を定義
  3. 推論するための関数を定義
  4. モデルの学習
  5. 訓練誤差とテスト誤差をプロット

 

損失関数と最適化手法を設定

 

まずは、学習に使用する損失関数と最適化アルゴリズムを以下のように設定しましょう。

# 損失関数の設定
criterion = nn.CrossEntropyLoss()

# 最適化手法を設定
optimizer = optim.SGD(model.parameters(), lr=0.01)

 

今回は、損失関数として『交差エントロピー誤差関数』を使用し、最適化アルゴリズムとしては、『確率的勾配降下法』を使用します。

optimizerの第一引数には、ネットワークのパラメータを入力します。

 

1エポックの訓練を行う関数を定義

 

実装の際になるべく小さいまとまりで関数を定義しておくと後からカスタマイズしやすいです。

そのため、1エポックを学習するための関数を定義していきます。

def train_epoch(model, optimizer, criterion, dataloader, device):
    train_loss = 0
    model.train()

    for step, (images, labels) in enumerate(dataloader):
        # viewで1次元配列に変更
        # toでgpuに転送
        images, labels = images.view(-1, 28*28).to(device), labels.to(device)
        # 勾配をリセット
        optimizer.zero_grad()
        # 順伝搬の計算
        outputs = model(images)
        # lossを計算
        loss = criterion(outputs, labels)
        # 逆伝搬の計算
        loss.backward()
        # 重みの更新
        optimizer.step()
        # lossのミニバッチ分を加算
        train_loss += loss.item()
    # データ数で割る
    train_loss = train_loss / len(train_loader.dataset)
    return train_loss

 

コントアウトでも記入していますが、各行がどのような役割をしているかを以下にまとめます。

1epoch単位の各行の意味

  1. net.train() : trainモードに変換
  2. optimizer.zero_grad() : 勾配を0にリセットする(勾配はbackwardメソッドが実行されるたびに積算されるため必要)
  3. outputs : 順伝搬の出力を計算
  4. loss : 出力とミニバッチのラベルからコスト関数を計算
  5. loss.backward() : lossの勾配を計算
  6. optimizer.step() : パラメータを更新

基本的にPytorchの学習の流れはどんな複雑なモデルでもこの枠組みが適用できます。

わざわざ、逆伝搬を実装しなくてもloss.backward()を書き込むだけで、逆伝搬を実行してくれるのは驚きですね!

 

推論するための関数を定義

 

次にテストデータから推論を行う際に使用する関数を定義します。

def inference(model, optimizer, criterion, dataloader, device):
    # 評価モードに切り替え
    model.eval()
    test_loss=0
    preds = []

    # 評価するとき勾配を計算しないように加える
    with torch.no_grad():
        for j, (images, labels) in enumerate(test_loader):
            images, labels = images.view(-1, 28*28).to(device), labels.to(device)
            outputs = model(images)
            loss = criterion(outputs, labels)
            test_loss += loss.item()
        test_loss = test_loss / len(test_loader.dataset)
    return test_loss

 

各行がどのような役割をしているかまとめておきます。

推論を行うための関数の詳細

  1. net.eval() : networkを評価モードに変換
  2. with torch.no_grad() : 逆伝搬が必要ないので余計な勾配計算を回避
  3. outputs : 予測値を計算

 

同様に、モデル・タスクがどんなに複雑になっても、基本的には、この枠組みが利用できます。

 

モデルの学習

 

これまで定義した関数を使って、モデルの学習と推論を行うコードを書いていきます。

def run(num_epochs, optimizer, criterion, device):
    train_loss_list = []
    test_loss_list = []
    for epoch in range(num_epochs):
        train_loss = train_epoch(model, optimizer, criterion, train_loader, device)
        test_loss = inference(model, optimizer, criterion, test_loader, device)

        print(f'Epoch [{epoch+1}], train_Loss : {train_loss:.4f}, val_Loss : {test_loss:.4f}')
        train_loss_list.append(train_loss)
        test_loss_list.append(test_loss)
    return train_loss_list, test_loss_list

 

それでは実際に実行してみましょう。

train_loss_list, test_loss_list = run(30, optimizer, criterion, device)

 

<出力>

Epoch [1], train_Loss : 0.0087, val_Loss : 0.0084
Epoch [2], train_Loss : 0.0072, val_Loss : 0.0059
Epoch [3], train_Loss : 0.0045, val_Loss : 0.0034
                         :
                         :
                         :
Epoch [28], train_Loss : 0.0009, val_Loss : 0.0009
Epoch [29], train_Loss : 0.0009, val_Loss : 0.0009
Epoch [30], train_Loss : 0.0009, val_Loss : 0.0009

 

今回は、学習がうまくいっているかを判断するために、TestデータとTrainデータの誤差関数を表示するように実装しています。

 

訓練誤差とテスト誤差をプロット

 

訓練誤差とテスト誤差をプロットし、学習が上手くいっているか確認しましょう。

num_epochs=30
fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(range(num_epochs), train_loss_list, c='b', label='train loss')
ax.plot(range(num_epochs), test_loss_list, c='r', label='test loss')
ax.set_xlabel('epoch', fontsize='20')
ax.set_ylabel('loss', fontsize='20')
ax.set_title('training and validation loss', fontsize='20')
ax.grid()
ax.legend(fontsize='25')
plt.show()

 

<output>

訓練誤差とテスト誤差訓練誤差とテスト誤差

 

無事に、訓練誤差と検証誤差が大きく乖離することなく適切に学習されていることが視覚的にチェックできましたね。

 

また、一つのサンプルを実際に取り出して、学習後のモデルが上手く数字を判別できるか確認してみます。

# datasetからサンプルを一つ取り出す
image, label = train_dataset[0]
sample = train_dataset[0][0].view(-1, 28*28)

# 学習後のモデルに予測される
prediction_label = torch.argmax(model(sample))

fig, ax = plt.subplots()
ax.imshow(sample.detach().to('cpu').numpy().reshape(28, 28))
ax.axis('off')
ax.set_title(f'True Label : {label}, Prediction : {prediction_label}', fontsize=20)
plt.show()

 

<output>

サンプルの予測

見事に本物のラベルを予測することに成功しました!!

 

 

 

まとめ

 

MNISTデータセットの分類を用いて、PyTorchの実装の流れを紹介しました。

本記事を通して、PyTorchを使用して機械学習(ディープラーニング)を行う流れはつかめたと思います。

次は、各パッケージ(Dataset, DataLoader等)を正しく理解することが大切です。

これらを理解しないと少しカスタマイズしただけで、Pytorchがバグだらけになり解決策がよくわからないという状況に陥ります…

ここまで、とりあえず動かしてみたという方は下記の記事を参考にしてさらに深く学んでください。

 

ABOUT ME
努力のガリレオ
【運営者】 : 東大で理論物理を研究中(経歴)東京大学, TOEIC950点, NASA留学, カナダ滞在経験有り, 最優秀塾講師賞, オンライン英会話講師試験合格, ブログと独自コンテンツで収益6桁達成 【編集者】: イングリッシュアドバイザーとして勤務中(経歴)中学校教諭一種免許取得[英語],カナダ留学経験あり, TOEIC650点
Python学習を効率化させるサービス

 

Pythonを学習するのに効率的なサービスを紹介していきます。

まず最初におすすめするのは、Udemyです。

Udemyは、Pythonに特化した授業がたくさんあり、どの授業も良質です。

また、セール中は1500円定義で利用することができ、コスパも最強です。

下記の記事では、実際に私が15個以上の講義を受講して特におすすめだった講義を紹介しています。

 

【最新】UdemyでおすすめのPythonコース|東大生が厳選!10万を超える講座があるUdemyの中で、Pythonに関係する講座を厳選しました。また、本記事では、Udemyを使用しながらPythonをどのような順番で勉強するべきかを紹介しました。ぜひ参考にしてください。...

 

他のPythonに特化したオンライン・オフラインスクールも下記の記事でまとめています。

 

【最新】Pythonに強いプログラミングスクール7選|東大生が厳選Pythonの流行と共に、Pythonに強いプログラミングスクールが増えてきました。本記事では、特にPythonを効率的に学ぶことができるプログラミングスクールを経験をもとに厳選して、内容を詳しく解説しています。...

 

自分の学習スタイルに合わせて最適なものを選びましょう。