回顧上節(jié)課:
但是對于負(fù)責(zé)的神經(jīng)網(wǎng)絡(luò),很難做到去計(jì)算每一個(gè)梯度并保存下來扔仓,例如:
引入了計(jì)算圖:
計(jì)算圖是用圖論語言表示數(shù)學(xué)函數(shù)的一種方式胚嘲。計(jì)算圖被定義為有向圖,其中節(jié)點(diǎn)對應(yīng)于數(shù)學(xué)運(yùn)算豆茫。節(jié)點(diǎn)由邊連接,圖中的一切要么是節(jié)點(diǎn)屋摇,要么是邊揩魂。
在計(jì)算圖中,節(jié)點(diǎn)是輸入值或用于組合值的函數(shù)摊册。當(dāng)數(shù)據(jù)流過圖形時(shí)肤京,邊會收到它們的權(quán)重颊艳。輸入節(jié)點(diǎn)的出站邊用該輸入值加權(quán)茅特;來自函數(shù)節(jié)點(diǎn)的出站節(jié)點(diǎn)通過使用指定函數(shù)組合入站邊的權(quán)重來加權(quán)。
為了防止展開后出現(xiàn)下面的情況棋枕,引入了非線性函數(shù):
Chain Rule:鏈?zhǔn)椒▌t
BP 算法
BP算法的學(xué)習(xí)過程由正向傳播過程和反向傳播過程組成白修。在正向傳播過程中,輸入信息通過輸入層經(jīng)隱含層重斑,逐層處理并傳向輸出層兵睛。如果在輸出層得不到期望的輸出值,則取輸出與期望的誤差的平方和作為目標(biāo)函數(shù)窥浪,轉(zhuǎn)入反向傳播祖很,逐層求出目標(biāo)函數(shù)對各神經(jīng)元權(quán)值的偏導(dǎo)數(shù),構(gòu)成目標(biāo)函數(shù)對權(quán)值向量的梯量漾脂,作為修改權(quán)值的依據(jù)假颇,網(wǎng)絡(luò)的學(xué)習(xí)在權(quán)值修改過程中完成。誤差達(dá)到所期望值時(shí)骨稿,網(wǎng)絡(luò)學(xué)習(xí)結(jié)束笨鸡。
其中藍(lán)色為正向(forward)姜钳,紅色為反向傳播(backward)。
例子:
線性模型的計(jì)算圖
代碼實(shí)現(xiàn)
Tensor的概念:
Tensor(張量)是一個(gè)多維數(shù)組形耗,它是標(biāo)量哥桥、向量、矩陣的高維拓展.
標(biāo)量是一個(gè)零維張量激涤,是沒有方向的拟糕,是一個(gè)數(shù)。一維張量只有一個(gè)維度昔期,是一行或者一列已卸。二維張量是一個(gè)矩陣,有兩個(gè)維度硼一,灰度圖片就是一個(gè)二維張量累澡。當(dāng)圖像是彩色圖像(RGB)的時(shí)候,就得使用三維張量了般贼。
w是Tensor(張量類型)愧哟,Tensor中包含data和grad,data和grad也是Tensor哼蛆。grad初始為None蕊梧,調(diào)用l.backward()方法后w.grad為Tensor,故更新w.data時(shí)需使用w.grad.data腮介。如果w需要計(jì)算梯度肥矢,那構(gòu)建的計(jì)算圖中,跟w相關(guān)的tensor都默認(rèn)需要計(jì)算梯度叠洗。
本算法中反向傳播主要體現(xiàn)在甘改,l.backward()。調(diào)用該方法后w.grad由None更新為Tensor類型灭抑,且w.grad.data的值用于后續(xù)w.data的更新十艾。
l.backward()會把計(jì)算圖中所有需要梯度(grad)的地方都會求出來,然后把梯度都存在對應(yīng)的待求的參數(shù)中腾节,最終計(jì)算圖被釋放忘嫉。取tensor中的data是不會構(gòu)建計(jì)算圖的。
import torch
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w = torch.tensor([1.0]) # w的初值為1.0
w.requires_grad = True # 需要計(jì)算梯度
def forward(x):
return x*w # w是一個(gè)Tensor
def loss(x, y):
y_pred = forward(x)
return (y_pred - y)**2
print("predict (before training)", 4, forward(4).item())
for epoch in range(100):
for x, y in zip(x_data, y_data):
l =loss(x,y) # l是一個(gè)張量案腺,tensor主要是在建立計(jì)算圖 forward, compute the loss
l.backward() # backward,compute grad for Tensor whose requires_grad set to True
print('\tgrad:', x, y, w.grad.item())
w.data = w.data - 0.01 * w.grad.data # 權(quán)重更新時(shí)庆冕,注意grad也是一個(gè)tensor
w.grad.data.zero_() # after update, remember set the grad to zero
print('progress:', epoch, l.item()) # 取出loss使用l.item,不要直接使用l(l是tensor會構(gòu)建計(jì)算圖)
print("predict (after training)", 4, forward(4).item())
作業(yè)
計(jì)算圖
import numpy as np
import matplotlib.pyplot as plt
import torch
x_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]
w1 = torch.Tensor([1.0])#初始權(quán)值
w1.requires_grad = True#計(jì)算梯度劈榨,默認(rèn)是不計(jì)算的
w2 = torch.Tensor([1.0])
w2.requires_grad = True
b = torch.Tensor([1.0])
b.requires_grad = True
def forward(x):
return w1 * x**2 + w2 * x + b
def loss(x,y):#構(gòu)建計(jì)算圖
y_pred = forward(x)
return (y_pred-y) **2
print('Predict (befortraining)',4,forward(4))
for epoch in range(100):
l = loss(1, 2)#為了在for循環(huán)之前定義l,以便之后的輸出访递,無實(shí)際意義
for x,y in zip(x_data,y_data):
l = loss(x, y)
l.backward()
print('\tgrad:',x,y,w1.grad.item(),w2.grad.item(),b.grad.item())
w1.data = w1.data - 0.01*w1.grad.data #注意這里的grad是一個(gè)tensor,所以要取他的data
w2.data = w2.data - 0.01 * w2.grad.data
b.data = b.data - 0.01 * b.grad.data
w1.grad.data.zero_() #釋放之前計(jì)算的梯度
w2.grad.data.zero_()
b.grad.data.zero_()
print('Epoch:',epoch,l.item())
print('Predict(after training)',4,forward(4).item())
參考
PyTorch 深度學(xué)習(xí)實(shí)踐 第4講_錯錯莫的博客-CSDN博客
PyTorch的Tensor(張量)_然后就去遠(yuǎn)行吧的博客-CSDN博客_pytorch的tensor
PyTorch學(xué)習(xí)(三)--反向傳播_陳同學(xué)愛吃方便面的博客-CSDN博客