PyTorch中圖像多分類的實現(xiàn)
多類圖像分類的目標(biāo)是為一組固定類別中的圖像分配標(biāo)簽。
加載和處理數(shù)據(jù)
將使用 PyTorch torchvision 包中提供的 STL-10 數(shù)據(jù)集,數(shù)據(jù)集中有 10 個類:飛機、鳥、車、貓、鹿、狗、馬、猴、船、卡車。圖像為96*96像素的RGB圖像。數(shù)據(jù)集包含 5,000 張訓(xùn)練圖像和 8,000 張測試圖像。在訓(xùn)練數(shù)據(jù)集和測試數(shù)據(jù)集中,每個類分別有 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)計標(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對象,設(shè)置分割次數(shù)為1,測試集大小為0.2,隨機種子為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]
# 對索引和標(biāo)簽進行分割
for test_index, val_index in sss.split(indices, y_test0):
# 打印測試集和驗證集的索引
print("test:", test_index, "val:", val_index)
# 打印測試集和驗證集的大小
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)計測試集和驗證集的標(biāo)簽數(shù)量 counter_test=collections.Counter(y_test) counter_val=collections.Counter(y_val) # 打印測試集和驗證集的標(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è)置隨機種子為0
np.random.seed(0)
# 定義一個函數(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
# 隨機生成4個索引
rnd_inds=np.random.randint(0,len(train_ds),grid_size)
print("image indices:",rnd_inds)
# 從訓(xùn)練集中獲取這4個索引對應(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個圖像拼接成一個網(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è)置隨機種子為0
np.random.seed(0)
# 設(shè)置網(wǎng)格大小
grid_size=4
# 從驗證數(shù)據(jù)集中隨機選擇grid_size個索引
rnd_inds=np.random.randint(0,len(val_ds),grid_size)
print("image indices:",rnd_inds)
# 從驗證數(shù)據(jù)集中選擇對應(yīng)的圖像
x_grid=[val_ds[i][0] for i in rnd_inds]
# 從驗證數(shù)據(jù)集中選擇對應(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 # 計算訓(xùn)練集中每個樣本的RGB均值 meanRGB=[np.mean(x.numpy(),axis=(1,2)) for x,_ in train_ds] # 計算訓(xùn)練集中每個樣本的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]) # 計算所有樣本的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]) # 計算所有樣本的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([
# 隨機水平翻轉(zhuǎn),翻轉(zhuǎn)概率為0.5
transforms.RandomHorizontalFlip(p=0.5),
# 隨機垂直翻轉(zhuǎn),翻轉(zhuǎn)概率為0.5
transforms.RandomVerticalFlip(p=0.5),
# 將圖像轉(zhuǎn)換為張量
transforms.ToTensor(),
# 對圖像進行歸一化,均值和標(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(),
# 對圖像進行歸一化,均值和標(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è)置隨機種子
np.random.seed(0)
torch.manual_seed(0)
# 定義網(wǎng)格大小
grid_size=4
# 從訓(xùn)練數(shù)據(jù)集中隨機選擇grid_size個樣本的索引
rnd_inds=np.random.randint(0,len(train_ds),grid_size)
print("image indices:",rnd_inds)
# 根據(jù)索引從訓(xùn)練數(shù)據(jù)集中獲取對應(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)建一個10x10的圖像
plt.figure(figsize=(10,10))
# 顯示網(wǎng)格和對應(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ù)據(jù)集
train_dl = DataLoader(train_ds, batch_size=32, shuffle=True)
# 創(chuàng)建驗證數(shù)據(jù)集的DataLoader,batch_size為64,shuffle為False,表示每次迭代時不會打亂數(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中的每個元素,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)建一個模型。torchvision軟件包提供了用于圖像分類的多個最先進的深度學(xué)習(xí)模型的實現(xiàn),包括 AlexNet、VGG、ResNet、SqueezeNet、DenseNet、Inception、GoogleNet、ShuffleNet。這些模型在 ImageNet 數(shù)據(jù)集上進行了訓(xùn)練,其中包含來自 1,000 個班級的 1400 多萬張圖像??梢苑謩e使用具有隨機初始化權(quán)重的架構(gòu)、預(yù)訓(xùn)練權(quán)重進行嘗試。
from torchvision import models import torch # 創(chuàng)建一個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")
# 將模型移動到GPU上
model_resnet18.to(device)
from torchsummary import summary # 打印模型結(jié)構(gòu),輸入大小為(3, 224, 224),即3個通道,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
# 計算參數(shù)的最小值
min_w=torch.min(w)
# 計算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())
# 計算網(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)建一個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")
# 將模型移動到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
# 計算w的最小值
min_w=torch.min(w)
# 計算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())
# 計算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)建一個5x5的圖像
plt.figure(figsize=(5,5))
show(x_grid)

