自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

萬(wàn)字長(zhǎng)文超全總結(jié)Pytorch核心操作!

人工智能
本文精心梳理了PyTorch的核心操作,這不僅是一份全面的技術(shù)指南,更是每一個(gè)PyTorch實(shí)踐者的智慧錦囊,建議收藏!

在深度學(xué)習(xí)與人工智能領(lǐng)域,PyTorch已成為研究者與開(kāi)發(fā)者手中的利劍,以其靈活高效的特性,不斷推動(dòng)著新技術(shù)的邊界。對(duì)于每一位致力于掌握PyTorch精髓的學(xué)習(xí)者來(lái)說(shuō),深入了解其核心操作不僅是提升技能的關(guān)鍵,也是邁向高級(jí)應(yīng)用與創(chuàng)新研究的必經(jīng)之路。本文精心梳理了PyTorch的核心操作,這不僅是一份全面的技術(shù)指南,更是每一個(gè)PyTorch實(shí)踐者的智慧錦囊,建議收藏!

一、張量創(chuàng)建和基本操作

1.張量創(chuàng)建

(1) 從Python列表或Numpy數(shù)組創(chuàng)建張量

使用torch.tensor()函數(shù)可以直接從Python列表創(chuàng)建張量。并且,PyTorch設(shè)計(jì)時(shí)考慮了與NumPy的互操作性,也可以使用torch.tensor()函數(shù)從NumPy數(shù)組創(chuàng)建張量。

import numpy as np
import torch

# 從列表創(chuàng)建張量
list_data = [1, 2, 3, 4]
tensor_from_list = torch.tensor(list_data)
print(tensor_from_list) # tensor([1, 2, 3, 4])

# 從NumPy數(shù)組創(chuàng)建張量
np_array = np.array([1, 2, 3])
tensor_from_np_tensor = torch.tensor(np_array)
print(tensor_from_np_tensor) # tensor([1, 2, 3], dtype=torch.int32)

(2) 使用固定數(shù)值創(chuàng)建張量

  • torch.zeros(shape)和torch.ones(shape):創(chuàng)建指定形狀的全零或全一張量。
'''
tensor([[0., 0., 0.],
        [0., 0., 0.]])
'''
zeros_tensor = torch.zeros(2, 3)
'''
tensor([[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]])
'''
ones_tensor = torch.ones(3, 4)
  • torch.rand(shape):創(chuàng)建指定形狀的隨機(jī)浮點(diǎn)數(shù)張量(0到1之間)或標(biāo)準(zhǔn)正態(tài)分布的張量。
'''
tensor([[0.7632, 0.9953, 0.8954],
        [0.8681, 0.7707, 0.8806]])
'''
random_tensor = torch.rand(2, 3)
'''
tensor([[ 0.1873, -1.6907,  0.4717,  1.0271],
        [-1.0680,  0.7490, -0.5693,  0.6490],
        [ 0.0429, -1.5796, -2.3312, -0.2733]])
'''
normal_tensor = torch.randn(3, 4)
  • torch.arange(start, end=None, step=1, dtype=None, layout=torch.strided, device=None, requires_grad=False):創(chuàng)建一個(gè)等差序列張量,默認(rèn)step為1。
arange_tensor = torch.arange(1, 10) #tensor([1, 2, 3, 4, 5, 6, 7, 8, 9])

2.張量的基本操作

(1) 張量索引和切片

張量的索引和切片類似于Python列表,可以訪問(wèn)和修改張量的特定元素或子集。

# 創(chuàng)建一個(gè)張量
tensor = torch.tensor([[1, 2, 3], [4, 5, 6]])

# 索引單個(gè)元素
element = tensor[0, 0]  # 1

# 切片
slice_1 = tensor[0, :]  # [1, 2, 3]
slice_2 = tensor[:, 1]  # [2, 5]

# 修改元素
tensor[0, 0] = 7
print(tensor)  # [[7, 2, 3], [4, 5, 6]]

(2) 形狀操作

  • shape屬性獲取張量的形狀:
shape = tensor.shape  # torch.Size([2, 3])
  • unsqueeze(dim)在指定維度添加一個(gè)大小為1的新維度:
expanded_tensor = tensor.unsqueeze(0)  # 添加一個(gè)新維度,形狀變?yōu)閇1, 2, 3]
  • reshape(shape)或view(shape)改變張量的形狀:
reshaped_tensor = tensor.reshape(6)  # 變?yōu)樾螤顬閇6]的一維張量
  • transpose(dim0, dim1)交換指定的兩個(gè)維度:
transposed_tensor = tensor.transpose(0, 1)  # 交換第一和第二維度

(3) 數(shù)學(xué)運(yùn)算

PyTorch張量支持廣泛的數(shù)學(xué)運(yùn)算,包括基本的算術(shù)運(yùn)算、元素級(jí)運(yùn)算、矩陣運(yùn)算等。以tensor = torch.tensor([[1, 2, 3], [4, 5, 6]])為例。

基本運(yùn)算(適用于標(biāo)量、一維或多維張量):

addition = tensor + tensor # [[2, 4, 6], [8, 10, 12]]。
  subtraction = tensor - tensor #[[0, 0, 0], [0, 0, 0]]
  multiplication = tensor * tensor #[[1, 4, 9], [16, 25, 36]]
  division = tensor / tensor #[[1, 1, 1], [1, 1, 1]]

元素級(jí)運(yùn)算(*運(yùn)算符在這種情況下表示逐元素乘法,而不是矩陣乘法):

elementwise_product = tensor * tensor # [[1, 4, 9], [16, 25, 36]]

矩陣運(yùn)算(使用@運(yùn)算符或torch.matmul()):

matrix_product = tensor @ tensor.t()  # 或者 torch.matmul(tensor, tensor.t())
  # tensor @ tensor.t() 結(jié)果是一個(gè)標(biāo)量,因?yàn)閺埩渴欠疥?,且張量與其轉(zhuǎn)置的點(diǎn)積等于1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32

廣播機(jī)制(使得不同形狀的張量能夠進(jìn)行運(yùn)算):

'''
  結(jié)果是一個(gè)2x3的張量,其中每個(gè)元素都是tensor對(duì)應(yīng)位置的元素加上1
  broadcasted_addition = [[2, 3, 4], [5, 6, 7]]
  '''
  broadcasted_addition = tensor + torch.tensor([1, 1, 1])

比較運(yùn)算(返回布爾張量):

# 返回一個(gè)2x3的布爾張量,所有元素都為False,因?yàn)槊總€(gè)元素都不大于自身。
  greater_than = tensor > tensor

聚合運(yùn)算(如求和、平均、最大值、最小值等):

sum = torch.sum(tensor) # 返回張量所有元素的總和,即1+2+3+4+5+6=21。
  mean = torch.mean(tensor) #返回張量的平均值,即21/6=3.5。
  # 返回最大值張量[4, 5, 6]和最大值的索引[1, 1, 1],因?yàn)榈诙械乃性囟际亲畲笾怠?  max_value, max_index = torch.max(tensor, dim=0)  # 按列求最大值和對(duì)應(yīng)索引

二、自動(dòng)求導(dǎo)

在深度學(xué)習(xí)中,自動(dòng)求導(dǎo)(automatic differentiation)是關(guān)鍵步驟,用于計(jì)算損失函數(shù)對(duì)模型參數(shù)的梯度。PyTorch提供了自動(dòng)求導(dǎo)機(jī)制,可以輕松地定義和計(jì)算復(fù)雜的神經(jīng)網(wǎng)絡(luò)。

