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');
訓練済みモデルに戻る