迁移学习(基于ResNet18的蜜蜂和蚂蚁分类)
生活随笔
收集整理的這篇文章主要介紹了
迁移学习(基于ResNet18的蜜蜂和蚂蚁分类)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
#實(shí)踐中,受限于數(shù)據(jù)集規(guī)模的約束,我們很少從頭開始端到端的訓(xùn)練一個神經(jīng)網(wǎng)絡(luò)。通常情況下,
# 我們會選擇在ImageNet數(shù)據(jù)集上預(yù)訓(xùn)練好的網(wǎng)絡(luò)模型上進(jìn)行適當(dāng)?shù)男薷?#xff0c;使其適用于目標(biāo)數(shù)據(jù)集。#首先,修改網(wǎng)絡(luò)模型的最后一個全連接層,使其適應(yīng)于目標(biāo)數(shù)據(jù)集,
# 使用預(yù)訓(xùn)練的網(wǎng)絡(luò)權(quán)重來初始化網(wǎng)絡(luò)模型的權(quán)重,用自己的圖像數(shù)據(jù)來微調(diào)訓(xùn)練網(wǎng)絡(luò)。微調(diào)網(wǎng)絡(luò)主要有以下兩種做法:#1.只訓(xùn)練最后一個全連接層,凍結(jié)除最后一個全連接層外的所有層的權(quán)重。
#2.所有網(wǎng)絡(luò)層都參與訓(xùn)練,不過最后一個全連接層在訓(xùn)練時使用更大的學(xué)習(xí)率,通常最后一個全連接層的學(xué)習(xí)率是前面層學(xué)習(xí)率的10倍。#下面基于遷移學(xué)習(xí)實(shí)現(xiàn)一個ResNet18來對蜜蜂和螞蟻分類,點(diǎn)擊這里下載數(shù)據(jù)集。螞蟻和蜜蜂大約均有120幅訓(xùn)練圖像。每個類別有75幅驗(yàn)證圖像。from __future__ import print_function, divisionimport torch
import torch.nn as nn
from torch.optim import lr_scheduler
from torchvision import datasets, models, transforms
import time
import os
import copy# 是否使用gpu運(yùn)算
use_gpu = torch.cuda.is_available()
# 數(shù)據(jù)預(yù)處理,Pytorch提供了一個數(shù)據(jù)預(yù)處理的操作對象。定義如下:
data_transforms = {'train': transforms.Compose([# 隨機(jī)在圖像上裁剪出224*224大小的圖像transforms.RandomResizedCrop(224),# 將圖像隨機(jī)翻轉(zhuǎn)transforms.RandomHorizontalFlip(),# 將圖像數(shù)據(jù),轉(zhuǎn)換為網(wǎng)絡(luò)訓(xùn)練所需的tensor向量transforms.ToTensor(),# 圖像歸一化處理# 個人理解,前面是3個通道的均值,后面是3個通道的方差transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),'val': transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),
}# 讀取數(shù)據(jù)
# 這種數(shù)據(jù)讀取方法,需要有train和val兩個文件夾,
# 每個文件夾下一類圖像存在一個文件夾下
#在對分類的數(shù)據(jù)進(jìn)行處理的時候,可以使用Pytorch提供的ImageFolder類來實(shí)現(xiàn)數(shù)據(jù)預(yù)處理。
#首先需要定義數(shù)據(jù)集的根目錄:
data_dir = '../data/hymenoptera_data'
#然后,對于train和val這兩個分別使用ImageFolder處理.這時,ImageFolder已經(jīng)完成了照片數(shù)據(jù)的分類,并將這些圖片的分類信息放倒了image_datasets變量中,
#可以看到,ImageFolder類已經(jīng)將ants,bees做好了分類,并賦值為0和1。并且,訓(xùn)練數(shù)據(jù)以及測試數(shù)據(jù)被很好的分開。
#data_transforms對象在ImageFolder進(jìn)行數(shù)據(jù)處理的時候作為參數(shù)傳入,可以將上面數(shù)據(jù)處理的代碼改為如下形式:
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),data_transforms[x])for x in ['train', 'val']}#有了ImageFolder獲取到的image_datasets,這里只是找到了數(shù)據(jù)的路徑以及相對應(yīng)的類別,
# Pytorch還提供了DataLoader類,用于在訓(xùn)練時,實(shí)時獲取數(shù)據(jù)對應(yīng)的訓(xùn)練數(shù)據(jù)。代碼如下:
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,shuffle=True, num_workers=4)for x in ['train', 'val']}
#DataLoader的第一個參數(shù)為上面獲取到的image_datasets,第二個參數(shù)為batch_size,
#表示的是批訓(xùn)練時每批樣本的數(shù)量。參數(shù)shuffle表示的是是否打亂數(shù)據(jù)的順序,True表示打亂。參數(shù)num_workers表示參與計算的CPU核心數(shù)。# 讀取數(shù)據(jù)集大小 train:244,val:153
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
# 數(shù)據(jù)類別 ['ants','bees']
class_names = image_datasets['train'].classes# 訓(xùn)練與驗(yàn)證網(wǎng)絡(luò)(所有層都參加訓(xùn)練)
def train_model(model, criterion, optimizer, scheduler, num_epochs):since = time.time() #返回的是毫秒# 保存網(wǎng)絡(luò)訓(xùn)練最好的權(quán)重best_model_wts = copy.deepcopy(model.state_dict())best_acc = 0.0for epoch in range(num_epochs):print('Epoch {}/{}'.format(epoch, num_epochs - 1))print('-' * 10)# 每訓(xùn)練一個epoch,測試一下網(wǎng)絡(luò)模型的準(zhǔn)確率for phase in ['train', 'val']: #phase=='train'if phase == 'train':# 學(xué)習(xí)率更新方式scheduler.step()# 調(diào)用模型訓(xùn)練model.train(True)else:# 調(diào)用模型測試model.train(False)running_loss = 0.0running_corrects = 0# 依次獲取所有圖像,參與模型訓(xùn)練或測試for data in dataloaders[phase]:# 獲取輸入inputs, labels = data# 判斷是否使用gpuif use_gpu:inputs = inputs.cuda()labels = labels.cuda()# 梯度清零optimizer.zero_grad()# 網(wǎng)絡(luò)前向運(yùn)行outputs = model(inputs)_, preds = torch.max(outputs.data, 1) #獲取最大值索引# 計算Loss值,交叉熵?fù)p失函數(shù),其內(nèi)部會自動加上Sofrmax層loss = criterion(outputs, labels)# 反傳梯度,更新權(quán)重if phase == 'train':# 反傳梯度loss.backward()# 更新權(quán)重optimizer.step()# 計算一個epoch的loss值和準(zhǔn)確率,inputs.size(0)=4,running_loss += loss.item() * inputs.size(0)running_corrects += torch.sum(preds == labels.data)# 計算Loss和準(zhǔn)確率的均值epoch_loss = running_loss / dataset_sizes[phase]epoch_acc = float(running_corrects) / dataset_sizes[phase]print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))# 保存測試階段,準(zhǔn)確率最高的模型if phase == 'val' and epoch_acc > best_acc:best_acc = epoch_accbest_model_wts = copy.deepcopy(model.state_dict())time_elapsed = time.time() - sinceprint('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))print('Best val Acc: {:4f}'.format(best_acc))# 網(wǎng)絡(luò)導(dǎo)入最好的網(wǎng)絡(luò)權(quán)重model.load_state_dict(best_model_wts)return model# 微調(diào)網(wǎng)絡(luò)
if __name__ == '__main__':# 導(dǎo)入Pytorch中自帶的resnet18網(wǎng)絡(luò)模型model_ft = models.resnet18(pretrained=True)# 將網(wǎng)絡(luò)模型的各層的梯度更新置為Falsefor param in model_ft.parameters():param.requires_grad = False# 修改網(wǎng)絡(luò)模型的最后一個全連接層# 獲取最后一個全連接層的輸入通道數(shù)num_ftrs = model_ft.fc.in_features# 修改最后一個全連接層的的輸出數(shù)為2model_ft.fc = nn.Linear(num_ftrs, 2)# 是否使用gpuif use_gpu:model_ft = model_ft.cuda()# 定義網(wǎng)絡(luò)模型的損失函數(shù)criterion = nn.CrossEntropyLoss()# 只訓(xùn)練最后一個層# 采用隨機(jī)梯度下降的方式,來優(yōu)化網(wǎng)絡(luò)模型optimizer_ft = torch.optim.SGD(model_ft.fc.parameters(), lr=0.001, momentum=0.9)# 定義學(xué)習(xí)率的更新方式,每5個epoch修改一次學(xué)習(xí)率exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=5, gamma=0.1)# 訓(xùn)練網(wǎng)絡(luò)模型model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler, num_epochs=10)# 存儲網(wǎng)絡(luò)模型的權(quán)重torch.save(model_ft.state_dict(),"model_only_fc.pkl")
總結(jié)
以上是生活随笔為你收集整理的迁移学习(基于ResNet18的蜜蜂和蚂蚁分类)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 遇到“该网页无法正常运作”,利用php的
- 下一篇: 腾讯阿里的螺丝钉,一样会生锈!