使用したGPU | 処理に要した時間 |
---|---|
GeForce RTX2080 | 21分11秒 |
GeForce GTX1050Ti | GPUのメモリ不足のため、処理が不可能 |
import numpy as np import pandas as pd import itertools import shutil from PIL import Image import os import glob import matplotlib.pyplot as plt import json import torch from torch import nn, utils, optim from torchvision import transforms, models from torch.utils.data import DataLoader from torch.utils.data import Dataset from sklearn.metrics import f1_score, accuracy_score from sklearn.model_selection import train_test_split
# GPUを使うかどうか USE_DEVICE = 'cuda:0' if torch.cuda.is_available() else 'cpu' device = torch.device(USE_DEVICE) # データがあるディレクトリ INPUT_DIR = '../20220526/forest-path-movie-dataset-main/forest-path-movie-dataset-main/'
# 検証用データを使う USE_VALIDATE = True # 検証用データ VALIDATIONS = 'unnormal-validations/*.png'
# PyTorchの内部を決定論的に設定する torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False # 乱数を初期化する np.random.seed(0) torch.manual_seed(0)
# データセットの定義ファイルを読み込む df = pd.read_csv(INPUT_DIR+'all_file2.csv') # シーン毎に分割するので、groupbyして取り出す file = [] for g in df.groupby(df.scene): file.append(g[1].file.values.tolist()) # シーン毎に学習用と評価用データに分ける train_X, test_X = [], [] for i in range(len(file)): trainX, testX = train_test_split(file[i], test_size=0.3, random_state=0) train_X.append(trainX) test_X.append(testX) # 全てのシーン内のデータを繋げた配列にする train_X = sum(train_X, []) test_X = sum(test_X, []) # ファイル名をディレクトリを含むものにする train_X = [INPUT_DIR+f for f in train_X] test_X = [INPUT_DIR+f for f in test_X]
if USE_VALIDATE: valid_X = glob.glob(VALIDATIONS) # 検証用データ一覧
class MyTransform: def __init__(self): self.data_transform = { 'train': transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.RandomErasing(p=1.0, scale=(0.3, 0.6), ratio=(0.5, 2.0), value='random'), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]), 'val': transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) } def __call__(self, img, phase='train'): return self.data_transform[phase](img)
# PyTorchの流儀でデータセットをクラスで定義する class MyDataset(Dataset): def __init__(self, X, transform, phase): # 初期化 Xはファイル名のリスト self.X = X self.transform = transform self.phase = phase def __len__(self): # データセットの長さを返す return len(self.X) def __getitem__(self, pos): # posの場所にあるデータを返す if self.phase == 'train': # 学習時には、Tripletを返す f1 = self.X[pos] # ベースとなるファイルのパス f2 = self.X[np.random.randint(len(self))] f3 = self.X[np.random.randint(len(self))] f1 = Image.open(f1) # ファイルを読み込む f2 = Image.open(f2) # ファイルを読み込む f3 = Image.open(f3) # ファイルを読み込む if np.random.random() < 0.5: # ランダムに、ペアを選ぶ X1 = self.transform(f1, phase='val') # ノーマルペア X2 = self.transform(f2, phase='val') # ノーマルペア X3 = self.transform(f3, phase='train') # 異常値 else: X1 = self.transform(f1, phase='train') # 異常値ペア X2 = self.transform(f2, phase='train') # 異常値ペア X3 = self.transform(f3, phase='val') # ノーマル return X1, X2, X3 else: # 検証時にはデータファイルのみを返す f1 = self.X[pos] # ファイルパス f1 = Image.open(f1) # ファイルを読み込む X1 = self.transform(f1, phase='val') # tensorにする return X1
# 保存しておいたモデルを読み込む model = models.resnet50(pretrained=False) model.fc = nn.Linear(2048, 2) model.load_state_dict(torch.load('../20220526/YAMA-DNN1/chapt02-model1.pth')) # 出力の次元数を8次元にする model.fc = nn.Linear(2048, 8) model.to(device)
params = model.parameters() # モデル全体のトレーニング optimizer = optim.SGD(params, lr=5e-5, momentum=0.9) # 学習率を設定 loss = nn.TripletMarginLoss(margin=10.0) # 損失関数を用意する
# 学習時と評価時のバッチサイズ BATCH_SIZE = 16 BATCH_SIZE_VALID = 4 # 学習エポック数 NUM_EPOCHS = 3
# 学習用のデータセットを作る train_ds = MyDataset(train_X, transform=MyTransform(), phase='train') # 検証用データを使う場合 if USE_VALIDATE: test_ds = MyDataset(test_X + valid_X, transform=MyTransform(), phase='val') else: test_ds = MyDataset(test_X, transform=MyTransform(), phase='val') data_loader = DataLoader(train_ds, batch_size=BATCH_SIZE, shuffle=True) data_loader_v = DataLoader(test_ds, batch_size=BATCH_SIZE_VALID, shuffle=False)
# 学習ループ for epoch in range(NUM_EPOCHS): total_loss = [] # 各バッチ実行時の損失値 model.train() # モデルを学習用に設定する for X1, X2, X3 in data_loader: # 画像を読み込んでtensorにする X1 = X1.to(device) # GPUを使うときはGPUメモリ上に乗せる X2 = X2.to(device) # GPUを使うときはGPUメモリ上に乗せる X3 = X3.to(device) # GPUを使うときはGPUメモリ上に乗せる # ニューラルネットワークを実行して損失値を求める losses = loss(model(X1), model(X2), model(X3)) # 新しいバッチ分の学習を行う optimizer.zero_grad() # 一つ前の勾配をクリア losses.backward() # 損失値を逆伝播させる optimizer.step() # 新しい勾配からパラメーターを更新する # 損失値を保存しておく total_loss.append(losses.detach().cpu().numpy()) # エポック終了時のスコアを求める total_loss = np.mean(total_loss) # 各バッチの損失の平均 # エポック終了時のスコアを表示する print(f'epoch #{epoch}: train_loss:{total_loss}') # 終了時のモデルを保存する torch.save(model.state_dict(), 'chapt03-model1.pth')
# 評価データに対して実行結果を求める with torch.no_grad(): results = [] # 結果を入れる配列 model.eval() # モデルを推論用に設定する for X in data_loader_v: X = X.to(device) # GPUを使うときはGPUメモリ上に乗せる res = model(X) # ニューラルネットワークの実行 res = res.detach().cpu().numpy() # CPUメモリに入れてnumpy化 results.extend(res.tolist()) # バッチ内のデータを結果に追加 # 最後の検証結果の、評価側の平均値を保存する with open('chapt03-normal.json', 'w') as f: test_result = results[:len(test_X)] # 実行結果の評価データ mean = np.mean(test_result, axis=0) # 平均値 std = np.std(test_result, axis=0, ddof=1) # 標準偏差 # 必要な情報をJSONにして保存 jsonobj = { 'mean':mean.astype(float).tolist(), 'std':std.astype(float).tolist() } f.write(json.dumps(jsonobj))
{"mean": [-1.8343112895477092, -0.922488931777048, -13.627072575536543, 15.296871670292377, 7.22925847714711, -10.513004684564706, -3.5175285682508517, 4.918352894614979], "std": [0.1685449808030565, 0.15452998731547973, 0.8660358608077123, 0.9035150665678513, 0.4539830573350091, 0.6456903330168292, 0.2434253724930038, 0.2838490809825809]}
if USE_VALIDATE: # 検証用データを使う場合 # 実行結果を散布図にして保存する results = np.array(results) # テストデータ+検証用データの結果 colors = ['pink'] * len(test_X) + ['blue'] * len(valid_X) # 色 plt.plot(figsize=(6,6)) # 8次元を2次元分ずつ散布図にする plt.subplot(221) plt.scatter(x=results[:,0], y=results[:,1], s=20, c=colors, alpha=0.5) plt.subplot(222) plt.scatter(x=results[:,2], y=results[:,3], s=20, c=colors, alpha=0.5) plt.subplot(223) plt.scatter(x=results[:,4], y=results[:,5], s=20, c=colors, alpha=0.5) plt.subplot(224) plt.scatter(x=results[:,6], y=results[:,7], s=20, c=colors, alpha=0.5) plt.savefig('scatter.png') # 画像として保存 plt.clf()
from google.colab import drive drive.mount('/content/drive')
処理に要した時間 |
---|
1時間25分54秒 |
import numpy as np import pandas as pd import itertools import shutil from PIL import Image import os import glob import matplotlib.pyplot as plt import json import torch from torch import nn, utils, optim from torchvision import transforms, models from torch.utils.data import DataLoader from torch.utils.data import Dataset from sklearn.metrics import f1_score, accuracy_score from sklearn.model_selection import train_test_split
# GPUを使うかどうか USE_DEVICE = 'cuda:0' if torch.cuda.is_available() else 'cpu' device = torch.device(USE_DEVICE) # データがあるディレクトリ INPUT_DIR = '/content/drive/MyDrive/data/forest-path-movie-dataset-main2/'
# 検証用データを使う USE_VALIDATE = True # 検証用データ VALIDATIONS = '/content/drive/MyDrive/data/unnormal-validations/*.png'
# PyTorchの内部を決定論的に設定する torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False # 乱数を初期化する np.random.seed(0) torch.manual_seed(0)
# データセットの定義ファイルを読み込む df = pd.read_csv(INPUT_DIR+'all_file2.csv') # シーン毎に分割するので、groupbyして取り出す file = [] for g in df.groupby(df.scene): file.append(g[1].file.values.tolist()) # シーン毎に学習用と評価用データに分ける train_X, test_X = [], [] for i in range(len(file)): trainX, testX = train_test_split(file[i], test_size=0.3, random_state=0) train_X.append(trainX) test_X.append(testX) # 全てのシーン内のデータを繋げた配列にする train_X = sum(train_X, []) test_X = sum(test_X, []) # ファイル名をディレクトリを含むものにする train_X = [INPUT_DIR+f for f in train_X] test_X = [INPUT_DIR+f for f in test_X]
if USE_VALIDATE: valid_X = glob.glob(VALIDATIONS) # 検証用データ一覧
class MyTransform: def __init__(self): self.data_transform = { 'train': transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.RandomErasing(p=1.0, scale=(0.3, 0.6), ratio=(0.5, 2.0), value='random'), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]), 'val': transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) } def __call__(self, img, phase='train'): return self.data_transform[phase](img)
# PyTorchの流儀でデータセットをクラスで定義する class MyDataset(Dataset): def __init__(self, X, transform, phase): # 初期化 Xはファイル名のリスト self.X = X self.transform = transform self.phase = phase def __len__(self): # データセットの長さを返す return len(self.X) def __getitem__(self, pos): # posの場所にあるデータを返す if self.phase == 'train': # 学習時には、Tripletを返す f1 = self.X[pos] # ベースとなるファイルのパス f2 = self.X[np.random.randint(len(self))] f3 = self.X[np.random.randint(len(self))] f1 = Image.open(f1) # ファイルを読み込む f2 = Image.open(f2) # ファイルを読み込む f3 = Image.open(f3) # ファイルを読み込む if np.random.random() < 0.5: # ランダムに、ペアを選ぶ X1 = self.transform(f1, phase='val') # ノーマルペア X2 = self.transform(f2, phase='val') # ノーマルペア X3 = self.transform(f3, phase='train') # 異常値 else: X1 = self.transform(f1, phase='train') # 異常値ペア X2 = self.transform(f2, phase='train') # 異常値ペア X3 = self.transform(f3, phase='val') # ノーマル return X1, X2, X3 else: # 検証時にはデータファイルのみを返す f1 = self.X[pos] # ファイルパス f1 = Image.open(f1) # ファイルを読み込む X1 = self.transform(f1, phase='val') # tensorにする return X1
# 保存しておいたモデルを読み込む model = models.resnet50(pretrained=False) model.fc = nn.Linear(2048, 2) model.load_state_dict(torch.load('/content/drive/MyDrive/data/chapt02-model1.pth')) # 出力の次元数を8次元にする model.fc = nn.Linear(2048, 8) model.to(device)
params = model.parameters() # モデル全体のトレーニング optimizer = optim.SGD(params, lr=5e-5, momentum=0.9) # 学習率を設定 loss = nn.TripletMarginLoss(margin=10.0) # 損失関数を用意する
# 学習時と評価時のバッチサイズ BATCH_SIZE = 16 BATCH_SIZE_VALID = 4 # 学習エポック数 NUM_EPOCHS = 3
# 学習用のデータセットを作る train_ds = MyDataset(train_X, transform=MyTransform(), phase='train') # 検証用データを使う場合 if USE_VALIDATE: test_ds = MyDataset(test_X + valid_X, transform=MyTransform(), phase='val') else: test_ds = MyDataset(test_X, transform=MyTransform(), phase='val') data_loader = DataLoader(train_ds, batch_size=BATCH_SIZE, shuffle=True) data_loader_v = DataLoader(test_ds, batch_size=BATCH_SIZE_VALID, shuffle=False)
import time time_start = time.perf_counter() # 学習ループ for epoch in range(NUM_EPOCHS): total_loss = [] # 各バッチ実行時の損失値 model.train() # モデルを学習用に設定する for X1, X2, X3 in data_loader: # 画像を読み込んでtensorにする X1 = X1.to(device) # GPUを使うときはGPUメモリ上に乗せる X2 = X2.to(device) # GPUを使うときはGPUメモリ上に乗せる X3 = X3.to(device) # GPUを使うときはGPUメモリ上に乗せる # ニューラルネットワークを実行して損失値を求める losses = loss(model(X1), model(X2), model(X3)) # 新しいバッチ分の学習を行う optimizer.zero_grad() # 一つ前の勾配をクリア losses.backward() # 損失値を逆伝播させる optimizer.step() # 新しい勾配からパラメーターを更新する # 損失値を保存しておく total_loss.append(losses.detach().cpu().numpy()) # エポック終了時のスコアを求める total_loss = np.mean(total_loss) # 各バッチの損失の平均 # エポック終了時のスコアを表示する print(f'epoch #{epoch}: train_loss:{total_loss}') # 終了時のモデルを保存する torch.save(model.state_dict(), '/content/drive/MyDrive/data/chapt03-model1.pth') time_end = time.perf_counter() time_process = time_end- time_start print(f'処理時間: {time_process} [s]')