JETBOT- collision_avoidance /Train Model

  • 這裡會使用 Pytorch 官方維護的資源庫-- Torchvision裡面主要收錄三大類資源,包括有名、常用的 Dataset常見的 Image transform 工具 ;以及有名、常用的 Model Architecture,這個範例就是使用alexnet。


  • 在這個遷移學習的過程中,我們把預先訓練過的模型(這模型之前可能是經過海量資料訓練過的)重新用比較少的資料進行訓練,在預先被訓練模型的原始訓練中學到的重要特徵可重新被用於新任務上。



簡單說,這個範例我們將使用 alexnet 模型架構,我們匯入alexnet模型並使用少量的照片,利用原本alexnet模型的特徵值來重新訓練,在把這個模型套用在新的任務上。


  • 這個Alexnet模型本來是被訓練用在有1000各類別標籤的資料集上的,但是我們的資料集上只有兩個類別標籤,所以我們將用一個新的、未經訓練的layer(只有兩個輸出的)來替換最後一層的layer。最後再把這模型傳送到GPU(CUDA)上去執行。

  • CUDACompute Unified Device Architecture,統一計算架構[1])是由輝達NVIDIA所推出的一種整合技術,是該公司對於GPGPU的正式名稱。透過這個技術,使用者可利用NVIDIA的GeForce 8以後的GPU和較新的Quadro GPU進行計算。亦是首次可以利用GPU作為C-編譯器的開發環境。NVIDIA行銷的時候[2],往往將編譯器與架構混合推廣,造成混亂。實際上,CUDA可以相容OpenCL或者自家的C-編譯器。無論是CUDA C-語言或是OpenCL,指令最終都會被驅動程式轉換成PTX代碼,交由顯示核心計算。[3]

  • https://zh.wikipedia.org/wiki/CUDA


訓練的程序(這裡是用alexnet來訓練dataset)


簡單說就是:引入 (import) Torchvision→使用 dataset→使用 Dataloader→使用 Model

程式碼詳細步驟:

  • 先匯入重新訓練模型需要的函式庫

  • 準備好要訓練的圖形資料(dataset)

  • 建立資料集的實例/體(dataset instance)

    • 使用 torchvision.datasets 包中提供的 ImageFolder 數據集類別(class),而且附加了從torchvision.transforms package 用來準備做訓練的資料,把資料進行轉換。

  • 把資料集分割為訓練與測試兩個子集

  • 建立資料加載器來批次載入資料

    • 創建兩個 DataLoader 容器(instance):train跟test兩個,這容器提供打亂數據、生成批量圖像的工具,而且在多線程下載入這些樣本。

    • 這裡一次放16筆資料(batch size),可以調整batch size的大小來提高精準度,同時Epochs也可以條小

  • 定義神經網路

    • 載入alexnet模型再用新的資料作訓練,並把最後一層的改為兩個輸出。

    • 再把訓練好的模型載入,放到GPU去做執行

  • 最後開始訓練神經網路

    • 這裡設定把資料丟進去做30期的訓練(EPOCHS)

    • 並做最佳化

#匯入會使用到的函式庫

#先引入pytroch跟torchvision

import torch

import torchvision

import torch.optim as optim

import torch.nn.functional as F

#我們需要資料集、模型跟轉換

import torchvision.datasets as datasets

import torchvision.models as models

import torchvision.transforms as transforms

  • 要進行模型訓練需要有之前蒐集的檔案,事實上不一定需要每次訓練都重拍,可以彙整大家拍好的照片,只要依照244*244的畫素拍照,經過整理挑選100張或更多,但是檔案數愈多,訓練出來的模型檔案就會愈大。

  • 如果是延續上一個資料蒐集已經蒐集到就不需要執行解壓縮的動作,其實也可以不用壓縮,壓縮是方便備分

  • 練習時候可以使用同一個場地他人已經拍好的照片

  • 但是要注意場地的環境:如燈光、場地位置要相同

!unzip -q dataset.zip

#解壓縮檔案名稱為dataset.zip的資料夾,根據自己的狀況選擇是不是該執行這一行

我們在處理圖片時,常用的方式有兩種:

  1. 所有的圖片都放在同一個資料夾,然後一個文字檔(.txt)做標籤,我印象中teachable machine就是這個方式,這時可以自訂一個Dataset

  2. 不同類別的圖片放在不同的資料夾內,就可以直接使用torchvision.datasets.ImageFolder來處理

