PyTorch中圖像多分類的實(shí)現(xiàn)
多類圖像分類的目標(biāo)是為一組固定類別中的圖像分配標(biāo)簽。
加載和處理數(shù)據(jù)
將使用 PyTorch torchvision 包中提供的 STL-10 數(shù)據(jù)集,數(shù)據(jù)集中有 10 個(gè)類:飛機(jī)、鳥、車、貓、鹿、狗、馬、猴、船、卡車。圖像為96*96像素的RGB圖像。數(shù)據(jù)集包含 5,000 張訓(xùn)練圖像和 8,000 張測試圖像。在訓(xùn)練數(shù)據(jù)集和測試數(shù)據(jù)集中,每個(gè)類分別有 500 和 800 張圖像。
from torchvision import datasets import torchvision.transforms as transforms import os path2data="./data" # 如果數(shù)據(jù)路徑不存在,則創(chuàng)建 if not os.path.exists(path2data): os.mkdir(path2data) # 定義數(shù)據(jù)轉(zhuǎn)換 data_transformer = transforms.Compose([transforms.ToTensor()]) # 從datasets庫中導(dǎo)入STL10數(shù)據(jù)集,并指定數(shù)據(jù)集的路徑、分割方式、是否下載以及數(shù)據(jù)轉(zhuǎn)換器 train_ds=datasets.STL10(path2data, split='train',download=True,transform=data_transformer) # 打印數(shù)據(jù)形狀 print(train_ds.data.shape)
若數(shù)據(jù)集導(dǎo)入較慢可直接下載:http://ai.stanford.edu/~acoates/stl10/stl10_binary.tar.gz
import collections # 獲取標(biāo)簽 y_train=[y for _,y in train_ds] # 統(tǒng)計(jì)標(biāo)簽 counter_train=collections.Counter(y_train) print(counter_train)
# 加載數(shù)據(jù) test0_ds=datasets.STL10(path2data, split='test', download=True,transform=data_transformer) # 打印數(shù)據(jù)形狀 print(test0_ds.data.shape)
# 導(dǎo)入StratifiedShuffleSplit模塊 from sklearn.model_selection import StratifiedShuffleSplit # 創(chuàng)建StratifiedShuffleSplit對(duì)象,設(shè)置分割次數(shù)為1,測試集大小為0.2,隨機(jī)種子為0 sss = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=0) # 獲取test0_ds的索引 indices=list(range(len(test0_ds))) # 獲取test0_ds的標(biāo)簽 y_test0=[y for _,y in test0_ds] # 對(duì)索引和標(biāo)簽進(jìn)行分割 for test_index, val_index in sss.split(indices, y_test0): # 打印測試集和驗(yàn)證集的索引 print("test:", test_index, "val:", val_index) # 打印測試集和驗(yàn)證集的大小 print(len(val_index),len(test_index))
# 從torch.utils.data中導(dǎo)入Subset類 from torch.utils.data import Subset # 從test0_ds中選取val_index索引的子集,賦值給val_ds val_ds=Subset(test0_ds,val_index) # 從test0_ds中選取test_index索引的子集,賦值給test_ds test_ds=Subset(test0_ds,test_index) import collections import numpy as np # 獲取標(biāo)簽 y_test=[y for _,y in test_ds] y_val=[y for _,y in val_ds] # 統(tǒng)計(jì)測試集和驗(yàn)證集的標(biāo)簽數(shù)量 counter_test=collections.Counter(y_test) counter_val=collections.Counter(y_val) # 打印測試集和驗(yàn)證集的標(biāo)簽數(shù)量 print(counter_test) print(counter_val)
from torchvision import utils import matplotlib.pyplot as plt import numpy as np %matplotlib inline # 設(shè)置隨機(jī)種子為0 np.random.seed(0) # 定義一個(gè)函數(shù),用于顯示圖像 def show(img,y=None,color=True): # 將圖像轉(zhuǎn)換為numpy數(shù)組 npimg = img.numpy() # 將圖像的維度從(C,H,W)轉(zhuǎn)換為(H,W,C) npimg_tr=np.transpose(npimg, (1,2,0)) # 顯示圖像 plt.imshow(npimg_tr) # 如果有標(biāo)簽,則顯示標(biāo)簽 if y is not None: plt.title("label: "+str(y)) # 定義網(wǎng)格大小 grid_size=4 # 隨機(jī)生成4個(gè)索引 rnd_inds=np.random.randint(0,len(train_ds),grid_size) print("image indices:",rnd_inds) # 從訓(xùn)練集中獲取這4個(gè)索引對(duì)應(yīng)的圖像和標(biāo)簽 x_grid=[train_ds[i][0] for i in rnd_inds] y_grid=[train_ds[i][1] for i in rnd_inds] # 將這4個(gè)圖像拼接成一個(gè)網(wǎng)格 x_grid=utils.make_grid(x_grid, nrow=4, padding=2) print(x_grid.shape) # 調(diào)用helper函數(shù)顯示網(wǎng)格 plt.figure(figsize=(10,10)) show(x_grid,y_grid)
# 設(shè)置隨機(jī)種子為0 np.random.seed(0) # 設(shè)置網(wǎng)格大小 grid_size=4 # 從驗(yàn)證數(shù)據(jù)集中隨機(jī)選擇grid_size個(gè)索引 rnd_inds=np.random.randint(0,len(val_ds),grid_size) print("image indices:",rnd_inds) # 從驗(yàn)證數(shù)據(jù)集中選擇對(duì)應(yīng)的圖像 x_grid=[val_ds[i][0] for i in rnd_inds] # 從驗(yàn)證數(shù)據(jù)集中選擇對(duì)應(yīng)的標(biāo)簽 y_grid=[val_ds[i][1] for i in rnd_inds] # 將圖像排列成網(wǎng)格 x_grid=utils.make_grid(x_grid, nrow=4, padding=2) print(x_grid.shape) # 調(diào)用輔助函數(shù) plt.figure(figsize=(10,10)) # 顯示網(wǎng)格圖像和標(biāo)簽 show(x_grid,y_grid)
import numpy as np # 計(jì)算訓(xùn)練集中每個(gè)樣本的RGB均值 meanRGB=[np.mean(x.numpy(),axis=(1,2)) for x,_ in train_ds] # 計(jì)算訓(xùn)練集中每個(gè)樣本的RGB標(biāo)準(zhǔn)差 stdRGB=[np.std(x.numpy(),axis=(1,2)) for x,_ in train_ds] meanR=np.mean([m[0] for m in meanRGB]) # 計(jì)算所有樣本的R通道均值的平均值 meanG=np.mean([m[1] for m in meanRGB]) meanB=np.mean([m[2] for m in meanRGB]) stdR=np.mean([s[0] for s in stdRGB]) # 計(jì)算所有樣本的R通道標(biāo)準(zhǔn)差的平均值 stdG=np.mean([s[1] for s in stdRGB]) stdB=np.mean([s[2] for s in stdRGB]) print(meanR,meanG,meanB) # 打印R、G、B通道的均值 print(stdR,stdG,stdB) # 打印R、G、B通道的標(biāo)準(zhǔn)差
# 定義訓(xùn)練數(shù)據(jù)的轉(zhuǎn)換器 train_transformer = transforms.Compose([ # 隨機(jī)水平翻轉(zhuǎn),翻轉(zhuǎn)概率為0.5 transforms.RandomHorizontalFlip(p=0.5), # 隨機(jī)垂直翻轉(zhuǎn),翻轉(zhuǎn)概率為0.5 transforms.RandomVerticalFlip(p=0.5), # 將圖像轉(zhuǎn)換為張量 transforms.ToTensor(), # 對(duì)圖像進(jìn)行歸一化,均值和標(biāo)準(zhǔn)差分別為meanR, meanG, meanB和stdR, stdG, stdB transforms.Normalize([meanR, meanG, meanB], [stdR, stdG, stdB])]) # 定義測試數(shù)據(jù)的轉(zhuǎn)換器 test0_transformer = transforms.Compose([ # 將圖像轉(zhuǎn)換為張量 transforms.ToTensor(), # 對(duì)圖像進(jìn)行歸一化,均值和標(biāo)準(zhǔn)差分別為meanR, meanG, meanB和stdR, stdG, stdB transforms.Normalize([meanR, meanG, meanB], [stdR, stdG, stdB]), ]) # 將訓(xùn)練數(shù)據(jù)集的轉(zhuǎn)換器賦值給訓(xùn)練數(shù)據(jù)集的transform屬性 train_ds.transform=train_transformer # 將測試數(shù)據(jù)集的轉(zhuǎn)換器賦值給測試數(shù)據(jù)集的transform屬性 test0_ds.transform=test0_transformer import torch import numpy as np import matplotlib.pyplot as plt # 設(shè)置隨機(jī)種子 np.random.seed(0) torch.manual_seed(0) # 定義網(wǎng)格大小 grid_size=4 # 從訓(xùn)練數(shù)據(jù)集中隨機(jī)選擇grid_size個(gè)樣本的索引 rnd_inds=np.random.randint(0,len(train_ds),grid_size) print("image indices:",rnd_inds) # 根據(jù)索引從訓(xùn)練數(shù)據(jù)集中獲取對(duì)應(yīng)的樣本 x_grid=[train_ds[i][0] for i in rnd_inds] y_grid=[train_ds[i][1] for i in rnd_inds] # 將樣本轉(zhuǎn)換為網(wǎng)格形式 x_grid=utils.make_grid(x_grid, nrow=4, padding=2) print(x_grid.shape) # 創(chuàng)建一個(gè)10x10的圖像 plt.figure(figsize=(10,10)) # 顯示網(wǎng)格和對(duì)應(yīng)的標(biāo)簽 show(x_grid,y_grid)
from torch.utils.data import DataLoader # 創(chuàng)建訓(xùn)練數(shù)據(jù)集的DataLoader,batch_size為32,shuffle為True,表示每次迭代時(shí)都會(huì)打亂數(shù)據(jù)集 train_dl = DataLoader(train_ds, batch_size=32, shuffle=True) # 創(chuàng)建驗(yàn)證數(shù)據(jù)集的DataLoader,batch_size為64,shuffle為False,表示每次迭代時(shí)不會(huì)打亂數(shù)據(jù)集 val_dl = DataLoader(val_ds, batch_size=64, shuffle=False) # 遍歷訓(xùn)練數(shù)據(jù)集 for x, y in train_dl: # 打印x的形狀 print(x.shape) # 打印y的形狀 print(y.shape) # 跳出循環(huán) break
# 遍歷val_dl中的每個(gè)元素,x和y分別表示輸入和標(biāo)簽 for x, y in val_dl: # 打印輸入的形狀 print(x.shape) # 打印標(biāo)簽的形狀 print(y.shape) # 退出循環(huán) break
# 從datasets庫中導(dǎo)入FashionMNIST數(shù)據(jù)集,并將其設(shè)置為訓(xùn)練集 fashion_train=datasets.FashionMNIST(path2data, train=True, download=True)
搭建模型
使用torchvision為多分類任務(wù)構(gòu)建一個(gè)模型。torchvision軟件包提供了用于圖像分類的多個(gè)最先進(jìn)的深度學(xué)習(xí)模型的實(shí)現(xiàn),包括 AlexNet、VGG、ResNet、SqueezeNet、DenseNet、Inception、GoogleNet、ShuffleNet。這些模型在 ImageNet 數(shù)據(jù)集上進(jìn)行了訓(xùn)練,其中包含來自 1,000 個(gè)班級(jí)的 1400 多萬張圖像??梢苑謩e使用具有隨機(jī)初始化權(quán)重的架構(gòu)、預(yù)訓(xùn)練權(quán)重進(jìn)行嘗試。
from torchvision import models import torch # 創(chuàng)建一個(gè)resnet18模型,pretrained參數(shù)設(shè)置為False,表示不使用預(yù)訓(xùn)練的權(quán)重 model_resnet18 = models.resnet18(pretrained=False) # 打印模型ResNet18 print(model_resnet18)
from torch import nn # 定義類別數(shù)量 num_classes=10 # 獲取模型ResNet18的全連接層輸入特征數(shù)量 num_ftrs = model_resnet18.fc.in_features # 將全連接層替換為新的全連接層,輸出特征數(shù)量為類別數(shù)量 model_resnet18.fc = nn.Linear(num_ftrs, num_classes) # 定義設(shè)備為GPU device = torch.device("cuda:0") # 將模型移動(dòng)到GPU上 model_resnet18.to(device)
from torchsummary import summary # 打印模型結(jié)構(gòu),輸入大小為(3, 224, 224),即3個(gè)通道,224x224大小的圖像 summary(model_resnet18, input_size=(3, 224, 224))
# 遍歷模型ResNet18的參數(shù) for w in model_resnet18.parameters(): # 將參數(shù)轉(zhuǎn)換為CPU數(shù)據(jù) w=w.data.cpu() # 打印參數(shù)的形狀 print(w.shape) break # 計(jì)算參數(shù)的最小值 min_w=torch.min(w) # 計(jì)算w1,其中w1 = (-1/(2*min_w))*w + 0.5 w1 = (-1/(2*min_w))*w + 0.5 # 打印w1的最小值和最大值 print(torch.min(w1).item(),torch.max(w1).item()) # 計(jì)算網(wǎng)格大小 grid_size=len(w1) # 生成網(wǎng)格 x_grid=[w1[i] for i in range(grid_size)] x_grid=utils.make_grid(x_grid, nrow=8, padding=1) print(x_grid.shape) # 創(chuàng)建一個(gè)5x5的圖像 plt.figure(figsize=(5,5)) show(x_grid)
采用預(yù)訓(xùn)練權(quán)重
from torchvision import models import torch # 加載預(yù)訓(xùn)練的resnet18模型 resnet18_pretrained = models.resnet18(pretrained=True) # 定義分類的類別數(shù) num_classes=10 # 獲取resnet18模型的最后一層全連接層的輸入特征數(shù) num_ftrs = resnet18_pretrained.fc.in_features # 將最后一層全連接層替換為新的全連接層,新的全連接層的輸出特征數(shù)為num_classes resnet18_pretrained.fc = nn.Linear(num_ftrs, num_classes) # 定義設(shè)備為cuda:0 device = torch.device("cuda:0") # 將模型移動(dòng)到cuda:0設(shè)備上 resnet18_pretrained.to(device)
# 遍歷resnet18_pretrained的參數(shù) for w in resnet18_pretrained.parameters(): # 將參數(shù)轉(zhuǎn)換為cpu格式 w=w.data.cpu() print(w.shape) break # 計(jì)算w的最小值 min_w=torch.min(w) # 計(jì)算w1,其中w1=(-1/(2*min_w))*w + 0.5 w1 = (-1/(2*min_w))*w + 0.5 # 打印w1的最小值和最大值 print(torch.min(w1).item(),torch.max(w1).item()) # 計(jì)算w1的網(wǎng)格大小 grid_size=len(w1) # 將w1轉(zhuǎn)換為網(wǎng)格形式 x_grid=[w1[i] for i in range(grid_size)] x_grid=utils.make_grid(x_grid, nrow=8, padding=1) print(x_grid.shape) # 創(chuàng)建一個(gè)5x5的圖像 plt.figure(figsize=(5,5)) show(x_grid)
定義損失函數(shù)
定義損失函數(shù)的目的是將模型優(yōu)化為預(yù)定義的指標(biāo)。分類任務(wù)的標(biāo)準(zhǔn)損失函數(shù)是交叉熵?fù)p失或?qū)?shù)損失。在定義損失函數(shù)時(shí),需要考慮模型輸出的數(shù)量及其激活函數(shù)。對(duì)于多類分類任務(wù),輸出數(shù)設(shè)置為類數(shù),輸出激活函數(shù)確確定損失函數(shù)。
輸出激活 | 輸出數(shù)量 | 損失函數(shù) |
---|---|---|
None | num_classes | nn.CrossEntropyLoss |
log_Softmax | num_classes | nn.NLLLoss |
torch.manual_seed(0) # 定義輸入數(shù)據(jù)的維度 n,c=4,5 # 生成隨機(jī)輸入數(shù)據(jù),并設(shè)置requires_grad=True,表示需要計(jì)算梯度 y = torch.randn(n, c, requires_grad=True) # 打印輸入數(shù)據(jù)的形狀 print(y.shape) # 定義交叉熵?fù)p失函數(shù),reduction參數(shù)設(shè)置為"sum",表示將所有樣本的損失相加 loss_func = nn.CrossEntropyLoss(reduction="sum") # 生成隨機(jī)目標(biāo)數(shù)據(jù),表示每個(gè)樣本的類別 target = torch.randint(c,size=(n,)) # 打印目標(biāo)數(shù)據(jù)的形狀 print(target.shape) # 計(jì)算損失 loss = loss_func(y, target) # 打印損失值 print(loss.item())
# 反向傳播,計(jì)算梯度 loss.backward() # 打印輸出y的值 print (y.data)
定義優(yōu)化器
torch.optim 包提供了通用優(yōu)化器的實(shí)現(xiàn)。優(yōu)化器將保持當(dāng)前狀態(tài),并根據(jù)計(jì)算出的梯度更新參數(shù)。對(duì)于分類任務(wù),隨機(jī)梯度下降 (SGD) 和 Adam 優(yōu)化器非常常用。Adam 優(yōu)化器在速度和準(zhǔn)確性方面通常優(yōu)于 SGD,因此這里選擇 Adam 優(yōu)化器。
from torch import optim # 定義優(yōu)化器,使用Adam優(yōu)化算法,優(yōu)化model_resnet18的參數(shù),學(xué)習(xí)率為1e-4 opt = optim.Adam(model_resnet18.parameters(), lr=1e-4) # 定義一個(gè)函數(shù),用于獲取優(yōu)化器的學(xué)習(xí)率 def get_lr(opt): # 遍歷優(yōu)化器的參數(shù)組 for param_group in opt.param_groups: # 返回學(xué)習(xí)率 return param_group['lr'] # 調(diào)用函數(shù),獲取當(dāng)前學(xué)習(xí)率 current_lr=get_lr(opt) # 打印當(dāng)前學(xué)習(xí)率 print('current lr={}'.format(current_lr))
from torch.optim.lr_scheduler import CosineAnnealingLR # 創(chuàng)建學(xué)習(xí)率調(diào)度器,T_max表示周期長度,eta_min表示最小學(xué)習(xí)率 lr_scheduler = CosineAnnealingLR(opt,T_max=2,eta_min=1e-5) # 定義一個(gè)空列表lrs lrs=[] # 循環(huán)10次 for i in range(10): # 調(diào)用lr_scheduler.step()方法 lr_scheduler.step() # 調(diào)用get_lr()方法獲取當(dāng)前學(xué)習(xí)率 lr=get_lr(opt) # 打印當(dāng)前epoch和對(duì)應(yīng)的學(xué)習(xí)率 print("epoch %s, lr: %.1e" %(i,lr)) # 將當(dāng)前學(xué)習(xí)率添加到列表lrs中 lrs.append(lr) # 繪制lrs列表中的數(shù)據(jù) plt.plot(lrs)
訓(xùn)練和遷移學(xué)習(xí)
到目前為止,已經(jīng)創(chuàng)建了數(shù)據(jù)集并定義了模型、損失函數(shù)和優(yōu)化器,接下來將進(jìn)行訓(xùn)練和驗(yàn)證。首先使用隨機(jī)初始化的權(quán)重訓(xùn)練模型。然后使用預(yù)先訓(xùn)練的權(quán)重訓(xùn)練模型,這也稱為遷移學(xué)習(xí)。遷移學(xué)習(xí)將從一個(gè)問題中學(xué)到的知識(shí)(權(quán)重)用于其他類似問題。訓(xùn)練和驗(yàn)證腳本可能很長且重復(fù)。為了提高代碼可讀性并避免代碼重復(fù),將先構(gòu)建一些輔助函數(shù)。
# 定義一個(gè)函數(shù)metrics_batch,用于計(jì)算預(yù)測結(jié)果和目標(biāo)之間的正確率 def metrics_batch(output, target): # 將輸出結(jié)果的最大值所在的索引作為預(yù)測結(jié)果 pred = output.argmax(dim=1, keepdim=True) # 計(jì)算預(yù)測結(jié)果和目標(biāo)之間的正確率 corrects=pred.eq(target.view_as(pred)).sum().item() # 返回正確率 return corrects def loss_batch(loss_func, output, target, opt=None): # 計(jì)算batch的損失 loss = loss_func(output, target) # 計(jì)算batch的評(píng)估指標(biāo) metric_b = metrics_batch(output,target) # 如果有優(yōu)化器,則進(jìn)行反向傳播和參數(shù)更新 if opt is not None: opt.zero_grad() loss.backward() opt.step() # 返回?fù)p失和評(píng)估指標(biāo) return loss.item(), metric_b device = torch.device("cuda") # 定義一個(gè)函數(shù)loss_epoch,用于計(jì)算模型在數(shù)據(jù)集上的損失 def loss_epoch(model,loss_func,dataset_dl,sanity_check=False,opt=None): # 初始化運(yùn)行損失和運(yùn)行指標(biāo) running_loss=0.0 running_metric=0.0 # 獲取數(shù)據(jù)集的長度 len_data=len(dataset_dl.dataset) # 遍歷數(shù)據(jù)集 for xb, yb in dataset_dl: # 將數(shù)據(jù)移動(dòng)到GPU上 xb=xb.to(device) yb=yb.to(device) # 獲取模型輸出 output=model(xb) # 計(jì)算當(dāng)前批次的損失和指標(biāo) loss_b,metric_b=loss_batch(loss_func, output, yb, opt) # 累加損失和指標(biāo) running_loss+=loss_b if metric_b is not None: running_metric+=metric_b # 如果是sanity_check模式,則只計(jì)算一個(gè)批次 if sanity_check is True: break # 計(jì)算平均損失和指標(biāo) loss=running_loss/float(len_data) metric=running_metric/float(len_data) # 返回平均損失和指標(biāo) return loss, metric def train_val(model, params): # 獲取參數(shù) num_epochs=params["num_epochs"] loss_func=params["loss_func"] opt=params["optimizer"] train_dl=params["train_dl"] val_dl=params["val_dl"] sanity_check=params["sanity_check"] lr_scheduler=params["lr_scheduler"] path2weights=params["path2weights"] # 初始化損失和指標(biāo)歷史記錄 loss_history={ "train": [], "val": [], } metric_history={ "train": [], "val": [], } # 復(fù)制模型參數(shù) best_model_wts = copy.deepcopy(model.state_dict()) # 初始化最佳損失 best_loss=float('inf') # 遍歷每個(gè)epoch for epoch in range(num_epochs): # 獲取當(dāng)前學(xué)習(xí)率 current_lr=get_lr(opt) print('Epoch {}/{}, current lr={}'.format(epoch, num_epochs - 1, current_lr)) # 訓(xùn)練模型 model.train() train_loss, train_metric=loss_epoch(model,loss_func,train_dl,sanity_check,opt) # 記錄訓(xùn)練損失和指標(biāo) loss_history["train"].append(train_loss) metric_history["train"].append(train_metric) # 評(píng)估模型 model.eval() with torch.no_grad(): val_loss, val_metric=loss_epoch(model,loss_func,val_dl,sanity_check) # 如果驗(yàn)證損失小于最佳損失,則更新最佳損失和最佳模型參數(shù) if val_loss < best_loss: best_loss = val_loss best_model_wts = copy.deepcopy(model.state_dict()) # 將最佳模型參數(shù)保存到本地文件 torch.save(model.state_dict(), path2weights) print("Copied best model weights!") # 記錄驗(yàn)證損失和指標(biāo) loss_history["val"].append(val_loss) metric_history["val"].append(val_metric) # 更新學(xué)習(xí)率 lr_scheduler.step() # 打印訓(xùn)練損失、驗(yàn)證損失和準(zhǔn)確率 print("train loss: %.6f, dev loss: %.6f, accuracy: %.2f" %(train_loss,val_loss,100*val_metric)) print("-"*10) # 加載最佳模型參數(shù) model.load_state_dict(best_model_wts) # 返回模型、損失歷史和指標(biāo)歷史 return model, loss_history, metric_history
用隨機(jī)權(quán)重進(jìn)行訓(xùn)練
import copy # 定義交叉熵?fù)p失函數(shù),reduction參數(shù)設(shè)置為"sum",表示將所有樣本的損失相加 loss_func = nn.CrossEntropyLoss(reduction="sum") # 定義Adam優(yōu)化器,優(yōu)化模型參數(shù),學(xué)習(xí)率為1e-4 opt = optim.Adam(model_resnet18.parameters(), lr=1e-4) # 定義余弦退火學(xué)習(xí)率調(diào)度器,T_max參數(shù)設(shè)置為5,eta_min參數(shù)設(shè)置為1e-6 lr_scheduler = CosineAnnealingLR(opt,T_max=5,eta_min=1e-6) # 定義訓(xùn)練參數(shù)字典 params_train={ "num_epochs": 3, # 訓(xùn)練輪數(shù) "optimizer": opt, # 優(yōu)化器 "loss_func": loss_func, # 損失函數(shù) "train_dl": train_dl, # 訓(xùn)練數(shù)據(jù)集 "val_dl": val_dl, # 驗(yàn)證數(shù)據(jù)集 "sanity_check": False, # 是否進(jìn)行sanity check "lr_scheduler": lr_scheduler, # 學(xué)習(xí)率調(diào)度器 "path2weights": "./models/resnet18.pt", # 模型權(quán)重保存路徑 } # 訓(xùn)練和驗(yàn)證模型 model_resnet18,loss_hist,metric_hist=train_val(model_resnet18,params_train)
# 獲取訓(xùn)練參數(shù)中的訓(xùn)練輪數(shù) num_epochs=params_train["num_epochs"] # 繪制訓(xùn)練和驗(yàn)證損失曲線 plt.title("Train-Val Loss") plt.plot(range(1,num_epochs+1),loss_hist["train"],label="train") plt.plot(range(1,num_epochs+1),loss_hist["val"],label="val") plt.ylabel("Loss") plt.xlabel("Training Epochs") plt.legend() plt.show() # 繪制訓(xùn)練和驗(yàn)證準(zhǔn)確率曲線 plt.title("Train-Val Accuracy") plt.plot(range(1,num_epochs+1),metric_hist["train"],label="train") plt.plot(range(1,num_epochs+1),metric_hist["val"],label="val") plt.ylabel("Accuracy") plt.xlabel("Training Epochs") plt.legend() plt.show()
用預(yù)訓(xùn)練權(quán)重進(jìn)行訓(xùn)練
import copy # 定義損失函數(shù),使用交叉熵?fù)p失,并設(shè)置reduction為sum loss_func = nn.CrossEntropyLoss(reduction="sum") # 定義優(yōu)化器,使用Adam優(yōu)化器,并設(shè)置學(xué)習(xí)率為1e-4 opt = optim.Adam(resnet18_pretrained.parameters(), lr=1e-4) # 定義學(xué)習(xí)率調(diào)度器,使用余弦退火調(diào)度器,設(shè)置最大周期為5,最小學(xué)習(xí)率為1e-6 lr_scheduler = CosineAnnealingLR(opt,T_max=5,eta_min=1e-6) # 定義訓(xùn)練參數(shù) params_train={ "num_epochs": 3, # 設(shè)置訓(xùn)練周期為3 "optimizer": opt, # 設(shè)置優(yōu)化器 "loss_func": loss_func, # 設(shè)置損失函數(shù) "train_dl": train_dl, # 設(shè)置訓(xùn)練數(shù)據(jù)集 "val_dl": val_dl, # 設(shè)置驗(yàn)證數(shù)據(jù)集 "sanity_check": False, # 設(shè)置是否進(jìn)行sanity check "lr_scheduler": lr_scheduler, # 設(shè)置學(xué)習(xí)率調(diào)度器 "path2weights": "./models/resnet18_pretrained.pt", # 設(shè)置權(quán)重保存路徑 } # 調(diào)用train_val函數(shù)進(jìn)行訓(xùn)練和驗(yàn)證,并返回訓(xùn)練后的模型、損失歷史和指標(biāo)歷史 resnet18_pretrained,loss_hist,metric_hist=train_val(resnet18_pretrained,params_train)
# 獲取訓(xùn)練參數(shù)中的訓(xùn)練輪數(shù) num_epochs=params_train["num_epochs"] # 繪制訓(xùn)練和驗(yàn)證損失曲線 plt.title("Train-Val Loss") plt.plot(range(1,num_epochs+1),loss_hist["train"],label="train") plt.plot(range(1,num_epochs+1),loss_hist["val"],label="val") plt.ylabel("Loss") plt.xlabel("Training Epochs") plt.legend() plt.show() # 繪制訓(xùn)練和驗(yàn)證準(zhǔn)確率曲線 plt.title("Train-Val Accuracy") plt.plot(range(1,num_epochs+1),metric_hist["train"],label="train") plt.plot(range(1,num_epochs+1),metric_hist["val"],label="val") plt.ylabel("Accuracy") plt.xlabel("Training Epochs") plt.legend() plt.show()
到此這篇關(guān)于PyTorch中圖像多分類的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)PyTorch 圖像多分類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- PyTorch使用CNN實(shí)現(xiàn)圖像分類
- 使用pytorch進(jìn)行圖像分類的詳細(xì)步驟
- 如何使用Pytorch完成圖像分類任務(wù)詳解
- Pytorch深度學(xué)習(xí)之實(shí)現(xiàn)病蟲害圖像分類
- Python Pytorch深度學(xué)習(xí)之圖像分類器
- Python深度學(xué)習(xí)pytorch實(shí)現(xiàn)圖像分類數(shù)據(jù)集
- 基于PyTorch實(shí)現(xiàn)一個(gè)簡單的CNN圖像分類器
- Pytorch 使用CNN圖像分類的實(shí)現(xiàn)
- 使用PyTorch訓(xùn)練一個(gè)圖像分類器實(shí)例
相關(guān)文章
Python中利用ItsDangerous快捷實(shí)現(xiàn)數(shù)據(jù)加密
這篇文章主要介紹了Python中利用ItsDangerous快捷實(shí)現(xiàn)數(shù)據(jù)加密,通過使用Python庫ItsDangerous,我們就可以高效快捷地完成數(shù)據(jù)加密/解密的過程,本文結(jié)合實(shí)例代碼給大家講解的非常詳細(xì),需要的朋友可以參考下2022-11-11在Pycharm中對(duì)代碼進(jìn)行注釋和縮進(jìn)的方法詳解
今天小編就為大家分享一篇在Pycharm中對(duì)代碼進(jìn)行注釋和縮進(jìn)的方法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01Python數(shù)學(xué)建模庫StatsModels統(tǒng)計(jì)回歸簡介初識(shí)
這篇文章主要為大家介紹了Python數(shù)學(xué)建模庫StatsModels統(tǒng)計(jì)回歸的基本概念,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝打擊多多進(jìn)步2021-10-10Python從list類型、range()序列簡單認(rèn)識(shí)類(class)【可迭代】
這篇文章主要介紹了Python從list類型、range()序列簡單認(rèn)識(shí)類(class),結(jié)合實(shí)例形式分析了list、range及自定義類等可迭代數(shù)據(jù)類型相關(guān)使用技巧,需要的朋友可以參考下2019-05-05Python實(shí)現(xiàn)嵌套列表及字典并按某一元素去重復(fù)功能示例
這篇文章主要介紹了Python實(shí)現(xiàn)嵌套列表及字典并按某一元素去重復(fù)功能,涉及Python列表嵌套列表、列表嵌套字典,及按照某一元素去重復(fù)的相關(guān)操作方法,需要的朋友可以參考下2017-11-11python源文件的字符編碼知識(shí)點(diǎn)詳解
在本篇文章里小編給大家整理的是一篇關(guān)于python源文件的字符編碼知識(shí)點(diǎn)詳解,有興趣的朋友們可以學(xué)習(xí)下。2021-03-03OpenCV實(shí)戰(zhàn)記錄之基于分水嶺算法的圖像分割
在機(jī)器視覺中,有時(shí)需要對(duì)產(chǎn)品進(jìn)行檢測和計(jì)數(shù),其難點(diǎn)無非是對(duì)于產(chǎn)品的圖像分割,這篇文章主要給大家介紹了關(guān)于OpenCV實(shí)戰(zhàn)記錄之基于分水嶺算法的圖像分割的相關(guān)資料,需要的朋友可以參考下2023-02-02Python黑魔法Descriptor描述符的實(shí)例解析
與迭代器和裝飾器等一樣,描述符也是Python編程中的一項(xiàng)高級(jí)技巧,這里我們就來講解Python黑魔法Descriptor描述符的實(shí)例解析:2016-06-06