1.張量的requires_grad屬性

在PyTorch中,requires_grad屬性用于決定張量是否應(yīng)該在計(jì)算過(guò)程中跟蹤其操作,以便進(jìn)行自動(dòng)求導(dǎo)。如果計(jì)算張量的梯度,就需要設(shè)置requires_grad=True。

import torch

# 創(chuàng)建一個(gè)張量并設(shè)置requires_grad=True
x = torch.tensor([1.0, 2.0], requires_grad=True)
# Original tensor: tensor([1., 2.], requires_grad=True)
print("Original tensor:", x)

2.張量操作與計(jì)算圖

在PyTorch中,張量操作與計(jì)算圖緊密相關(guān),因?yàn)橛?jì)算圖是實(shí)現(xiàn)自動(dòng)求導(dǎo)(autograd)的關(guān)鍵。當(dāng)一個(gè)張量的requires_grad屬性被設(shè)置為True時(shí),PyTorch會(huì)記錄對(duì)該張量的所有操作,形成一個(gè)計(jì)算圖。這個(gè)圖描述了從輸入張量到輸出張量的計(jì)算路徑,每個(gè)節(jié)點(diǎn)代表一個(gè)張量,邊代表操作。

import torch

# 創(chuàng)建一個(gè)需要梯度的張量
x = torch.tensor([1.0, 2.0], requires_grad=True)

# 張量操作
y = x + 2  # 加法操作
z = y * y * 3  # 乘法操作
out = z.mean()  # 平均值操作

此時(shí),計(jì)算圖已經(jīng)隱含地構(gòu)建完成,記錄了從x到out的所有操作。其中,x是計(jì)算圖的起點(diǎn),out是終點(diǎn)。

3.計(jì)算梯度

要計(jì)算梯度,只需對(duì)計(jì)算圖的最終輸出調(diào)用.backward()方法。

# 計(jì)算梯度
out.backward()

# 現(xiàn)在,x的梯度已經(jīng)計(jì)算出來(lái)了,可以通過(guò)x.grad屬性獲取
print("Gradient of x with respect to the output:", x.grad)

out.backward()會(huì)沿著計(jì)算圖反向傳播,計(jì)算所有涉及張量的梯度。在本例中,x.grad將會(huì)給出x相對(duì)于out的梯度,即out關(guān)于x的偏導(dǎo)數(shù)。這在訓(xùn)練神經(jīng)網(wǎng)絡(luò)時(shí)非常有用,因?yàn)榭梢杂脕?lái)更新網(wǎng)絡(luò)的權(quán)重。

4.阻止梯度追蹤

在某些場(chǎng)景下,比如驗(yàn)證模型或計(jì)算某些不需要更新參數(shù)的中間結(jié)果時(shí),阻止梯度追蹤可以減少內(nèi)存消耗和提高效率。使用.detach()或torch.no_grad()是實(shí)現(xiàn)這一目的的有效手段。

  • 使用.detach()方法: 返回一個(gè)與原始張量數(shù)值相同的新張量,但不跟蹤梯度。
new_tensor = original_tensor.detach()
  • 使用torch.no_grad()上下文管理器。
with torch.no_grad():
       # 在此區(qū)域內(nèi)進(jìn)行的操作不會(huì)追蹤梯度
       intermediate_result = some_operation(original_tensor)

5.控制梯度計(jì)算的上下文管理器

torch.autograd.set_grad_enabled(True|False) 是另一個(gè)強(qiáng)大的工具,用于全局控制是否在代碼的特定部分進(jìn)行梯度計(jì)算。相比.detach()和torch.no_grad(),它提供了更多的靈活性,因?yàn)樗试S在代碼的不同部分動(dòng)態(tài)開(kāi)啟或關(guān)閉梯度追蹤,這對(duì)于復(fù)雜的模型調(diào)試、性能優(yōu)化或混合精度訓(xùn)練等場(chǎng)景特別有用。

import torch

# 默認(rèn)情況下,梯度追蹤是開(kāi)啟的
print(f"當(dāng)前梯度追蹤狀態(tài): {torch.is_grad_enabled()}")  # 輸出: True

# 使用set_grad_enabled(False)關(guān)閉梯度追蹤
with torch.autograd.set_grad_enabled(False):
    x = torch.tensor([1.0, 2.0], requires_grad=True)
    y = x * 2
    print(f"在上下文中,梯度追蹤狀態(tài): {torch.is_grad_enabled()}")  # 輸出: False
    print(f"y的requires_grad屬性: {y.requires_grad}")  # 輸出: False

# 離開(kāi)上下文后,梯度追蹤狀態(tài)恢復(fù)到之前的狀態(tài)
print(f"離開(kāi)上下文后,梯度追蹤狀態(tài): {torch.is_grad_enabled()}")  # 輸出: True

# 這里x的梯度追蹤仍然是開(kāi)啟的,除非在其他地方被改變

6.優(yōu)化器與自動(dòng)求導(dǎo)結(jié)合

在訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型時(shí),通常會(huì)使用優(yōu)化器(optimizer)來(lái)更新模型的參數(shù)。優(yōu)化器利用自動(dòng)求導(dǎo)計(jì)算出的梯度來(lái)調(diào)整參數(shù),以最小化損失函數(shù)。以下是一個(gè)使用隨機(jī)梯度下降(SGD)優(yōu)化器的簡(jiǎn)單示例:

import torch
from torch import nn, optim

# 定義一個(gè)簡(jiǎn)單的線性模型
model = nn.Linear(2, 1)  # 輸入2個(gè)特征,輸出1個(gè)值

# 假設(shè)有一些輸入數(shù)據(jù)和標(biāo)簽
inputs = torch.randn(10, 2)  # 10個(gè)樣本,每個(gè)樣本2個(gè)特征
labels = torch.randn(10, 1)  # 10個(gè)樣本,每個(gè)樣本1個(gè)標(biāo)簽

# 創(chuàng)建優(yōu)化器,指定要更新的模型參數(shù)
optimizer = optim.SGD(model.parameters(), lr=0.01)  # 學(xué)習(xí)率為0.01

# 前向傳播
outputs = model(inputs)

# 損失函數(shù)
loss = nn.MSELoss()(outputs, labels)

# 反向傳播并計(jì)算梯度
loss.backward()

# 使用優(yōu)化器更新參數(shù)
optimizer.step()

# 清除梯度(防止梯度累積)
optimizer.zero_grad()

三、神經(jīng)網(wǎng)絡(luò)層

在PyTorch中,nn.Module是構(gòu)建神經(jīng)網(wǎng)絡(luò)模型的核心類,它提供了一個(gè)模塊化的框架,可以方便地組合各種層和操作。

1.創(chuàng)建自定義神經(jīng)網(wǎng)絡(luò)層:

創(chuàng)建自定義神經(jīng)網(wǎng)絡(luò)層是PyTorch中常見(jiàn)的做法。以下是如何創(chuàng)建一個(gè)名為CustomLayer的自定義層,它包含一個(gè)線性層和一個(gè)激活函數(shù)(例如ReLU):

import torch
import torch.nn as nn