官方資料集 https://pytorch.org/vision/stable/datasets.html

#建立名稱為dataset的物件,並使用ImageFolder這個class,讀入dataset的資料

#'dataset'是資料夾名稱,可以視自己的資料夾名稱去修改

#使用 transforms對圖片做處理,這裡的處理是:改變圖像的的屬性、重設圖像大小、轉換成Tensor的型態做標準化處理使模型更容易收敛

dataset = datasets.ImageFolder(

'dataset',

transforms.Compose([

transforms.ColorJitter(0.1, 0.1, 0.1, 0.1),

transforms.Resize((224, 224)),

transforms.ToTensor(),

transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

])

)

#把資料集分為訓練與測試兩個子集

#這兩個子集內的100張隨機取的一半做訓練與測試

#如果數量超過100,就用實際數量除以2

train_dataset, test_dataset = torch.utils.data.random_split(dataset, [len(dataset) - 50, 50])

#這邊就是載入並設定一個batch大小...其實就不用修改,直接使用

#使用 Dataloder 讀進這些 dataset

#依照資料夾屬性建立每張影像歸屬之類別

train_loader = torch.utils.data.DataLoader(

train_dataset, #Tensordataset格式,在上一個cell隨機取50個為train_dataset

batch_size=8, #最小的batch size

shuffle=True, #打亂數據

num_workers=0 #多線程讀取數據

)


test_loader = torch.utils.data.DataLoader(

test_dataset, #Tensordataset格式,在上一個cell隨機取50個為test_dataset

batch_size=8, #最小的batch size

shuffle=True, #打亂數據

num_workers=0 #多線程讀取數據

#定義神經網路,並下載alexnet模型,第一次下載會需要時間,跟據您的網路速度


model = models.alexnet(pretrained=True)

#alexnet這個模型是訓練好的,所以需要透過網路下載,其時我第一次執行時沒看到下載,但保險起見可以多等一下再執行下面的程式碼

#獲取classifier()的最後一个Linear層,更換最底層的輸出為2個輸出


model.classifier[6] = torch.nn.Linear(model.classifier[6].in_features, 2)


#將模型轉移到 GPU 上執行

device = torch.device('cuda')

model = model.to(device)


在神經網路優化器當中,為了優化神經網路,使神經網路在訓練的過程加快,並節省時間,所以Pytorch提供了六種優化的方法(torch.optim )。

有關Pytorch的優化方法有六種,但是可以簡單區分為兩大類:

  • SGD及其改進(加Momentum--動量:即時間累積效益 ---我們這個範例就是使用SGD

  • Per-parameter adaptive learning rate methods(逐參數適應學習率方法),包括AdaGradRMSPropAdam


其中我們使用的SDG,的参数分別是,1)opfunc;2)x;3)config;4)state

#進行神經網路的訓練,會產出一個best_model.pth(可以改名字),檔案大小近300MB,所以需要等待幾分鐘

NUM_EPOCHS = 30

BEST_MODEL_PATH = 'best_model.pth'

best_accuracy = 0.0

#建構優化器來進行優化,保存目前的參數狀態並且基於計算梯度來進行更新

optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

#model.parameters()是用來把建構好的神經網路參數都存放在parameters()中,另外學習率(梯度下向速率)與momentum是動量

for epoch in range(NUM_EPOCHS):

#以下開始進行優化

for images, labels in iter(train_loader):

images = images.to(device)

labels = labels.to(device)

optimizer.zero_grad()

outputs = model(images)

loss = F.cross_entropy(outputs, labels)

loss.backward() #用backward方法來計算梯度

optimizer.step() #以step()方法來對優化器更新

test_error_count = 0.0

for images, labels in iter(test_loader): #iter()使用迭代器

images = images.to(device)

labels = labels.to(device)

outputs = model(images)

test_error_count += float(torch.sum(torch.abs(labels - outputs.argmax(1))))

test_accuracy = 1.0 - float(test_error_count) / float(len(test_dataset))

print('%d: %f' % (epoch, test_accuracy))

if test_accuracy > best_accuracy:

torch.save(model.state_dict(), BEST_MODEL_PATH)

best_accuracy = test_accuracy


接下來就是等待產出,休息一下吧