使用Pytorch來擬合函數(shù)方式
其實各大深度學(xué)習(xí)框架背后的原理都可以理解為擬合一個參數(shù)數(shù)量特別龐大的函數(shù),所以各框架都能用來擬合任意函數(shù),Pytorch也能。
在這篇博客中,就以擬合y = ax + b為例(a和b為需要擬合的參數(shù)),說明在Pytorch中如何擬合一個函數(shù)。
一、定義擬合網(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) # 計算損失 loss = loss_op(tag, outputs) # 清空梯度 optimizer.zero_grad() # 向后傳播 loss.backward() # 更新梯度 optimizer.step()
上面的代碼就是一般情況下的流程。為了能使用Pytorch內(nèi)置的優(yōu)化器,所以我們需要定義一個一個網(wǎng)絡(luò),實現(xiàn)函數(shù)parameters(返回需要優(yōu)化的參數(shù))和forward(向前傳播);為了能支持GPU優(yōu)化,還需要實現(xiàn)cuda和cpu兩個函數(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):
# 實現(xiàn)向前傳播,就是根據(jù)輸入inputs計算一遍輸出
pass
def parameters(self):
# 返回參數(shù)
pass
在擬合數(shù)據(jù)量很大時,還可以使用GPU來加速;如果沒有英偉達(dá)顯卡,則可以不實現(xiàn)cuda和cpu這兩個函數(shù)。
2、初始化網(wǎng)絡(luò)
回顧本文目的,擬合: y = ax + b, 所以在__init__函數(shù)中就需要定義a和b兩個參數(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、實現(xiàn)向前傳播
def forward(self, inputs):
return self.a * inputs + self.b
非常的簡單,就是根據(jù)輸入inputs計算一遍輸出,在本例中,就是計算一下 y = ax + b。計算完了要記得返回計算的結(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_,是為了避免錯誤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)化器,就要實現(xiàn)parameters函數(shù),觀察Pytorch里面的實現(xiàn):
def parameters(self, recurse=True):
r"""...
"""
for name, param in self.named_parameters(recurse=recurse):
yield param
實際上就是使用yield返回網(wǎng)絡(luò)的所有參數(shù),因此本例中的實現(xiàn)如下:
def parameters(self):
for name, param in self.__parameters.items():
yield param
完整的實現(xiàn)將會放在后面。
二、測試
1、生成測試數(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)
# 計算損失
loss = loss_op(y, out)
# 清空梯度(非常重要)
optimizer.zero_grad()
# 向后傳播,計算梯度
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)
# 計算損失
loss = loss_op(y, out)
# 清空梯度(非常重要)
optimizer.zero_grad()
# 向后傳播,計算梯度
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()
以上這篇使用Pytorch來擬合函數(shù)方式就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
- pytorch中的nn.ZeroPad2d()零填充函數(shù)實例詳解
- Pytorch 圖像變換函數(shù)集合小結(jié)
- Pytorch上下采樣函數(shù)--interpolate用法
- pytorch 常用函數(shù) max ,eq說明
- Pytorch十九種損失函數(shù)的使用詳解
- pytorch之Resize()函數(shù)具體使用詳解
- 使用 pytorch 創(chuàng)建神經(jīng)網(wǎng)絡(luò)擬合sin函數(shù)的實現(xiàn)
- Pytorch mask_select 函數(shù)的用法詳解
- PyTorch筆記之scatter()函數(shù)的使用
- pytorch方法測試——激活函數(shù)(ReLU)詳解
- pytorch 常用線性函數(shù)詳解
- 如何利用Pytorch計算三角函數(shù)
相關(guān)文章
keras 使用Lambda 快速新建層 添加多個參數(shù)操作
這篇文章主要介紹了keras 使用Lambda 快速新建層 添加多個參數(shù)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-06-06
selenium python 實現(xiàn)基本自動化測試的示例代碼
這篇文章主要介紹了selenium python 實現(xiàn)基本自動化測試的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-02-02
python3中的logging記錄日志實現(xiàn)過程及封裝成類的操作
這篇文章主要介紹了python3中的logging記錄日志實現(xiàn)過程及封裝成類的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05
Django模板導(dǎo)入母版繼承和自定義返回Html片段過程解析
這篇文章主要介紹了Django模板導(dǎo)入母版繼承和自定義返回Html片段過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-09-09
python操作數(shù)據(jù)庫獲取結(jié)果之fetchone和fetchall的區(qū)別說明
這篇文章主要介紹了python操作數(shù)據(jù)庫獲取結(jié)果之fetchone和fetchall的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04

