欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

PyTorch中圖像多分類的實(shí)現(xiàn)

 更新時(shí)間:2025年09月08日 14:29:49   作者:F_D_Z  
本文介紹了使用PyTorch進(jìn)行多類圖像分類的完整流程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

多類圖像分類的目標(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)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論