class CustomLayer(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(CustomLayer, self).__init__()

        # 創(chuàng)建線性層
        self.linear = nn.Linear(input_size, hidden_size)

        # 創(chuàng)建ReLU激活函數(shù)
        self.relu = nn.ReLU()

        # 創(chuàng)建輸出線性層(如果需要的話,例如對(duì)于分類任務(wù))
        self.output_linear = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        # 應(yīng)用線性變換
        x = self.linear(x)

        # 應(yīng)用ReLU激活函數(shù)
        x = self.relu(x)

        # 如果需要,可以添加更多的操作,例如另一個(gè)線性層
        x = self.output_linear(x)

        return x

其中,CustomLayer類繼承自nn.Module,并在__init__方法中定義了兩個(gè)線性層(一個(gè)輸入層和一個(gè)輸出層)以及一個(gè)ReLU激活函數(shù)。forward方法描述了輸入到輸出的計(jì)算流程:首先,輸入通過(guò)線性層,然后通過(guò)ReLU激活,最后通過(guò)輸出線性層。如果只需要一個(gè)線性變換和激活,可以去掉output_linear。

使用這個(gè)自定義層,可以像使用內(nèi)置層一樣在模型中實(shí)例化和使用它:

input_size = 10
hidden_size = 20
output_size = 5

model = CustomLayer(input_size, hidden_size, output_size)

2.構(gòu)建復(fù)雜的神經(jīng)網(wǎng)絡(luò)模型

構(gòu)建復(fù)雜的神經(jīng)網(wǎng)絡(luò)模型通常涉及到將多個(gè)基本層或者自定義層按照特定順序組合起來(lái)。以下是一個(gè)使用自定義SimpleLayer類來(lái)構(gòu)建多層感知機(jī)(MLP)的示例:

import torch
import torch.nn as nn

class SimpleLayer(nn.Module):
    def __init__(self, input_size, output_size):
        super(SimpleLayer, self).__init__()
        self.linear = nn.Linear(input_size, output_size)
        self.relu = nn.ReLU()

    def forward(self, x):
        x = self.linear(x)
        x = self.relu(x)
        return x

class MLP(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(MLP, self).__init__()
        
        # 第一層:輸入層到隱藏層
        self.layer1 = SimpleLayer(input_dim, hidden_dim)
        
        # 第二層:隱藏層到輸出層
        self.layer2 = SimpleLayer(hidden_dim, output_dim)

    def forward(self, x):
        x = self.layer1(x)  # 第一層前向傳播
        x = self.layer2(x)  # 第二層前向傳播
        return x

# 實(shí)例化一個(gè)MLP模型
input_dim = 784  # 假設(shè)輸入維度為784(例如,MNIST數(shù)據(jù)集)
hidden_dim = 128  # 隱藏層維度
output_dim = 10  # 輸出維度(例如,10類分類問(wèn)題)
model = MLP(input_dim, hidden_dim, output_dim)

# 打印模型結(jié)構(gòu)
print(model)

在以上代碼中,MLP類定義了一個(gè)包含兩個(gè)SimpleLayer實(shí)例的多層感知機(jī)。第一個(gè)SimpleLayer接收輸入數(shù)據(jù)并轉(zhuǎn)換到隱藏層空間,第二個(gè)SimpleLayer則負(fù)責(zé)從隱藏層空間映射到輸出層。通過(guò)這種方式,可以靈活地堆疊多個(gè)層來(lái)構(gòu)造復(fù)雜的神經(jīng)網(wǎng)絡(luò)模型,每增加一層,模型的表達(dá)能力就可能增強(qiáng),從而能學(xué)習(xí)到更復(fù)雜的輸入-輸出映射關(guān)系。

3.模塊的嵌套和子模塊

在PyTorch中,nn.Module的嵌套和子模塊是構(gòu)建復(fù)雜神經(jīng)網(wǎng)絡(luò)架構(gòu)的關(guān)鍵。下面是一個(gè)名為ComplexModel的示例,它包含了兩個(gè)子模塊:一個(gè)CustomLayer和一個(gè)MLP:

import torch
import torch.nn as nn

class ComplexModel(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(ComplexModel, self).__init__()

        # 創(chuàng)建一個(gè)CustomLayer實(shí)例
        self.custom_layer = CustomLayer(input_size, hidden_size, output_size)

        # 創(chuàng)建一個(gè)MLP實(shí)例
        self.mlp = MLP(hidden_size, hidden_size, output_size)

    def forward(self, x):
        x = self.custom_layer(x)
        x = self.mlp(x)
        return x

# 實(shí)例化一個(gè)ComplexModel
input_size = 784  # 假設(shè)輸入維度為784
hidden_size = 128  # 隱藏層維度
output_size = 10  # 輸出維度
model = ComplexModel(input_size, hidden_size, output_size)

# 打印模型結(jié)構(gòu)
print(model)

其中,ComplexModel類包含兩個(gè)子模塊:custom_layer和mlp。custom_layer是一個(gè)自定義層,而mlp是一個(gè)多層感知機(jī)。當(dāng)在ComplexModel的forward方法中調(diào)用這些子模塊時(shí),它們的計(jì)算將按順序進(jìn)行,并且所有子模塊的參數(shù)和梯度都會(huì)被自動(dòng)跟蹤。這種模塊化的方法使得代碼易于理解和維護(hù),同時(shí)可以方便地重用和組合現(xiàn)有的層和模型。

4.訪問(wèn)模塊的參數(shù)

在PyTorch中,nn.Module類提供了兩種方法來(lái)訪問(wèn)模型的參數(shù):parameters()和named_parameters()。這兩個(gè)方法都可以用來(lái)遍歷模型的所有參數(shù),但它們的區(qū)別在于返回的內(nèi)容。

  • parameters()方法: 返回一個(gè)可迭代的生成器,其中每個(gè)元素是一個(gè)張量,代表模型的一個(gè)參數(shù)。
model = ComplexModel()
   for param in model.parameters():
       print(param)
  • named_parameters()方法: 返回一個(gè)可迭代的生成器,其中每個(gè)元素是一個(gè)元組,包含參數(shù)的名稱和對(duì)應(yīng)的張量。
model = ComplexModel()
   for name, param in model.named_parameters():
       print(f"Name: {name}, Parameter: {param}")

在實(shí)際應(yīng)用中,通常使用named_parameters()方法,因?yàn)檫@樣可以同時(shí)獲取參數(shù)的名稱,這對(duì)于調(diào)試和可視化模型參數(shù)很有用。

5.模型的保存與加載

要保存模型的狀態(tài)字典,可以使用state_dict()方法,然后使用torch.save()將其寫入磁盤。加載模型時(shí),首先創(chuàng)建一個(gè)模型實(shí)例,然后使用load_state_dict()方法加載保存的參數(shù)。

  • 保存模型:
torch.save(model.state_dict(), 'model.pth')
  • 加載模型:
model = ComplexModel(input_size, hidden_size, output_size)
   model.load_state_dict(torch.load('model.pth'))

6.模型的設(shè)備移動(dòng)

使用to()方法可以將模型及其所有參數(shù)移到GPU或CPU上。如果設(shè)備可用,它會(huì)嘗試將模型移動(dòng)到GPU上,否則保留在CPU上。將模型移動(dòng)到GPU(如果可用):

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
   model.to(device)

7.自定義層和操作

要?jiǎng)?chuàng)建自定義的神經(jīng)網(wǎng)絡(luò)層或操作,可以繼承nn.Module,再實(shí)現(xiàn)新的前向傳播邏輯,包括新的數(shù)學(xué)函數(shù)、正則化、注意力機(jī)制等。例如,假設(shè)要?jiǎng)?chuàng)建一個(gè)自定義的歸一化層:

class CustomNormalization(nn.Module):
       def __init__(self, dim):
           super(CustomNormalization, self).__init__()
           self.dim = dim

       def forward(self, x):
           mean = x.mean(dim=self.dim, keepdim=True)
           std = x.std(dim=self.dim, keepdim=True)
           return (x - mean) / (std + 1e-8)

   model.add_module('custom_normalization', CustomNormalization(1))

