'Deep CARs:使用Pytorch學習框架實現遷移學習'

"
全文共13449字,預計學習時長26分鐘或更長
"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

Deep CARs:使用Pytorch學習框架實現遷移學習


什麼是遷移學習?


遷移學習是深度學習的一種方法,即為解決某個任務而開發的模型會被重複使用作為另一個任務的起點。例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。

大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。一些人使用的預訓練的模型有VGGNet、ResNet、DenseNet、谷歌的Inception等等。這些網絡大多是在ImageNet上訓練的。ImageNet是一個龐大的數據集,包含100多萬張標記圖像,種類達1000個。

在Pytorch學習框架中,基於ImageNet這個龐大的數據庫,很容易就能加載來自torchvision的預訓練網絡。這其中一些預訓練模型將會用來訓練這些的網絡。

"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

Deep CARs:使用Pytorch學習框架實現遷移學習


什麼是遷移學習?


遷移學習是深度學習的一種方法,即為解決某個任務而開發的模型會被重複使用作為另一個任務的起點。例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。

大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。一些人使用的預訓練的模型有VGGNet、ResNet、DenseNet、谷歌的Inception等等。這些網絡大多是在ImageNet上訓練的。ImageNet是一個龐大的數據集,包含100多萬張標記圖像,種類達1000個。

在Pytorch學習框架中,基於ImageNet這個龐大的數據庫,很容易就能加載來自torchvision的預訓練網絡。這其中一些預訓練模型將會用來訓練這些的網絡。

Deep CARs:使用Pytorch學習框架實現遷移學習


通過以下步驟在Google Colab之上建立模型


相關筆記:https://github.com/ivyclare/DeepCars---Transfer-Learning-With-Pytorch/blob/master/Ivy__Deep_Cars_Identifying_Car_Brands.ipynb


1. 加載數據並執行轉換

2. 構建和訓練模型

3. 用不可視數據測試模型

導入庫

這一步只是加載庫,確保GPU是打開的。由於將使用深層網絡的預訓練模型,所以對CPU進行訓練並不是個好的選擇,原因是需要它花費很長的時間。GPU與此同時執行線性代數計算,訓練速度會提高100倍。

如果沒有運行GPU,使用的是Colab工具的情況下,那就在電腦上點擊編輯 =>電腦設置。確保運行時間設為python3 並且低於硬件加速器的速度,選擇GPU。

接下來,檢測cuda(統一計算設備架構)是否可行。大多數深層學習框架使用CUDA在GPU上計算前後次數。

#importing libraries
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import torch
from torchvision import datasets,transforms,models
from torch import nn,optim
import torch.nn.functional as F
from torch.utils.data import *
import time
import json
import copy
import os
from PIL import Image
from collections import OrderedDict
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')


"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

Deep CARs:使用Pytorch學習框架實現遷移學習


什麼是遷移學習?


遷移學習是深度學習的一種方法,即為解決某個任務而開發的模型會被重複使用作為另一個任務的起點。例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。

大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。一些人使用的預訓練的模型有VGGNet、ResNet、DenseNet、谷歌的Inception等等。這些網絡大多是在ImageNet上訓練的。ImageNet是一個龐大的數據集,包含100多萬張標記圖像,種類達1000個。

在Pytorch學習框架中,基於ImageNet這個龐大的數據庫,很容易就能加載來自torchvision的預訓練網絡。這其中一些預訓練模型將會用來訓練這些的網絡。

Deep CARs:使用Pytorch學習框架實現遷移學習


通過以下步驟在Google Colab之上建立模型


相關筆記:https://github.com/ivyclare/DeepCars---Transfer-Learning-With-Pytorch/blob/master/Ivy__Deep_Cars_Identifying_Car_Brands.ipynb


1. 加載數據並執行轉換

2. 構建和訓練模型

3. 用不可視數據測試模型

導入庫

這一步只是加載庫,確保GPU是打開的。由於將使用深層網絡的預訓練模型,所以對CPU進行訓練並不是個好的選擇,原因是需要它花費很長的時間。GPU與此同時執行線性代數計算,訓練速度會提高100倍。

如果沒有運行GPU,使用的是Colab工具的情況下,那就在電腦上點擊編輯 =>電腦設置。確保運行時間設為python3 並且低於硬件加速器的速度,選擇GPU。

接下來,檢測cuda(統一計算設備架構)是否可行。大多數深層學習框架使用CUDA在GPU上計算前後次數。

#importing libraries
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import torch
from torchvision import datasets,transforms,models
from torch import nn,optim
import torch.nn.functional as F
from torch.utils.data import *
import time
import json
import copy
import os
from PIL import Image
from collections import OrderedDict
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')


Deep CARs:使用Pytorch學習框架實現遷移學習


1. 加載數據並執行轉換


1.1 下載數據集


現在導入了庫,從Kaggle中加載數據集:https://www.kaggle.com/c/virtual-hack/data。該數據集中包含196個汽車品牌。

"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

Deep CARs:使用Pytorch學習框架實現遷移學習


什麼是遷移學習?


遷移學習是深度學習的一種方法,即為解決某個任務而開發的模型會被重複使用作為另一個任務的起點。例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。

大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。一些人使用的預訓練的模型有VGGNet、ResNet、DenseNet、谷歌的Inception等等。這些網絡大多是在ImageNet上訓練的。ImageNet是一個龐大的數據集,包含100多萬張標記圖像,種類達1000個。

在Pytorch學習框架中,基於ImageNet這個龐大的數據庫,很容易就能加載來自torchvision的預訓練網絡。這其中一些預訓練模型將會用來訓練這些的網絡。

Deep CARs:使用Pytorch學習框架實現遷移學習


通過以下步驟在Google Colab之上建立模型


相關筆記:https://github.com/ivyclare/DeepCars---Transfer-Learning-With-Pytorch/blob/master/Ivy__Deep_Cars_Identifying_Car_Brands.ipynb


1. 加載數據並執行轉換

2. 構建和訓練模型

3. 用不可視數據測試模型

導入庫

這一步只是加載庫,確保GPU是打開的。由於將使用深層網絡的預訓練模型,所以對CPU進行訓練並不是個好的選擇,原因是需要它花費很長的時間。GPU與此同時執行線性代數計算,訓練速度會提高100倍。

如果沒有運行GPU,使用的是Colab工具的情況下,那就在電腦上點擊編輯 =>電腦設置。確保運行時間設為python3 並且低於硬件加速器的速度,選擇GPU。

接下來,檢測cuda(統一計算設備架構)是否可行。大多數深層學習框架使用CUDA在GPU上計算前後次數。

#importing libraries
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import torch
from torchvision import datasets,transforms,models
from torch import nn,optim
import torch.nn.functional as F
from torch.utils.data import *
import time
import json
import copy
import os
from PIL import Image
from collections import OrderedDict
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')


Deep CARs:使用Pytorch學習框架實現遷移學習


1. 加載數據並執行轉換


1.1 下載數據集


現在導入了庫,從Kaggle中加載數據集:https://www.kaggle.com/c/virtual-hack/data。該數據集中包含196個汽車品牌。

Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/@pixabay


此時,下載數據集並使用Pytorch dataloader加載。因為數據將直接下載到谷歌驅動器中,所以必須獲得授權訪問。

#Mounting google drive inorder to access data
from google.colab import drive
drive.mount('/content/drive')

