PyTorch的损失函数和优化器
文章目錄
- PyTorch的損失函數(shù)和優(yōu)化器
- 損失函數(shù)
- 優(yōu)化器
- 總結(jié)
PyTorch的損失函數(shù)和優(yōu)化器
損失函數(shù)
一般來說,PyTorch的損失函數(shù)有兩種形式:函數(shù)形式和模塊形式。前者調(diào)用的是torch.nn.functional庫中的函數(shù),通過傳入神經(jīng)網(wǎng)絡(luò)預(yù)測(cè)值和目標(biāo)值來計(jì)算損失函數(shù)。后者是torch.nn庫里的模塊,通過建立一個(gè)模塊的實(shí)例,然后通過調(diào)用模塊方法來計(jì)算最終的損失函數(shù)。
對(duì)于回歸問題,一般情況下使用的是torch.nn.MSELoss模塊,即平方損失函數(shù),在實(shí)例中傳入神經(jīng)網(wǎng)絡(luò)的預(yù)測(cè)值和目標(biāo)值,能夠計(jì)算得到最終的損失函數(shù)。
mse = nn.MSELoss() # 初始化平方損失函數(shù)模塊t1 = torch.randn(5, requires_grad=True) t2 = torch.randn(5, requires_grad=True)print(mse(t1, t2)) # 計(jì)算t1和t2之間的平方損失函數(shù)得到的結(jié)果為:
tensor(2.2568, grad_fn=<MseLossBackward>)對(duì)于分類問題,如果是二分類用到的交叉熵?fù)p失函數(shù),可以使用torch.nn.BCELoss模塊實(shí)現(xiàn)。同樣,在初始化這個(gè)模塊的時(shí)候可以用默認(rèn)參數(shù),輸出所有損失函數(shù)的平均。該模塊一般接受的是Sigmoid函數(shù)的輸出。注意這個(gè)損失函數(shù)接受兩個(gè)張量,第一個(gè)張量是正分類標(biāo)簽的概率值,第二個(gè)張量是以0為負(fù)分類標(biāo)簽、1為正分類標(biāo)簽的目標(biāo)數(shù)據(jù)值,這兩個(gè)值必須是浮點(diǎn)類型。
bce = nn.BCELoss()t1 = torch.randn(5, requires_grad=True) t1s = torch.sigmoid(t1) # 對(duì)張量求Sigmoid函數(shù),轉(zhuǎn)換為(0, 1)之間的概率 t2 = torch.randint(0, 2, (5, )).float() # 隨機(jī)生成(0, 1)之間的整數(shù)序列并轉(zhuǎn)換為浮點(diǎn)數(shù)print(bce(t1s, t2)) # 計(jì)算交叉熵得到的結(jié)果為:
tensor(0.8664, grad_fn=<BinaryCrossEntropyBackward>)另外在二分類問題中也經(jīng)常用到對(duì)數(shù)交叉熵?fù)p失函數(shù)torch.nn.BECWithLogitsLoss,這個(gè)函數(shù)和前面的交叉熵?fù)p失函數(shù)的區(qū)別在于可以直接省略Sigmoid函數(shù)部分的計(jì)算。這是因?yàn)樵摵瘮?shù)會(huì)自動(dòng)在損失函數(shù)內(nèi)部的實(shí)現(xiàn)部分添加Sigmoid激活函數(shù),在訓(xùn)練時(shí)可以增加計(jì)算的數(shù)值穩(wěn)定性。
bce_logits = nn.BCEWithLogitsLoss() # 使用交叉熵對(duì)數(shù)損失函數(shù)print(bce_logits(t1, t2)) # 計(jì)算交叉熵,結(jié)果應(yīng)和前面的一致得到的結(jié)果為:
tensor(0.8664, grad_fn=<BinaryCrossEntropyWithLogitsBackward>)在多分類的情況下,也可以使用兩個(gè)模塊。第一個(gè)模塊是torch.nn.NLLLoss,即負(fù)對(duì)數(shù)似然函數(shù),這個(gè)損失函數(shù)的運(yùn)算過程是根據(jù)預(yù)測(cè)值和目標(biāo)值計(jì)算這兩個(gè)值按照元素值一一對(duì)應(yīng)的乘積,然后對(duì)乘積求和,并去負(fù)值。注意這里的預(yù)測(cè)值是經(jīng)過Softmax的計(jì)算和對(duì)數(shù)計(jì)算的,目標(biāo)值使用one-hot編碼。 因此這個(gè)損失函數(shù)在使用之前必須先計(jì)算Softmax函數(shù)去對(duì)數(shù)的結(jié)果。可以用PyTorch中的torch.nn.functional.log_softmax實(shí)現(xiàn)。
N = 10 # 定義分類數(shù)目t1 = torch.randn(5, N, requires_grad=True) # 隨機(jī)產(chǎn)生預(yù)測(cè)張量 t1s = torch.nn.functional.log_softmax(t1, -1) # 計(jì)算預(yù)測(cè)張量的LogSoftmax t2 = torch.randint(0, N, (5, )) # 隨機(jī)產(chǎn)生目標(biāo)張量nll = nn.NLLLoss() # 定義損失函數(shù)print(nll(t1s, t2)) # 計(jì)算損失函數(shù)得到的結(jié)果為:
tensor(2.4824, grad_fn=<NllLossBackward>)第二個(gè)模塊是torch.nn.CrossEntroyLoss,用于構(gòu)建目標(biāo)損失函數(shù),這個(gè)損失函數(shù)可以避免LogSoftmax的計(jì)算,在損失函數(shù)里整合Softmax輸出概率,以及對(duì)概率取對(duì)數(shù)輸出損失函數(shù)。
ce = nn.CrossEntropyLoss()print(ce(t1, t2))此時(shí)得到的結(jié)果與NLL損失函數(shù)的結(jié)果一致。
優(yōu)化器
有了損失函數(shù),就可以對(duì)模型進(jìn)行優(yōu)化。
接下來會(huì)演示如何擬合一個(gè)線性模型。
首先構(gòu)建一個(gè)有13個(gè)參數(shù)的線性回歸模型,然后構(gòu)建損失函數(shù)的計(jì)算模塊criterion,并將其設(shè)置為MSELoss模塊的實(shí)例。有了損失函數(shù)后就可以構(gòu)建一個(gè)隨機(jī)梯度下降算法的優(yōu)化器。關(guān)于torch.optim.SGD的第一個(gè)參數(shù)是線性回歸模型的生成器,第二個(gè)參數(shù)是學(xué)習(xí)率。接下來構(gòu)建訓(xùn)練的輸入特征和預(yù)測(cè)目標(biāo),傳入的參數(shù)是載入的波士頓房?jī)r(jià)的特征和預(yù)測(cè)目標(biāo)的Numpy數(shù)組。
為了實(shí)現(xiàn)前向和反向傳播計(jì)算,在構(gòu)建輸入特征的時(shí)候需要設(shè)置requires_grad=True,這樣就能在計(jì)算過程中構(gòu)建計(jì)算圖。
接下來就是優(yōu)化過程,需要先獲取當(dāng)前參數(shù)下模型的預(yù)測(cè)結(jié)果,并且使用這個(gè)結(jié)果計(jì)算出損失函數(shù),然后清空梯度,損失函數(shù)調(diào)用反向傳播算法,計(jì)算得到內(nèi)個(gè)參數(shù)對(duì)應(yīng)的梯度,最后執(zhí)行一步優(yōu)化的算法。
import torch import torch.nn as nn from sklearn.datasets import load_bostonclass LinearModel(nn.Module):def __init__(self, ndim):super(LinearModel, self).__init__()self.ndim = ndimself.weight = nn.Parameter(torch.randn(ndim, 1))self.bias = nn.Parameter(torch.randn(1))def forward(self, x):return x.mm(self.weight) + self.biasboston = load_boston()lm = LinearModel(13) criterion = nn.MSELoss() optim = torch.optim.SGD(lm.parameters(), lr = 1e-6) # 定義優(yōu)化器 data = torch.tensor(boston["data"], requires_grad=True, dtype=torch.float32) # 該數(shù)據(jù)為雙精度類型,需要轉(zhuǎn)換為單精度 target = torch.tensor(boston["target"], dtype=torch.float32)for step in range(10000):predict = lm(data) # 輸出模型預(yù)測(cè)結(jié)果loss = criterion(predict, target) # 輸出損失函數(shù)if step and step % 1000 == 0:print("Loss:{:.3f}".format(loss.item()))optim.zero_grad() # 清零梯度loss.backward() # 反向傳播optim.step()上述代碼使用波士頓地區(qū)房?jī)r(jià)數(shù)據(jù),通過安裝scikit-learn庫。該數(shù)據(jù)有13個(gè)特征,一共506條數(shù)據(jù)。為簡(jiǎn)便起見,直接使用全局?jǐn)?shù)據(jù)來進(jìn)行訓(xùn)練。另外由于數(shù)據(jù)量比較小,每一次模型的優(yōu)化都會(huì)使用全局?jǐn)?shù)據(jù)而不是用Mini-batch。
以下是得到的結(jié)果,可以看到損失函數(shù)在每一步優(yōu)化的時(shí)候逐漸下降了。
Loss:337.852 Loss:257.781 Loss:228.257 Loss:210.646 Loss:197.336 Loss:186.189 Loss:176.497 Loss:167.958 Loss:160.397在如上的代碼中,可以看到隨機(jī)梯度下降算法算法優(yōu)化器torch.optim.SGD構(gòu)建了一個(gè)方法,能夠?qū)魅雲(yún)?shù)生成器中的每個(gè)參數(shù)進(jìn)行優(yōu)化。在優(yōu)化之前,首先要執(zhí)行兩個(gè)步驟,第一個(gè)是調(diào)用zero_grad方法清空所有的參數(shù)前一次反向傳播的梯度,第二個(gè)是調(diào)用損失函數(shù)的backward方法來計(jì)算所有參數(shù)的當(dāng)前反向傳播的梯度。
PyTorch的優(yōu)化器對(duì)于不同的參數(shù)可以使用不同的學(xué)習(xí)率。默認(rèn)的學(xué)習(xí)率是10-2,默認(rèn)動(dòng)量為0.9,但對(duì)于model.classifier子模塊來說,默認(rèn)的學(xué)習(xí)率是10-3。通過使用字典的列表分別指定學(xué)習(xí)率,可以達(dá)到對(duì)不同的參數(shù)使用不同的學(xué)習(xí)率的目的。如下所示:
optim.SGD([{'params': model.base.parameters()},{'params': model.classifier.parameters(), 'lr': 1e-3} ], lr=1e-2, momentum=0.9)在優(yōu)化器以外,torch.optim包還提供了學(xué)習(xí)衰減的相關(guān)類,這些類都在torch.optim的子包torch.optim.lr_scheduler中。
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)for epoch in range(100):train(...)validate(...)scheduler.step()如上所示,在使用的時(shí)候需要傳入具體的優(yōu)化器,以及隔多少步進(jìn)行學(xué)習(xí)率衰減以及衰減的系數(shù)。在上述代碼中就是每次經(jīng)過30個(gè)迭代期,學(xué)習(xí)率會(huì)變成原來的0.1倍,每次經(jīng)過一個(gè)迭代期都會(huì)調(diào)用梯度衰減類的step方法,學(xué)習(xí)率衰減類會(huì)記錄當(dāng)前的迭代期,并根據(jù)當(dāng)前的迭代期決定是否發(fā)生學(xué)習(xí)率的衰減。
總結(jié)
PyTorch定義了一系列的損失函數(shù),包括回歸的損失函數(shù)和分類的損失函數(shù)以及其他的一些損失函數(shù)分別用于不同的深度學(xué)習(xí)任務(wù)。同時(shí)在優(yōu)化器方法提供了大量成熟的實(shí)現(xiàn),包括SGD、RMSProp等等。通過優(yōu)化器的類,可以很容易地根據(jù)模型的參數(shù)構(gòu)建對(duì)應(yīng)優(yōu)化器的實(shí)例,然后通過反向傳播計(jì)算出模型參數(shù)對(duì)應(yīng)的梯度,最后調(diào)用優(yōu)化器相關(guān)的優(yōu)化方法對(duì)模型的參數(shù)進(jìn)行優(yōu)化,整個(gè)過程非常方便和直觀。同時(shí)為了能夠在模型訓(xùn)練過程中提供學(xué)習(xí)率的動(dòng)態(tài)調(diào)節(jié)方法,PyTorch也提供了相關(guān)的類來調(diào)整學(xué)習(xí)率。
總結(jié)
以上是生活随笔為你收集整理的PyTorch的损失函数和优化器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PyTorch的计算图和自动求导机制
- 下一篇: PyTorch中的数据输入和预处理