首先定義了一個(gè)新的層CustomNormalization,它計(jì)算輸入張量在指定維度上的平均值和標(biāo)準(zhǔn)差,然后對(duì)輸入進(jìn)行歸一化。這個(gè)新層可以像其他任何nn.Module實(shí)例一樣添加到模型中,并在forward方法中使用。

四、優(yōu)化器

在 PyTorch 中,優(yōu)化器(Optimizer)是用于更新神經(jīng)網(wǎng)絡(luò)模型參數(shù)的工具。優(yōu)化器基于模型參數(shù)的梯度信息來(lái)調(diào)整參數(shù),從而最小化或最大化某個(gè)損失函數(shù)。PyTorch 提供了多種優(yōu)化器,包括隨機(jī)梯度下降(SGD)、Adam、RMSprop 等。

1.SGD

SGD是最基礎(chǔ)的優(yōu)化算法,它根據(jù)梯度的方向逐步調(diào)整模型參數(shù),以減少損失函數(shù)的值。在PyTorch中,可以通過(guò)以下方式創(chuàng)建一個(gè)SGD優(yōu)化器:

import torch.optim as optim
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

其中,model.parameters()用于獲取模型的所有可學(xué)習(xí)參數(shù)。lr是學(xué)習(xí)率,決定了參數(shù)更新的步長(zhǎng)。momentum是動(dòng)量項(xiàng),默認(rèn)為0,可以加速學(xué)習(xí)過(guò)程并有助于跳出局部最小值。

2.Adam

Adam(Adaptive Moment Estimation)是另一種廣泛使用的優(yōu)化器,它結(jié)合了動(dòng)量和自適應(yīng)學(xué)習(xí)率的優(yōu)點(diǎn),可自動(dòng)調(diào)整每個(gè)參數(shù)的學(xué)習(xí)率,通常不需要手動(dòng)調(diào)整學(xué)習(xí)率衰減。

optimizer = optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))

其中,betas是兩個(gè)超參數(shù),分別控制了一階矩和二階矩估計(jì)的衰減率。

3.RMSprop

RMSprop(Root Mean Square Propagation)也是自適應(yīng)學(xué)習(xí)率的一種方法,它主要根據(jù)歷史梯度的平方根來(lái)調(diào)整學(xué)習(xí)率。

optimizer = optim.RMSprop(model.parameters(), lr=0.001, alpha=0.99)

其中,alpha是平滑常數(shù),用于計(jì)算梯度的移動(dòng)平均。

五、損失函數(shù)

損失函數(shù)(Loss Function)在機(jī)器學(xué)習(xí)和深度學(xué)習(xí)領(lǐng)域扮演著核心角色,它是評(píng)估模型預(yù)測(cè)質(zhì)量的重要標(biāo)準(zhǔn)。損失函數(shù)量化了模型預(yù)測(cè)值與真實(shí)標(biāo)簽之間的偏差,訓(xùn)練過(guò)程本質(zhì)上是通過(guò)優(yōu)化算法(如梯度下降)不斷調(diào)整模型參數(shù),以最小化這個(gè)損失值。PyTorch,作為一個(gè)強(qiáng)大的深度學(xué)習(xí)框架,內(nèi)置了多種損失函數(shù),以適應(yīng)不同類型的機(jī)器學(xué)習(xí)任務(wù),主要包括但不限于以下幾類:

1.均方誤差損失(Mean Squared Error, MSE)

用于回歸問(wèn)題,計(jì)算預(yù)測(cè)值與真實(shí)值之間差的平方的平均值。

import torch
import torch.nn as nn

# 假設(shè)模型輸出和真實(shí)標(biāo)簽
outputs = model(inputs)  # 模型的預(yù)測(cè)輸出
targets = labels  # 真實(shí)標(biāo)簽

# 定義損失函數(shù)
mse_loss = nn.MSELoss()

# 計(jì)算損失
loss = mse_loss(outputs, targets)

2.交叉熵?fù)p失(Cross-Entropy)

用于分類問(wèn)題,計(jì)算預(yù)測(cè)概率分布與真實(shí)標(biāo)簽之間的交叉熵?fù)p失。

# 假設(shè)模型輸出為每個(gè)類別的概率分布
outputs = model(inputs)
# 確保標(biāo)簽是類別索引(而非one-hot編碼),對(duì)于多分類問(wèn)題
targets = torch.LongTensor(labels)  # 確保標(biāo)簽是整數(shù)

cross_entropy_loss = nn.CrossEntropyLoss()

loss = cross_entropy_loss(outputs, targets)

3.二元交叉熵?fù)p失(Binary Cross-Entropy)

二元交叉熵?fù)p失通常用于二分類問(wèn)題,其中每個(gè)樣本屬于兩個(gè)類別之一。

# 假設(shè)二分類問(wèn)題,直接輸出概率
outputs = model(inputs)  # 輸出已經(jīng)是概率
targets = labels.float()  # 標(biāo)簽轉(zhuǎn)換為float,二分類通常為0或1

bce_loss = nn.BCELoss()

loss = bce_loss(outputs, targets)

如果兩類樣本數(shù)量嚴(yán)重不平衡,可以使用加權(quán)二元交叉熵?fù)p失(Weighted Binary Cross-Entropy Loss)來(lái)調(diào)整不同類別的權(quán)重,以確保模型在訓(xùn)練時(shí)對(duì)較少出現(xiàn)的類別給予更多關(guān)注。

import torch
import torch.nn as nn

# 假設(shè)有兩類,其中類0的樣本較少
num_samples = [100, 1000]  # 類別0有100個(gè)樣本,類別1有1000個(gè)樣本
weights = [1 / num_samples[0], 1 / num_samples[1]]  # 計(jì)算類別權(quán)重

# 創(chuàng)建一個(gè)加權(quán)二元交叉熵?fù)p失函數(shù)
weighted_bce_loss = nn.BCEWithLogitsLoss(weight=torch.tensor(weights))

# 假設(shè)model是模型,inputs是輸入數(shù)據(jù),labels是二進(jìn)制標(biāo)簽(0或1)
outputs = model(inputs)
labels = labels.float()  # 將標(biāo)簽轉(zhuǎn)換為浮點(diǎn)數(shù),因?yàn)锽CEWithLogitsLoss期望的是概率

# 計(jì)算加權(quán)損失
loss = weighted_bce_loss(outputs, labels)

4.K-L 散度損失(Kullback-Leibler Divergence Loss)

衡量?jī)蓚€(gè)概率分布的差異,常用于生成模型訓(xùn)練,如VAEs和GANs中的鑒別器部分。

Kullback-Leibler散度(KLDivLoss)是一種衡量?jī)蓚€(gè)概率分布之間差異的方法,常用于信息論和機(jī)器學(xué)習(xí)中。在PyTorch中,nn.KLDivLoss是實(shí)現(xiàn)這一概念的模塊,用于比較預(yù)測(cè)概率分布(通常是softmax函數(shù)的輸出)與目標(biāo)概率分布或“真實(shí)”分布。

KLDivLoss的數(shù)學(xué)定義為:

這里,(P)是真實(shí)分布,而(Q)是預(yù)測(cè)或近似分布。KLDivLoss總是非負(fù)的,并且只有當(dāng)兩個(gè)分布完全相同時(shí)才為零。

import torch
import torch.nn as nn

