Open6

pytorch + pytorch lightningの基本まとめ

ピン留めされたアイテム
そのうえそのうえ

概要

自分でPyTorchのチュートリアルを訳しながらメモしないとちゃんと読まないなということ、チュートリアルをひたすら意訳していってます (翻訳ソフト禁止)。

そのうえそのうえ

pytorchのtutorialをざっくりと翻訳していく。

pytorch

機械学習ワークフローはデータ、モデルの作成、パラメターの最適化や学習済みモデルの保存において機能する。ここではpytorchにおいて、一貫したワークフローを実装し、各コンセプトについて学んでいく。

ここではFashionMNISTデータセットをニューラルネットワークを学習させるためのデータとして用いる。FashionMNISTデータは

  • T-shirt/top
  • Trouser
  • Pullover
  • Dress
  • Coat
  • Sandal
  • Shirt
  • Sneaker
  • Bags
  • Ankle boot
    のクラスへ分類することができる。

チュートリアルのコードを実行する

このチュートリアルは複数の方法で実行することができる。

  • クラウド上で: これは初めての人には一番簡単な方法。各セクションの一番上には、"Run in Microsoft" および "Run in Google Colab"というボタンがある。これらのページを開くとMicrosoft LearnおよびGoogle colab上のページを開くことができ、構築済みの環境でコードを動かすことが可能になる
  • ローカルで: この方法は自分のマシンで環境を構築する必要がある。さらにnotebookをダウンロードしてもいいし、自分の好きなIDE上でコードすることもできる。
そのうえそのうえ

Quick start

このセクションでは機械学習の一般的なタスクについてAPIを通して実行していく。またさらに深く理解するために、各セクションへのリンクも貼ってある。

データを動かしてみる

PyTorchは2つの初期的なデータを有している。

  • torch.utils.data.DataLoader
  • torch.utils.data.Dataset

Datasetはサンプルと対応したラベルを格納しており、DataLoaderはDatasetをiterableで包んでいる。

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor

PyTorchはドメイン特異的なライブラリを有しており、それぞれはデータセットを含んでいる。いかに例を挙げる

  • TorchText
  • TorchVision
  • TorchAudio

このチュートリアルではTorchVision datasetを利用する。

torchvision.datasets モジュールは多くの実世界データ (CIFARやCOCO) をDataset オブジェクトとして含んでいる。このチュートリアルではFashionMNISTデータを利用する。全てのTorchVision Datasetはサンプルとラベルの操作を行うために二つのargumentsを持っている。

  • transform
  • target_transform
# training dataをopen datasetsからダウンロードする
training_data = datasets.FashionMNIST(
    root = "data",
    train=True,
    download=True,
    transform=ToTensor(),
)

test_data = datasets.FashionMNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor(),
)

次にDatasetをDataLoaderにargumentとして受け渡す。これはデータセットに対してiterable (反復可能な) ない方であり、自動的なバッチ、サンプリング、シャッフル、複数プロセスのデータ読み込みなどに対応する。
ここでは、batch sizeを64としていく。

batch_size = 64

# data loaderを作成する
train_dataloader = DataLoader(training_data, batch_size = batch_size)
test_dataloader = DataLoader(test_data, batch_size = batch_size)

for X, y in test_dataloader:
    print(f"Shape of X [N, C, H, W]: {X.shape}")
    print(f"Shape of y: {y.shape} {y.dtype}")
    break

実行結果は

Shape of X [N, C, H, W]; torch.Size([64, 1, 28, 28])
Shape of y: torch.Size([64]) torch.int64

となる。

詳しくはPyTorchにおけるデータの読み込み

そのうえそのうえ

モデルの作成

PyTorch上でNNを構築するために、ここではnn.Moduleを継承してクラスを作成する。
init 関数において、NNのレイヤーを定義し、forward関数においてネットワークがどのようにデータを処理するのかを指定する。
これらのNNを高速に処理するために、モデルをGPUやMPS (Macのdevice) へ渡す。

# 学習のためのCPU, GPU, MPSを指定する
device = (
    "cuda"
    if torch.cuda.is_available()
    else "mps"
    if torch.backends.mps.is_available()
    else "cpu"
)
print(f"Using {device} device")

# モデルを定義する (最近だとここまで明確に書かない気がする、、、)
class NeuralNetwork(nn.Module):
     def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(28 * 28, 512)
            nn.ReLU()
            nn.Linear(512, 512)
            nn.ReLU()
            nn.Linear(512, 10)
        )

    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits

model = NeuralNetwork().to(device)
print(model)

出力としては

Using cuda device
NeuralNetwork(
  (flatten): Flatten(start_dim=1, end_dim=-1)
  (linear_relu_stack): Sequential(
    (0): Linear(in_features=784, out_features=512, bias=True)
    (1): ReLU()
    (2): Linear(in_features=512, out_features=512, bias=True)
    (3): ReLU()
    (4): Linear(in_features=512, out_features=10, bias=True)
  )
)

詳しくはPyTorchにおけるニューラルネットワークの構築

そのうえそのうえ

モデルパラメタの最適化

モデルを学習するために、loss functionとoptimizerを設定する。

loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr = 1e-3) # lrはlearning rate

一回の学習ループにおいて、モデルが学習データを使ってパラメタの誤差を減少させていく。

