參考:https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.htmlhtml
如下是兩種主要的遷移學習場景python
一開始先導入須要的包:網絡
# License: BSD # Author: Sasank Chilamkurthy from __future__ import print_function, division import torch import torch.nn as nn import torch.optim as optim from torch.optim import lr_scheduler import numpy as np import torchvision from torchvision import datasets, models, transforms import matplotlib.pyplot as plt import time import os import copy plt.ion() # 交互模式
1)下載數據app
將會使用torchvision和torch.utils.data包去下載數據dom
今天咱們 要解決的問題是創建一個模型去分類螞蟻和蜜蜂。對於螞蟻和蜜蜂,咱們分別有大約120張訓練圖片。對於每一個類有75張驗證圖像。一般,若是從零開始訓練,這是一個很是小的數據集。因爲使用了遷移學習,咱們應該可以很好地歸納。
這個數據集是imagenet的一個很是小的子集。python2.7
⚠️從 here下載數據集,並將其從當前目錄中抽取出來函數
# 爲訓練對數據進行擴充和規範化,其實就是經過剪切,翻轉等方法來擴充數據集的大小 # 驗證只進行規範化 data_transforms = { 'train': transforms.Compose([ #將多個transform組合起來使用 transforms.RandomResizedCrop(224), #將給定的圖片隨機切,而後再resize成給定的size=224大小 transforms.RandomHorizontalFlip(), #圖片有一半機率進行翻轉,另外一半機率不翻轉 transforms.ToTensor(), #將圖片的像素值[0,255]轉成取值範圍爲[0,1]的tensor transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) #兩個參數分別表明均值mean和方差std,有三個值是對應三類像素image=[R,G,B],Normalized_image=(image-mean)/std ]), 'val': transforms.Compose([ transforms.Resize(256), #改變大小 transforms.CenterCrop(224), #進行中心切割,獲得給定的size,切出來的圖形形狀是正方形的 transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), } data_dir = './data/hymenoptera_data' image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),data_transforms[x]) for x in ['train', 'val']} dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,shuffle=True, num_workers=4) for x in ['train', 'val']} dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']} class_names = image_datasets['train'].classes #若是有CUDA則使用它,不然使用CPU device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
2)可視化一些圖像學習
讓咱們可視化一些訓練圖像,以便理解數據擴充。優化
def imshow(inp, title=None): """Imshow for Tensor.""" inp = inp.numpy().transpose((1, 2, 0)) mean = np.array([0.485, 0.456, 0.406]) std = np.array([0.229, 0.224, 0.225]) inp = std * inp + mean inp = np.clip(inp, 0, 1) plt.imshow(inp) if title is not None: plt.title(title) plt.pause(0.001) # 暫停一下,以便更新繪圖 # 得到一批訓練數據 inputs, classes = next(iter(dataloaders['train'])) # Make a grid from batch out = torchvision.utils.make_grid(inputs) imshow(out, title=[class_names[x] for x in classes])
運行到這裏的時候就會顯示以下圖所示的圖像:ui
3)訓練模型
如今,讓咱們編寫一個通用函數來訓練模型。在這裏,咱們將舉例說明:
在下面,變量scheduler是一個來自torch.optim.lr_scheduler的LR調度對象,
def train_model(model, criterion, optimizer, scheduler, num_epochs=25): since = time.time() best_model_wts = copy.deepcopy(model.state_dict()) best_acc = 0.0 for epoch in range(num_epochs): print('Epoch {}/{}'.format(epoch, num_epochs - 1)) print('-' * 10) # 每一個週期都有一個訓練和驗證階段 for phase in ['train', 'val']: if phase == 'train': scheduler.step() model.train() # 設置模型爲訓練模式 else: model.eval() # 設置模型爲評估模式 running_loss = 0.0 running_corrects = 0 #迭代數據 for inputs, labels in dataloaders[phase]: inputs = inputs.to(device) labels = labels.to(device) # zero the parameter gradients optimizer.zero_grad() # forward # 若是隻是在訓練要追蹤歷史 with torch.set_grad_enabled(phase == 'train'): outputs = model(inputs) _, preds = torch.max(outputs, 1) loss = criterion(outputs, labels) # backward + optimize ,僅在訓練階段 if phase == 'train': loss.backward() optimizer.step() # 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] print('{} Loss: {:.4f} Acc: {:.4f}'.format( phase, epoch_loss, epoch_acc)) # 深度拷貝模型 if phase == 'val' and epoch_acc > best_acc: best_acc = epoch_acc best_model_wts = copy.deepcopy(model.state_dict()) print() time_elapsed = time.time() - since print('Training complete in {:.0f}m {:.0f}s'.format( time_elapsed // 60, time_elapsed % 60)) print('Best val Acc: {:4f}'.format(best_acc)) # 下載最好的模型權重 model.load_state_dict(best_model_wts) return model
4)可視化模型預測
泛型函數,顯示對一些圖像的預測
def visualize_model(model, num_images=6): was_training = model.training model.eval() images_so_far = 0 fig = plt.figure() with torch.no_grad(): for i, (inputs, labels) in enumerate(dataloaders['val']): inputs = inputs.to(device) labels = labels.to(device) outputs = model(inputs) _, preds = torch.max(outputs, 1) for j in range(inputs.size()[0]): images_so_far += 1 ax = plt.subplot(num_images//2, 2, images_so_far) ax.axis('off') ax.set_title('predicted: {}'.format(class_names[preds[j]])) imshow(inputs.cpu().data[j]) if images_so_far == num_images: model.train(mode=was_training) return model.train(mode=was_training)
5)
1》微調convent
下載預訓練模型並從新設置最後的全鏈接層
model_ft = models.resnet18(pretrained=True) num_ftrs = model_ft.fc.in_features model_ft.fc = nn.Linear(num_ftrs, 2) model_ft = model_ft.to(device) criterion = nn.CrossEntropyLoss() # 觀察到全部參數都被優化 optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9) # 每7個週期,LR衰減0.1倍 exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
2》訓練和評估
CPU可能會使用15-25分鐘。若是使用的是GPU,將花費少於一分鐘
model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler, num_epochs=25)
⚠️使用的python2.7,若是使用的是python3則會報錯:
(deeplearning) userdeMBP:neural transfer user$ python neural_style_tutorial.py 2019-03-13 19:30:06.194 python[4926:206321] -[NSApplication _setup:]: unrecognized selector sent to instance 0x7f8eb4895080 2019-03-13 19:30:06.199 python[4926:206321] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSApplication _setup:]: unrecognized selector sent to instance 0x7f8eb4895080'
終端運行:(我是在CPU上運行的)
(deeplearning2) userdeMBP:transfer learning user$ python transfer_learning_tutorial.py Downloading: "https://download.pytorch.org/models/resnet18-5c106cde.pth" to /Users/user/.torch/models/resnet18-5c106cde.pth 100.0% Epoch 0/24 ---------- train Loss: 0.5703 Acc: 0.7049 val Loss: 0.2565 Acc: 0.9020 Epoch 1/24 ---------- train Loss: 0.6009 Acc: 0.7951 val Loss: 0.3604 Acc: 0.8627 Epoch 2/24 ---------- train Loss: 0.5190 Acc: 0.7869 val Loss: 0.4421 Acc: 0.8105 Epoch 3/24 ---------- train Loss: 0.5072 Acc: 0.7910 val Loss: 0.4037 Acc: 0.8431 Epoch 4/24 ---------- train Loss: 0.6503 Acc: 0.7869 val Loss: 0.2961 Acc: 0.9085 Epoch 5/24 ---------- train Loss: 0.3840 Acc: 0.8730 val Loss: 0.2648 Acc: 0.8954 Epoch 6/24 ---------- train Loss: 0.6137 Acc: 0.7705 val Loss: 0.6852 Acc: 0.8170 Epoch 7/24 ---------- train Loss: 0.4130 Acc: 0.8279 val Loss: 0.3730 Acc: 0.8954 Epoch 8/24 ---------- train Loss: 0.3953 Acc: 0.8648 val Loss: 0.3300 Acc: 0.9216 Epoch 9/24 ---------- train Loss: 0.2753 Acc: 0.8934 val Loss: 0.2949 Acc: 0.9020 Epoch 10/24 ---------- train Loss: 0.3192 Acc: 0.8648 val Loss: 0.2984 Acc: 0.9020 Epoch 11/24 ---------- train Loss: 0.2942 Acc: 0.8852 val Loss: 0.2624 Acc: 0.9150 Epoch 12/24 ---------- train Loss: 0.2738 Acc: 0.8811 val Loss: 0.2855 Acc: 0.9020 Epoch 13/24 ---------- train Loss: 0.2697 Acc: 0.8648 val Loss: 0.2675 Acc: 0.9020 Epoch 14/24 ---------- train Loss: 0.2534 Acc: 0.9016 val Loss: 0.2780 Acc: 0.9085 Epoch 15/24 ---------- train Loss: 0.2514 Acc: 0.8811 val Loss: 0.2873 Acc: 0.9020 Epoch 16/24 ---------- train Loss: 0.2430 Acc: 0.9098 val Loss: 0.2901 Acc: 0.9085 Epoch 17/24 ---------- train Loss: 0.2970 Acc: 0.8402 val Loss: 0.2570 Acc: 0.9150 Epoch 18/24 ---------- train Loss: 0.2779 Acc: 0.8934 val Loss: 0.2792 Acc: 0.9085 Epoch 19/24 ---------- train Loss: 0.2271 Acc: 0.9262 val Loss: 0.2655 Acc: 0.9150 Epoch 20/24 ---------- train Loss: 0.2741 Acc: 0.8975 val Loss: 0.2726 Acc: 0.9085 Epoch 21/24 ---------- train Loss: 0.3221 Acc: 0.8320 val Loss: 0.2738 Acc: 0.9150 Epoch 22/24 ---------- train Loss: 0.2228 Acc: 0.9139 val Loss: 0.2712 Acc: 0.9020 Epoch 23/24 ---------- train Loss: 0.2881 Acc: 0.8975 val Loss: 0.2565 Acc: 0.9150 Epoch 24/24 ---------- train Loss: 0.3219 Acc: 0.8648 val Loss: 0.2669 Acc: 0.9150 Training complete in 16m 22s Best val Acc: 0.921569
實現可視化:
visualize_model(model_ft)
第一次返回圖像爲:
6)
1》將ConvNet做爲固定的特徵提取器
這裏咱們須要將除了最後一層的全部網絡凍結。咱們須要設置requires_grad == False去凍結參數以便梯度在backward()中不會被計算
咱們能夠從here讀取更詳細的內容
model_conv = torchvision.models.resnet18(pretrained=True) for param in model_conv.parameters(): param.requires_grad = False # 最新構造函數的參數默認設置requires_grad=True num_ftrs = model_conv.fc.in_features model_conv.fc = nn.Linear(num_ftrs, 2) model_conv = model_conv.to(device) criterion = nn.CrossEntropyLoss() # 觀察到與以前相比,只有最後一層的參數被優化 optimizer_conv = optim.SGD(model_conv.fc.parameters(), lr=0.001, momentum=0.9) # 每7個週期,LR衰減0.1倍 exp_lr_scheduler = lr_scheduler.StepLR(optimizer_conv, step_size=7, gamma=0.1)
2》訓練和評估
在CPU上,與以前的場景相比,這將只花費大約其一半的時間。由於這預期了對於大部分網絡梯度不須要計算。固然forward仍是須要計算的
model_conv = train_model(model_conv, criterion, optimizer_conv, exp_lr_scheduler, num_epochs=25)
接下來繼續訓練:(我是在CPU上運行的)
Epoch 0/24 ---------- train Loss: 0.6719 Acc: 0.6516 val Loss: 0.2252 Acc: 0.9281 Epoch 1/24 ---------- train Loss: 0.6582 Acc: 0.7254 val Loss: 0.4919 Acc: 0.7778 Epoch 2/24 ---------- train Loss: 0.5313 Acc: 0.8115 val Loss: 0.2488 Acc: 0.9085 Epoch 3/24 ---------- train Loss: 0.5134 Acc: 0.7623 val Loss: 0.1881 Acc: 0.9412 Epoch 4/24 ---------- train Loss: 0.3834 Acc: 0.8525 val Loss: 0.2220 Acc: 0.9085 Epoch 5/24 ---------- train Loss: 0.5442 Acc: 0.7910 val Loss: 0.2865 Acc: 0.8954 Epoch 6/24 ---------- train Loss: 0.6136 Acc: 0.7213 val Loss: 0.2915 Acc: 0.9085 Epoch 7/24 ---------- train Loss: 0.3393 Acc: 0.8730 val Loss: 0.1839 Acc: 0.9542 Epoch 8/24 ---------- train Loss: 0.3616 Acc: 0.8156 val Loss: 0.1967 Acc: 0.9346 Epoch 9/24 ---------- train Loss: 0.3798 Acc: 0.8402 val Loss: 0.1903 Acc: 0.9542 Epoch 10/24 ---------- train Loss: 0.3918 Acc: 0.8320 val Loss: 0.1860 Acc: 0.9477 Epoch 11/24 ---------- train Loss: 0.3950 Acc: 0.8115 val Loss: 0.1803 Acc: 0.9542 Epoch 12/24 ---------- train Loss: 0.3094 Acc: 0.8566 val Loss: 0.1978 Acc: 0.9542 Epoch 13/24 ---------- train Loss: 0.2791 Acc: 0.8811 val Loss: 0.1932 Acc: 0.9542 Epoch 14/24 ---------- train Loss: 0.3797 Acc: 0.8484 val Loss: 0.2318 Acc: 0.9346 Epoch 15/24 ---------- train Loss: 0.3456 Acc: 0.8689 val Loss: 0.1965 Acc: 0.9412 Epoch 16/24 ---------- train Loss: 0.4585 Acc: 0.7910 val Loss: 0.2264 Acc: 0.9346 Epoch 17/24 ---------- train Loss: 0.3889 Acc: 0.8566 val Loss: 0.1847 Acc: 0.9477 Epoch 18/24 ---------- train Loss: 0.3636 Acc: 0.8361 val Loss: 0.2680 Acc: 0.9346 Epoch 19/24 ---------- train Loss: 0.2616 Acc: 0.8730 val Loss: 0.1892 Acc: 0.9477 Epoch 20/24 ---------- train Loss: 0.3114 Acc: 0.8648 val Loss: 0.2295 Acc: 0.9346 Epoch 21/24 ---------- train Loss: 0.3597 Acc: 0.8443 val Loss: 0.1857 Acc: 0.9477 Epoch 22/24 ---------- train Loss: 0.3794 Acc: 0.8402 val Loss: 0.1822 Acc: 0.9477 Epoch 23/24 ---------- train Loss: 0.3553 Acc: 0.8279 val Loss: 0.1992 Acc: 0.9608 Epoch 24/24 ---------- train Loss: 0.3514 Acc: 0.8238 val Loss: 0.2144 Acc: 0.9346 Training complete in 13m 33s Best val Acc: 0.960784
實現可視化:
visualize_model(model_conv) plt.ioff() plt.show()
返回圖像爲: