优达学城《DeepLearning》2-2:迁移学习
目錄
加載和預(yù)處理數(shù)據(jù)
轉(zhuǎn)換數(shù)據(jù)
數(shù)據(jù)加載器和數(shù)據(jù)可視化
定義模型
最終分類器層
指定損失函數(shù)和優(yōu)化器
訓練
測試
可視化樣本測試結(jié)果
大多數(shù)時候,你不會想自己訓練一個完整的卷積網(wǎng)絡(luò)。像ImageNet這樣的大型數(shù)據(jù)集上的現(xiàn)代卷積網(wǎng)絡(luò)訓練需要在多個gpu上花費數(shù)周時間。
作為替代,大多數(shù)人使用預(yù)先訓練好的網(wǎng)絡(luò)作為固定的特征提取器,或者作為初始網(wǎng)絡(luò)進行微調(diào)。
在本筆記本中,您將使用在ImageNet數(shù)據(jù)集上訓練的VGGNet作為特征提取器。下面是VGGNet體系結(jié)構(gòu)的示意圖,有一系列卷積層和最大池層,最后是三個完全連接的層,它們對ImageNet數(shù)據(jù)庫中的1000個類進行了分類。
VGGNet之所以偉大,是因為它簡單且性能優(yōu)異,在ImageNet的競爭中曾名列第二。這里的想法是我們保留所有的卷積層,但是用我們自己的分類器替換最后一個完全連接的層。通過這種方式,我們可以使用VGGNet作為圖像的固定特征提取器,然后在此基礎(chǔ)上輕松地訓練一個簡單的分類器。
- 使用除最后一個全連接層以外的所有層作為固定的特征提取器。
- 定義一個新的、最終的分類層,并將其應(yīng)用到我們選擇的任務(wù)中!
你可以從CS231n斯坦福課程筆記中關(guān)于遷移學習的內(nèi)容。
這里我們將使用VGGNet對花的圖像進行分類。我們將像往常一樣,從導(dǎo)入我們通常的數(shù)據(jù)集開始。然后檢查是否可以在GPU上訓練我們的模型。
加載和預(yù)處理數(shù)據(jù)
我們將使用PyTorch的ImageFolder類,這使得從目錄加載數(shù)據(jù)非常容易。例如,訓練圖像都存儲在如下目錄路徑中:
其中,在本例中,training的根文件夾是flower_photos/train/,類別名是花類型的名稱。
轉(zhuǎn)換數(shù)據(jù)
當我們進行遷移學習時,我們必須將輸入數(shù)據(jù)改造成預(yù)先訓練好的模型所期望的形狀。VGG16需要224維度的正方形圖像作為輸入,因此,我們調(diào)整每個花圖像的大小以適應(yīng)這個模型。
數(shù)據(jù)加載器和數(shù)據(jù)可視化
定義模型
為了定義一個訓練模型,我們將遵循以下步驟:
- 1.加載一個預(yù)先訓練過的VGG16模型
- 2.凍結(jié)所有參數(shù),使網(wǎng)絡(luò)充當一個固定的特征提取器
- 3.刪除最后一層
- 4.用我們自己的線性分類器替換最后一層
凍結(jié)僅僅意味著預(yù)訓練模型中的參數(shù)在訓練過程中不會改變。
打印結(jié)果:
Downloading: "https://download.pytorch.org/models/vgg16-397923af.pth" to C:\Users\yinm/.cache\torch\hub\checkpoints\vgg16-397923af.pth
100%|██████████| 528M/528M [03:56<00:00, 2.34MB/s]
VGG((features): Sequential((0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True)(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(6): ReLU(inplace=True)(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(8): ReLU(inplace=True)(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(11): ReLU(inplace=True)(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(13): ReLU(inplace=True)(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(15): ReLU(inplace=True)(16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(18): ReLU(inplace=True)(19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(20): ReLU(inplace=True)(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(22): ReLU(inplace=True)(23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(25): ReLU(inplace=True)(26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(27): ReLU(inplace=True)(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(29): ReLU(inplace=True)(30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False))(avgpool): AdaptiveAvgPool2d(output_size=(7, 7))(classifier): Sequential((0): Linear(in_features=25088, out_features=4096, bias=True)(1): ReLU(inplace=True)(2): Dropout(p=0.5, inplace=False)(3): Linear(in_features=4096, out_features=4096, bias=True)(4): ReLU(inplace=True)(5): Dropout(p=0.5, inplace=False)(6): Linear(in_features=4096, out_features=1000, bias=True))
)
最終分類器層
您可以通過名稱和(有時)編號訪問預(yù)訓練網(wǎng)絡(luò)中的任何層,例如:vgg16.classifier[6]是名為 “classifier” 層組中的第六層。
TODO:將最后一個全連接的層替換為適當數(shù)量的類輸出層。
指定損失函數(shù)和優(yōu)化器
下面我們將使用交叉熵損失和小學習率的隨機梯度下降。注意,優(yōu)化器只接受可訓練參數(shù)vgg.classifier.parameters()作為輸入。
訓練
在這里,我們將訓練網(wǎng)絡(luò)。
練習:到目前為止,我們已經(jīng)為您提供了訓練代碼。在這里,我將給你一個更大的挑戰(zhàn),讓你寫代碼來訓練網(wǎng)絡(luò)。當然,如果你需要幫助,你可以看到我的解決方案。
# number of epochs to train the model
n_epochs = 2## TODO complete epoch and training batch loops
## These loops should update the classifier-weights of this model
## And track (and print out) the training loss over timefor epoch in range(1, n_epochs + 1):train_loss = 0.0 # 每n個batch的平均損失for batch_i, (data, target) in enumerate(train_loader):if train_on_gpu:data, target = data.cuda(), target.cuda()optimizer.zero_grad() #清除優(yōu)化器中梯度output = vgg16(data) #前向傳播loss = criterion(output, target)#計算損失loss.backward() #反向傳播optimizer.step() # 參數(shù)更新train_loss += loss.item() #累計本批次損失if batch_i % 20 == 19:print('Epoch %d, Batch %d loss: %.16f' % (epoch, batch_i + 1, train_loss/20))train_loss = 0.0
結(jié)果:
測試
下面是每個flower類的測試精度。
# track test loss
# over 5 flower classes
test_loss = 0.0
class_correct = list(0. for i in range(5))
class_total = list(0. for i in range(5))vgg16.eval() # eval mode# iterate over test data
for data, target in test_loader:# move tensors to GPU if CUDA is availableif train_on_gpu:data, target = data.cuda(), target.cuda()# forward pass: compute predicted outputs by passing inputs to the modeloutput = vgg16(data)# calculate the batch lossloss = criterion(output, target)# update test loss test_loss += loss.item()*data.size(0)# convert output probabilities to predicted class_, pred = torch.max(output, 1) # compare predictions to true labelcorrect_tensor = pred.eq(target.data.view_as(pred))correct = np.squeeze(correct_tensor.numpy()) if not train_on_gpu else np.squeeze(correct_tensor.cpu().numpy())# calculate test accuracy for each object classfor i in range(batch_size):if i >= len(target): #防止最后一個batch不夠20個。continuelabel = target.data[i]class_correct[label] += correct[i].item()class_total[label] += 1# calculate avg test loss
test_loss = test_loss/len(test_loader.dataset)
print('Test Loss: {:.6f}\n'.format(test_loss))for i in range(5):if class_total[i] > 0:print('Test Accuracy of %5s: %2d%% (%2d/%2d)' % (classes[i], 100 * class_correct[i] / class_total[i],np.sum(class_correct[i]), np.sum(class_total[i])))else:print('Test Accuracy of %5s: N/A (no training examples)' % (classes[i]))print('\nTest Accuracy (Overall): %2d%% (%2d/%2d)' % (100. * np.sum(class_correct) / np.sum(class_total),np.sum(class_correct), np.sum(class_total)))
結(jié)果:
可視化樣本測試結(jié)果
?
?
?
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的优达学城《DeepLearning》2-2:迁移学习的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 优达学城《DeepLearning》2-
- 下一篇: 优达学城《DeepLearning》2-