# 假設(shè)有兩個(gè)概率分布,preds是模型預(yù)測(cè)的概率分布,targets是實(shí)際的概率分布
preds = torch.randn(3, 5).softmax(dim=1)  # 預(yù)測(cè)概率分布,使用softmax轉(zhuǎn)換
targets = torch.randn(3, 5).softmax(dim=1)  # 真實(shí)概率分布

# 初始化KLDivLoss實(shí)例,reduction參數(shù)定義了損失的聚合方式,可以是'mean'、'sum'或'none'
criterion = nn.KLDivLoss(reduction='batchmean')  # 'batchmean'表示對(duì)批量數(shù)據(jù)求平均

# 計(jì)算KLDivLoss
loss = criterion(preds.log(), targets)  # 注意:preds應(yīng)該取對(duì)數(shù),因?yàn)镵LDivLoss默認(rèn)期望log_softmax的輸出

print('KLDivLoss:', loss.item())

5.三元組損失(Triplet Margin Loss)

三元組損失(Triplet Margin Loss)是深度學(xué)習(xí)中用于學(xué)習(xí)特征表示的一種損失函數(shù),尤其在人臉識(shí)別、圖像檢索等領(lǐng)域廣泛應(yīng)用。它的目標(biāo)是學(xué)習(xí)到一個(gè)特征空間,在這個(gè)空間中,同類別的樣本之間的距離小于不同類別樣本之間的距離,且保持一定的邊際差(margin)。

三元組損失函數(shù)的數(shù)學(xué)定義為:

其中,

  • a是錨點(diǎn)樣本的特征向量
  • p是正樣本的特征向量
  • n是負(fù)樣本的特征向量
  • d(x, y)表示樣本x和樣本y之間的距離(通常是歐氏距離或余弦距離)
  • m是預(yù)設(shè)的邊際值,用于保證正樣本和負(fù)樣本之間的差距至少為m。

這個(gè)損失函數(shù)的目的是最小化所有滿足的三元組的損失,這樣就能確保錨點(diǎn)樣本與正樣本的距離小于與負(fù)樣本的距離至少m個(gè)單位。

在PyTorch中,可以使用torch.nn.TripletMarginLoss來(lái)實(shí)現(xiàn)三元組損失。

import torch
import torch.nn as nn

# 設(shè)置隨機(jī)種子以獲得可復(fù)現(xiàn)的結(jié)果
torch.manual_seed(42)

# 假設(shè)特征維度
feature_dim = 128

# 生成隨機(jī)三元組數(shù)據(jù)
num_triplets = 10
anchors = torch.randn(num_triplets, feature_dim)
positives = torch.randn(num_triplets, feature_dim)
negatives = torch.randn(num_triplets, feature_dim)

# 將它們組合成形狀為 (num_triplets, 3, feature_dim) 的張量
triplets = torch.stack((anchors, positives, negatives), dim=1)

# 初始化三元組損失函數(shù),設(shè)置邊際值m
triplet_loss = nn.TripletMarginLoss(margin=1.0)

# 計(jì)算損失
loss = triplet_loss(triplets[:, 0], triplets[:, 1], triplets[:, 2])

print('Triplet Margin Loss:', loss.item())

6.使用損失函數(shù)進(jìn)行訓(xùn)練

在訓(xùn)練循環(huán)中,通過(guò)計(jì)算模型輸出與真實(shí)標(biāo)簽的損失,并調(diào)用反向傳播和優(yōu)化器更新參數(shù)來(lái)訓(xùn)練模型。

output = model(inputs)
loss = criterion(output, labels)

optimizer.zero_grad()
loss.backward()
optimizer.step()

六、數(shù)據(jù)加載與預(yù)處理

在PyTorch中,數(shù)據(jù)加載與預(yù)處理是構(gòu)建深度學(xué)習(xí)模型不可或缺的環(huán)節(jié),它確保數(shù)據(jù)以高效、規(guī)范的方式被送入模型進(jìn)行訓(xùn)練或測(cè)試。

1.數(shù)據(jù)集的定義

在PyTorch中,數(shù)據(jù)集的定義通常通過(guò)創(chuàng)建一個(gè)新的類來(lái)實(shí)現(xiàn),這個(gè)類繼承自torch.utils.data.Dataset。這個(gè)自定義類需要實(shí)現(xiàn)以下兩個(gè)核心方法:

  • __len__方法:這個(gè)方法返回?cái)?shù)據(jù)集中的樣本數(shù)量。它告訴外界調(diào)用者數(shù)據(jù)集中有多少個(gè)樣本可以用來(lái)訓(xùn)練或測(cè)試模型。
  • __getitem__方法:這個(gè)方法根據(jù)給定的索引返回一個(gè)樣本數(shù)據(jù)及其對(duì)應(yīng)的標(biāo)簽(如果有)。它允許按需訪問(wèn)數(shù)據(jù)集中的任意一個(gè)樣本,通常包括數(shù)據(jù)的加載和必要的預(yù)處理。

一個(gè)基本的數(shù)據(jù)集定義示例如下:

from torch.utils.data import Dataset

class CustomDataset(Dataset):
    def __init__(self, data, labels, transform=None):
        self.data = data
        self.labels = labels
        self.transform = transform

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        sample = {'data': self.data[idx], 'label': self.labels[idx]}

        if self.transform:
            sample = self.transform(sample)

        return sample

其中,CustomDataset類接收3個(gè)參數(shù):data和labels、transform,分別代表數(shù)據(jù)集中的樣本數(shù)據(jù)和對(duì)應(yīng)的標(biāo)簽及預(yù)處理變換。在__init__方法中,將這些參數(shù)存儲(chǔ)在類的屬性中,以便在__getitem__方法中訪問(wèn)。__len__方法返回?cái)?shù)據(jù)集的長(zhǎng)度,即樣本數(shù)量。__getitem__方法通過(guò)索引index獲取對(duì)應(yīng)的數(shù)據(jù)和標(biāo)簽。

此外,為了增強(qiáng)數(shù)據(jù)的多樣性和模型的泛化能力,可以在數(shù)據(jù)集類中集成數(shù)據(jù)預(yù)處理邏輯,或者通過(guò)傳遞一個(gè)變換對(duì)象(如torchvision.transforms中的變換)來(lái)動(dòng)態(tài)地對(duì)數(shù)據(jù)進(jìn)行變換,如旋轉(zhuǎn)、縮放、裁剪等。

2.數(shù)據(jù)加載器

數(shù)據(jù)加載器(DataLoader)在PyTorch中是一個(gè)非常重要的組件,它負(fù)責(zé)從數(shù)據(jù)集中高效地加載數(shù)據(jù),并為模型訓(xùn)練和驗(yàn)證提供批次(batch)數(shù)據(jù)。DataLoader類位于torch.utils.data模塊中,提供了以下幾個(gè)關(guān)鍵功能:

  • 批量加載:它能夠?qū)?shù)據(jù)集分割成多個(gè)小批量(batch),這是深度學(xué)習(xí)訓(xùn)練過(guò)程中的標(biāo)準(zhǔn)做法,有助于提高訓(xùn)練效率和內(nèi)存利用率。
  • 數(shù)據(jù)混洗:通過(guò)設(shè)置shuffle=True,可以在每個(gè)訓(xùn)練epoch開(kāi)始前隨機(jī)打亂數(shù)據(jù)集的順序,增加模型訓(xùn)練的隨機(jī)性,有助于提高模型的泛化能力。
  • 多線程加載:通過(guò)num_workers參數(shù),可以在后臺(tái)使用多個(gè)線程并發(fā)地加載數(shù)據(jù),減少數(shù)據(jù)I/O等待時(shí)間,進(jìn)一步加速訓(xùn)練過(guò)程。
  • 內(nèi)存節(jié)?。篋ataLoader通過(guò)按需加載數(shù)據(jù)(即僅在訓(xùn)練過(guò)程中需要時(shí)才從磁盤加載數(shù)據(jù)到內(nèi)存),避免一次性將整個(gè)數(shù)據(jù)集加載到內(nèi)存中,這對(duì)于大規(guī)模數(shù)據(jù)集尤為重要。

