チートシート (ラボクオリティなので、ご利用は自己責任でお願いします)
PyTroch
PyTorch(1.7.0+cu110), Torchvision(0.8.1+cu110)
データセット  訓練済みモデル 
データセット
一覧  データ準備(CIFAR10) 

torchvision.datasets(外部リンク):https://pytorch.org/vision/stable/datasets.html


・一覧
import torchvision.datasets as datasets
from torchvision import transforms

# 使えるデータセットなど一覧(バージョンによって変化がある可能性)
print(dir(datasets))
データセットに戻る ・データ準備(CIFAR10)
import matplotlib.pyplot as plt
import torchvision.datasets as datasets
from torchvision import transforms
plt.style.use('dark_background')

# データ保存先パスは適宜変更(162MB)
# 訓練データ(50000枚、transform: 前処理)
train = datasets.CIFAR10('D:/Data/PyTorch/', train=True, download=True, transform=transforms.ToTensor())
# テストデータ(10000枚)
test = datasets.CIFAR10('D:/Data/PyTorch/', train=False, download=True, transform=transforms.ToTensor())
print()

# 画像確認
# 表示用numpy.arrayに変換
img = train[7][0].permute(1,2,0).numpy()
plt.imshow(img);
データセットに戻る

訓練済みモデル
(Jupyter Lab などで、順にコードを実行することで動作)

初期準備  データ準備(CIFAR10)  モデル作成(VGG16)  訓練  評価 

・初期準備
# ライブラリインストール
import time

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
import seaborn as sns
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.model_selection import train_test_split
import torch
import torch.nn.functional as F
from torch.utils.data import DataLoader
import torchvision as tv
import torchvision.transforms as T

plt.style.use('dark_background')

# 再現性確保
seed = 0
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
torch.backends.cudnn.deterministic = True
訓練済みモデル

・データ準備(CIFAR10)

前処理・データ拡張設定  データ取得(CIFAR10)  データ分割  データセット作成  データローダー作成 


前処理・データ拡張設定

transforms(外部リンク):https://pytorch.org/vision/0.9/transforms.html

# データセット読込時・作成時に使用
# 訓練データ用
train_transform = T.Compose([
    T.RandomRotation(10),
    T.RandomHorizontalFlip(0.2),
    T.ColorJitter(0.1, 0.1, 0.1, 0.1),
    T.ToTensor(),
    T.Normalize(0.5, 0.5)
])

# 検証・テストデータ用
valtest_transform = T.Compose([
    T.ToTensor(),
    T.Normalize(0.5, 0.5)
])
訓練済みモデルに戻る

データ取得

# データ保存先パスは適宜変更(162MB)
# 訓練データ(50000枚)
train = tv.datasets.CIFAR10('D:/Data/PyTorch/', train=True, download=True)
# テストデータ(10000枚、transform: 前処理)
test = tv.datasets.CIFAR10('D:/Data/PyTorch/', train=False, download=True, transform=valtest_transform)
訓練済みモデルに戻る

データ分割

# インデックスで分割(stratify可能)
train_index, val_index = train_test_split(range(len(train.targets)), stratify=train.targets)
train_data = train.data[train_index]
val_data = train.data[val_index]
train_targets = np.array(train.targets)[train_index]
val_targets = np.array(train.targets)[val_index]

# PILに変換
train_data_pil = [Image.fromarray(i) for i in train_data]
val_data_pil = [Image.fromarray(i) for i in val_data]
訓練済みモデルに戻る

データセット作成

# データセット作成用クラス
class MakeDataset(torch.utils.data.Dataset):
    def __init__(self, image_list, target_list, train=True):
        self.image_list = image_list
        # LongTensorに変換
        self.target_list = torch.LongTensor(target_list)
        # 前処理、データ拡張
        if train == True:
            self.transform = train_transform
        else:
            self.transform = valtest_transform
        
    def __len__(self):
        return len(self.image_list)
    
    def __getitem__(self, index):
        image = self.image_list[index]
        target = self.target_list[index]
        return self.transform(image), target

# データセット作成
train_dataset = MakeDataset(train_data_pil, train_targets)
val_dataset = MakeDataset(val_data_pil, val_targets, train=False)
訓練済みモデルに戻る

データローダー作成

# バッチサイズ指定
batch_size = 128

# データローダー作成
train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
val_dataloader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)

# データ確認(再現性必要な場合は実行しない)
# images, labels = iter(train_dataloader).next()
# print('1バッチあたり画像データ:', images.shape)
# print('1バッチあたりラベルデータ:', labels.shape)
訓練済みモデルに戻る

・モデル作成(VGG16)