def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset) #データサイズみる
    #モデルを学習
    model.train()
    for batch, (X, y) in enumerate(dataloader):
        X, y = X.to(device), y.to(device) #deviceへデータを送る

        # 予測誤差を計算する
        pred = model(X)
        loss = loss_fn(pred, y)

        # 誤差逆伝播法
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()

        if batch % 100 == 0:
            loss, current = loss.item(), (batch + 1) * len(X)
            print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")

次に学習済みのモデルに対するtestデータでの性能を測る。

def test(dataloader, model, loss_fn):
    size = len(dataloader,dataset)
    num_batches = len(dataloader)
    mode.eval()
    test_loss, correct = 0, 0
    with torch.no_grad():
        for X, y in dataloader:
            X, y = X.to(device), y.to(device)
            pred = model(X)
            test_loss += loss_fn(pred, y).item()
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
    test_loss /= num_batches
    correct /= size
    print(f"Test Error: \n Accuracy: {(100*correct): >0.1f}%, Avg loss: {test_loss:>8f} \n")

学習ステップは複数の反復 (epochs) で行われる。各epochsでモデルは予測が良くなるようにパラメタを学習する。各エポックにおけるモデルの精度と損失を可視化する。

epochs = 5
for t in range(epochs):
    print(f"Epoch {t+1}\n-------------------------------")
    train(train_dataloader, model, loss_fn, optimizer)
    test(test_dataloader, model, loss_fn)
print("Done!")
Epoch 1
-------------------------------
loss: 2.303494  [   64/60000]
loss: 2.294637  [ 6464/60000]
loss: 2.277102  [12864/60000]
loss: 2.269977  [19264/60000]
loss: 2.254234  [25664/60000]
loss: 2.237145  [32064/60000]
loss: 2.231056  [38464/60000]
loss: 2.205036  [44864/60000]
loss: 2.203239  [51264/60000]
loss: 2.170890  [57664/60000]
Test Error:
 Accuracy: 53.9%, Avg loss: 2.168587

Epoch 2
-------------------------------
loss: 2.177784  [   64/60000]
loss: 2.168083  [ 6464/60000]
loss: 2.114908  [12864/60000]
loss: 2.130411  [19264/60000]
loss: 2.087470  [25664/60000]
loss: 2.039667  [32064/60000]
loss: 2.054271  [38464/60000]
loss: 1.985452  [44864/60000]
loss: 1.996019  [51264/60000]
loss: 1.917239  [57664/60000]
Test Error:
 Accuracy: 60.2%, Avg loss: 1.920371

Epoch 3
-------------------------------
loss: 1.951699  [   64/60000]
loss: 1.919513  [ 6464/60000]
loss: 1.808724  [12864/60000]
loss: 1.846544  [19264/60000]
loss: 1.740612  [25664/60000]
loss: 1.698728  [32064/60000]
loss: 1.708887  [38464/60000]
loss: 1.614431  [44864/60000]
loss: 1.646473  [51264/60000]
loss: 1.524302  [57664/60000]
Test Error:
 Accuracy: 61.4%, Avg loss: 1.547089

Epoch 4
-------------------------------
loss: 1.612693  [   64/60000]
loss: 1.570868  [ 6464/60000]
loss: 1.424729  [12864/60000]
loss: 1.489538  [19264/60000]
loss: 1.367247  [25664/60000]
loss: 1.373463  [32064/60000]
loss: 1.376742  [38464/60000]
loss: 1.304958  [44864/60000]
loss: 1.347153  [51264/60000]
loss: 1.230657  [57664/60000]
Test Error:
 Accuracy: 62.7%, Avg loss: 1.260888

Epoch 5
-------------------------------
loss: 1.337799  [   64/60000]
loss: 1.313273  [ 6464/60000]
loss: 1.151835  [12864/60000]
loss: 1.252141  [19264/60000]
loss: 1.123040  [25664/60000]
loss: 1.159529  [32064/60000]
loss: 1.175010  [38464/60000]
loss: 1.115551  [44864/60000]
loss: 1.160972  [51264/60000]
loss: 1.062725  [57664/60000]
Test Error:
 Accuracy: 64.6%, Avg loss: 1.087372

Done!

詳しくはモデルの学習にある

そのうえそのうえ

モデルの保存

モデルを保存するための一般的な方法は内部のstate dictionaryを変換することです (パラメタを含む)。

torch.save(model.state_dict(), "model.pth")
print("Saved PyTorch Model State to model.pth")

モデルの読み込み

モデルの読み込みの操作は、モデル構造の再構築とstate dictionaryの読み込みを含んでいる。

model = NeuralNetwork().to(device)
model.load_state_dict(torch.load("model.pth"))

このモデルは予測に利用することができる

classes = [
    "T-shirt/top",
    "Trouser",
    "Pullover",
    "Dress",
    "Coat",
    "Sandal",
    "Shirt",
    "Sneaker",
    "Bag",
    "Ankle boot"
]

model.eval()
x, y = test_data[0][0], test_data[0][1]
with torch.no_grad():
    x = x.to(device)
    pred = model(x)
    predicted, actual = classes[pred[0].argmax(0)], classes[y]
    print(f"Predicted: "{predicted}", Actual: "{actural}"")

詳しくはモデルの保存と読み込みを見る