運行此操作後,單擊出現的鏈接,登錄個人帳戶,單擊允許,然後將生成的文本複製粘貼到你的筆記本中。這篇文章(https://towardsdatascience.com/setting-up-kaggle-in-google-colab-ebb281b61463)將闡釋如何輕鬆獲取API(應用程序編程接口)的關鍵,下載數據集。


添加unzip \\*.zip來解壓下載的文件。相關代碼應該是這樣的:

# Downloading the data from Kaggle
!pip install kaggle
!mkdir .kaggle
import json
token = {"username":"yourusername","key":"184ee8bd3b41486d62e7eb9257bd812d4"}
with open('/content/.kaggle/kaggle.json', 'w') as file:
json.dump(token, file)
!chmod 600 /content/.kaggle/kaggle.json
!cp /content/.kaggle/kaggle.json ~/.kaggle/kaggle.json

!kaggle config set -n path -v{/content}
!kaggle competitions download -c virtual-hack -p /content
#Unzipping dowloaded files
!unzip \\*.zip


注意,有訓練和測試兩個目錄。稍後編程員將使用模型來預測測試集的值。與此同時,必須將訓練數據分為訓練和驗證兩部分。分解之前,需要先理解什麼是轉換,然後編寫轉換條目。

1.2 數據轉換

數據集下載完成後,對數據執行轉換操作。轉換是將數據從一種形式轉換成另一種形式。兩個主要的轉換將應用到圖像中:

· 數據擴張

在沒有收集新數據的情況下,這是一種增加用於訓練的數據集的多樣性和大小的策略。調整大小、裁剪、水平翻轉、填充甚至生成對抗網絡(GANs)等技術應用於數據集上的圖像,和“新”圖像的生成上。這樣做有兩個主要優勢:1.從有限數據中生成更多的數據;2.防止過度擬合。

然而,不要寄希望於在數據集中看到這些生成的圖像。它們只會在分批操作期間呈現,因此,即使訓練期間數據集中圖像數量沒有進行肉眼的增加,實際圖像在訓練期間也會有增加。

在模型中,應用了3種擴張策略:調整大小(隨機調整大小)、裁剪(隨機裁切)和水平翻轉(水平翻轉圖像)。

對於測試數據,並不執行隨機調整大小、隨機旋轉和隨機水平翻轉的轉換操作。相反,只是將測試圖像的規模調整到256×256,並裁剪出224×224的中心,以便能夠與預訓練模型一起使用。

· 數據規範化

數據擴張後,利用ImageNet中所有圖像的均值和標準差將目標圖像轉化為一個張量從而進行規範統一。通常,大型數據集本身的平均值和標準偏差是有用到的。如果給出的數據集不是太大,ImageNet中使用的數據集為:[0.485,0.456,0.406],[0.229,0.224,0.225]

# Tansform with data augmentation and normalization for training
# Just normalization for validation
data_transforms = {
'train': transforms.Compose([
transforms.RandomRotation(30),
transforms.RandomResizedCrop(224),
#transforms.RandomResizedCrop(299), #size for inception architecture
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'valid': transforms.Compose([
#transforms.Resize(256),
transforms.CenterCrop(224),
transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),

'test': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
#transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
]),
}


執行這些轉換後,利用Pytorch的ImageFolder來加載數據。但是需要先驗證數據,所以才需要將訓練集分成兩部分。只有1%的數據用於驗證,其餘則用於訓練。

#Loading in the dataset
train_dir = 'car_data/train'
test_dir = 'car_data/test'
label_dir = 'names.csv'
batch_size=32
dataset = datasets.ImageFolder(train_dir,transform=data_transforms['train'])
# splitting our data
valid_size = int(0.1 * len(dataset))
train_size = len(dataset) - valid_size
dataset_sizes = {'train': train_size, 'valid': valid_size}
# now we get our datasets
train_dataset, valid_dataset = torch.utils.data.random_split(dataset, [train_size, valid_size])
# Loading datasets into dataloader
dataloaders = {'train': DataLoader(train_dataset, batch_size = batch_size, shuffle = True),
'valid': DataLoader(valid_dataset, batch_size = batch_size, shuffle = False)}
print("Total Number of Samples: ",len(dataset))
print("Number of Samples in Train: ",len(train_dataset))
print("Number of Samples in Valid: ",len(valid_dataset))
print("Number of Classes: ",len(dataset.classes))
print(dataset.classes[0])


· 可視化標籤

將標籤可視化,瞭解文件結構。


"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

Deep CARs:使用Pytorch學習框架實現遷移學習


什麼是遷移學習?


遷移學習是深度學習的一種方法,即為解決某個任務而開發的模型會被重複使用作為另一個任務的起點。例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。

大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。一些人使用的預訓練的模型有VGGNet、ResNet、DenseNet、谷歌的Inception等等。這些網絡大多是在ImageNet上訓練的。ImageNet是一個龐大的數據集,包含100多萬張標記圖像,種類達1000個。

在Pytorch學習框架中,基於ImageNet這個龐大的數據庫,很容易就能加載來自torchvision的預訓練網絡。這其中一些預訓練模型將會用來訓練這些的網絡。

Deep CARs:使用Pytorch學習框架實現遷移學習


通過以下步驟在Google Colab之上建立模型


相關筆記:https://github.com/ivyclare/DeepCars---Transfer-Learning-With-Pytorch/blob/master/Ivy__Deep_Cars_Identifying_Car_Brands.ipynb


1. 加載數據並執行轉換

2. 構建和訓練模型

3. 用不可視數據測試模型

導入庫

這一步只是加載庫,確保GPU是打開的。由於將使用深層網絡的預訓練模型,所以對CPU進行訓練並不是個好的選擇,原因是需要它花費很長的時間。GPU與此同時執行線性代數計算,訓練速度會提高100倍。

如果沒有運行GPU,使用的是Colab工具的情況下,那就在電腦上點擊編輯 =>電腦設置。確保運行時間設為python3 並且低於硬件加速器的速度,選擇GPU。

接下來,檢測cuda(統一計算設備架構)是否可行。大多數深層學習框架使用CUDA在GPU上計算前後次數。

#importing libraries
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import torch
from torchvision import datasets,transforms,models
from torch import nn,optim
import torch.nn.functional as F
from torch.utils.data import *
import time
import json
import copy
import os
from PIL import Image
from collections import OrderedDict
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')


Deep CARs:使用Pytorch學習框架實現遷移學習


1. 加載數據並執行轉換


1.1 下載數據集


現在導入了庫,從Kaggle中加載數據集:https://www.kaggle.com/c/virtual-hack/data。該數據集中包含196個汽車品牌。

Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/@pixabay


此時,下載數據集並使用Pytorch dataloader加載。因為數據將直接下載到谷歌驅動器中,所以必須獲得授權訪問。

#Mounting google drive inorder to access data
from google.colab import drive
drive.mount('/content/drive')

運行此操作後,單擊出現的鏈接,登錄個人帳戶,單擊允許,然後將生成的文本複製粘貼到你的筆記本中。這篇文章(https://towardsdatascience.com/setting-up-kaggle-in-google-colab-ebb281b61463)將闡釋如何輕鬆獲取API(應用程序編程接口)的關鍵,下載數據集。


添加unzip \\*.zip來解壓下載的文件。相關代碼應該是這樣的:

# Downloading the data from Kaggle
!pip install kaggle
!mkdir .kaggle
import json
token = {"username":"yourusername","key":"184ee8bd3b41486d62e7eb9257bd812d4"}
with open('/content/.kaggle/kaggle.json', 'w') as file:
json.dump(token, file)
!chmod 600 /content/.kaggle/kaggle.json
!cp /content/.kaggle/kaggle.json ~/.kaggle/kaggle.json

!kaggle config set -n path -v{/content}
!kaggle competitions download -c virtual-hack -p /content
#Unzipping dowloaded files
!unzip \\*.zip


注意,有訓練和測試兩個目錄。稍後編程員將使用模型來預測測試集的值。與此同時,必須將訓練數據分為訓練和驗證兩部分。分解之前,需要先理解什麼是轉換,然後編寫轉換條目。

1.2 數據轉換

數據集下載完成後,對數據執行轉換操作。轉換是將數據從一種形式轉換成另一種形式。兩個主要的轉換將應用到圖像中:

· 數據擴張

在沒有收集新數據的情況下,這是一種增加用於訓練的數據集的多樣性和大小的策略。調整大小、裁剪、水平翻轉、填充甚至生成對抗網絡(GANs)等技術應用於數據集上的圖像,和“新”圖像的生成上。這樣做有兩個主要優勢:1.從有限數據中生成更多的數據;2.防止過度擬合。

然而,不要寄希望於在數據集中看到這些生成的圖像。它們只會在分批操作期間呈現,因此,即使訓練期間數據集中圖像數量沒有進行肉眼的增加,實際圖像在訓練期間也會有增加。

在模型中,應用了3種擴張策略:調整大小(隨機調整大小)、裁剪(隨機裁切)和水平翻轉(水平翻轉圖像)。

對於測試數據,並不執行隨機調整大小、隨機旋轉和隨機水平翻轉的轉換操作。相反,只是將測試圖像的規模調整到256×256,並裁剪出224×224的中心,以便能夠與預訓練模型一起使用。

· 數據規範化

數據擴張後,利用ImageNet中所有圖像的均值和標準差將目標圖像轉化為一個張量從而進行規範統一。通常,大型數據集本身的平均值和標準偏差是有用到的。如果給出的數據集不是太大,ImageNet中使用的數據集為:[0.485,0.456,0.406],[0.229,0.224,0.225]

# Tansform with data augmentation and normalization for training
# Just normalization for validation
data_transforms = {
'train': transforms.Compose([
transforms.RandomRotation(30),
transforms.RandomResizedCrop(224),
#transforms.RandomResizedCrop(299), #size for inception architecture
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'valid': transforms.Compose([
#transforms.Resize(256),
transforms.CenterCrop(224),
transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),

'test': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
#transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
]),
}


執行這些轉換後,利用Pytorch的ImageFolder來加載數據。但是需要先驗證數據,所以才需要將訓練集分成兩部分。只有1%的數據用於驗證,其餘則用於訓練。

#Loading in the dataset
train_dir = 'car_data/train'
test_dir = 'car_data/test'
label_dir = 'names.csv'
batch_size=32
dataset = datasets.ImageFolder(train_dir,transform=data_transforms['train'])
# splitting our data
valid_size = int(0.1 * len(dataset))
train_size = len(dataset) - valid_size
dataset_sizes = {'train': train_size, 'valid': valid_size}
# now we get our datasets
train_dataset, valid_dataset = torch.utils.data.random_split(dataset, [train_size, valid_size])
# Loading datasets into dataloader
dataloaders = {'train': DataLoader(train_dataset, batch_size = batch_size, shuffle = True),
'valid': DataLoader(valid_dataset, batch_size = batch_size, shuffle = False)}
print("Total Number of Samples: ",len(dataset))
print("Number of Samples in Train: ",len(train_dataset))
print("Number of Samples in Valid: ",len(valid_dataset))
print("Number of Classes: ",len(dataset.classes))
print(dataset.classes[0])


· 可視化標籤

將標籤可視化,瞭解文件結構。


Deep CARs:使用Pytorch學習框架實現遷移學習


以打印名稱csv輸出


汽車的名稱出現在0上面。因此,在讀取csv文件時,必須添加一個標題名稱以便得到正確的輸出結果。需要提醒的是,標籤是從0到195開始的(敲黑板)


"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

Deep CARs:使用Pytorch學習框架實現遷移學習


什麼是遷移學習?


遷移學習是深度學習的一種方法,即為解決某個任務而開發的模型會被重複使用作為另一個任務的起點。例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。

大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。一些人使用的預訓練的模型有VGGNet、ResNet、DenseNet、谷歌的Inception等等。這些網絡大多是在ImageNet上訓練的。ImageNet是一個龐大的數據集,包含100多萬張標記圖像,種類達1000個。

在Pytorch學習框架中,基於ImageNet這個龐大的數據庫,很容易就能加載來自torchvision的預訓練網絡。這其中一些預訓練模型將會用來訓練這些的網絡。

Deep CARs:使用Pytorch學習框架實現遷移學習


通過以下步驟在Google Colab之上建立模型


相關筆記:https://github.com/ivyclare/DeepCars---Transfer-Learning-With-Pytorch/blob/master/Ivy__Deep_Cars_Identifying_Car_Brands.ipynb


1. 加載數據並執行轉換

2. 構建和訓練模型

3. 用不可視數據測試模型

導入庫

這一步只是加載庫,確保GPU是打開的。由於將使用深層網絡的預訓練模型,所以對CPU進行訓練並不是個好的選擇,原因是需要它花費很長的時間。GPU與此同時執行線性代數計算,訓練速度會提高100倍。

如果沒有運行GPU,使用的是Colab工具的情況下,那就在電腦上點擊編輯 =>電腦設置。確保運行時間設為python3 並且低於硬件加速器的速度,選擇GPU。

接下來,檢測cuda(統一計算設備架構)是否可行。大多數深層學習框架使用CUDA在GPU上計算前後次數。

#importing libraries
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import torch
from torchvision import datasets,transforms,models
from torch import nn,optim
import torch.nn.functional as F
from torch.utils.data import *
import time
import json
import copy
import os
from PIL import Image
from collections import OrderedDict
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')


Deep CARs:使用Pytorch學習框架實現遷移學習


1. 加載數據並執行轉換


1.1 下載數據集


現在導入了庫,從Kaggle中加載數據集:https://www.kaggle.com/c/virtual-hack/data。該數據集中包含196個汽車品牌。

Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/@pixabay


此時,下載數據集並使用Pytorch dataloader加載。因為數據將直接下載到谷歌驅動器中,所以必須獲得授權訪問。

#Mounting google drive inorder to access data
from google.colab import drive
drive.mount('/content/drive')

運行此操作後,單擊出現的鏈接,登錄個人帳戶,單擊允許,然後將生成的文本複製粘貼到你的筆記本中。這篇文章(https://towardsdatascience.com/setting-up-kaggle-in-google-colab-ebb281b61463)將闡釋如何輕鬆獲取API(應用程序編程接口)的關鍵,下載數據集。


添加unzip \\*.zip來解壓下載的文件。相關代碼應該是這樣的:

# Downloading the data from Kaggle
!pip install kaggle
!mkdir .kaggle
import json
token = {"username":"yourusername","key":"184ee8bd3b41486d62e7eb9257bd812d4"}
with open('/content/.kaggle/kaggle.json', 'w') as file:
json.dump(token, file)
!chmod 600 /content/.kaggle/kaggle.json
!cp /content/.kaggle/kaggle.json ~/.kaggle/kaggle.json

!kaggle config set -n path -v{/content}
!kaggle competitions download -c virtual-hack -p /content
#Unzipping dowloaded files
!unzip \\*.zip


注意,有訓練和測試兩個目錄。稍後編程員將使用模型來預測測試集的值。與此同時,必須將訓練數據分為訓練和驗證兩部分。分解之前,需要先理解什麼是轉換,然後編寫轉換條目。

1.2 數據轉換

數據集下載完成後,對數據執行轉換操作。轉換是將數據從一種形式轉換成另一種形式。兩個主要的轉換將應用到圖像中:

· 數據擴張

在沒有收集新數據的情況下,這是一種增加用於訓練的數據集的多樣性和大小的策略。調整大小、裁剪、水平翻轉、填充甚至生成對抗網絡(GANs)等技術應用於數據集上的圖像,和“新”圖像的生成上。這樣做有兩個主要優勢:1.從有限數據中生成更多的數據;2.防止過度擬合。

然而,不要寄希望於在數據集中看到這些生成的圖像。它們只會在分批操作期間呈現,因此,即使訓練期間數據集中圖像數量沒有進行肉眼的增加,實際圖像在訓練期間也會有增加。

在模型中,應用了3種擴張策略:調整大小(隨機調整大小)、裁剪(隨機裁切)和水平翻轉(水平翻轉圖像)。

對於測試數據,並不執行隨機調整大小、隨機旋轉和隨機水平翻轉的轉換操作。相反,只是將測試圖像的規模調整到256×256,並裁剪出224×224的中心,以便能夠與預訓練模型一起使用。

· 數據規範化

數據擴張後,利用ImageNet中所有圖像的均值和標準差將目標圖像轉化為一個張量從而進行規範統一。通常,大型數據集本身的平均值和標準偏差是有用到的。如果給出的數據集不是太大,ImageNet中使用的數據集為:[0.485,0.456,0.406],[0.229,0.224,0.225]

# Tansform with data augmentation and normalization for training
# Just normalization for validation
data_transforms = {
'train': transforms.Compose([
transforms.RandomRotation(30),
transforms.RandomResizedCrop(224),
#transforms.RandomResizedCrop(299), #size for inception architecture
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'valid': transforms.Compose([
#transforms.Resize(256),
transforms.CenterCrop(224),
transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),

'test': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
#transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
]),
}


執行這些轉換後,利用Pytorch的ImageFolder來加載數據。但是需要先驗證數據,所以才需要將訓練集分成兩部分。只有1%的數據用於驗證,其餘則用於訓練。

#Loading in the dataset
train_dir = 'car_data/train'
test_dir = 'car_data/test'
label_dir = 'names.csv'
batch_size=32
dataset = datasets.ImageFolder(train_dir,transform=data_transforms['train'])
# splitting our data
valid_size = int(0.1 * len(dataset))
train_size = len(dataset) - valid_size
dataset_sizes = {'train': train_size, 'valid': valid_size}
# now we get our datasets
train_dataset, valid_dataset = torch.utils.data.random_split(dataset, [train_size, valid_size])
# Loading datasets into dataloader
dataloaders = {'train': DataLoader(train_dataset, batch_size = batch_size, shuffle = True),
'valid': DataLoader(valid_dataset, batch_size = batch_size, shuffle = False)}
print("Total Number of Samples: ",len(dataset))
print("Number of Samples in Train: ",len(train_dataset))
print("Number of Samples in Valid: ",len(valid_dataset))
print("Number of Classes: ",len(dataset.classes))
print(dataset.classes[0])


· 可視化標籤

將標籤可視化,瞭解文件結構。


Deep CARs:使用Pytorch學習框架實現遷移學習


以打印名稱csv輸出


汽車的名稱出現在0上面。因此,在讀取csv文件時,必須添加一個標題名稱以便得到正確的輸出結果。需要提醒的是,標籤是從0到195開始的(敲黑板)


Deep CARs:使用Pytorch學習框架實現遷移學習



1.3 可視化圖像

現在可以加載看到這些數據。使用imshow()(來自挑戰課程)的方法來顯示圖像。

## Method to display Image for Tensor
def imshow(image, ax=None, title=None, normalize=True):
"""Imshow for Tensor."""
if ax is None:
fig, ax = plt.subplots()
image = image.numpy().transpose((1, 2, 0))
if normalize:
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = std * image + mean
image = np.clip(image, 0, 1)
ax.imshow(image)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.tick_params(axis='both', length=0)
ax.set_xticklabels('')
ax.set_yticklabels('')
return ax
print(" Sizes of Datasets: ", len(valid_dataset), len(train_dataset))
# Displaying Training Images
images, labels = next(iter(dataloaders['train']))
fig, axes = plt.subplots(figsize=(16,5), ncols=5)
for ii in range(5):
ax = axes[ii]
#ax.set_title(label_map[class_names[labels[ii].item()]])
imshow(images[ii], ax=ax, normalize=True)


訓練集裡的圖像看起來如下圖所見。能發現其中一些圖像是已經發生了翻轉或旋轉的變化。


"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

Deep CARs:使用Pytorch學習框架實現遷移學習


什麼是遷移學習?


遷移學習是深度學習的一種方法,即為解決某個任務而開發的模型會被重複使用作為另一個任務的起點。例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。

大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。一些人使用的預訓練的模型有VGGNet、ResNet、DenseNet、谷歌的Inception等等。這些網絡大多是在ImageNet上訓練的。ImageNet是一個龐大的數據集,包含100多萬張標記圖像,種類達1000個。

在Pytorch學習框架中,基於ImageNet這個龐大的數據庫,很容易就能加載來自torchvision的預訓練網絡。這其中一些預訓練模型將會用來訓練這些的網絡。

Deep CARs:使用Pytorch學習框架實現遷移學習


通過以下步驟在Google Colab之上建立模型


相關筆記:https://github.com/ivyclare/DeepCars---Transfer-Learning-With-Pytorch/blob/master/Ivy__Deep_Cars_Identifying_Car_Brands.ipynb


1. 加載數據並執行轉換

2. 構建和訓練模型

3. 用不可視數據測試模型

導入庫

這一步只是加載庫,確保GPU是打開的。由於將使用深層網絡的預訓練模型,所以對CPU進行訓練並不是個好的選擇,原因是需要它花費很長的時間。GPU與此同時執行線性代數計算,訓練速度會提高100倍。

如果沒有運行GPU,使用的是Colab工具的情況下,那就在電腦上點擊編輯 =>電腦設置。確保運行時間設為python3 並且低於硬件加速器的速度,選擇GPU。

接下來,檢測cuda(統一計算設備架構)是否可行。大多數深層學習框架使用CUDA在GPU上計算前後次數。

#importing libraries
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import torch
from torchvision import datasets,transforms,models
from torch import nn,optim
import torch.nn.functional as F
from torch.utils.data import *
import time
import json
import copy
import os
from PIL import Image
from collections import OrderedDict
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')


Deep CARs:使用Pytorch學習框架實現遷移學習


1. 加載數據並執行轉換


1.1 下載數據集


現在導入了庫,從Kaggle中加載數據集:https://www.kaggle.com/c/virtual-hack/data。該數據集中包含196個汽車品牌。

Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/@pixabay


此時,下載數據集並使用Pytorch dataloader加載。因為數據將直接下載到谷歌驅動器中,所以必須獲得授權訪問。

#Mounting google drive inorder to access data
from google.colab import drive
drive.mount('/content/drive')

運行此操作後,單擊出現的鏈接,登錄個人帳戶,單擊允許,然後將生成的文本複製粘貼到你的筆記本中。這篇文章(https://towardsdatascience.com/setting-up-kaggle-in-google-colab-ebb281b61463)將闡釋如何輕鬆獲取API(應用程序編程接口)的關鍵,下載數據集。


添加unzip \\*.zip來解壓下載的文件。相關代碼應該是這樣的:

# Downloading the data from Kaggle
!pip install kaggle
!mkdir .kaggle
import json
token = {"username":"yourusername","key":"184ee8bd3b41486d62e7eb9257bd812d4"}
with open('/content/.kaggle/kaggle.json', 'w') as file:
json.dump(token, file)
!chmod 600 /content/.kaggle/kaggle.json
!cp /content/.kaggle/kaggle.json ~/.kaggle/kaggle.json

!kaggle config set -n path -v{/content}
!kaggle competitions download -c virtual-hack -p /content
#Unzipping dowloaded files
!unzip \\*.zip


注意,有訓練和測試兩個目錄。稍後編程員將使用模型來預測測試集的值。與此同時,必須將訓練數據分為訓練和驗證兩部分。分解之前,需要先理解什麼是轉換,然後編寫轉換條目。

1.2 數據轉換

數據集下載完成後,對數據執行轉換操作。轉換是將數據從一種形式轉換成另一種形式。兩個主要的轉換將應用到圖像中:

· 數據擴張

在沒有收集新數據的情況下,這是一種增加用於訓練的數據集的多樣性和大小的策略。調整大小、裁剪、水平翻轉、填充甚至生成對抗網絡(GANs)等技術應用於數據集上的圖像,和“新”圖像的生成上。這樣做有兩個主要優勢:1.從有限數據中生成更多的數據;2.防止過度擬合。

然而,不要寄希望於在數據集中看到這些生成的圖像。它們只會在分批操作期間呈現,因此,即使訓練期間數據集中圖像數量沒有進行肉眼的增加,實際圖像在訓練期間也會有增加。

在模型中,應用了3種擴張策略:調整大小(隨機調整大小)、裁剪(隨機裁切)和水平翻轉(水平翻轉圖像)。

對於測試數據,並不執行隨機調整大小、隨機旋轉和隨機水平翻轉的轉換操作。相反,只是將測試圖像的規模調整到256×256,並裁剪出224×224的中心,以便能夠與預訓練模型一起使用。

· 數據規範化

數據擴張後,利用ImageNet中所有圖像的均值和標準差將目標圖像轉化為一個張量從而進行規範統一。通常,大型數據集本身的平均值和標準偏差是有用到的。如果給出的數據集不是太大,ImageNet中使用的數據集為:[0.485,0.456,0.406],[0.229,0.224,0.225]

# Tansform with data augmentation and normalization for training
# Just normalization for validation
data_transforms = {
'train': transforms.Compose([
transforms.RandomRotation(30),
transforms.RandomResizedCrop(224),
#transforms.RandomResizedCrop(299), #size for inception architecture
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'valid': transforms.Compose([
#transforms.Resize(256),
transforms.CenterCrop(224),
transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),

'test': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
#transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
]),
}


執行這些轉換後,利用Pytorch的ImageFolder來加載數據。但是需要先驗證數據,所以才需要將訓練集分成兩部分。只有1%的數據用於驗證,其餘則用於訓練。

#Loading in the dataset
train_dir = 'car_data/train'
test_dir = 'car_data/test'
label_dir = 'names.csv'
batch_size=32
dataset = datasets.ImageFolder(train_dir,transform=data_transforms['train'])
# splitting our data
valid_size = int(0.1 * len(dataset))
train_size = len(dataset) - valid_size
dataset_sizes = {'train': train_size, 'valid': valid_size}
# now we get our datasets
train_dataset, valid_dataset = torch.utils.data.random_split(dataset, [train_size, valid_size])
# Loading datasets into dataloader
dataloaders = {'train': DataLoader(train_dataset, batch_size = batch_size, shuffle = True),
'valid': DataLoader(valid_dataset, batch_size = batch_size, shuffle = False)}
print("Total Number of Samples: ",len(dataset))
print("Number of Samples in Train: ",len(train_dataset))
print("Number of Samples in Valid: ",len(valid_dataset))
print("Number of Classes: ",len(dataset.classes))
print(dataset.classes[0])


· 可視化標籤

將標籤可視化,瞭解文件結構。


Deep CARs:使用Pytorch學習框架實現遷移學習


以打印名稱csv輸出


汽車的名稱出現在0上面。因此,在讀取csv文件時,必須添加一個標題名稱以便得到正確的輸出結果。需要提醒的是,標籤是從0到195開始的(敲黑板)


Deep CARs:使用Pytorch學習框架實現遷移學習



1.3 可視化圖像

現在可以加載看到這些數據。使用imshow()(來自挑戰課程)的方法來顯示圖像。

## Method to display Image for Tensor
def imshow(image, ax=None, title=None, normalize=True):
"""Imshow for Tensor."""
if ax is None:
fig, ax = plt.subplots()
image = image.numpy().transpose((1, 2, 0))
if normalize:
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = std * image + mean
image = np.clip(image, 0, 1)
ax.imshow(image)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.tick_params(axis='both', length=0)
ax.set_xticklabels('')
ax.set_yticklabels('')
return ax
print(" Sizes of Datasets: ", len(valid_dataset), len(train_dataset))
# Displaying Training Images
images, labels = next(iter(dataloaders['train']))
fig, axes = plt.subplots(figsize=(16,5), ncols=5)
for ii in range(5):
ax = axes[ii]
#ax.set_title(label_map[class_names[labels[ii].item()]])
imshow(images[ii], ax=ax, normalize=True)


訓練集裡的圖像看起來如下圖所見。能發現其中一些圖像是已經發生了翻轉或旋轉的變化。


Deep CARs:使用Pytorch學習框架實現遷移學習


轉換後的訓練集圖像



"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

Deep CARs:使用Pytorch學習框架實現遷移學習


什麼是遷移學習?


遷移學習是深度學習的一種方法,即為解決某個任務而開發的模型會被重複使用作為另一個任務的起點。例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。

大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。一些人使用的預訓練的模型有VGGNet、ResNet、DenseNet、谷歌的Inception等等。這些網絡大多是在ImageNet上訓練的。ImageNet是一個龐大的數據集,包含100多萬張標記圖像,種類達1000個。

在Pytorch學習框架中,基於ImageNet這個龐大的數據庫,很容易就能加載來自torchvision的預訓練網絡。這其中一些預訓練模型將會用來訓練這些的網絡。

Deep CARs:使用Pytorch學習框架實現遷移學習


通過以下步驟在Google Colab之上建立模型


相關筆記:https://github.com/ivyclare/DeepCars---Transfer-Learning-With-Pytorch/blob/master/Ivy__Deep_Cars_Identifying_Car_Brands.ipynb


1. 加載數據並執行轉換

2. 構建和訓練模型

3. 用不可視數據測試模型

導入庫

這一步只是加載庫,確保GPU是打開的。由於將使用深層網絡的預訓練模型,所以對CPU進行訓練並不是個好的選擇,原因是需要它花費很長的時間。GPU與此同時執行線性代數計算,訓練速度會提高100倍。

如果沒有運行GPU,使用的是Colab工具的情況下,那就在電腦上點擊編輯 =>電腦設置。確保運行時間設為python3 並且低於硬件加速器的速度,選擇GPU。

接下來,檢測cuda(統一計算設備架構)是否可行。大多數深層學習框架使用CUDA在GPU上計算前後次數。

#importing libraries
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import torch
from torchvision import datasets,transforms,models
from torch import nn,optim
import torch.nn.functional as F
from torch.utils.data import *
import time
import json
import copy
import os
from PIL import Image
from collections import OrderedDict
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')


Deep CARs:使用Pytorch學習框架實現遷移學習


1. 加載數據並執行轉換


1.1 下載數據集


現在導入了庫,從Kaggle中加載數據集:https://www.kaggle.com/c/virtual-hack/data。該數據集中包含196個汽車品牌。

Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/@pixabay


此時,下載數據集並使用Pytorch dataloader加載。因為數據將直接下載到谷歌驅動器中,所以必須獲得授權訪問。

#Mounting google drive inorder to access data
from google.colab import drive
drive.mount('/content/drive')

運行此操作後,單擊出現的鏈接,登錄個人帳戶,單擊允許,然後將生成的文本複製粘貼到你的筆記本中。這篇文章(https://towardsdatascience.com/setting-up-kaggle-in-google-colab-ebb281b61463)將闡釋如何輕鬆獲取API(應用程序編程接口)的關鍵,下載數據集。


添加unzip \\*.zip來解壓下載的文件。相關代碼應該是這樣的:

# Downloading the data from Kaggle
!pip install kaggle
!mkdir .kaggle
import json
token = {"username":"yourusername","key":"184ee8bd3b41486d62e7eb9257bd812d4"}
with open('/content/.kaggle/kaggle.json', 'w') as file:
json.dump(token, file)
!chmod 600 /content/.kaggle/kaggle.json
!cp /content/.kaggle/kaggle.json ~/.kaggle/kaggle.json

!kaggle config set -n path -v{/content}
!kaggle competitions download -c virtual-hack -p /content
#Unzipping dowloaded files
!unzip \\*.zip


注意,有訓練和測試兩個目錄。稍後編程員將使用模型來預測測試集的值。與此同時,必須將訓練數據分為訓練和驗證兩部分。分解之前,需要先理解什麼是轉換,然後編寫轉換條目。

1.2 數據轉換

數據集下載完成後,對數據執行轉換操作。轉換是將數據從一種形式轉換成另一種形式。兩個主要的轉換將應用到圖像中:

· 數據擴張

在沒有收集新數據的情況下,這是一種增加用於訓練的數據集的多樣性和大小的策略。調整大小、裁剪、水平翻轉、填充甚至生成對抗網絡(GANs)等技術應用於數據集上的圖像,和“新”圖像的生成上。這樣做有兩個主要優勢:1.從有限數據中生成更多的數據;2.防止過度擬合。

然而,不要寄希望於在數據集中看到這些生成的圖像。它們只會在分批操作期間呈現,因此,即使訓練期間數據集中圖像數量沒有進行肉眼的增加,實際圖像在訓練期間也會有增加。

在模型中,應用了3種擴張策略:調整大小(隨機調整大小)、裁剪(隨機裁切)和水平翻轉(水平翻轉圖像)。

對於測試數據,並不執行隨機調整大小、隨機旋轉和隨機水平翻轉的轉換操作。相反,只是將測試圖像的規模調整到256×256,並裁剪出224×224的中心,以便能夠與預訓練模型一起使用。

· 數據規範化

數據擴張後,利用ImageNet中所有圖像的均值和標準差將目標圖像轉化為一個張量從而進行規範統一。通常,大型數據集本身的平均值和標準偏差是有用到的。如果給出的數據集不是太大,ImageNet中使用的數據集為:[0.485,0.456,0.406],[0.229,0.224,0.225]

# Tansform with data augmentation and normalization for training
# Just normalization for validation
data_transforms = {
'train': transforms.Compose([
transforms.RandomRotation(30),
transforms.RandomResizedCrop(224),
#transforms.RandomResizedCrop(299), #size for inception architecture
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'valid': transforms.Compose([
#transforms.Resize(256),
transforms.CenterCrop(224),
transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),

'test': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
#transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
]),
}


執行這些轉換後,利用Pytorch的ImageFolder來加載數據。但是需要先驗證數據,所以才需要將訓練集分成兩部分。只有1%的數據用於驗證,其餘則用於訓練。

#Loading in the dataset
train_dir = 'car_data/train'
test_dir = 'car_data/test'
label_dir = 'names.csv'
batch_size=32
dataset = datasets.ImageFolder(train_dir,transform=data_transforms['train'])
# splitting our data
valid_size = int(0.1 * len(dataset))
train_size = len(dataset) - valid_size
dataset_sizes = {'train': train_size, 'valid': valid_size}
# now we get our datasets
train_dataset, valid_dataset = torch.utils.data.random_split(dataset, [train_size, valid_size])
# Loading datasets into dataloader
dataloaders = {'train': DataLoader(train_dataset, batch_size = batch_size, shuffle = True),
'valid': DataLoader(valid_dataset, batch_size = batch_size, shuffle = False)}
print("Total Number of Samples: ",len(dataset))
print("Number of Samples in Train: ",len(train_dataset))
print("Number of Samples in Valid: ",len(valid_dataset))
print("Number of Classes: ",len(dataset.classes))
print(dataset.classes[0])


· 可視化標籤

將標籤可視化,瞭解文件結構。


Deep CARs:使用Pytorch學習框架實現遷移學習


以打印名稱csv輸出


汽車的名稱出現在0上面。因此,在讀取csv文件時,必須添加一個標題名稱以便得到正確的輸出結果。需要提醒的是,標籤是從0到195開始的(敲黑板)


Deep CARs:使用Pytorch學習框架實現遷移學習



1.3 可視化圖像

現在可以加載看到這些數據。使用imshow()(來自挑戰課程)的方法來顯示圖像。

## Method to display Image for Tensor
def imshow(image, ax=None, title=None, normalize=True):
"""Imshow for Tensor."""
if ax is None:
fig, ax = plt.subplots()
image = image.numpy().transpose((1, 2, 0))
if normalize:
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = std * image + mean
image = np.clip(image, 0, 1)
ax.imshow(image)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.tick_params(axis='both', length=0)
ax.set_xticklabels('')
ax.set_yticklabels('')
return ax
print(" Sizes of Datasets: ", len(valid_dataset), len(train_dataset))
# Displaying Training Images
images, labels = next(iter(dataloaders['train']))
fig, axes = plt.subplots(figsize=(16,5), ncols=5)
for ii in range(5):
ax = axes[ii]
#ax.set_title(label_map[class_names[labels[ii].item()]])
imshow(images[ii], ax=ax, normalize=True)


訓練集裡的圖像看起來如下圖所見。能發現其中一些圖像是已經發生了翻轉或旋轉的變化。


Deep CARs:使用Pytorch學習框架實現遷移學習


轉換後的訓練集圖像



Deep CARs:使用Pytorch學習框架實現遷移學習


2. 構建和訓練模型

綜上所述,將使用基於ImageNet的預訓練模型。

構建和訓練將採取的步驟如下:

2.1 加載預訓練模型

接下來將嘗試不同的架構比如densenet161、inceptionv3、resnet121和vggnet。在這一階段,需要加載不同的模型,指定模型完全連接層中輸入要素的數量,因為構建自定義分類器時需要這一前提。

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model_name = 'resnet' #vgg
# Densenet
if model_name == 'densenet':
model = models.densenet161(pretrained=True)
num_in_features = 2208
print(model)
# VGGNet
elif model_name == 'vgg':
model = models.vgg19(pretrained=True)
num_in_features = 25088
print(model.classifier)
# Resnet
elif model_name == 'resnet':
model = models.resnet152(pretrained=True)
#model = models.resnet34(pretrained=True)
num_in_features = 2048 #512
print(model.fc)
# Inception
elif model_name == 'inception':
model = models.inception_v3(pretrained=True)
model.aux_logits=False
num_in_features = 2048
print(model.fc)
else:
print("Unknown model, please choose 'densenet' or 'vgg'")


2.2 凍結參數,創建自定義分類器

由於預訓練模型中的大多數參數都已經過訓練,所以筆者並不傾向於這些數據。於是會為早期卷積層保留預訓練的權重(這裡的目的為特徵提取)。所以,將requires_grad字段重置為錯誤。

在這之後,替換掉完全連接的網絡,該網絡與預訓練的神經元擁有相同的輸入、自定義隱藏層和輸出內容。build_classifer方法是靈活的,當網絡中不需要隱藏層或者當需要多個隱藏層時,它就會起作用。同時也定義了激活函數(在本例中是relu)和dropout層。

# Freezing parameters
for param in model.parameters():
param.require_grad = False

# Create Custom Classifier
def build_classifier(num_in_features, hidden_layers, num_out_features):
classifier = nn.Sequential()
# when we don't have any hidden layers
if hidden_layers == None:
classifier.add_module('fc0', nn.Linear(num_in_features, 196))
#when we have hidden layers
else:
layer_sizes = zip(hidden_layers[:-1], hidden_layers[1:])
classifier.add_module('fc0', nn.Linear(num_in_features, hidden_layers[0]))
classifier.add_module('relu0', nn.ReLU())
classifier.add_module('drop0', nn.Dropout(.6))

for i, (h1, h2) in enumerate(layer_sizes):
classifier.add_module('fc'+str(i+1), nn.Linear(h1, h2))
classifier.add_module('relu'+str(i+1), nn.ReLU())
classifier.add_module('drop'+str(i+1), nn.Dropout(.5))
classifier.add_module('output', nn.Linear(hidden_layers[-1], num_out_features))

return classifier


現在指定超參數和隱藏層。

#define our hidden layers
hidden_layers = None #[1050,500]
classifier = build_classifier(num_in_features, hidden_layers, 196)
print(classifier)
# Defining model hyperparameters
if model_name == 'densenet':
model.classifier = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adadelta(model.parameters()) # Adadelta #weight optim.Adam(model.parameters(), lr=0.001, momentum=0.9)
# Decay Learning Rate by a factor of 0.1 every 4 epochs
sched = optim.lr_scheduler.StepLR(optimizer, step_size=4)
elif model_name == 'vgg':
model.classifier = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.classifier.parameters(), lr=0.0001)
sched = optim.lr_scheduler.StepLR(optimizer, step_size=4, gamma=0.1)
elif model_name == 'resnet':
model.fc = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
sched = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', patience=3, threshold = 0.9)
elif model_name == 'inception':
model.fc = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001,momentum=0.9)
else:
pass


然後指定標準,指定不同的優化器,如Adam, Adadelta, SGD等,包含學習率和動量。對不同的預訓練網絡使用這些超參數,選擇那些有用的超參數。針對resnet和vggnet使用兩種不同的調度程序。具體做法如下:

torch.optim.lr_scheduler提供了幾種依據epoch數量調整學習率的方法。

torch.optim.lr_scheduler.ReduceLROnPlateau(https://pytorch.org/docs/stable/optim.html#torch.optim.lr_scheduler.ReduceLROnPlateau) 允許基於一些驗證測量的動態學習率降低。詳情:https://pytorch.org/docs/stable/optim.html。


2.3 訓練與驗證

為了PyTorch訓練模型,通常會在每個epoch迭代時對其執行以下操作:

· 在網絡中使用前向(傳播)進行前向傳播

· 使用標準函數中的網絡輸出計算損耗

· 使用loss.backwards()對網絡執行反向傳播來計算梯度

· 利用優化器更新權重optimizer. step()

optimizer.zero_grad()用於歸零累積梯度

早停法技術是用於防止過度擬合的。驗證數據集上的性能開始下降時,該法可中止訓練。當在訓練過程中獲得最佳精度時,它會保存模型(檢查點)。這樣的話,如果因斷電或某原因中斷訓練,檢查點仍可恢復,訓練還可以繼續進行。

該模型改編自 PyTorch Website:https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html


# Training 
def train_model(model, criterion, optimizer, sched, num_epochs=5,device='cuda'):
start = time.time()
train_results = []
valid_results = []
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
for epoch in range(num_epochs):
print('Epoch {}/{}'.format(epoch+1, num_epochs))
print('-' * 10)
# Each epoch has a training and validation phase
for phase in ['train', 'valid']:
if phase == 'train':
model.train() # Set model to training mode
else:
model.eval() # Set model to evaluate mode
# statistics
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_corrects.double() / dataset_sizes[phase]

if(phase == 'train'):
train_results.append([epoch_loss,epoch_acc])
if(phase == 'valid'):
valid_results.append([epoch_loss,epoch_acc])

print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
# deep copy the model (Early Stopping) and Saving our model, when we get best accuracy
if phase == 'valid' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
model_save_name = "resnetCars.pt"
path = F"/content/drive/My Drive/{model_save_name}"
torch.save(model.state_dict(), path)
print()
# Calculating time it took for model to train
time_elapsed = time.time() - start
print('Training complete in {:.0f}m {:.0f}s'.format(
time_elapsed // 60, time_elapsed % 60))
print('Best val Acc: {:4f}'.format(best_acc))
#load best model weights
model.load_state_dict(best_model_wts)

return model,train_results,valid_results


現在訓練該模型。

epochs = 60
#move model to GPU
model.to(device)
model,train_results,valid_results = train_model(model, criterion, optimizer, sched, epochs)
Epoch 1/60
----------
train Loss: 0.5672 Acc: 0.8441
valid Loss: 0.6750 Acc: 0.8329
Epoch 2/60
----------
train Loss: 0.6184 Acc: 0.8357
valid Loss: 0.5980 Acc: 0.8415
Epoch 3/60
----------
train Loss: 0.5695 Acc: 0.8487
valid Loss: 0.5503 Acc: 0.8575
...


這看起來非常有發展空間。模型似乎在每一個epoch中都進行學習。此外,模型似乎沒有過度擬合,因為練訓和驗證度量沒有太大的差異。第二次訓練是通過ResNet結構得到了該模型的特定epoch結果。一開始的精確度很低,但隨著時間的推移有所提高。影響精確度的超參數有很多,如優化器、調度程序、epoch數量和體系結構等。對這些值進行調整,要麼精確度非常低(低到0,甚至是負值),要麼從0.013這樣的精度開始,隨著時間間隔的增加而增加精準度(耐心是關鍵)。

"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

Deep CARs:使用Pytorch學習框架實現遷移學習


什麼是遷移學習?


遷移學習是深度學習的一種方法,即為解決某個任務而開發的模型會被重複使用作為另一個任務的起點。例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。

大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。一些人使用的預訓練的模型有VGGNet、ResNet、DenseNet、谷歌的Inception等等。這些網絡大多是在ImageNet上訓練的。ImageNet是一個龐大的數據集,包含100多萬張標記圖像,種類達1000個。

在Pytorch學習框架中,基於ImageNet這個龐大的數據庫,很容易就能加載來自torchvision的預訓練網絡。這其中一些預訓練模型將會用來訓練這些的網絡。

Deep CARs:使用Pytorch學習框架實現遷移學習


通過以下步驟在Google Colab之上建立模型


相關筆記:https://github.com/ivyclare/DeepCars---Transfer-Learning-With-Pytorch/blob/master/Ivy__Deep_Cars_Identifying_Car_Brands.ipynb


1. 加載數據並執行轉換

2. 構建和訓練模型

3. 用不可視數據測試模型

導入庫

這一步只是加載庫,確保GPU是打開的。由於將使用深層網絡的預訓練模型,所以對CPU進行訓練並不是個好的選擇,原因是需要它花費很長的時間。GPU與此同時執行線性代數計算,訓練速度會提高100倍。

如果沒有運行GPU,使用的是Colab工具的情況下,那就在電腦上點擊編輯 =>電腦設置。確保運行時間設為python3 並且低於硬件加速器的速度,選擇GPU。

接下來,檢測cuda(統一計算設備架構)是否可行。大多數深層學習框架使用CUDA在GPU上計算前後次數。

#importing libraries
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import torch
from torchvision import datasets,transforms,models
from torch import nn,optim
import torch.nn.functional as F
from torch.utils.data import *
import time
import json
import copy
import os
from PIL import Image
from collections import OrderedDict
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')


Deep CARs:使用Pytorch學習框架實現遷移學習


1. 加載數據並執行轉換


1.1 下載數據集


現在導入了庫,從Kaggle中加載數據集:https://www.kaggle.com/c/virtual-hack/data。該數據集中包含196個汽車品牌。

Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/@pixabay


此時,下載數據集並使用Pytorch dataloader加載。因為數據將直接下載到谷歌驅動器中,所以必須獲得授權訪問。

#Mounting google drive inorder to access data
from google.colab import drive
drive.mount('/content/drive')

運行此操作後,單擊出現的鏈接,登錄個人帳戶,單擊允許,然後將生成的文本複製粘貼到你的筆記本中。這篇文章(https://towardsdatascience.com/setting-up-kaggle-in-google-colab-ebb281b61463)將闡釋如何輕鬆獲取API(應用程序編程接口)的關鍵,下載數據集。


添加unzip \\*.zip來解壓下載的文件。相關代碼應該是這樣的:

# Downloading the data from Kaggle
!pip install kaggle
!mkdir .kaggle
import json
token = {"username":"yourusername","key":"184ee8bd3b41486d62e7eb9257bd812d4"}
with open('/content/.kaggle/kaggle.json', 'w') as file:
json.dump(token, file)
!chmod 600 /content/.kaggle/kaggle.json
!cp /content/.kaggle/kaggle.json ~/.kaggle/kaggle.json

!kaggle config set -n path -v{/content}
!kaggle competitions download -c virtual-hack -p /content
#Unzipping dowloaded files
!unzip \\*.zip


注意,有訓練和測試兩個目錄。稍後編程員將使用模型來預測測試集的值。與此同時,必須將訓練數據分為訓練和驗證兩部分。分解之前,需要先理解什麼是轉換,然後編寫轉換條目。

1.2 數據轉換

數據集下載完成後,對數據執行轉換操作。轉換是將數據從一種形式轉換成另一種形式。兩個主要的轉換將應用到圖像中:

· 數據擴張

在沒有收集新數據的情況下,這是一種增加用於訓練的數據集的多樣性和大小的策略。調整大小、裁剪、水平翻轉、填充甚至生成對抗網絡(GANs)等技術應用於數據集上的圖像,和“新”圖像的生成上。這樣做有兩個主要優勢:1.從有限數據中生成更多的數據;2.防止過度擬合。

然而,不要寄希望於在數據集中看到這些生成的圖像。它們只會在分批操作期間呈現,因此,即使訓練期間數據集中圖像數量沒有進行肉眼的增加,實際圖像在訓練期間也會有增加。

在模型中,應用了3種擴張策略:調整大小(隨機調整大小)、裁剪(隨機裁切)和水平翻轉(水平翻轉圖像)。

對於測試數據,並不執行隨機調整大小、隨機旋轉和隨機水平翻轉的轉換操作。相反,只是將測試圖像的規模調整到256×256,並裁剪出224×224的中心,以便能夠與預訓練模型一起使用。

· 數據規範化

數據擴張後,利用ImageNet中所有圖像的均值和標準差將目標圖像轉化為一個張量從而進行規範統一。通常,大型數據集本身的平均值和標準偏差是有用到的。如果給出的數據集不是太大,ImageNet中使用的數據集為:[0.485,0.456,0.406],[0.229,0.224,0.225]

# Tansform with data augmentation and normalization for training
# Just normalization for validation
data_transforms = {
'train': transforms.Compose([
transforms.RandomRotation(30),
transforms.RandomResizedCrop(224),
#transforms.RandomResizedCrop(299), #size for inception architecture
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'valid': transforms.Compose([
#transforms.Resize(256),
transforms.CenterCrop(224),
transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),

'test': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
#transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
]),
}


執行這些轉換後,利用Pytorch的ImageFolder來加載數據。但是需要先驗證數據,所以才需要將訓練集分成兩部分。只有1%的數據用於驗證,其餘則用於訓練。

#Loading in the dataset
train_dir = 'car_data/train'
test_dir = 'car_data/test'
label_dir = 'names.csv'
batch_size=32
dataset = datasets.ImageFolder(train_dir,transform=data_transforms['train'])
# splitting our data
valid_size = int(0.1 * len(dataset))
train_size = len(dataset) - valid_size
dataset_sizes = {'train': train_size, 'valid': valid_size}
# now we get our datasets
train_dataset, valid_dataset = torch.utils.data.random_split(dataset, [train_size, valid_size])
# Loading datasets into dataloader
dataloaders = {'train': DataLoader(train_dataset, batch_size = batch_size, shuffle = True),
'valid': DataLoader(valid_dataset, batch_size = batch_size, shuffle = False)}
print("Total Number of Samples: ",len(dataset))
print("Number of Samples in Train: ",len(train_dataset))
print("Number of Samples in Valid: ",len(valid_dataset))
print("Number of Classes: ",len(dataset.classes))
print(dataset.classes[0])


· 可視化標籤

將標籤可視化,瞭解文件結構。


Deep CARs:使用Pytorch學習框架實現遷移學習


以打印名稱csv輸出


汽車的名稱出現在0上面。因此,在讀取csv文件時,必須添加一個標題名稱以便得到正確的輸出結果。需要提醒的是,標籤是從0到195開始的(敲黑板)


Deep CARs:使用Pytorch學習框架實現遷移學習



1.3 可視化圖像

現在可以加載看到這些數據。使用imshow()(來自挑戰課程)的方法來顯示圖像。

## Method to display Image for Tensor
def imshow(image, ax=None, title=None, normalize=True):
"""Imshow for Tensor."""
if ax is None:
fig, ax = plt.subplots()
image = image.numpy().transpose((1, 2, 0))
if normalize:
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = std * image + mean
image = np.clip(image, 0, 1)
ax.imshow(image)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.tick_params(axis='both', length=0)
ax.set_xticklabels('')
ax.set_yticklabels('')
return ax
print(" Sizes of Datasets: ", len(valid_dataset), len(train_dataset))
# Displaying Training Images
images, labels = next(iter(dataloaders['train']))
fig, axes = plt.subplots(figsize=(16,5), ncols=5)
for ii in range(5):
ax = axes[ii]
#ax.set_title(label_map[class_names[labels[ii].item()]])
imshow(images[ii], ax=ax, normalize=True)


訓練集裡的圖像看起來如下圖所見。能發現其中一些圖像是已經發生了翻轉或旋轉的變化。


Deep CARs:使用Pytorch學習框架實現遷移學習


轉換後的訓練集圖像



Deep CARs:使用Pytorch學習框架實現遷移學習


2. 構建和訓練模型

綜上所述,將使用基於ImageNet的預訓練模型。

構建和訓練將採取的步驟如下:

2.1 加載預訓練模型

接下來將嘗試不同的架構比如densenet161、inceptionv3、resnet121和vggnet。在這一階段,需要加載不同的模型,指定模型完全連接層中輸入要素的數量,因為構建自定義分類器時需要這一前提。

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model_name = 'resnet' #vgg
# Densenet
if model_name == 'densenet':
model = models.densenet161(pretrained=True)
num_in_features = 2208
print(model)
# VGGNet
elif model_name == 'vgg':
model = models.vgg19(pretrained=True)
num_in_features = 25088
print(model.classifier)
# Resnet
elif model_name == 'resnet':
model = models.resnet152(pretrained=True)
#model = models.resnet34(pretrained=True)
num_in_features = 2048 #512
print(model.fc)
# Inception
elif model_name == 'inception':
model = models.inception_v3(pretrained=True)
model.aux_logits=False
num_in_features = 2048
print(model.fc)
else:
print("Unknown model, please choose 'densenet' or 'vgg'")


2.2 凍結參數,創建自定義分類器

由於預訓練模型中的大多數參數都已經過訓練,所以筆者並不傾向於這些數據。於是會為早期卷積層保留預訓練的權重(這裡的目的為特徵提取)。所以,將requires_grad字段重置為錯誤。

在這之後,替換掉完全連接的網絡,該網絡與預訓練的神經元擁有相同的輸入、自定義隱藏層和輸出內容。build_classifer方法是靈活的,當網絡中不需要隱藏層或者當需要多個隱藏層時,它就會起作用。同時也定義了激活函數(在本例中是relu)和dropout層。

# Freezing parameters
for param in model.parameters():
param.require_grad = False

# Create Custom Classifier
def build_classifier(num_in_features, hidden_layers, num_out_features):
classifier = nn.Sequential()
# when we don't have any hidden layers
if hidden_layers == None:
classifier.add_module('fc0', nn.Linear(num_in_features, 196))
#when we have hidden layers
else:
layer_sizes = zip(hidden_layers[:-1], hidden_layers[1:])
classifier.add_module('fc0', nn.Linear(num_in_features, hidden_layers[0]))
classifier.add_module('relu0', nn.ReLU())
classifier.add_module('drop0', nn.Dropout(.6))

for i, (h1, h2) in enumerate(layer_sizes):
classifier.add_module('fc'+str(i+1), nn.Linear(h1, h2))
classifier.add_module('relu'+str(i+1), nn.ReLU())
classifier.add_module('drop'+str(i+1), nn.Dropout(.5))
classifier.add_module('output', nn.Linear(hidden_layers[-1], num_out_features))

return classifier


現在指定超參數和隱藏層。

#define our hidden layers
hidden_layers = None #[1050,500]
classifier = build_classifier(num_in_features, hidden_layers, 196)
print(classifier)
# Defining model hyperparameters
if model_name == 'densenet':
model.classifier = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adadelta(model.parameters()) # Adadelta #weight optim.Adam(model.parameters(), lr=0.001, momentum=0.9)
# Decay Learning Rate by a factor of 0.1 every 4 epochs
sched = optim.lr_scheduler.StepLR(optimizer, step_size=4)
elif model_name == 'vgg':
model.classifier = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.classifier.parameters(), lr=0.0001)
sched = optim.lr_scheduler.StepLR(optimizer, step_size=4, gamma=0.1)
elif model_name == 'resnet':
model.fc = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
sched = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', patience=3, threshold = 0.9)
elif model_name == 'inception':
model.fc = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001,momentum=0.9)
else:
pass


然後指定標準,指定不同的優化器,如Adam, Adadelta, SGD等,包含學習率和動量。對不同的預訓練網絡使用這些超參數,選擇那些有用的超參數。針對resnet和vggnet使用兩種不同的調度程序。具體做法如下:

torch.optim.lr_scheduler提供了幾種依據epoch數量調整學習率的方法。

torch.optim.lr_scheduler.ReduceLROnPlateau(https://pytorch.org/docs/stable/optim.html#torch.optim.lr_scheduler.ReduceLROnPlateau) 允許基於一些驗證測量的動態學習率降低。詳情:https://pytorch.org/docs/stable/optim.html。


2.3 訓練與驗證

為了PyTorch訓練模型,通常會在每個epoch迭代時對其執行以下操作:

· 在網絡中使用前向(傳播)進行前向傳播

· 使用標準函數中的網絡輸出計算損耗

· 使用loss.backwards()對網絡執行反向傳播來計算梯度

· 利用優化器更新權重optimizer. step()

optimizer.zero_grad()用於歸零累積梯度

早停法技術是用於防止過度擬合的。驗證數據集上的性能開始下降時,該法可中止訓練。當在訓練過程中獲得最佳精度時,它會保存模型(檢查點)。這樣的話,如果因斷電或某原因中斷訓練,檢查點仍可恢復,訓練還可以繼續進行。

該模型改編自 PyTorch Website:https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html


# Training 
def train_model(model, criterion, optimizer, sched, num_epochs=5,device='cuda'):
start = time.time()
train_results = []
valid_results = []
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
for epoch in range(num_epochs):
print('Epoch {}/{}'.format(epoch+1, num_epochs))
print('-' * 10)
# Each epoch has a training and validation phase
for phase in ['train', 'valid']:
if phase == 'train':
model.train() # Set model to training mode
else:
model.eval() # Set model to evaluate mode
# statistics
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_corrects.double() / dataset_sizes[phase]

if(phase == 'train'):
train_results.append([epoch_loss,epoch_acc])
if(phase == 'valid'):
valid_results.append([epoch_loss,epoch_acc])

print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
# deep copy the model (Early Stopping) and Saving our model, when we get best accuracy
if phase == 'valid' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
model_save_name = "resnetCars.pt"
path = F"/content/drive/My Drive/{model_save_name}"
torch.save(model.state_dict(), path)
print()
# Calculating time it took for model to train
time_elapsed = time.time() - start
print('Training complete in {:.0f}m {:.0f}s'.format(
time_elapsed // 60, time_elapsed % 60))
print('Best val Acc: {:4f}'.format(best_acc))
#load best model weights
model.load_state_dict(best_model_wts)

return model,train_results,valid_results


現在訓練該模型。

epochs = 60
#move model to GPU
model.to(device)
model,train_results,valid_results = train_model(model, criterion, optimizer, sched, epochs)
Epoch 1/60
----------
train Loss: 0.5672 Acc: 0.8441
valid Loss: 0.6750 Acc: 0.8329
Epoch 2/60
----------
train Loss: 0.6184 Acc: 0.8357
valid Loss: 0.5980 Acc: 0.8415
Epoch 3/60
----------
train Loss: 0.5695 Acc: 0.8487
valid Loss: 0.5503 Acc: 0.8575
...


這看起來非常有發展空間。模型似乎在每一個epoch中都進行學習。此外,模型似乎沒有過度擬合,因為練訓和驗證度量沒有太大的差異。第二次訓練是通過ResNet結構得到了該模型的特定epoch結果。一開始的精確度很低,但隨著時間的推移有所提高。影響精確度的超參數有很多,如優化器、調度程序、epoch數量和體系結構等。對這些值進行調整,要麼精確度非常低(低到0,甚至是負值),要麼從0.013這樣的精度開始,隨著時間間隔的增加而增加精準度(耐心是關鍵)。

Deep CARs:使用Pytorch學習框架實現遷移學習


3. 用不可視數據測試模型


一旦對驗證的準確度感到滿意,就加載保留的模型,在測試數據的基礎上做預測。課堂比賽要求提交的是以Id,Predicted的形式放在一個csv文件夾裡。這裡的Id是指沒有拓展的圖像文件名。jpg 和Predicted屬於為每個模型圖像預測的類別(應該在1到196之間)。記住標籤從0到195開始,所以必須在預測的類中添加1才能得到正確的值。

加載保存的模型

model.load_state_dict(torch.load('/content/drive/MyDrive/ResnetCars.pt'))

model.to(device)

現在加載測試數據集,通過數據集傳播模型。因為只做了預測,所以無需計算梯度。藉助torch.no_grad()來進行操作,將其設為evaluation model.eval()。開始預測。

# import pathlib libary to get filename without the extension
from pathlib import Path
# Load the datasets with ImageFolder
label_df = pd.read_csv('names.csv', names=["label"])
test_dir = 'car_data/test'
with torch.no_grad():
print("Predictions on Test Set:")
model.eval()
dataset = datasets.ImageFolder(test_dir,transform=data_transforms['test'])

testloader = torch.utils.data.DataLoader(dataset, batch_size=64,
shuffle=False, num_workers=2)

image_names = []
pred = []
for index in testloader.dataset.imgs:
image_names.append(Path(index[0]).stem)

results = []
file_names = []
predicted_car = []
predicted_class = []
for inputs,labels in testloader:
inputs = inputs.to(device)
#labels = labels.to(device)
outputs = model(inputs)
_, pred = torch.max(outputs, 1)

for i in range(len(inputs)):
file_names.append(image_names[i])
predicted_car.append(int(pred[i] + 1))

results.append((file_names, predicted_car))


得到結果之後,打印數據框架,將結果寫入.csv文件,以便能將結果能上傳到比賽官網上。

print("Predictions on Test Set:")
df = pd.DataFrame({'Id': image_names, 'Predicted': results})
pd.set_option('display.max_colwidth', -1)
# df = df.sort_values(by=['Id'])
df.to_csv('/content/drive/My Drive/predictions.csv')
df



"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

Deep CARs:使用Pytorch學習框架實現遷移學習


什麼是遷移學習?


遷移學習是深度學習的一種方法,即為解決某個任務而開發的模型會被重複使用作為另一個任務的起點。例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。

大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。一些人使用的預訓練的模型有VGGNet、ResNet、DenseNet、谷歌的Inception等等。這些網絡大多是在ImageNet上訓練的。ImageNet是一個龐大的數據集,包含100多萬張標記圖像,種類達1000個。

在Pytorch學習框架中,基於ImageNet這個龐大的數據庫,很容易就能加載來自torchvision的預訓練網絡。這其中一些預訓練模型將會用來訓練這些的網絡。

Deep CARs:使用Pytorch學習框架實現遷移學習


通過以下步驟在Google Colab之上建立模型


相關筆記:https://github.com/ivyclare/DeepCars---Transfer-Learning-With-Pytorch/blob/master/Ivy__Deep_Cars_Identifying_Car_Brands.ipynb


1. 加載數據並執行轉換

2. 構建和訓練模型

3. 用不可視數據測試模型

導入庫

這一步只是加載庫,確保GPU是打開的。由於將使用深層網絡的預訓練模型,所以對CPU進行訓練並不是個好的選擇,原因是需要它花費很長的時間。GPU與此同時執行線性代數計算,訓練速度會提高100倍。

如果沒有運行GPU,使用的是Colab工具的情況下,那就在電腦上點擊編輯 =>電腦設置。確保運行時間設為python3 並且低於硬件加速器的速度,選擇GPU。

接下來,檢測cuda(統一計算設備架構)是否可行。大多數深層學習框架使用CUDA在GPU上計算前後次數。

#importing libraries
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import torch
from torchvision import datasets,transforms,models
from torch import nn,optim
import torch.nn.functional as F
from torch.utils.data import *
import time
import json
import copy
import os
from PIL import Image
from collections import OrderedDict
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')


Deep CARs:使用Pytorch學習框架實現遷移學習


1. 加載數據並執行轉換


1.1 下載數據集


現在導入了庫,從Kaggle中加載數據集:https://www.kaggle.com/c/virtual-hack/data。該數據集中包含196個汽車品牌。

Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/@pixabay


此時,下載數據集並使用Pytorch dataloader加載。因為數據將直接下載到谷歌驅動器中,所以必須獲得授權訪問。

#Mounting google drive inorder to access data
from google.colab import drive
drive.mount('/content/drive')

運行此操作後,單擊出現的鏈接,登錄個人帳戶,單擊允許,然後將生成的文本複製粘貼到你的筆記本中。這篇文章(https://towardsdatascience.com/setting-up-kaggle-in-google-colab-ebb281b61463)將闡釋如何輕鬆獲取API(應用程序編程接口)的關鍵,下載數據集。


添加unzip \\*.zip來解壓下載的文件。相關代碼應該是這樣的:

# Downloading the data from Kaggle
!pip install kaggle
!mkdir .kaggle
import json
token = {"username":"yourusername","key":"184ee8bd3b41486d62e7eb9257bd812d4"}
with open('/content/.kaggle/kaggle.json', 'w') as file:
json.dump(token, file)
!chmod 600 /content/.kaggle/kaggle.json
!cp /content/.kaggle/kaggle.json ~/.kaggle/kaggle.json

!kaggle config set -n path -v{/content}
!kaggle competitions download -c virtual-hack -p /content
#Unzipping dowloaded files
!unzip \\*.zip


注意,有訓練和測試兩個目錄。稍後編程員將使用模型來預測測試集的值。與此同時,必須將訓練數據分為訓練和驗證兩部分。分解之前,需要先理解什麼是轉換,然後編寫轉換條目。

1.2 數據轉換

數據集下載完成後,對數據執行轉換操作。轉換是將數據從一種形式轉換成另一種形式。兩個主要的轉換將應用到圖像中:

· 數據擴張

在沒有收集新數據的情況下,這是一種增加用於訓練的數據集的多樣性和大小的策略。調整大小、裁剪、水平翻轉、填充甚至生成對抗網絡(GANs)等技術應用於數據集上的圖像,和“新”圖像的生成上。這樣做有兩個主要優勢:1.從有限數據中生成更多的數據;2.防止過度擬合。

然而,不要寄希望於在數據集中看到這些生成的圖像。它們只會在分批操作期間呈現,因此,即使訓練期間數據集中圖像數量沒有進行肉眼的增加,實際圖像在訓練期間也會有增加。

在模型中,應用了3種擴張策略:調整大小(隨機調整大小)、裁剪(隨機裁切)和水平翻轉(水平翻轉圖像)。

對於測試數據,並不執行隨機調整大小、隨機旋轉和隨機水平翻轉的轉換操作。相反,只是將測試圖像的規模調整到256×256,並裁剪出224×224的中心,以便能夠與預訓練模型一起使用。

· 數據規範化

數據擴張後,利用ImageNet中所有圖像的均值和標準差將目標圖像轉化為一個張量從而進行規範統一。通常,大型數據集本身的平均值和標準偏差是有用到的。如果給出的數據集不是太大,ImageNet中使用的數據集為:[0.485,0.456,0.406],[0.229,0.224,0.225]

# Tansform with data augmentation and normalization for training
# Just normalization for validation
data_transforms = {
'train': transforms.Compose([
transforms.RandomRotation(30),
transforms.RandomResizedCrop(224),
#transforms.RandomResizedCrop(299), #size for inception architecture
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'valid': transforms.Compose([
#transforms.Resize(256),
transforms.CenterCrop(224),
transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),

'test': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
#transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
]),
}


執行這些轉換後,利用Pytorch的ImageFolder來加載數據。但是需要先驗證數據,所以才需要將訓練集分成兩部分。只有1%的數據用於驗證,其餘則用於訓練。

#Loading in the dataset
train_dir = 'car_data/train'
test_dir = 'car_data/test'
label_dir = 'names.csv'
batch_size=32
dataset = datasets.ImageFolder(train_dir,transform=data_transforms['train'])
# splitting our data
valid_size = int(0.1 * len(dataset))
train_size = len(dataset) - valid_size
dataset_sizes = {'train': train_size, 'valid': valid_size}
# now we get our datasets
train_dataset, valid_dataset = torch.utils.data.random_split(dataset, [train_size, valid_size])
# Loading datasets into dataloader
dataloaders = {'train': DataLoader(train_dataset, batch_size = batch_size, shuffle = True),
'valid': DataLoader(valid_dataset, batch_size = batch_size, shuffle = False)}
print("Total Number of Samples: ",len(dataset))
print("Number of Samples in Train: ",len(train_dataset))
print("Number of Samples in Valid: ",len(valid_dataset))
print("Number of Classes: ",len(dataset.classes))
print(dataset.classes[0])


· 可視化標籤

將標籤可視化,瞭解文件結構。


Deep CARs:使用Pytorch學習框架實現遷移學習


以打印名稱csv輸出


汽車的名稱出現在0上面。因此,在讀取csv文件時,必須添加一個標題名稱以便得到正確的輸出結果。需要提醒的是,標籤是從0到195開始的(敲黑板)


Deep CARs:使用Pytorch學習框架實現遷移學習



1.3 可視化圖像

現在可以加載看到這些數據。使用imshow()(來自挑戰課程)的方法來顯示圖像。

## Method to display Image for Tensor
def imshow(image, ax=None, title=None, normalize=True):
"""Imshow for Tensor."""
if ax is None:
fig, ax = plt.subplots()
image = image.numpy().transpose((1, 2, 0))
if normalize:
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = std * image + mean
image = np.clip(image, 0, 1)
ax.imshow(image)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.tick_params(axis='both', length=0)
ax.set_xticklabels('')
ax.set_yticklabels('')
return ax
print(" Sizes of Datasets: ", len(valid_dataset), len(train_dataset))
# Displaying Training Images
images, labels = next(iter(dataloaders['train']))
fig, axes = plt.subplots(figsize=(16,5), ncols=5)
for ii in range(5):
ax = axes[ii]
#ax.set_title(label_map[class_names[labels[ii].item()]])
imshow(images[ii], ax=ax, normalize=True)


訓練集裡的圖像看起來如下圖所見。能發現其中一些圖像是已經發生了翻轉或旋轉的變化。


Deep CARs:使用Pytorch學習框架實現遷移學習


轉換後的訓練集圖像



Deep CARs:使用Pytorch學習框架實現遷移學習


2. 構建和訓練模型

綜上所述,將使用基於ImageNet的預訓練模型。

構建和訓練將採取的步驟如下:

2.1 加載預訓練模型

接下來將嘗試不同的架構比如densenet161、inceptionv3、resnet121和vggnet。在這一階段,需要加載不同的模型,指定模型完全連接層中輸入要素的數量,因為構建自定義分類器時需要這一前提。

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model_name = 'resnet' #vgg
# Densenet
if model_name == 'densenet':
model = models.densenet161(pretrained=True)
num_in_features = 2208
print(model)
# VGGNet
elif model_name == 'vgg':
model = models.vgg19(pretrained=True)
num_in_features = 25088
print(model.classifier)
# Resnet
elif model_name == 'resnet':
model = models.resnet152(pretrained=True)
#model = models.resnet34(pretrained=True)
num_in_features = 2048 #512
print(model.fc)
# Inception
elif model_name == 'inception':
model = models.inception_v3(pretrained=True)
model.aux_logits=False
num_in_features = 2048
print(model.fc)
else:
print("Unknown model, please choose 'densenet' or 'vgg'")


2.2 凍結參數,創建自定義分類器

由於預訓練模型中的大多數參數都已經過訓練,所以筆者並不傾向於這些數據。於是會為早期卷積層保留預訓練的權重(這裡的目的為特徵提取)。所以,將requires_grad字段重置為錯誤。

在這之後,替換掉完全連接的網絡,該網絡與預訓練的神經元擁有相同的輸入、自定義隱藏層和輸出內容。build_classifer方法是靈活的,當網絡中不需要隱藏層或者當需要多個隱藏層時,它就會起作用。同時也定義了激活函數(在本例中是relu)和dropout層。

# Freezing parameters
for param in model.parameters():
param.require_grad = False

# Create Custom Classifier
def build_classifier(num_in_features, hidden_layers, num_out_features):
classifier = nn.Sequential()
# when we don't have any hidden layers
if hidden_layers == None:
classifier.add_module('fc0', nn.Linear(num_in_features, 196))
#when we have hidden layers
else:
layer_sizes = zip(hidden_layers[:-1], hidden_layers[1:])
classifier.add_module('fc0', nn.Linear(num_in_features, hidden_layers[0]))
classifier.add_module('relu0', nn.ReLU())
classifier.add_module('drop0', nn.Dropout(.6))

for i, (h1, h2) in enumerate(layer_sizes):
classifier.add_module('fc'+str(i+1), nn.Linear(h1, h2))
classifier.add_module('relu'+str(i+1), nn.ReLU())
classifier.add_module('drop'+str(i+1), nn.Dropout(.5))
classifier.add_module('output', nn.Linear(hidden_layers[-1], num_out_features))

return classifier


現在指定超參數和隱藏層。

#define our hidden layers
hidden_layers = None #[1050,500]
classifier = build_classifier(num_in_features, hidden_layers, 196)
print(classifier)
# Defining model hyperparameters
if model_name == 'densenet':
model.classifier = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adadelta(model.parameters()) # Adadelta #weight optim.Adam(model.parameters(), lr=0.001, momentum=0.9)
# Decay Learning Rate by a factor of 0.1 every 4 epochs
sched = optim.lr_scheduler.StepLR(optimizer, step_size=4)
elif model_name == 'vgg':
model.classifier = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.classifier.parameters(), lr=0.0001)
sched = optim.lr_scheduler.StepLR(optimizer, step_size=4, gamma=0.1)
elif model_name == 'resnet':
model.fc = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
sched = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', patience=3, threshold = 0.9)
elif model_name == 'inception':
model.fc = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001,momentum=0.9)
else:
pass


然後指定標準,指定不同的優化器,如Adam, Adadelta, SGD等,包含學習率和動量。對不同的預訓練網絡使用這些超參數,選擇那些有用的超參數。針對resnet和vggnet使用兩種不同的調度程序。具體做法如下:

torch.optim.lr_scheduler提供了幾種依據epoch數量調整學習率的方法。

torch.optim.lr_scheduler.ReduceLROnPlateau(https://pytorch.org/docs/stable/optim.html#torch.optim.lr_scheduler.ReduceLROnPlateau) 允許基於一些驗證測量的動態學習率降低。詳情:https://pytorch.org/docs/stable/optim.html。


2.3 訓練與驗證

為了PyTorch訓練模型,通常會在每個epoch迭代時對其執行以下操作:

· 在網絡中使用前向(傳播)進行前向傳播

· 使用標準函數中的網絡輸出計算損耗

· 使用loss.backwards()對網絡執行反向傳播來計算梯度

· 利用優化器更新權重optimizer. step()

optimizer.zero_grad()用於歸零累積梯度

早停法技術是用於防止過度擬合的。驗證數據集上的性能開始下降時,該法可中止訓練。當在訓練過程中獲得最佳精度時,它會保存模型(檢查點)。這樣的話,如果因斷電或某原因中斷訓練,檢查點仍可恢復,訓練還可以繼續進行。

該模型改編自 PyTorch Website:https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html


# Training 
def train_model(model, criterion, optimizer, sched, num_epochs=5,device='cuda'):
start = time.time()
train_results = []
valid_results = []
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
for epoch in range(num_epochs):
print('Epoch {}/{}'.format(epoch+1, num_epochs))
print('-' * 10)
# Each epoch has a training and validation phase
for phase in ['train', 'valid']:
if phase == 'train':
model.train() # Set model to training mode
else:
model.eval() # Set model to evaluate mode
# statistics
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_corrects.double() / dataset_sizes[phase]

if(phase == 'train'):
train_results.append([epoch_loss,epoch_acc])
if(phase == 'valid'):
valid_results.append([epoch_loss,epoch_acc])

print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
# deep copy the model (Early Stopping) and Saving our model, when we get best accuracy
if phase == 'valid' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
model_save_name = "resnetCars.pt"
path = F"/content/drive/My Drive/{model_save_name}"
torch.save(model.state_dict(), path)
print()
# Calculating time it took for model to train
time_elapsed = time.time() - start
print('Training complete in {:.0f}m {:.0f}s'.format(
time_elapsed // 60, time_elapsed % 60))
print('Best val Acc: {:4f}'.format(best_acc))
#load best model weights
model.load_state_dict(best_model_wts)

return model,train_results,valid_results


現在訓練該模型。

epochs = 60
#move model to GPU
model.to(device)
model,train_results,valid_results = train_model(model, criterion, optimizer, sched, epochs)
Epoch 1/60
----------
train Loss: 0.5672 Acc: 0.8441
valid Loss: 0.6750 Acc: 0.8329
Epoch 2/60
----------
train Loss: 0.6184 Acc: 0.8357
valid Loss: 0.5980 Acc: 0.8415
Epoch 3/60
----------
train Loss: 0.5695 Acc: 0.8487
valid Loss: 0.5503 Acc: 0.8575
...


這看起來非常有發展空間。模型似乎在每一個epoch中都進行學習。此外,模型似乎沒有過度擬合,因為練訓和驗證度量沒有太大的差異。第二次訓練是通過ResNet結構得到了該模型的特定epoch結果。一開始的精確度很低,但隨著時間的推移有所提高。影響精確度的超參數有很多,如優化器、調度程序、epoch數量和體系結構等。對這些值進行調整,要麼精確度非常低(低到0,甚至是負值),要麼從0.013這樣的精度開始,隨著時間間隔的增加而增加精準度(耐心是關鍵)。

Deep CARs:使用Pytorch學習框架實現遷移學習


3. 用不可視數據測試模型


一旦對驗證的準確度感到滿意,就加載保留的模型,在測試數據的基礎上做預測。課堂比賽要求提交的是以Id,Predicted的形式放在一個csv文件夾裡。這裡的Id是指沒有拓展的圖像文件名。jpg 和Predicted屬於為每個模型圖像預測的類別(應該在1到196之間)。記住標籤從0到195開始,所以必須在預測的類中添加1才能得到正確的值。

加載保存的模型

model.load_state_dict(torch.load('/content/drive/MyDrive/ResnetCars.pt'))

model.to(device)

現在加載測試數據集,通過數據集傳播模型。因為只做了預測,所以無需計算梯度。藉助torch.no_grad()來進行操作,將其設為evaluation model.eval()。開始預測。

# import pathlib libary to get filename without the extension
from pathlib import Path
# Load the datasets with ImageFolder
label_df = pd.read_csv('names.csv', names=["label"])
test_dir = 'car_data/test'
with torch.no_grad():
print("Predictions on Test Set:")
model.eval()
dataset = datasets.ImageFolder(test_dir,transform=data_transforms['test'])

testloader = torch.utils.data.DataLoader(dataset, batch_size=64,
shuffle=False, num_workers=2)

image_names = []
pred = []
for index in testloader.dataset.imgs:
image_names.append(Path(index[0]).stem)

results = []
file_names = []
predicted_car = []
predicted_class = []
for inputs,labels in testloader:
inputs = inputs.to(device)
#labels = labels.to(device)
outputs = model(inputs)
_, pred = torch.max(outputs, 1)

for i in range(len(inputs)):
file_names.append(image_names[i])
predicted_car.append(int(pred[i] + 1))

results.append((file_names, predicted_car))


得到結果之後,打印數據框架,將結果寫入.csv文件,以便能將結果能上傳到比賽官網上。

print("Predictions on Test Set:")
df = pd.DataFrame({'Id': image_names, 'Predicted': results})
pd.set_option('display.max_colwidth', -1)
# df = df.sort_values(by=['Id'])
df.to_csv('/content/drive/My Drive/predictions.csv')
df



Deep CARs:使用Pytorch學習框架實現遷移學習


提交的CSV文件


如圖可以看到Khush Patel(https://medium.com/@iKhushPatel)的驚人內核(https://www.kaggle.com/ikhushpatel/ignite-car-classification-ikhushpatel-khush),以99.18%的準確率成為贏家。他使用了inceptionV3架構,以及CrossEntropyLoss 和SGD優化器。


你可以在inclass competition on Kaggle上參與進來:https://www.kaggle.com/c/virtual-hack/overview


"
全文共13449字,預計學習時長26分鐘或更長
Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/photo/vehicles-parked-inside-elevated-parking-lot-63294/


如何讓電腦識別不同的汽車品牌?想用手機拍任何一輛車就能知道車的牌子嗎?本文將介紹一個能識別196種類型汽車的模型。

本模型將通過神經網絡來實現目標。更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。

想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。

我們將使用一種叫做遷移學習的方法來訓練分類器。

Deep CARs:使用Pytorch學習框架實現遷移學習


什麼是遷移學習?


遷移學習是深度學習的一種方法,即為解決某個任務而開發的模型會被重複使用作為另一個任務的起點。例如,如果想要構建一個網絡識別鳥類,與其從頭開始編寫一個複雜的模型,不如用一個現成的的模型,用於針對相同或相似任務的模型(在該實例中,可以使用一個識別其他動物的網絡系統來完成任務)。遷移學習法的優勢在於:學習過程更快、信息更準確,所需的訓練數據也更少。在遷移學習中,現有的這個模型稱為預訓練模型。

大多數用於遷移學習的預訓練模型都是基於大型卷積神經網絡之上的。一些人使用的預訓練的模型有VGGNet、ResNet、DenseNet、谷歌的Inception等等。這些網絡大多是在ImageNet上訓練的。ImageNet是一個龐大的數據集,包含100多萬張標記圖像,種類達1000個。

在Pytorch學習框架中,基於ImageNet這個龐大的數據庫,很容易就能加載來自torchvision的預訓練網絡。這其中一些預訓練模型將會用來訓練這些的網絡。

Deep CARs:使用Pytorch學習框架實現遷移學習


通過以下步驟在Google Colab之上建立模型


相關筆記:https://github.com/ivyclare/DeepCars---Transfer-Learning-With-Pytorch/blob/master/Ivy__Deep_Cars_Identifying_Car_Brands.ipynb


1. 加載數據並執行轉換

2. 構建和訓練模型

3. 用不可視數據測試模型

導入庫

這一步只是加載庫,確保GPU是打開的。由於將使用深層網絡的預訓練模型,所以對CPU進行訓練並不是個好的選擇,原因是需要它花費很長的時間。GPU與此同時執行線性代數計算,訓練速度會提高100倍。

如果沒有運行GPU,使用的是Colab工具的情況下,那就在電腦上點擊編輯 =>電腦設置。確保運行時間設為python3 並且低於硬件加速器的速度,選擇GPU。

接下來,檢測cuda(統一計算設備架構)是否可行。大多數深層學習框架使用CUDA在GPU上計算前後次數。

#importing libraries
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import torch
from torchvision import datasets,transforms,models
from torch import nn,optim
import torch.nn.functional as F
from torch.utils.data import *
import time
import json
import copy
import os
from PIL import Image
from collections import OrderedDict
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')


Deep CARs:使用Pytorch學習框架實現遷移學習


1. 加載數據並執行轉換


1.1 下載數據集


現在導入了庫,從Kaggle中加載數據集:https://www.kaggle.com/c/virtual-hack/data。該數據集中包含196個汽車品牌。

Deep CARs:使用Pytorch學習框架實現遷移學習

圖片來源:https://www.pexels.com/@pixabay


此時,下載數據集並使用Pytorch dataloader加載。因為數據將直接下載到谷歌驅動器中,所以必須獲得授權訪問。

#Mounting google drive inorder to access data
from google.colab import drive
drive.mount('/content/drive')

運行此操作後,單擊出現的鏈接,登錄個人帳戶,單擊允許,然後將生成的文本複製粘貼到你的筆記本中。這篇文章(https://towardsdatascience.com/setting-up-kaggle-in-google-colab-ebb281b61463)將闡釋如何輕鬆獲取API(應用程序編程接口)的關鍵,下載數據集。


添加unzip \\*.zip來解壓下載的文件。相關代碼應該是這樣的:

# Downloading the data from Kaggle
!pip install kaggle
!mkdir .kaggle
import json
token = {"username":"yourusername","key":"184ee8bd3b41486d62e7eb9257bd812d4"}
with open('/content/.kaggle/kaggle.json', 'w') as file:
json.dump(token, file)
!chmod 600 /content/.kaggle/kaggle.json
!cp /content/.kaggle/kaggle.json ~/.kaggle/kaggle.json

!kaggle config set -n path -v{/content}
!kaggle competitions download -c virtual-hack -p /content
#Unzipping dowloaded files
!unzip \\*.zip


注意,有訓練和測試兩個目錄。稍後編程員將使用模型來預測測試集的值。與此同時,必須將訓練數據分為訓練和驗證兩部分。分解之前,需要先理解什麼是轉換,然後編寫轉換條目。

1.2 數據轉換

數據集下載完成後,對數據執行轉換操作。轉換是將數據從一種形式轉換成另一種形式。兩個主要的轉換將應用到圖像中:

· 數據擴張

在沒有收集新數據的情況下,這是一種增加用於訓練的數據集的多樣性和大小的策略。調整大小、裁剪、水平翻轉、填充甚至生成對抗網絡(GANs)等技術應用於數據集上的圖像,和“新”圖像的生成上。這樣做有兩個主要優勢:1.從有限數據中生成更多的數據;2.防止過度擬合。

然而,不要寄希望於在數據集中看到這些生成的圖像。它們只會在分批操作期間呈現,因此,即使訓練期間數據集中圖像數量沒有進行肉眼的增加,實際圖像在訓練期間也會有增加。

在模型中,應用了3種擴張策略:調整大小(隨機調整大小)、裁剪(隨機裁切)和水平翻轉(水平翻轉圖像)。

對於測試數據,並不執行隨機調整大小、隨機旋轉和隨機水平翻轉的轉換操作。相反,只是將測試圖像的規模調整到256×256,並裁剪出224×224的中心,以便能夠與預訓練模型一起使用。

· 數據規範化

數據擴張後,利用ImageNet中所有圖像的均值和標準差將目標圖像轉化為一個張量從而進行規範統一。通常,大型數據集本身的平均值和標準偏差是有用到的。如果給出的數據集不是太大,ImageNet中使用的數據集為:[0.485,0.456,0.406],[0.229,0.224,0.225]

# Tansform with data augmentation and normalization for training
# Just normalization for validation
data_transforms = {
'train': transforms.Compose([
transforms.RandomRotation(30),
transforms.RandomResizedCrop(224),
#transforms.RandomResizedCrop(299), #size for inception architecture
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'valid': transforms.Compose([
#transforms.Resize(256),
transforms.CenterCrop(224),
transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),

'test': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
#transforms.CenterCrop(299),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
]),
}


執行這些轉換後,利用Pytorch的ImageFolder來加載數據。但是需要先驗證數據,所以才需要將訓練集分成兩部分。只有1%的數據用於驗證,其餘則用於訓練。

#Loading in the dataset
train_dir = 'car_data/train'
test_dir = 'car_data/test'
label_dir = 'names.csv'
batch_size=32
dataset = datasets.ImageFolder(train_dir,transform=data_transforms['train'])
# splitting our data
valid_size = int(0.1 * len(dataset))
train_size = len(dataset) - valid_size
dataset_sizes = {'train': train_size, 'valid': valid_size}
# now we get our datasets
train_dataset, valid_dataset = torch.utils.data.random_split(dataset, [train_size, valid_size])
# Loading datasets into dataloader
dataloaders = {'train': DataLoader(train_dataset, batch_size = batch_size, shuffle = True),
'valid': DataLoader(valid_dataset, batch_size = batch_size, shuffle = False)}
print("Total Number of Samples: ",len(dataset))
print("Number of Samples in Train: ",len(train_dataset))
print("Number of Samples in Valid: ",len(valid_dataset))
print("Number of Classes: ",len(dataset.classes))
print(dataset.classes[0])


· 可視化標籤

將標籤可視化,瞭解文件結構。


Deep CARs:使用Pytorch學習框架實現遷移學習


以打印名稱csv輸出


汽車的名稱出現在0上面。因此,在讀取csv文件時,必須添加一個標題名稱以便得到正確的輸出結果。需要提醒的是,標籤是從0到195開始的(敲黑板)


Deep CARs:使用Pytorch學習框架實現遷移學習



1.3 可視化圖像

現在可以加載看到這些數據。使用imshow()(來自挑戰課程)的方法來顯示圖像。

## Method to display Image for Tensor
def imshow(image, ax=None, title=None, normalize=True):
"""Imshow for Tensor."""
if ax is None:
fig, ax = plt.subplots()
image = image.numpy().transpose((1, 2, 0))
if normalize:
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = std * image + mean
image = np.clip(image, 0, 1)
ax.imshow(image)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.tick_params(axis='both', length=0)
ax.set_xticklabels('')
ax.set_yticklabels('')
return ax
print(" Sizes of Datasets: ", len(valid_dataset), len(train_dataset))
# Displaying Training Images
images, labels = next(iter(dataloaders['train']))
fig, axes = plt.subplots(figsize=(16,5), ncols=5)
for ii in range(5):
ax = axes[ii]
#ax.set_title(label_map[class_names[labels[ii].item()]])
imshow(images[ii], ax=ax, normalize=True)


訓練集裡的圖像看起來如下圖所見。能發現其中一些圖像是已經發生了翻轉或旋轉的變化。


Deep CARs:使用Pytorch學習框架實現遷移學習


轉換後的訓練集圖像



Deep CARs:使用Pytorch學習框架實現遷移學習


2. 構建和訓練模型

綜上所述,將使用基於ImageNet的預訓練模型。

構建和訓練將採取的步驟如下:

2.1 加載預訓練模型

接下來將嘗試不同的架構比如densenet161、inceptionv3、resnet121和vggnet。在這一階段,需要加載不同的模型,指定模型完全連接層中輸入要素的數量,因為構建自定義分類器時需要這一前提。

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model_name = 'resnet' #vgg
# Densenet
if model_name == 'densenet':
model = models.densenet161(pretrained=True)
num_in_features = 2208
print(model)
# VGGNet
elif model_name == 'vgg':
model = models.vgg19(pretrained=True)
num_in_features = 25088
print(model.classifier)
# Resnet
elif model_name == 'resnet':
model = models.resnet152(pretrained=True)
#model = models.resnet34(pretrained=True)
num_in_features = 2048 #512
print(model.fc)
# Inception
elif model_name == 'inception':
model = models.inception_v3(pretrained=True)
model.aux_logits=False
num_in_features = 2048
print(model.fc)
else:
print("Unknown model, please choose 'densenet' or 'vgg'")


2.2 凍結參數,創建自定義分類器

由於預訓練模型中的大多數參數都已經過訓練,所以筆者並不傾向於這些數據。於是會為早期卷積層保留預訓練的權重(這裡的目的為特徵提取)。所以,將requires_grad字段重置為錯誤。

在這之後,替換掉完全連接的網絡,該網絡與預訓練的神經元擁有相同的輸入、自定義隱藏層和輸出內容。build_classifer方法是靈活的,當網絡中不需要隱藏層或者當需要多個隱藏層時,它就會起作用。同時也定義了激活函數(在本例中是relu)和dropout層。

# Freezing parameters
for param in model.parameters():
param.require_grad = False

# Create Custom Classifier
def build_classifier(num_in_features, hidden_layers, num_out_features):
classifier = nn.Sequential()
# when we don't have any hidden layers
if hidden_layers == None:
classifier.add_module('fc0', nn.Linear(num_in_features, 196))
#when we have hidden layers
else:
layer_sizes = zip(hidden_layers[:-1], hidden_layers[1:])
classifier.add_module('fc0', nn.Linear(num_in_features, hidden_layers[0]))
classifier.add_module('relu0', nn.ReLU())
classifier.add_module('drop0', nn.Dropout(.6))

for i, (h1, h2) in enumerate(layer_sizes):
classifier.add_module('fc'+str(i+1), nn.Linear(h1, h2))
classifier.add_module('relu'+str(i+1), nn.ReLU())
classifier.add_module('drop'+str(i+1), nn.Dropout(.5))
classifier.add_module('output', nn.Linear(hidden_layers[-1], num_out_features))

return classifier


現在指定超參數和隱藏層。

#define our hidden layers
hidden_layers = None #[1050,500]
classifier = build_classifier(num_in_features, hidden_layers, 196)
print(classifier)
# Defining model hyperparameters
if model_name == 'densenet':
model.classifier = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adadelta(model.parameters()) # Adadelta #weight optim.Adam(model.parameters(), lr=0.001, momentum=0.9)
# Decay Learning Rate by a factor of 0.1 every 4 epochs
sched = optim.lr_scheduler.StepLR(optimizer, step_size=4)
elif model_name == 'vgg':
model.classifier = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.classifier.parameters(), lr=0.0001)
sched = optim.lr_scheduler.StepLR(optimizer, step_size=4, gamma=0.1)
elif model_name == 'resnet':
model.fc = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
sched = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', patience=3, threshold = 0.9)
elif model_name == 'inception':
model.fc = classifier
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001,momentum=0.9)
else:
pass


然後指定標準,指定不同的優化器,如Adam, Adadelta, SGD等,包含學習率和動量。對不同的預訓練網絡使用這些超參數,選擇那些有用的超參數。針對resnet和vggnet使用兩種不同的調度程序。具體做法如下:

torch.optim.lr_scheduler提供了幾種依據epoch數量調整學習率的方法。

torch.optim.lr_scheduler.ReduceLROnPlateau(https://pytorch.org/docs/stable/optim.html#torch.optim.lr_scheduler.ReduceLROnPlateau) 允許基於一些驗證測量的動態學習率降低。詳情:https://pytorch.org/docs/stable/optim.html。


2.3 訓練與驗證

為了PyTorch訓練模型,通常會在每個epoch迭代時對其執行以下操作:

· 在網絡中使用前向(傳播)進行前向傳播

· 使用標準函數中的網絡輸出計算損耗

· 使用loss.backwards()對網絡執行反向傳播來計算梯度

· 利用優化器更新權重optimizer. step()

optimizer.zero_grad()用於歸零累積梯度

早停法技術是用於防止過度擬合的。驗證數據集上的性能開始下降時,該法可中止訓練。當在訓練過程中獲得最佳精度時,它會保存模型(檢查點)。這樣的話,如果因斷電或某原因中斷訓練,檢查點仍可恢復,訓練還可以繼續進行。

該模型改編自 PyTorch Website:https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html


# Training 
def train_model(model, criterion, optimizer, sched, num_epochs=5,device='cuda'):
start = time.time()
train_results = []
valid_results = []
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
for epoch in range(num_epochs):
print('Epoch {}/{}'.format(epoch+1, num_epochs))
print('-' * 10)
# Each epoch has a training and validation phase
for phase in ['train', 'valid']:
if phase == 'train':
model.train() # Set model to training mode
else:
model.eval() # Set model to evaluate mode
# statistics
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_corrects.double() / dataset_sizes[phase]

if(phase == 'train'):
train_results.append([epoch_loss,epoch_acc])
if(phase == 'valid'):
valid_results.append([epoch_loss,epoch_acc])

print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
# deep copy the model (Early Stopping) and Saving our model, when we get best accuracy
if phase == 'valid' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
model_save_name = "resnetCars.pt"
path = F"/content/drive/My Drive/{model_save_name}"
torch.save(model.state_dict(), path)
print()
# Calculating time it took for model to train
time_elapsed = time.time() - start
print('Training complete in {:.0f}m {:.0f}s'.format(
time_elapsed // 60, time_elapsed % 60))
print('Best val Acc: {:4f}'.format(best_acc))
#load best model weights
model.load_state_dict(best_model_wts)

return model,train_results,valid_results


現在訓練該模型。

epochs = 60
#move model to GPU
model.to(device)
model,train_results,valid_results = train_model(model, criterion, optimizer, sched, epochs)
Epoch 1/60
----------
train Loss: 0.5672 Acc: 0.8441
valid Loss: 0.6750 Acc: 0.8329
Epoch 2/60
----------
train Loss: 0.6184 Acc: 0.8357
valid Loss: 0.5980 Acc: 0.8415
Epoch 3/60
----------
train Loss: 0.5695 Acc: 0.8487
valid Loss: 0.5503 Acc: 0.8575
...


這看起來非常有發展空間。模型似乎在每一個epoch中都進行學習。此外,模型似乎沒有過度擬合,因為練訓和驗證度量沒有太大的差異。第二次訓練是通過ResNet結構得到了該模型的特定epoch結果。一開始的精確度很低,但隨著時間的推移有所提高。影響精確度的超參數有很多,如優化器、調度程序、epoch數量和體系結構等。對這些值進行調整,要麼精確度非常低(低到0,甚至是負值),要麼從0.013這樣的精度開始,隨著時間間隔的增加而增加精準度(耐心是關鍵)。

Deep CARs:使用Pytorch學習框架實現遷移學習


3. 用不可視數據測試模型


一旦對驗證的準確度感到滿意,就加載保留的模型,在測試數據的基礎上做預測。課堂比賽要求提交的是以Id,Predicted的形式放在一個csv文件夾裡。這裡的Id是指沒有拓展的圖像文件名。jpg 和Predicted屬於為每個模型圖像預測的類別(應該在1到196之間)。記住標籤從0到195開始,所以必須在預測的類中添加1才能得到正確的值。

加載保存的模型

model.load_state_dict(torch.load('/content/drive/MyDrive/ResnetCars.pt'))

model.to(device)

現在加載測試數據集,通過數據集傳播模型。因為只做了預測,所以無需計算梯度。藉助torch.no_grad()來進行操作,將其設為evaluation model.eval()。開始預測。

# import pathlib libary to get filename without the extension
from pathlib import Path
# Load the datasets with ImageFolder
label_df = pd.read_csv('names.csv', names=["label"])
test_dir = 'car_data/test'
with torch.no_grad():
print("Predictions on Test Set:")
model.eval()
dataset = datasets.ImageFolder(test_dir,transform=data_transforms['test'])

testloader = torch.utils.data.DataLoader(dataset, batch_size=64,
shuffle=False, num_workers=2)

image_names = []
pred = []
for index in testloader.dataset.imgs:
image_names.append(Path(index[0]).stem)

results = []
file_names = []
predicted_car = []
predicted_class = []
for inputs,labels in testloader:
inputs = inputs.to(device)
#labels = labels.to(device)
outputs = model(inputs)
_, pred = torch.max(outputs, 1)

for i in range(len(inputs)):
file_names.append(image_names[i])
predicted_car.append(int(pred[i] + 1))

results.append((file_names, predicted_car))


得到結果之後,打印數據框架,將結果寫入.csv文件,以便能將結果能上傳到比賽官網上。

print("Predictions on Test Set:")
df = pd.DataFrame({'Id': image_names, 'Predicted': results})
pd.set_option('display.max_colwidth', -1)
# df = df.sort_values(by=['Id'])
df.to_csv('/content/drive/My Drive/predictions.csv')
df



Deep CARs:使用Pytorch學習框架實現遷移學習


提交的CSV文件


如圖可以看到Khush Patel(https://medium.com/@iKhushPatel)的驚人內核(https://www.kaggle.com/ikhushpatel/ignite-car-classification-ikhushpatel-khush),以99.18%的準確率成為贏家。他使用了inceptionV3架構,以及CrossEntropyLoss 和SGD優化器。


你可以在inclass competition on Kaggle上參與進來:https://www.kaggle.com/c/virtual-hack/overview


Deep CARs:使用Pytorch學習框架實現遷移學習

留言 點贊 關注

我們一起分享AI學習與發展的乾貨

編譯組:陳曼芳、孫夢琪

相關鏈接:

https://towardsdatascience.com/deep-cars-transfer-learning-with-pytorch-3e7541212e85

如需轉載,請後臺留言,遵守轉載規範

"

相關推薦

推薦中...