models(外部リンク):https://pytorch.org/vision/0.8/models.html
loss-functions(外部リンク):https://pytorch.org/docs/stable/nn.html#loss-functions
optim(外部リンク):https://pytorch.org/docs/stable/optim.html

# 使える訓練済modelなど
# print(dir(tv.models))

# VGG16
# model = tv.models.vgg16(pretrained=True)
weights = tv.models.VGG16_Weights
model = tv.models.vgg16(weights=weights)

# GPU設定
device = "cuda" if torch.cuda.is_available() else "cpu"
model.to(device)

# 損失関数
criterion = torch.nn.CrossEntropyLoss()

# 最適化アルゴリズム
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
訓練済みモデルに戻る

・訓練

eval(外部リンク):https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module.eval
no_grad(外部リンク):https://pytorch.org/docs/stable/generated/torch.no_grad.html

# GTX1080Tiで60sec/epoch程度
num_epochs = 10
loss_list = []
acc_list = []
val_loss_list = []
val_acc_list = []

for epoch in range(num_epochs):
    start = time.time()
    
    # train
    # 訓練モード
    model.train()
    epoch_loss = 0
    epoch_acc = 0
    for images, labels in train_dataloader:
        images = images.to(device)
        labels = labels.to(device)
        optimizer.zero_grad()
        output = model(images)
        loss = criterion(output, labels)
        loss.backward()
        epoch_loss += loss.item()
        pred = torch.argmax(output, dim=1)
        epoch_acc += torch.mean(pred.eq(labels).float()).item()
        optimizer.step()
    epoch_loss /= len(train_dataloader)
    epoch_acc /= len(train_dataloader)
    loss_list.append(epoch_loss)
    acc_list.append(epoch_acc)
    
    # validation
    # 評価モード(Dropout, BatchNormなどのON/OFF)
    model.eval()
    val_epoch_loss = 0
    val_epoch_acc = 0
    for val_images, val_labels in val_dataloader:
        val_images = val_images.to(device)
        val_labels = val_labels.to(device)
        # 勾配計算無効
        with torch.no_grad():
            val_output = model(val_images)
            val_loss = criterion(val_output, val_labels)
        val_epoch_loss += val_loss.item()
        val_pred = torch.argmax(val_output, dim=1)
        val_epoch_acc += torch.mean(val_pred.eq(val_labels).float()).item()
    val_epoch_loss /= len(val_dataloader)
    val_epoch_acc /= len(val_dataloader)
    val_loss_list.append(val_epoch_loss)
    val_acc_list.append(val_epoch_acc)
    
    # 経過を表示
    print(f'( epoch: {epoch+1:2} ) \
loss: {epoch_loss:7.5f}, acc: {epoch_acc:7.5f}, \
val_loss: {val_epoch_loss:7.5f}, val_acc: {val_epoch_acc:7.5f} \
({time.time()-start:6.1f} sec )')

print('Done!')
訓練済みモデルに戻る

・評価

グラフ 
テストデータ評価:  正解率  分類レポート  ヒートマップ 


グラフ

fig, ax = plt.subplots(1,2, figsize=(10,5))
ax[0].plot(acc_list, label='acc')
ax[0].plot(val_acc_list, label='val_acc')
ax[0].set_title('Accuracy')
ax[0].legend()
ax[1].plot(loss_list, label='loss')
ax[1].plot(val_loss_list, label='val_loss')
ax[1].set_title('Loss')
ax[1].legend();
訓練済みモデルに戻る

正解率(テストデータ)

test_dataloader = DataLoader(test, batch_size=batch_size, shuffle=False)
test_correct_list = []
test_pred_list = []
test_labels_list = []
model.eval()
for test_images, test_labels in test_dataloader:
    test_loss = 0
    test_acc = 0
    test_images = test_images.to(device)
    test_labels = test_labels.to(device)
    with torch.no_grad():
        test_output = model(test_images)
    test_pred = torch.argmax(test_output, dim=1)
    batch_correct_list = list(test_pred.eq(test_labels).float().cpu().numpy())
    test_correct_list += batch_correct_list
    test_pred_list += list(test_pred.cpu().numpy())
    test_labels_list += list(test_labels.cpu().numpy())
print('正解率:', sum(test_correct_list) / len(test_correct_list))
訓練済みモデルに戻る

分類レポート(テストデータ)

print('classification_report')
print(classification_report(test_labels_list, test_pred_list))
訓練済みモデルに戻る

ヒートマップ(テストデータ)

cm = confusion_matrix(test_labels_list, test_pred_list)
plt.figure(figsize=(8,5))
sns.heatmap(cm, square=True, cbar=True, annot=True, fmt='d', cmap='gray')
plt.tight_layout()
plt.ylabel('True')
plt.xlabel('Pred');
訓練済みモデルに戻る