您好,登錄后才能下訂單哦!
這篇文章給大家介紹怎么在Pytorch中擬合函數(shù),內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
一、定義擬合網(wǎng)絡(luò)
1、觀察普通的神經(jīng)網(wǎng)絡(luò)的優(yōu)化流程
# 定義網(wǎng)絡(luò) net = ... # 定義優(yōu)化器 optimizer = torch.optim.Adam(net.parameters(), lr=0.001, weight_decay=0.0005) # 定義損失函數(shù) loss_op = torch.nn.MSELoss(reduction='sum') # 優(yōu)化 for step, (inputs, tag) in enumerate(dataset_loader): # 向前傳播 outputs = net(inputs) # 計(jì)算損失 loss = loss_op(tag, outputs) # 清空梯度 optimizer.zero_grad() # 向后傳播 loss.backward() # 更新梯度 optimizer.step()
上面的代碼就是一般情況下的流程。為了能使用Pytorch內(nèi)置的優(yōu)化器,所以我們需要定義一個(gè)一個(gè)網(wǎng)絡(luò),實(shí)現(xiàn)函數(shù)parameters(返回需要優(yōu)化的參數(shù))和forward(向前傳播);為了能支持GPU優(yōu)化,還需要實(shí)現(xiàn)cuda和cpu兩個(gè)函數(shù),把參數(shù)從內(nèi)存復(fù)制到GPU上和從GPU復(fù)制回內(nèi)存。
基于以上要求,網(wǎng)絡(luò)的定義就類似于:
class Net: def __init__(self): # 在這里定義要求的參數(shù) pass def cuda(self): # 傳輸參數(shù)到GPU pass def cpu(self): # 把參數(shù)傳輸回內(nèi)存 pass def forward(self, inputs): # 實(shí)現(xiàn)向前傳播,就是根據(jù)輸入inputs計(jì)算一遍輸出 pass def parameters(self): # 返回參數(shù) pass
在擬合數(shù)據(jù)量很大時(shí),還可以使用GPU來加速;如果沒有英偉達(dá)顯卡,則可以不實(shí)現(xiàn)cuda和cpu這兩個(gè)函數(shù)。
2、初始化網(wǎng)絡(luò)
回顧本文目的,擬合: y = ax + b, 所以在__init__函數(shù)中就需要定義a和b兩個(gè)參數(shù),另外為了實(shí)現(xiàn)parameters、cpu和cuda,還需要定義屬性__parameters和__gpu:
def __init__(self): # y = a*x + b self.a = torch.rand(1, requires_grad=True) # 參數(shù)a self.b = torch.rand(1, requires_grad=True) # 參數(shù)b self.__parameters = dict(a=self.a, b=self.b) # 參數(shù)字典 self.___gpu = False # 是否使用gpu來擬合
要擬合的參數(shù),不能初始化為0! ,一般使用隨機(jī)值即可。還需要把requires_grad參數(shù)設(shè)置為True,這是為了支持向后傳播。
3、實(shí)現(xiàn)向前傳播
def forward(self, inputs): return self.a * inputs + self.b
非常的簡(jiǎn)單,就是根據(jù)輸入inputs計(jì)算一遍輸出,在本例中,就是計(jì)算一下 y = ax + b。計(jì)算完了要記得返回計(jì)算的結(jié)果。
4、把參數(shù)傳送到GPU
為了支持GPU來加速擬合,需要把參數(shù)傳輸?shù)紾PU,且需要更新參數(shù)字典__parameters:
def cuda(self): if not self.___gpu: self.a = self.a.cuda().detach().requires_grad_(True) # 把a(bǔ)傳輸?shù)絞pu self.b = self.b.cuda().detach().requires_grad_(True) # 把b傳輸?shù)絞pu self.__parameters = dict(a=self.a, b=self.b) # 更新參數(shù) self.___gpu = True # 更新標(biāo)志,表示參數(shù)已經(jīng)傳輸?shù)絞pu了 # 返回self,以支持鏈?zhǔn)秸{(diào)用 return self
參數(shù)a和b,都是先調(diào)用detach再調(diào)用requires_grad_,是為了避免錯(cuò)誤raise ValueError("can't optimize a non-leaf Tensor")(參考:ValueError: can't optimize a non-leaf Tensor?)。
4、把參數(shù)傳輸回內(nèi)存
類似于cuda函數(shù),不做過多解釋。
def cpu(self): if self.___gpu: self.a = self.a.cpu().detach().requires_grad_(True) self.b = self.b.cpu().detach().requires_grad_(True) self.__parameters = dict(a=self.a, b=self.b) self.___gpu = False return self
5、返回網(wǎng)絡(luò)參數(shù)
為了能使用Pytorch內(nèi)置的優(yōu)化器,就要實(shí)現(xiàn)parameters函數(shù),觀察Pytorch里面的實(shí)現(xiàn):
def parameters(self, recurse=True): r"""... """ for name, param in self.named_parameters(recurse=recurse): yield param
實(shí)際上就是使用yield返回網(wǎng)絡(luò)的所有參數(shù),因此本例中的實(shí)現(xiàn)如下:
def parameters(self): for name, param in self.__parameters.items(): yield param
完整的實(shí)現(xiàn)將會(huì)放在后面。
二、測(cè)試
1、生成測(cè)試數(shù)據(jù)
def main(): # 生成虛假數(shù)據(jù) x = np.linspace(1, 50, 50) # 系數(shù)a、b a = 2 b = 1 # 生成y y = a * x + b # 轉(zhuǎn)換為Tensor x = torch.from_numpy(x.astype(np.float32)) y = torch.from_numpy(y.astype(np.float32))
2、定義網(wǎng)絡(luò)
# 定義網(wǎng)絡(luò) net = Net() # 定義優(yōu)化器 optimizer = torch.optim.Adam(net.parameters(), lr=0.001, weight_decay=0.0005) # 定義損失函數(shù) loss_op = torch.nn.MSELoss(reduction='sum')
3、把數(shù)據(jù)傳輸?shù)紾PU(可選)
# 傳輸?shù)紾PU if torch.cuda.is_available(): x = x.cuda() y = y.cuda() net = net.cuda()
4、定義優(yōu)化器和損失函數(shù)
如果要使用GPU加速,優(yōu)化器必須要在網(wǎng)絡(luò)的參數(shù)傳輸?shù)紾PU之后在定義,否則優(yōu)化器里的參數(shù)還是內(nèi)存里的那些參數(shù),傳到GPU里面的參數(shù)不能被更新。 可以根據(jù)代碼來理解這句話。
# 定義優(yōu)化器 optimizer = torch.optim.Adam(net.parameters(), lr=0.001, weight_decay=0.0005) # 定義損失函數(shù) loss_op = torch.nn.MSELoss(reduction='sum')
5、擬合(也是優(yōu)化)
# 最多優(yōu)化20001次 for i in range(1, 20001, 1): # 向前傳播 out = net.forward(x) # 計(jì)算損失 loss = loss_op(y, out) # 清空梯度(非常重要) optimizer.zero_grad() # 向后傳播,計(jì)算梯度 loss.backward() # 更新參數(shù) optimizer.step() # 得到損失的numpy值 loss_numpy = loss.cpu().detach().numpy() if i % 1000 == 0: # 每1000次打印一下?lián)p失 print(i, loss_numpy) if loss_numpy < 0.00001: # 如果損失小于0.00001 # 打印參數(shù) a = net.a.cpu().detach().numpy() b = net.b.cpu().detach().numpy() print(a, b) # 退出 exit()
6、完整示例代碼
# coding=utf-8 from __future__ import absolute_import, division, print_function import torch import numpy as np class Net: def __init__(self): # y = a*x + b self.a = torch.rand(1, requires_grad=True) # 參數(shù)a self.b = torch.rand(1, requires_grad=True) # 參數(shù)b self.__parameters = dict(a=self.a, b=self.b) # 參數(shù)字典 self.___gpu = False # 是否使用gpu來擬合 def cuda(self): if not self.___gpu: self.a = self.a.cuda().detach().requires_grad_(True) # 把a(bǔ)傳輸?shù)絞pu self.b = self.b.cuda().detach().requires_grad_(True) # 把b傳輸?shù)絞pu self.__parameters = dict(a=self.a, b=self.b) # 更新參數(shù) self.___gpu = True # 更新標(biāo)志,表示參數(shù)已經(jīng)傳輸?shù)絞pu了 # 返回self,以支持鏈?zhǔn)秸{(diào)用 return self def cpu(self): if self.___gpu: self.a = self.a.cpu().detach().requires_grad_(True) self.b = self.b.cpu().detach().requires_grad_(True) self.__parameters = dict(a=self.a, b=self.b) # 更新參數(shù) self.___gpu = False return self def forward(self, inputs): return self.a * inputs + self.b def parameters(self): for name, param in self.__parameters.items(): yield param def main(): # 生成虛假數(shù)據(jù) x = np.linspace(1, 50, 50) # 系數(shù)a、b a = 2 b = 1 # 生成y y = a * x + b # 轉(zhuǎn)換為Tensor x = torch.from_numpy(x.astype(np.float32)) y = torch.from_numpy(y.astype(np.float32)) # 定義網(wǎng)絡(luò) net = Net() # 傳輸?shù)紾PU if torch.cuda.is_available(): x = x.cuda() y = y.cuda() net = net.cuda() # 定義優(yōu)化器 optimizer = torch.optim.Adam(net.parameters(), lr=0.001, weight_decay=0.0005) # 定義損失函數(shù) loss_op = torch.nn.MSELoss(reduction='sum') # 最多優(yōu)化20001次 for i in range(1, 20001, 1): # 向前傳播 out = net.forward(x) # 計(jì)算損失 loss = loss_op(y, out) # 清空梯度(非常重要) optimizer.zero_grad() # 向后傳播,計(jì)算梯度 loss.backward() # 更新參數(shù) optimizer.step() # 得到損失的numpy值 loss_numpy = loss.cpu().detach().numpy() if i % 1000 == 0: # 每1000次打印一下?lián)p失 print(i, loss_numpy) if loss_numpy < 0.00001: # 如果損失小于0.00001 # 打印參數(shù) a = net.a.cpu().detach().numpy() b = net.b.cpu().detach().numpy() print(a, b) # 退出 exit() if __name__ == '__main__': main()
1.PyTorch是相當(dāng)簡(jiǎn)潔且高效快速的框架;2.設(shè)計(jì)追求最少的封裝;3.設(shè)計(jì)符合人類思維,它讓用戶盡可能地專注于實(shí)現(xiàn)自己的想法;4.與google的Tensorflow類似,F(xiàn)AIR的支持足以確保PyTorch獲得持續(xù)的開發(fā)更新;5.PyTorch作者親自維護(hù)的論壇 供用戶交流和求教問題6.入門簡(jiǎn)單
關(guān)于怎么在Pytorch中擬合函數(shù)就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。