1. 環境は、Window 10 Home (64bit) 上で行った。
2. Anaconda3 (64bit) – Spyder上で、動作確認を行った。
3. python の バージョンは、python 3.7.0 である。
4. pytorch の バージョンは、pytorch 0.4.1 である。
5. GPU は, NVIDIA社 の GeForce GTX 1050 である。
6. CPU は, Intel社 の Core(TM) i7-7700HQ である。
今回確認した内容は、現場で使える! PyTorch開発入門 深層学習モデルの作成とアプリケーションへの実装 (AI & TECHNOLOGY) の 4.3.1 転移学習(P.072 – P.082) である。
※1. プログラムの詳細は、書籍を参考(P.072 – P.082)にして下さい。
※2. 転移学習の前に, CNN の理解が怪しかったので, 復習した.
■転移学習(書籍の一部を抜粋・改変).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# -*- coding: utf-8 -*- # 1. library import. from __future__ import print_function import torch from torch import nn, optim from torch.utils.data import DataLoader from torchvision.datasets import ImageFolder from torchvision import transforms from tqdm import tqdm import time ~(略)~ # 3. make Dataset. train_imgs = ImageFolder( # ".spyder-py3\\taco_and_burrito\\train\\", # -> 以下のようなエラーが出力されたので, pathを修正. # FileNotFoundError: [WinError 3] 指定されたパスが見つかりません。: #'.spyder-py3\\taco_and_burrito\\train\\' "taco_and_burrito\\train\\", transform = transforms.Compose([ transforms.RandomCrop(224), transforms.ToTensor()]) ) ~(略)~ # https://github.com/andreh7/ecal-rechits-pytorch-training/blob/master/FlattenLayer.py class FlattenLayer(nn.Module): # a 'View' reshaping the input to dimension (minibatch, product of remaining dimensions) # typically to be used after a convolutional network and before the dense layers ### def __init__(self): ### super(FlattenLayer, self).__init__() def forward(self, x): # see e.g. https://github.com/pytorch/vision/blob/master/torchvision/models/alexnet.py#L44 # https://pytorch.org/docs/stable/tensors.html # the size -1 is inferred from other dimensions # print(x.size()) # torch.Size([1, 128, 24, 24]) return x.view(x.size(0), -1) def __repr__(self): return self.__class__.__name__ + " ()" # 定番のConvolutional Neural Networkをゼロから理解する. # https://deepage.net/deep_learning/2016/11/07/convolutional_neural_network.html # in: torch.Size([1, 3, 224, 224]) # out: torch.Size([1, 128, 24, 24]) conv_net = nn.Sequential( # 以下のように略記. # H: image height, W: image width # P: padding, KH: kernel height, KW: kernel weight # SH: stride height, SW: stride weight # in: dimension 3, out: dimension 32. # 220 = {(H)224 + 2 * (P)0 - (KH)5 / (SH)1} + 1 nn.Conv2d(3, 32, 5), # 110 = 220 / (KH)2 nn.MaxPool2d(2), nn.ReLU(), # in: dimension 32. nn.BatchNorm2d(32), # in: dimension 32, out: dimension 64. # 106 = {(H)110 + 2 * (P)0 - (KH)5 / (SH)1} + 1 nn.Conv2d(32, 64, 5), # 53 = 106 / (KH)2 nn.MaxPool2d(2), nn.ReLU(), # in: dimension 64. nn.BatchNorm2d(64), # in: dimension 64, out: dimension 128. # 49 = {(H)53 + 2 * (P)0 - (KH)5 / (SH)1} + 1 nn.Conv2d(64, 128, 5), # 24 = 49 / (KH)2 nn.MaxPool2d(2), nn.ReLU(), # in: dimension 128. nn.BatchNorm2d(128), # torch.Size([1, 128, 24, 24]) FlattenLayer() ) # 5. Finally, by convolution, check what kind of size it is. test_input = torch.ones(1, 3, 224, 224) # tensor: torch.Size([1, 3, 224, 224]) # 1 × (RGB)3 × (image height)224 × (image weight)224 print('-test_input---------------------------------------') print(test_input.size()) conv_output_size = conv_net(test_input).size()[-1] print('-conv_net-----------------------------------------') print(conv_net) print('-conv_output_size---------------------------------') print(conv_output_size) # 73728 = 1 * 128 * 24 * 24. ~(略)~ # 8. display processing time. end = time.time() print('--------------------------------------------------') print('Elapsed Time: ' + str(end - start) + "[sec]") |
※上記ソースについて, 下記のようなコメントの読み替えが必要です.
nn.Conv2d(3, 32, 5) … # 220 = {(H)224 + 2 * (P)0 – (KH)5} / (SH)1 + 1
nn.Conv2d(32, 64, 5) … # 106 = {(H)110 + 2 * (P)0 – (KH)5} / (SH)1 + 1
nn.Conv2d(64, 128, 5) … # 49 = {(H)53 + 2 * (P)0 – (KH)5} / (SH)1 + 1
■実行結果(epoch = 10).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
-test_input--------------------------------------- torch.Size([1, 3, 224, 224]) -conv_net----------------------------------------- Sequential( (0): Conv2d(3, 32, kernel_size=(5, 5), stride=(1, 1)) (1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (2): ReLU() (3): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (4): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1)) (5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (6): ReLU() (7): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (8): Conv2d(64, 128, kernel_size=(5, 5), stride=(1, 1)) (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (10): ReLU() (11): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (12): FlattenLayer () ) -conv_output_size--------------------------------- 73728 100%|██████████| 23/23 [00:05<00:00, 4.07it/s] 0 2.1239339912479576 0.5379213483146067 0.5166667103767395 100%|██████████| 23/23 [00:05<00:00, 4.06it/s] 1 2.9489047635685313 0.5912921348314607 0.6166666746139526 100%|██████████| 23/23 [00:05<00:00, 4.18it/s] 2 2.7068503390658987 0.6221910112359551 0.7000000476837158 100%|██████████| 23/23 [00:05<00:00, 4.26it/s] 3 3.0366936163468794 0.625 0.6166666746139526 100%|██████████| 23/23 [00:05<00:00, 5.11it/s] 4 2.7064651305025276 0.6165730337078652 0.6666666865348816 100%|██████████| 23/23 [00:05<00:00, 4.24it/s] 5 2.357206783511422 0.6573033707865169 0.6333333849906921 100%|██████████| 23/23 [00:05<00:00, 4.40it/s] 6 2.1463713212446733 0.6446629213483146 0.6666666865348816 100%|██████████| 23/23 [00:05<00:00, 4.37it/s] 7 1.9633805778893558 0.6741573033707865 0.6666666865348816 100%|██████████| 23/23 [00:05<00:00, 4.32it/s] 8 2.0187623500823975 0.6629213483146067 0.6666666865348816 100%|██████████| 23/23 [00:05<00:00, 4.35it/s] 9 1.9592277868227526 0.672752808988764 0.7500000596046448 -------------------------------------------------- Elapsed Time: 56.54160785675049[sec] |
■以上の実行結果から, 以下のことが分かった.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
① ImageFolderの使い方として, Spyderのホームフォルダである, [.spyder-py3]フォルダをトップとして, [.spyder-py3\\taco_and_burrito\\train\\]フォルダを指定すると, FileNotFoundError: [WinError 3] 指定されたパスが見つかりません。: のようなエラーが出力されたため, Spyderのホームフォルダ内 の [taco_and_burrito\\train\\]フォルダ を 指定する形に修正したところ, 動作確認出来た. ② 書籍上(P.82)出てくる FlattenLayer層 について, 実装が見当たらなかったので, 下記, 参照URL③ から, そのままソースを持ってくる対応を行った. ③ epoch = 10 における精度は, おおよそ 67% 程度と判明した. ④ view の 引数に, -1 が出てきたので, 参照URL②(# the size -1 is inferred from other dimensions の 説明があった) を 確認した. ⑤ CNN の 構造 が, 理解できてなかったので, 以下のように追跡し, 参照URL① の 計算式を使って, 説明を追加した. [入力値(test_input)] 画像: 1枚 × (RGBの)3種類 × (高)224px × (幅)224px -> torch.Size([1, 3, 224, 224]) [Convolution Layer(その1)] nn.Conv2d(3, 32, 5) … in(第一引数): dimension 3, out(第二引数): dimension 32 の 設定. -> 220 = {(H)224 + 2 * (P)0 - (KH)5} / (SH)1 + 1 ※画像: 1枚 × (RGBのチャンネル???)32種類 × (高)220px × (幅)220px に変換されるイメージ. [Pooling Layer(その1)] nn.MaxPool2d(2) … サイズが1/2となる. -> 110 = 220 / (KH)2 ※画像: 1枚 × (RGBのチャンネル???)32種類 × (高)110px × (幅)110px に変換されるイメージ. [Batch Normalization(その1)] nn.BatchNorm2d(32) … サイズは, 変わらない, [Convolution Layer(その1)] の out(第二引数): dimension 32 を 引数とするらしい. [Convolution Layer(その2)] nn.Conv2d(32, 64, 5) … in(第一引数): dimension 32, out(第二引数): dimension 64 の 設定. -> 106 = {(H)110 + 2 * (P)0 - (KH)5} / (SH)1 + 1 ※画像: 1枚 × (RGBのチャンネル???)64種類 × (高)106px × (幅)106px に変換されるイメージ. [Pooling Layer(その2)] nn.MaxPool2d(2) … サイズが1/2となる. -> 53 = 106 / (KH)2 ※画像: 1枚 × (RGBのチャンネル???)64種類 × (高)53px × (幅)53px に変換されるイメージ. [Batch Normalization(その2)] nn.BatchNorm2d(64) … サイズは, 変わらない, [Convolution Layer(その2)] の out(第二引数): dimension 64 を 引数とするらしい. [Convolution Layer(その3)] nn.Conv2d(64, 128, 5) … in(第一引数): dimension 64, out(第二引数): dimension 128 の 設定. -> 49 = {(H)53 + 2 * (P)0 - (KH)5} / (SH)1 + 1 ※画像: 1枚 × (RGBのチャンネル???)128種類 × (高)49px × (幅)49px に変換されるイメージ. [Pooling Layer(その3)] nn.MaxPool2d(2) … サイズが1/2となる. -> 24 = 49 / (KH)2 ※画像: 1枚 × (RGBのチャンネル???)128種類 × (高)24px × (幅)24px に変換されるイメージ. [Batch Normalization(その3)] nn.BatchNorm2d(128) … サイズは, 変わらない, [Convolution Layer(その3)] の out(第二引数): dimension 128 を 引数とするらしい. [Flatten Layer] FlattenLayer() … サイズは, torch.Size([1, 128, 24, 24]) から, torch.Size([1, 73728]) に変換される. ※画像: 1枚 × (情報量)73728個 に変換されるイメージ. [出力値(conv_output_size)] ※画像: (情報量)73728個 に変換されるイメージ. |
■参照サイト
【参照URL①】定番のConvolutional Neural Networkをゼロから理解する.
【参照URL②】torch.Tensor
【参照URL③】andreh7/ecal-rechits-pytorch-training
■参考書籍
現場で使える! PyTorch開発入門 深層学習モデルの作成とアプリケーションへの実装 (AI & TECHNOLOGY)