定義損失函數(shù)
定義損失函數(shù)的目的是將模型優(yōu)化為預(yù)定義的指標(biāo)。分類任務(wù)的標(biāo)準(zhǔn)損失函數(shù)是交叉熵損失或?qū)?shù)損失。在定義損失函數(shù)時,需要考慮模型輸出的數(shù)量及其激活函數(shù)。對于多類分類任務(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 # 生成隨機輸入數(shù)據(jù),并設(shè)置requires_grad=True,表示需要計算梯度 y = torch.randn(n, c, requires_grad=True) # 打印輸入數(shù)據(jù)的形狀 print(y.shape) # 定義交叉熵損失函數(shù),reduction參數(shù)設(shè)置為"sum",表示將所有樣本的損失相加 loss_func = nn.CrossEntropyLoss(reduction="sum") # 生成隨機目標(biāo)數(shù)據(jù),表示每個樣本的類別 target = torch.randint(c,size=(n,)) # 打印目標(biāo)數(shù)據(jù)的形狀 print(target.shape) # 計算損失 loss = loss_func(y, target) # 打印損失值 print(loss.item())

# 反向傳播,計算梯度 loss.backward() # 打印輸出y的值 print (y.data)

定義優(yōu)化器
torch.optim 包提供了通用優(yōu)化器的實現(xiàn)。優(yōu)化器將保持當(dāng)前狀態(tài),并根據(jù)計算出的梯度更新參數(shù)。對于分類任務(wù),隨機梯度下降 (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)
# 定義一個函數(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)
# 定義一個空列表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和對應(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)化器,接下來將進行訓(xùn)練和驗證。首先使用隨機初始化的權(quán)重訓(xùn)練模型。然后使用預(yù)先訓(xùn)練的權(quán)重訓(xùn)練模型,這也稱為遷移學(xué)習(xí)。遷移學(xué)習(xí)將從一個問題中學(xué)到的知識(權(quán)重)用于其他類似問題。訓(xùn)練和驗證腳本可能很長且重復(fù)。為了提高代碼可讀性并避免代碼重復(fù),將先構(gòu)建一些輔助函數(shù)。
# 定義一個函數(shù)metrics_batch,用于計算預(yù)測結(jié)果和目標(biāo)之間的正確率
def metrics_batch(output, target):
# 將輸出結(jié)果的最大值所在的索引作為預(yù)測結(jié)果
pred = output.argmax(dim=1, keepdim=True)
# 計算預(yù)測結(jié)果和目標(biāo)之間的正確率
corrects=pred.eq(target.view_as(pred)).sum().item()
# 返回正確率
return corrects
def loss_batch(loss_func, output, target, opt=None):
# 計算batch的損失
loss = loss_func(output, target)
# 計算batch的評估指標(biāo)
metric_b = metrics_batch(output,target)
# 如果有優(yōu)化器,則進行反向傳播和參數(shù)更新
if opt is not None:
opt.zero_grad()
loss.backward()
opt.step()
# 返回損失和評估指標(biāo)
return loss.item(), metric_b
device = torch.device("cuda")
# 定義一個函數(shù)loss_epoch,用于計算模型在數(shù)據(jù)集上的損失
def loss_epoch(model,loss_func,dataset_dl,sanity_check=False,opt=None):
# 初始化運行損失和運行指標(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ù)移動到GPU上
xb=xb.to(device)
yb=yb.to(device)
# 獲取模型輸出
output=model(xb)
# 計算當(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模式,則只計算一個批次
if sanity_check is True:
break
# 計算平均損失和指標(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')
# 遍歷每個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)
# 評估模型
model.eval()
with torch.no_grad():
val_loss, val_metric=loss_epoch(model,loss_func,val_dl,sanity_check)
# 如果驗證損失小于最佳損失,則更新最佳損失和最佳模型參數(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!")
# 記錄驗證損失和指標(biāo)
loss_history["val"].append(val_loss)
metric_history["val"].append(val_metric)
# 更新學(xué)習(xí)率
lr_scheduler.step()
# 打印訓(xù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用隨機權(quán)重進行訓(xùn)練
import copy
# 定義交叉熵損失函數(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, # 驗證數(shù)據(jù)集
"sanity_check": False, # 是否進行sanity check
"lr_scheduler": lr_scheduler, # 學(xué)習(xí)率調(diào)度器
"path2weights": "./models/resnet18.pt", # 模型權(quán)重保存路徑
}
# 訓(xù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)練和驗證損失曲線
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)練和驗證準(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)重進行訓(xùn)練
import copy
# 定義損失函數(shù),使用交叉熵損失,并設(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è)置驗證數(shù)據(jù)集
"sanity_check": False, # 設(shè)置是否進行sanity check
"lr_scheduler": lr_scheduler, # 設(shè)置學(xué)習(xí)率調(diào)度器
"path2weights": "./models/resnet18_pretrained.pt", # 設(shè)置權(quán)重保存路徑
}
# 調(diào)用train_val函數(shù)進行訓(xù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)練和驗證損失曲線
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)練和驗證準(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中圖像多分類的實現(xiàn)的文章就介紹到這了,更多相關(guān)PyTorch 圖像多分類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用Python腳本實現(xiàn)批量將圖片轉(zhuǎn)換為WebP格式
Python語言的簡潔語法和庫支持使其成為圖像處理的理想選擇,本文將介紹如何利用Python實現(xiàn)批量將圖片轉(zhuǎn)換為WebP格式的腳本,WebP作為一種高效的圖像格式,能顯著減小文件大小,優(yōu)化網(wǎng)絡(luò)傳輸,需要的朋友可以參考下2025-06-06
python taipy庫輕松地將數(shù)據(jù)和機器學(xué)習(xí)模型轉(zhuǎn)為功能性Web應(yīng)用
taipy 是一個開源的 Python 庫,任何具有基本 Python 技能的人都可以使用,對于數(shù)據(jù)科學(xué)家、機器學(xué)習(xí)工程師和 Python 程序員來說,它是一個方便的工具,借助 Taipy,你可以輕松地將數(shù)據(jù)和機器學(xué)習(xí)模型轉(zhuǎn)變?yōu)楣δ苄缘?nbsp;Web 應(yīng)用程序2024-01-01
python基礎(chǔ)pandas的drop()用法示例詳解
這篇文章主要介紹了python基礎(chǔ)pandas的drop()用法,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04
回歸預(yù)測分析python數(shù)據(jù)化運營線性回歸總結(jié)
本文主要介紹了python數(shù)據(jù)化運營中的線性回歸一般應(yīng)用場景,常用方法,回歸實現(xiàn),回歸評估指標(biāo),效果可視化等,并采用了回歸預(yù)測分析的數(shù)據(jù)預(yù)測方法2021-08-08