創(chuàng)建一個(gè)DataLoader實(shí)例的基本用法如下:

from torch.utils.data import DataLoader
from your_dataset_module import YourCustomDataset

custom_dataset = CustomDataset(data, labels,transform=...)

# 創(chuàng)建DataLoader實(shí)例
data_loader = DataLoader(
    dataset=custom_dataset,  # 數(shù)據(jù)集實(shí)例
    batch_size=32,           # 每個(gè)批次的樣本數(shù)
    shuffle=True,            # 是否在每個(gè)epoch開(kāi)始時(shí)打亂數(shù)據(jù)
    num_workers=4,           # 使用的子進(jìn)程數(shù),用于數(shù)據(jù)加載(0表示不使用多線程)
    drop_last=False,         # 如果數(shù)據(jù)集大小不能被batch_size整除,是否丟棄最后一個(gè)不完整的batch
)

# 使用data_loader在訓(xùn)練循環(huán)中迭代獲取數(shù)據(jù)
for inputs, labels in data_loader:
    # 在這里執(zhí)行模型訓(xùn)練或驗(yàn)證的代碼
    pass

3.數(shù)據(jù)預(yù)處理與轉(zhuǎn)換

在PyTorch中,torchvision.transforms模塊提供了豐富的預(yù)處理和轉(zhuǎn)換功能,以下是一些常用的轉(zhuǎn)換操作:

(1) 常見(jiàn)的預(yù)處理與轉(zhuǎn)換操作:

  • Resize:調(diào)整圖像大小到指定尺寸,例如,transforms.Resize((256, 256))會(huì)將圖像調(diào)整為256x256像素。
  • CenterCrop:從圖像中心裁剪出指定大小的區(qū)域,如transforms.CenterCrop(224)。
  • RandomCrop:隨機(jī)從圖像中裁剪出指定大小的區(qū)域,增加了數(shù)據(jù)多樣性,有利于模型學(xué)習(xí)。
  • RandomHorizontalFlip:以一定概率水平翻轉(zhuǎn)圖像,是常用的數(shù)據(jù)增強(qiáng)手段之一。
  • RandomRotation:隨機(jī)旋轉(zhuǎn)圖像一定角度,進(jìn)一步增強(qiáng)數(shù)據(jù)多樣性。
  • ToTensor:將PIL圖像或numpy數(shù)組轉(zhuǎn)換為PyTorch的Tensor,并將顏色通道從RGB調(diào)整為Tensorflow所期望的格式(HWC -> CHW)。
  • Normalize:對(duì)圖像像素值進(jìn)行標(biāo)準(zhǔn)化,通常使用特定數(shù)據(jù)集(如ImageNet)的均值和標(biāo)準(zhǔn)差,例如transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])。

(2) 組合變換

為了簡(jiǎn)化應(yīng)用多個(gè)變換的過(guò)程,可以使用Compose類將多個(gè)變換操作組合在一起,形成一個(gè)變換管道,如:

transform = transforms.Compose([
    transforms.Resize((256, 256)),
    transforms.RandomCrop((224, 224)),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

# 將轉(zhuǎn)換應(yīng)用于數(shù)據(jù)集
dataset = CustomDataset(data, labels, transform=transform)

七、模型的保存與加載

在PyTorch中,保存和加載模型是通過(guò)torch.save()和torch.load()函數(shù)完成的。以下是詳細(xì)的解釋和代碼示例:

1.模型的保存

模型的參數(shù)和狀態(tài)可以保存為狀態(tài)字典(state_dict),或者保存整個(gè)模型對(duì)象,包括模型結(jié)構(gòu)和參數(shù)。

  • 保存狀態(tài)字典(僅參數(shù)):
# 定義模型
model = SimpleModel()

# 保存狀態(tài)字典
torch.save(model.state_dict(), 'model_state.pth')
  • 保存整個(gè)模型(結(jié)構(gòu)+參數(shù)):
# 保存整個(gè)模型
torch.save(model, 'model.pth')

2.模型的加載

加載模型時(shí),可以單獨(dú)加載狀態(tài)字典并重新構(gòu)建模型,或者直接加載整個(gè)模型。

  • 加載狀態(tài)字典并重建模型:
# 加載狀態(tài)字典
loaded_state_dict = torch.load('model_state.pth')

# 創(chuàng)建相同結(jié)構(gòu)的新模型
new_model = SimpleModel()

# 將加載的狀態(tài)字典加載到新模型
new_model.load_state_dict(loaded_state_dict)
  • 加載整個(gè)模型:
# 加載整個(gè)模型
loaded_model = torch.load('model.pth')

3.跨設(shè)備加載模型

如果模型在GPU上訓(xùn)練并保存,但在CPU上加載,可以使用map_location參數(shù):

# 在CPU上加載GPU上保存的模型
loaded_model = torch.load('model.pth', map_location=torch.device('cpu'))

4.保存與加載模型的結(jié)構(gòu)和參數(shù)

在保存整個(gè)模型時(shí),模型的結(jié)構(gòu)和參數(shù)都會(huì)被保存。

# 保存整個(gè)模型(包括結(jié)構(gòu)和參數(shù))
torch.save(model, 'model.pth')

# 加載整個(gè)模型
loaded_model = torch.load('model.pth')

5.僅保存與加載模型的結(jié)構(gòu)

如果只想保存和加載模型的結(jié)構(gòu)而不包含參數(shù),可以使用 torch.save 時(shí)設(shè)置 save_model_obj=False。

# 保存模型結(jié)構(gòu)
torch.save(model, 'model_structure.pth', save_model_obj=False)

# 加載模型結(jié)構(gòu)
loaded_model_structure = torch.load('model_structure.pth')

6.僅保存和加載模型的參數(shù)

如果只想保存和加載模型參數(shù)而不包含模型結(jié)構(gòu),可以使用 torch.save 時(shí)設(shè)置 save_model_obj=False。

# 保存模型參數(shù)
torch.save(model.state_dict(), 'model_parameters.pth')

# 加載模型參數(shù)
loaded_parameters = torch.load('model_parameters.pth')
model.load_state_dict(loaded_parameters)

八、學(xué)習(xí)率調(diào)整

學(xué)習(xí)率調(diào)整是深度學(xué)習(xí)模型訓(xùn)練過(guò)程中的一個(gè)重要環(huán)節(jié),它有助于模型在訓(xùn)練過(guò)程中找到更好的權(quán)重。PyTorch 提供了torch.optim.lr_scheduler模塊來(lái)實(shí)現(xiàn)各種學(xué)習(xí)率調(diào)整策略。

1.StepLR

StepLR是一種基礎(chǔ)且常用的學(xué)習(xí)率調(diào)整策略,它按照預(yù)定的周期(通常是按 epoch 計(jì)算)來(lái)調(diào)整學(xué)習(xí)率。其中,step_size參數(shù)指定了衰減發(fā)生的時(shí)間間隔。比如,如果step_size=5,則學(xué)習(xí)率每過(guò)5個(gè)epoch就會(huì)調(diào)整一次。 gamma參數(shù)控制了每次調(diào)整時(shí)學(xué)習(xí)率的衰減比例。如果gamma=0.1,這意味著每到達(dá)一個(gè)step_size,學(xué)習(xí)率就會(huì)乘以0.1,也就是衰減到原來(lái)的10%。

import torch.optim as optim
from torch.optim.lr_scheduler import StepLR

# 初始化模型和優(yōu)化器
model = YourModel()
optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)

# 創(chuàng)建 StepLR 調(diào)度器
scheduler = StepLR(optimizer, step_size=5, gamma=0.1)

# 訓(xùn)練循環(huán)
for epoch in range(num_epochs):
    # 訓(xùn)練過(guò)程...

    # 在每個(gè)epoch結(jié)束時(shí)調(diào)用scheduler的step()方法來(lái)更新學(xué)習(xí)率
    scheduler.step()

如上示例中,學(xué)習(xí)率會(huì)在每個(gè)第5、10、15...個(gè)epoch后自動(dòng)減少為原來(lái)的10%,直到訓(xùn)練結(jié)束。

2.MultiStepLR

MultiStepLR 與 StepLR 類似,都是基于周期(epoch)來(lái)調(diào)整學(xué)習(xí)率,但提供了更靈活的衰減時(shí)間點(diǎn)控制。通過(guò) milestones 參數(shù),可以精確指定學(xué)習(xí)率應(yīng)該在哪些特定的周期數(shù)下降。gamma 參數(shù)則決定了每次在這些指定周期學(xué)習(xí)率下降的比例。

例如,如果設(shè)置milestones=[10, 20, 30]和gamma=0.1,則:

  • 在訓(xùn)練的第10個(gè)epoch結(jié)束后,學(xué)習(xí)率會(huì)首次乘以0.1,即減少到原來(lái)的10%。
  • 接著,在第20個(gè)epoch后,學(xué)習(xí)率再次乘以0.1,相對(duì)于初始值衰減為原來(lái)的1%。
  • 最后,在第30個(gè)epoch后,學(xué)習(xí)率又一次乘以0.1,最終相對(duì)于初始值衰減為原來(lái)的0.1%。

這種方式允許根據(jù)訓(xùn)練過(guò)程中的性能變化或預(yù)期的學(xué)習(xí)曲線,更加精細(xì)地控制學(xué)習(xí)率的下降時(shí)機(jī),有助于模型更好地收斂或避免過(guò)擬合。下面是使用 MultiStepLR 的簡(jiǎn)單示例代碼:

import torch.optim as optim
from torch.optim.lr_scheduler import MultiStepLR

# 初始化模型和優(yōu)化器
model = YourModel()
optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)

