はじめに
前回の続きで言語処理100本ノック解いていきたいと思います。
今回は第8章後半です。
前回から引き続きニューラルネットの実装にチャレンジしてます。
第8章: ニューラルネット
深層学習フレームワークの使い方を学び,ニューラルネットワークに基づくカテゴリ分類を実装します.
第6章で取り組んだニュース記事のカテゴリ分類を題材として,ニューラルネットワークでカテゴリ分類モデルを実装する.なお,この章ではPyTorch, TensorFlow, Chainerなどの機械学習プラットフォームを活用せよ.
問題70~76は前半のほうでやっています。
前半の変数等引き継いでます。
77. ミニバッチ化
問題76のコードを改変し,B事例ごとに損失・勾配を計算し,行列Wの値を更新せよ(ミニバッチ化).Bの値を1,2,4,8,…と変化させながら,1エポックの学習に要する時間を比較せよ.
データローダのバッチサイズの引数を変えるだけでミニバッチ化できるように作ってあるので簡単ですね。
学習用の関数内で時間を測る処理を加えておきます。
import time # 学習用の関数を定義 def train_model(net, dataloaders_dict, criterion, optimizer, num_epochs): train_loss = [] train_acc = [] valid_loss = [] valid_acc = [] # epochのループ for epoch in range(num_epochs): # 開始時刻の記録 start = time.time() print('Epoch {} / {}'.format(epoch + 1, num_epochs)) print('--------------------------------------------') # epochごとの学習と検証のループ for phase in ['train', 'val']: if phase == 'train': net.train() # 訓練モード else: net.eval() # 検証モード epoch_loss = 0.0 # epochの損失和 epoch_corrects = 0 # epochの正解数 # データローダーからミニバッチを取り出すループ for inputs, labels in tqdm(dataloaders_dict[phase]): optimizer.zero_grad() # optimizerを初期化 # 順伝播計算(forward) with torch.set_grad_enabled(phase == 'train'): outputs = net(inputs) loss = criterion(outputs, labels) # 損失を計算 _, preds = torch.max(outputs, 1) # ラベルを予想 # 訓練時は逆伝播 if phase == 'train': loss.backward() optimizer.step() # イテレーション結果の計算 # lossの合計を更新 epoch_loss += loss.item() * inputs.size(0) # 正解数の合計を更新 epoch_corrects += torch.sum(preds == labels.data) # epochごとのlossと正解率の表示 epoch_loss = epoch_loss / len(dataloaders_dict[phase].dataset) epoch_acc = epoch_corrects.double() / len(dataloaders_dict[phase].dataset) if phase == 'train': train_loss.append(epoch_loss) train_acc.append(epoch_acc) else: valid_loss.append(epoch_loss) valid_acc.append(epoch_acc) print('{} Loss: {:.4f}, Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc)) # 修了時刻の記録 end = time.time() calc_time = end - start print('batch_size {} calc_time: {:.4f} sec'.format(batch_size, calc_time)) return train_loss, train_acc, valid_loss, valid_acc, calc_time # 学習を実行する batch_sizes = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048] cpu_times = [] for batch_size in batch_sizes: print('batch_size: {}'.format(batch_size)) # DataLoaderを作成 train_dataloader = data.DataLoader( train_dataset, batch_size=batch_size, shuffle=True) valid_dataloader = data.DataLoader( valid_dataset, batch_size=len(valid_dataset), shuffle=False) test_dataloader = data.DataLoader( test_dataset, batch_size=len(test_dataset), shuffle=False) dataloaders_dict = {'train': train_dataloader, 'val': valid_dataloader, 'test': test_dataloader, } # モデルの定義 net = SLNet(300, 4) net.train() # 損失関数の定義 criterion = nn.CrossEntropyLoss() # 最適化手法の定義 optimizer = torch.optim.SGD(net.parameters(), lr=0.01, momentum=0.9) num_epochs = 1 train_loss, train_acc, valid_loss, valid_acc, calc_time = \ train_model(net, dataloaders_dict, criterion, optimizer, num_epochs=num_epochs) cpu_times.append(calc_time)
以下出力です。
batch_size: 1 Epoch 1 / 1 -------------------------------------------- 100%|██████████████████████████████████████████████████████████████████████████| 10672/10672 [00:03<00:00, 3022.37it/s] train Loss: 0.4164, Acc: 0.8588 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 99.74it/s] val Loss: 0.3099, Acc: 0.9025 batch_size 1 calc_time: 3.5450 sec batch_size: 2 Epoch 1 / 1 -------------------------------------------- 100%|████████████████████████████████████████████████████████████████████████████| 5336/5336 [00:02<00:00, 2278.40it/s] train Loss: 0.4742, Acc: 0.8438 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 62.50it/s] val Loss: 0.3447, Acc: 0.8936 batch_size 2 calc_time: 2.3640 sec batch_size: 4 Epoch 1 / 1 -------------------------------------------- 100%|████████████████████████████████████████████████████████████████████████████| 2668/2668 [00:01<00:00, 2203.14it/s] train Loss: 0.5576, Acc: 0.8087 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 83.34it/s] val Loss: 0.4072, Acc: 0.8718 batch_size 4 calc_time: 1.2290 sec batch_size: 8 Epoch 1 / 1 -------------------------------------------- 100%|████████████████████████████████████████████████████████████████████████████| 1334/1334 [00:00<00:00, 2194.08it/s] train Loss: 0.6572, Acc: 0.7843 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 111.10it/s] val Loss: 0.4944, Acc: 0.8441 batch_size 8 calc_time: 0.6220 sec batch_size: 16 Epoch 1 / 1 -------------------------------------------- 100%|██████████████████████████████████████████████████████████████████████████████| 667/667 [00:00<00:00, 1961.75it/s] train Loss: 0.7730, Acc: 0.7547 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 76.91it/s] val Loss: 0.5991, Acc: 0.7931 batch_size 16 calc_time: 0.3570 sec batch_size: 32 Epoch 1 / 1 -------------------------------------------- 100%|██████████████████████████████████████████████████████████████████████████████| 334/334 [00:00<00:00, 1525.13it/s] train Loss: 0.8799, Acc: 0.7579 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 83.33it/s] val Loss: 0.7069, Acc: 0.7849 batch_size 32 calc_time: 0.2360 sec batch_size: 64 Epoch 1 / 1 -------------------------------------------- 100%|██████████████████████████████████████████████████████████████████████████████| 167/167 [00:00<00:00, 1018.30it/s] train Loss: 0.9974, Acc: 0.7436 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 83.33it/s] val Loss: 0.8305, Acc: 0.7834 batch_size 64 calc_time: 0.1820 sec batch_size: 128 Epoch 1 / 1 -------------------------------------------- 100%|█████████████████████████████████████████████████████████████████████████████████| 84/84 [00:00<00:00, 595.76it/s] train Loss: 1.1072, Acc: 0.7258 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 83.34it/s] val Loss: 0.9553, Acc: 0.7826 batch_size 128 calc_time: 0.1610 sec batch_size: 256 Epoch 1 / 1 -------------------------------------------- 100%|█████████████████████████████████████████████████████████████████████████████████| 42/42 [00:00<00:00, 362.07it/s] train Loss: 1.2273, Acc: 0.5810 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 83.32it/s] val Loss: 1.0692, Acc: 0.7714 batch_size 256 calc_time: 0.1330 sec batch_size: 512 Epoch 1 / 1 -------------------------------------------- 100%|█████████████████████████████████████████████████████████████████████████████████| 21/21 [00:00<00:00, 253.01it/s] train Loss: 1.3051, Acc: 0.4915 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 90.91it/s] val Loss: 1.1971, Acc: 0.7076 batch_size 512 calc_time: 0.0990 sec batch_size: 1024 Epoch 1 / 1 -------------------------------------------- 100%|█████████████████████████████████████████████████████████████████████████████████| 11/11 [00:00<00:00, 146.67it/s] train Loss: 1.3788, Acc: 0.2822 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 111.11it/s] val Loss: 1.3110, Acc: 0.5600 batch_size 1024 calc_time: 0.0900 sec batch_size: 2048 Epoch 1 / 1 -------------------------------------------- 100%|████████████████████████████████████████████████████████████████████████████████████| 6/6 [00:00<00:00, 67.42it/s] train Loss: 1.4050, Acc: 0.1233 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 76.92it/s] val Loss: 1.3746, Acc: 0.4018 batch_size 2048 calc_time: 0.1070 sec
バッチサイズ大きくなればなるほどメモリは多く使うけど早く計算できるといった感じでしょうか?
78. GPU上での学習
問題77のコードを改変し,GPU上で学習を実行せよ.
学習用の関数をGPU対応に変更します。
# 学習用の関数を定義 def train_model(net, dataloaders_dict, criterion, optimizer, num_epochs): # 初期設定 # GPUが使えるか確認 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print("使用デバイス:", device) # ネットワークをgpuへ net.to(device) # ネットワークがある程度固定なら高速化させる torch.backends.cudnn.benchmark = True train_loss = [] train_acc = [] valid_loss = [] valid_acc = [] # epochのループ for epoch in range(num_epochs): # 開始時刻の記録 start = time.time() print('Epoch {} / {}'.format(epoch + 1, num_epochs)) print('--------------------------------------------') # epochごとの学習と検証のループ for phase in ['train', 'val']: if phase == 'train': net.train() # 訓練モード else: net.eval() # 検証モード epoch_loss = 0.0 # epochの損失和 epoch_corrects = 0 # epochの正解数 # データローダーからミニバッチを取り出すループ for inputs, labels in tqdm(dataloaders_dict[phase]): # GPUが使えるならGPUにおっくる inputs = inputs.to(device) labels = labels.to(device) optimizer.zero_grad() # optimizerを初期化 # 順伝播計算(forward) with torch.set_grad_enabled(phase == 'train'): outputs = net(inputs) loss = criterion(outputs, labels) # 損失を計算 _, preds = torch.max(outputs, 1) # ラベルを予想 # 訓練時は逆伝播 if phase == 'train': loss.backward() optimizer.step() # イテレーション結果の計算 # lossの合計を更新 epoch_loss += loss.item() * inputs.size(0) # 正解数の合計を更新 epoch_corrects += torch.sum(preds == labels.data) # epochごとのlossと正解率の表示 epoch_loss = epoch_loss / len(dataloaders_dict[phase].dataset) epoch_acc = epoch_corrects.double() / len(dataloaders_dict[phase].dataset) if phase == 'train': train_loss.append(epoch_loss) train_acc.append(epoch_acc) else: valid_loss.append(epoch_loss) valid_acc.append(epoch_acc) print('{} Loss: {:.4f}, Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc)) # 修了時刻の記録 end = time.time() calc_time = end - start print('batch_size {} calc_time: {:.4f} sec'.format(batch_size, calc_time)) return train_loss, train_acc, valid_loss, valid_acc, calc_time
出力は以下。
batch_size: 1 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|███████████████████████████████████████████████████████████████████████████| 10672/10672 [00:13<00:00, 819.16it/s] train Loss: 0.4165, Acc: 0.8594 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 110.79it/s] val Loss: 0.3130, Acc: 0.8966 batch_size 1 calc_time: 13.0489 sec batch_size: 2 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|████████████████████████████████████████████████████████████████████████████| 5336/5336 [00:04<00:00, 1236.44it/s] train Loss: 0.4785, Acc: 0.8397 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 125.03it/s] val Loss: 0.3481, Acc: 0.9003 batch_size 2 calc_time: 4.3276 sec batch_size: 4 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|████████████████████████████████████████████████████████████████████████████| 2668/2668 [00:02<00:00, 1233.47it/s] train Loss: 0.5596, Acc: 0.8135 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 125.02it/s] val Loss: 0.4078, Acc: 0.8718 batch_size 4 calc_time: 2.1750 sec batch_size: 8 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|████████████████████████████████████████████████████████████████████████████| 1334/1334 [00:01<00:00, 1188.95it/s] train Loss: 0.6587, Acc: 0.7796 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 125.02it/s] val Loss: 0.4937, Acc: 0.8403 batch_size 8 calc_time: 1.1340 sec batch_size: 16 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|██████████████████████████████████████████████████████████████████████████████| 667/667 [00:00<00:00, 1160.00it/s] train Loss: 0.7698, Acc: 0.7682 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 125.01it/s] val Loss: 0.5959, Acc: 0.7954 batch_size 16 calc_time: 0.5880 sec batch_size: 32 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|███████████████████████████████████████████████████████████████████████████████| 334/334 [00:00<00:00, 982.35it/s] train Loss: 0.8840, Acc: 0.7559 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 111.15it/s] val Loss: 0.7097, Acc: 0.7879 batch_size 32 calc_time: 0.3530 sec batch_size: 64 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|███████████████████████████████████████████████████████████████████████████████| 167/167 [00:00<00:00, 818.63it/s] train Loss: 1.0040, Acc: 0.7269 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 16.39it/s] val Loss: 0.8337, Acc: 0.7871 batch_size 64 calc_time: 0.2700 sec batch_size: 128 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|█████████████████████████████████████████████████████████████████████████████████| 84/84 [00:00<00:00, 651.11it/s] train Loss: 1.1024, Acc: 0.7233 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 124.99it/s] val Loss: 0.9509, Acc: 0.7781 batch_size 128 calc_time: 0.1410 sec batch_size: 256 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|█████████████████████████████████████████████████████████████████████████████████| 42/42 [00:00<00:00, 466.68it/s] train Loss: 1.1995, Acc: 0.6498 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 124.57it/s] val Loss: 1.0585, Acc: 0.7714 batch_size 256 calc_time: 0.1030 sec batch_size: 512 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|█████████████████████████████████████████████████████████████████████████████████| 21/21 [00:00<00:00, 295.79it/s] train Loss: 1.3066, Acc: 0.4277 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 111.12it/s] val Loss: 1.1904, Acc: 0.6184 batch_size 512 calc_time: 0.0840 sec batch_size: 1024 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|█████████████████████████████████████████████████████████████████████████████████| 11/11 [00:00<00:00, 161.77it/s] train Loss: 1.3539, Acc: 0.3698 100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 90.89it/s] val Loss: 1.2941, Acc: 0.6229 batch_size 1024 calc_time: 0.0840 sec batch_size: 2048 使用デバイス: cuda:0 Epoch 1 / 1 -------------------------------------------- 100%|████████████████████████████████████████████████████████████████████████████████████| 6/6 [00:00<00:00, 88.20it/s] train Loss: 1.3785, Acc: 0.3351 100%|███████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 142.89it/s] val Loss: 1.3489, Acc: 0.5330 batch_size 2048 calc_time: 0.0810 sec
バッチサイズが小さいときはCPUのほうが早いですが、ある程度のバッチサイズになってくるとgpuのほうが高速で学習が進んでおりますね。
GPUのほうが行列計算速度に分があるはずなので、バッチサイズが小さいときにはあまりその利点を生かせないんだと思います。
79. 多層ニューラルネットワーク
問題78のコードを改変し,バイアス項の導入や多層化など,ニューラルネットワークの形状を変更しながら,高性能なカテゴリ分類器を構築せよ.
層のサイズの設定とかよくわかりませんが、多層ニューラルネットモデル適当に作ってみます。
今回は入力層(サイズ300)、隠れ層(サイズ256)、出力層(サイズ4)の構成で行きます。
過学習を抑えるために適当にbatch normalizationの層を挟んでおきます。
まずはモデルの定義から行います。
class MLNet(nn.Module): def __init__(self, input_size, mid_size, output_size): super().__init__() self.layers = nn.Sequential( nn.Linear(input_size, mid_size), nn.BatchNorm1d(mid_size), nn.ReLU(), nn.Linear(mid_size, mid_size), nn.BatchNorm1d(mid_size), nn.ReLU(), nn.Linear(mid_size, output_size), ) def forward(self, x): logits = self.layers(x) return logits net = MLNet(300, 256, 4) print(net)
出力は以下。
MLNet( (layers): Sequential( (0): Linear(in_features=300, out_features=256, bias=True) (1): BatchNorm1d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (2): ReLU() (3): Linear(in_features=256, out_features=256, bias=True) (4): BatchNorm1d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (5): ReLU() (6): Linear(in_features=256, out_features=4, bias=True) ) )
学習用関数を定義して、学習していきます。
バッチサイズは2048とします。
# 学習用の関数を定義 def train_model(net, dataloaders_dict, criterion, optimizer, num_epochs): # 初期設定 # GPUが使えるか確認 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print("使用デバイス:", device) # ネットワークをgpuへ net.to(device) # ネットワークがある程度固定なら高速化させる torch.backends.cudnn.benchmark = False torch.backends.cudnn.deterministic = True train_loss = [] train_acc = [] valid_loss = [] valid_acc = [] scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, num_epochs, eta_min=1e-6, last_epoch=-1) # epochのループ for epoch in range(num_epochs): # epochごとの学習と検証のループ for phase in ['train', 'val']: if phase == 'train': net.train() # 訓練モード else: net.eval() # 検証モード epoch_loss = 0.0 # epochの損失和 epoch_corrects = 0 # epochの正解数 # データローダーからミニバッチを取り出すループ for inputs, labels in dataloaders_dict[phase]: # GPUが使えるならGPUにおっくる inputs = inputs.to(device) labels = labels.to(device) optimizer.zero_grad() # optimizerを初期化 # 順伝播計算(forward) with torch.set_grad_enabled(phase == 'train'): outputs = net(inputs) loss = criterion(outputs, labels) # 損失を計算 _, preds = torch.max(outputs, 1) # ラベルを予想 # 訓練時は逆伝播 if phase == 'train': loss.backward() optimizer.step() # イテレーション結果の計算 # lossの合計を更新 epoch_loss += loss.item() * inputs.size(0) # 正解数の合計を更新 epoch_corrects += torch.sum(preds == labels.data) # epochごとのlossと正解率の表示 epoch_loss = epoch_loss / len(dataloaders_dict[phase].dataset) epoch_acc = epoch_corrects.double() / len(dataloaders_dict[phase].dataset) if phase == 'train': train_loss.append(epoch_loss) train_acc.append(epoch_acc.cpu()) else: valid_loss.append(epoch_loss) valid_acc.append(epoch_acc.cpu()) print('Epoch {} / {} (train) Loss: {:.4f}, Acc: {:.4f}, (val) Loss: {:.4f}, Acc: {:.4f}'.format(epoch + 1, num_epochs, train_loss[-1], train_acc[-1], valid_loss[-1], valid_acc[-1])) scheduler.step() return train_loss, train_acc, valid_loss, valid_acc batch_size = 2048 num_epochs = 200 # DataLoaderを作成 train_dataloader = data.DataLoader( train_dataset, batch_size=batch_size, shuffle=True) valid_dataloader = data.DataLoader( valid_dataset, batch_size=len(valid_dataset), shuffle=False) test_dataloader = data.DataLoader( test_dataset, batch_size=len(test_dataset), shuffle=False) dataloaders_dict = {'train': train_dataloader, 'val': valid_dataloader, 'test': test_dataloader, } # モデルの定義 net = MLNet(300, 256, 4) net.train() # 損失関数の定義 criterion = nn.CrossEntropyLoss() # 最適化手法の定義 optimizer = torch.optim.Adam(net.parameters(), lr=0.0001) train_loss, train_acc, valid_loss, valid_acc = \ train_model(net, dataloaders_dict, criterion, optimizer, num_epochs=num_epochs)
出力は以下長いので途中省略。
使用デバイス: cuda:0 Epoch 1 / 200 (train) Loss: 1.3631, Acc: 0.3142, (val) Loss: 1.4112, Acc: 0.0697 Epoch 2 / 200 (train) Loss: 1.1337, Acc: 0.6022, (val) Loss: 1.3906, Acc: 0.1642 Epoch 3 / 200 (train) Loss: 0.9533, Acc: 0.7463, (val) Loss: 1.3463, Acc: 0.5397 Epoch 4 / 200 (train) Loss: 0.8177, Acc: 0.7941, (val) Loss: 1.2753, Acc: 0.6402 Epoch 5 / 200 (train) Loss: 0.7179, Acc: 0.8168, (val) Loss: 1.1769, Acc: 0.6957 Epoch 6 / 200 (train) Loss: 0.6449, Acc: 0.8293, (val) Loss: 1.0551, Acc: 0.7579 Epoch 7 / 200 (train) Loss: 0.5897, Acc: 0.8396, (val) Loss: 0.9165, Acc: 0.7939 Epoch 8 / 200 (train) Loss: 0.5472, Acc: 0.8471, (val) Loss: 0.7792, Acc: 0.8268 Epoch 9 / 200 (train) Loss: 0.5137, Acc: 0.8550, (val) Loss: 0.6590, Acc: 0.8493 Epoch 10 / 200 (train) Loss: 0.4856, Acc: 0.8641, (val) Loss: 0.5668, Acc: 0.8576 ... Epoch 196 / 200 (train) Loss: 0.0702, Acc: 0.9903, (val) Loss: 0.2397, Acc: 0.9205 Epoch 197 / 200 (train) Loss: 0.0703, Acc: 0.9898, (val) Loss: 0.2395, Acc: 0.9205 Epoch 198 / 200 (train) Loss: 0.0702, Acc: 0.9898, (val) Loss: 0.2398, Acc: 0.9190 Epoch 199 / 200 (train) Loss: 0.0701, Acc: 0.9899, (val) Loss: 0.2398, Acc: 0.9183 Epoch 200 / 200 (train) Loss: 0.0700, Acc: 0.9900, (val) Loss: 0.2398, Acc: 0.9190
最終的な正解率の出力及び、学習中のロス、精度をプロットしてみましょう。
def calc_acc(net, dataloader): device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") net.eval() corrects = 0 with torch.no_grad(): for inputs, labels in dataloader: inputs = inputs.to(device) labels = labels.to(device) outputs = net(inputs) _, preds = torch.max(outputs, 1) # ラベルを予想 corrects += torch.sum(preds == labels.data).cpu() return corrects / len(dataloader.dataset) acc_train = calc_acc(net, train_dataloader) acc_valid = calc_acc(net, valid_dataloader) acc_test = calc_acc(net, test_dataloader) print('学習データの正解率: {:.4f}'.format(acc_train)) print('検証データの正解率: {:.4f}'.format(acc_valid)) print('テストデータの正解率: {:.4f}'.format(acc_test)) fig, ax = plt.subplots(1,2, figsize=(10, 5)) epochs = np.arange(num_epochs) ax[0].plot(epochs, train_loss, label='train') ax[0].plot(epochs, valid_loss, label='valid') ax[0].set_title('loss') ax[0].set_xlabel('epoch') ax[0].set_ylabel('loss') ax[1].plot(epochs, train_acc, label='train') ax[1].plot(epochs, valid_acc, label='valid') ax[1].set_title('acc') ax[1].set_xlabel('epoch') ax[1].set_ylabel('acc') ax[0].legend(loc='best') ax[1].legend(loc='best') plt.tight_layout() plt.savefig('fig79.png') plt.show()
結果は以下の通り
単層の時に比べ1%ほど精度が上がりました!うれしいですね。
学習データの正解率: 0.9897 検証データの正解率: 0.9190 テストデータの正解率: 0.9033
おわりに
8章終わりです。
pytorch初めて使いましたが、以下の本が入門としても大変参考になりました。