# 創(chuàng)建 MultiStepLR 調(diào)度器
scheduler = MultiStepLR(optimizer, milestones=[10, 20, 30], gamma=0.1)

# 訓(xùn)練循環(huán)
for epoch in range(num_epochs):
    # 訓(xùn)練過(guò)程...

    # 每個(gè)epoch結(jié)束時(shí)調(diào)用scheduler的step()方法檢查是否需要調(diào)整學(xué)習(xí)率
    scheduler.step()

3.ExponentialLR

ExponentialLR 是一種學(xué)習(xí)率調(diào)整策略,它使學(xué)習(xí)率按照指數(shù)函數(shù)的方式逐漸衰減。與 StepLR 和 MultiStepLR 在特定的周期突然改變學(xué)習(xí)率不同,ExponentialLR 在每個(gè)訓(xùn)練步驟(或每個(gè)epoch,具體取決于調(diào)度器的更新頻率)后,都按照一個(gè)固定的比率逐漸減少學(xué)習(xí)率。這對(duì)于需要平滑降低學(xué)習(xí)率,以更細(xì)致地探索解空間或在訓(xùn)練后期緩慢逼近最優(yōu)解的場(chǎng)景非常有用。

使用 ExponentialLR 的代碼示例如下:

import torch.optim as optim
from torch.optim.lr_scheduler import ExponentialLR

# 初始化模型和優(yōu)化器
model = YourModel()
optimizer = optim.SGD(model.parameters(), lr=initial_lr, momentum=0.9)

# 創(chuàng)建 ExponentialLR 調(diào)度器
# 其中 gamma 參數(shù)指定了學(xué)習(xí)率衰減的速率,例如 gamma=0.9 表示每經(jīng)過(guò)一個(gè)調(diào)整周期,學(xué)習(xí)率變?yōu)樵瓉?lái)的 90%
scheduler = ExponentialLR(optimizer, gamma=0.9)

# 訓(xùn)練循環(huán)
for epoch in range(num_epochs):
    # 訓(xùn)練過(guò)程...

    # 每個(gè)epoch結(jié)束時(shí)調(diào)用scheduler的step()方法更新學(xué)習(xí)率
    scheduler.step()

其中,initial_lr即為設(shè)定的初始學(xué)習(xí)率,gamma=0.9 表示每次更新后,學(xué)習(xí)率都會(huì)乘以0.9,因此學(xué)習(xí)率會(huì)以指數(shù)形式逐漸減小。

4.使用學(xué)習(xí)率調(diào)整器

在PyTorch中使用學(xué)習(xí)率調(diào)整器(Learning Rate Scheduler)是一個(gè)提高模型訓(xùn)練效率和性能的有效策略。下面以StepLR為例展示如何使用學(xué)習(xí)率調(diào)整器。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR

# 假設(shè)的模型定義
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.linear = nn.Linear(10, 1)

    def forward(self, x):
        return self.linear(x)

# 實(shí)例化模型和優(yōu)化器
model = SimpleModel()
optimizer = optim.SGD(model.parameters(), lr=0.1)

# 創(chuàng)建學(xué)習(xí)率調(diào)整器
scheduler = StepLR(optimizer, step_size=5, gamma=0.1)  # 每5個(gè)epoch學(xué)習(xí)率減半

# 訓(xùn)練循環(huán)
num_epochs = 30
for epoch in range(num_epochs):
    # 假設(shè)的訓(xùn)練步驟,這里簡(jiǎn)化處理
    for batch_idx, (data, target) in enumerate(train_loader):
        optimizer.zero_grad()
        output = model(data)
        loss = F.mse_loss(output, target)
        loss.backward()
        optimizer.step()

    # 每個(gè)epoch結(jié)束時(shí)更新學(xué)習(xí)率
    scheduler.step()
    print(f"Epoch [{epoch+1}/{num_epochs}], LR: {scheduler.get_last_lr()[0]}")

九、模型評(píng)估

模型評(píng)估是機(jī)器學(xué)習(xí)項(xiàng)目中不可或缺的一環(huán),它旨在量化模型在未知數(shù)據(jù)上的表現(xiàn),確保模型具有良好的泛化能力。以下是模型評(píng)估的關(guān)鍵步驟。

1.設(shè)置模型為評(píng)估模式

在PyTorch中,通過(guò)調(diào)用model.eval()方法,模型會(huì)被設(shè)置為評(píng)估模式。這一步驟至關(guān)重要,因?yàn)樗鼤?huì)影響到某些層的行為,比如關(guān)閉Dropout層和Batch Normalization層的訓(xùn)練時(shí)特有的特性,確保模型的預(yù)測(cè)是確定性的,并且不會(huì)影響模型的內(nèi)部狀態(tài)。

model.eval()

2.使用驗(yàn)證集或測(cè)試集進(jìn)行推理

遍歷驗(yàn)證集或測(cè)試集,對(duì)輸入數(shù)據(jù)進(jìn)行前向傳播,得到模型的預(yù)測(cè)輸出。

model.eval()

with torch.no_grad():
    for inputs, labels in dataloader:
        outputs = model(inputs)
        # 進(jìn)行后續(xù)處理..

3.計(jì)算性能指標(biāo)

(1) 準(zhǔn)確率(Accuracy)

準(zhǔn)確率(Accuracy)是機(jī)器學(xué)習(xí)中最基本且直觀的性能評(píng)估指標(biāo)之一,尤其適用于多分類問(wèn)題。它定義為模型正確分類的樣本數(shù)占總樣本數(shù)的比例。

import torch

# 假設(shè) outputs 和 labels 都是形狀為 (batch_size,) 的張量
# 對(duì)于多分類問(wèn)題,outputs 通常包含每個(gè)類別的概率,需要獲取預(yù)測(cè)類別
_, predicted = torch.max(outputs.data, 1)

# 將預(yù)測(cè)和真實(shí)標(biāo)簽轉(zhuǎn)換為相同的數(shù)據(jù)類型(例如,都轉(zhuǎn)為整數(shù))
if isinstance(predicted, torch.Tensor):
    predicted = predicted.cpu().numpy()
if isinstance(labels, torch.Tensor):
    labels = labels.cpu().numpy()

# 計(jì)算并輸出準(zhǔn)確率
accuracy = (predicted == labels).sum() / len(labels)
print(f'Accuracy: {accuracy}')

(2) 精確度(Precision)

精確度(Precision)是模型預(yù)測(cè)為正類的樣本中,真正為正類的比例。

from sklearn.metrics import precision_score

# 假設(shè) predictions 和 true_labels 是形狀為 (n_samples,) 的數(shù)組
# predictions 是模型的預(yù)測(cè)結(jié)果,true_labels 是對(duì)應(yīng)的真值標(biāo)簽
# 如果是多分類問(wèn)題,labels 參數(shù)是所有類別的列表

# 二分類問(wèn)題
precision_binary = precision_score(true_labels, predictions)

# 多分類問(wèn)題,宏平均
precision_macro = precision_score(true_labels, predictions, average='macro')

# 多分類問(wèn)題,微平均
precision_micro = precision_score(true_labels, predictions, average='micro')

print(f'Binary Precision: {precision_binary}')
print(f'Macro Average Precision: {precision_macro}')
print(f'Micro Average Precision: {precision_micro}')

(3) 召回率(Recall)

召回率(Recall),也稱為靈敏度或真正率,衡量的是模型識(shí)別出的所有正類樣本中,正確識(shí)別的比例。

from sklearn.metrics import recall_score

# 假設(shè) predictions 和 true_labels 是形狀為 (n_samples,) 的數(shù)組
# predictions 是模型的預(yù)測(cè)結(jié)果,true_labels 是對(duì)應(yīng)的真值標(biāo)簽
# 對(duì)于多分類問(wèn)題,labels 參數(shù)是所有類別的列表

# 二分類問(wèn)題
recall_binary = recall_score(true_labels, predictions)

# 多分類問(wèn)題,宏平均
recall_macro = recall_score(true_labels, predictions, average='macro')

# 多分類問(wèn)題,微平均
recall_micro = recall_score(true_labels, predictions, average='micro')

print(f'Binary Recall: {recall_binary}')
print(f'Macro Average Recall: {recall_macro}')
print(f'Micro Average Recall: {recall_micro}')

(4) F1分?jǐn)?shù)(F1 Score)

F1分?jǐn)?shù)是精確度(Precision)和召回率(Recall)的調(diào)和平均值,旨在提供一個(gè)綜合評(píng)價(jià)指標(biāo),特別是對(duì)于類別不平衡的數(shù)據(jù)集。

from sklearn.metrics import f1_score

# 假設(shè) predictions 和 true_labels 是形狀為 (n_samples,) 的數(shù)組
# predictions 是模型的預(yù)測(cè)結(jié)果,true_labels 是對(duì)應(yīng)的真值標(biāo)簽
# 對(duì)于多分類問(wèn)題,labels 參數(shù)是所有類別的列表

# 二分類問(wèn)題
f1_binary = f1_score(true_labels, predictions)

# 多分類問(wèn)題,宏平均
f1_macro = f1_score(true_labels, predictions, average='macro')

# 多分類問(wèn)題,微平均
f1_micro = f1_score(true_labels, predictions, average='micro')

print(f'Binary F1 Score: {f1_binary}')
print(f'Macro Average F1 Score: {f1_macro}')
print(f'Micro Average F1 Score: {f1_micro}')

4.ROC曲線

ROC曲線(Receiver Operating Characteristic Curve)是一種評(píng)估二分類模型性能的方法,特別是在正負(fù)樣本比例不平衡或者對(duì)假陽(yáng)性(False Positives, FP)和假陰性(False Negatives, FN)的代價(jià)不等同的場(chǎng)景下特別有用。ROC曲線通過(guò)改變決策閾值,展示了模型在不同閾值下的真正例率(True Positive Rate, TPR)與假正例率(False Positive Rate, FPR)之間的關(guān)系。

from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as plt

# 假設(shè) y_true 是二分類的真值標(biāo)簽,y_scores 是模型的得分或概率輸出
y_true = [0, 1, 1, 0, 1, 0, 1, 1, 0, 1]  # 真實(shí)標(biāo)簽
y_scores = [0.1, 0.4, 0.35, 0.8, 0.6, 0.1, 0.9, 0.7, 0.2, 0.5]  # 模型得分

# 計(jì)算ROC曲線的點(diǎn)
fpr, tpr, thresholds = roc_curve(y_true, y_scores)

# 計(jì)算ROC曲線下面積(AUC)
roc_auc = auc(fpr, tpr)

# 繪制ROC曲線
plt.plot(fpr, tpr, label=f'ROC curve (area = {roc_auc:.2f})')
plt.plot([0, 1], [0, 1], 'k--')  # 繪制隨機(jī)猜測(cè)的ROC曲線
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver Operating Characteristic')
plt.legend(loc="lower right")
plt.show()


責(zé)任編輯:趙寧寧 來(lái)源: 小喵學(xué)AI
相關(guān)推薦

2024-01-11 09:53:31

面試C++

2021-10-18 11:58:56

負(fù)載均衡虛擬機(jī)

2022-09-06 08:02:40

死鎖順序鎖輪詢鎖

2021-01-19 05:49:44

DNS協(xié)議

2022-09-14 09:01:55

shell可視化

2021-06-07 15:49:51

AI 數(shù)據(jù)人工智能

2020-07-15 08:57:40

HTTPSTCP協(xié)議

2020-11-16 10:47:14

FreeRTOS應(yīng)用嵌入式

2020-07-09 07:54:35

ThreadPoolE線程池

2024-03-07 18:11:39

Golang采集鏈接

2022-07-19 16:03:14

KubernetesLinux

2022-10-10 08:35:17

kafka工作機(jī)制消息發(fā)送

2019-11-06 10:12:19

B端設(shè)計(jì)流程分析

2023-06-12 08:49:12

RocketMQ消費(fèi)邏輯

2021-08-26 05:02:50

分布式設(shè)計(jì)

2022-09-08 10:14:29

人臉識(shí)別算法

2022-07-15 16:31:49

Postman測(cè)試

2024-01-05 08:30:26

自動(dòng)駕駛算法

2021-06-04 07:27:24

sourcemap前端技術(shù)

2022-04-25 10:56:33

前端優(yōu)化性能
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)