一個(gè)前向傳播網(wǎng)絡(luò)框架
網(wǎng)絡(luò)計(jì)算流程
y=f(w, x) = Wx
y'=f'(w, x)w' = X
神經(jīng)網(wǎng)絡(luò)的訓(xùn)練需要使用損失函數(shù)的梯度,torch提供了一個(gè)torch.autograd的自動(dòng)求導(dǎo)機(jī)制尺栖。
創(chuàng)建一個(gè)網(wǎng)絡(luò)嫡纠,并獲取梯度
import torch
x = torch.ones(5) # input tensor
y = torch.zeros(3) # expected output
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w)+b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)
print(f"Gradient function for z = {z.grad_fn}")
print(f"Gradient function for loss = {loss.grad_fn}")
這里拆分了w和b,在一些網(wǎng)絡(luò)的計(jì)算中延赌,可以按W = [w, b]除盏,作為統(tǒng)一參數(shù)。
使用 grad() 計(jì)算梯度
對(duì)于一個(gè)網(wǎng)絡(luò)默認(rèn)只會(huì)對(duì)最后一層網(wǎng)絡(luò)進(jìn)行自動(dòng)求導(dǎo)挫以,即最后一層requires_grad=true
如需對(duì)全網(wǎng)絡(luò)進(jìn)行求導(dǎo)者蠕,需使用
loss.backward()
print(w.grad)
print(b.grad)
關(guān)閉梯度計(jì)算
在網(wǎng)絡(luò)的應(yīng)用(前向計(jì)算, 使用部分已訓(xùn)練網(wǎng)絡(luò))中,為了計(jì)算效率掐松,可以關(guān)閉梯度的自動(dòng)計(jì)算
z = torch.matmul(x, w)+b
print(z.requires_grad)
with torch.no_grad():
z = torch.matmul(x, w)+b
print(z.requires_grad)
或者
z = torch.matmul(x, w)+b
z_det = z.detach()
print(z_det.requires_grad)
網(wǎng)絡(luò)的正向踱侣,反向傳播
在torch中網(wǎng)絡(luò)表達(dá)為DAG(directed acyclic graph),這里考慮mini-batch的情況大磺。
在前向計(jì)算中autograd 完成如下兩件事:
- 根據(jù)單層網(wǎng)絡(luò)計(jì)算tensor結(jié)果
- 維護(hù)網(wǎng)絡(luò)梯度計(jì)算函數(shù)
在反向傳播中抡句,調(diào)用.backward(),完成如下事情: - 使用tensor的梯度函數(shù) .grad_fn計(jì)算梯度
- 累計(jì)梯度結(jié)果到 .grad中
- 使用鏈?zhǔn)椒▌t杠愧,計(jì)算每一層
Jacobin矩陣的計(jì)算
對(duì)于多維loss function待榔, 在計(jì)算y=f(x),在backward中會(huì)自動(dòng)計(jì)算Jacobian Product: v^T*J,其中v是對(duì)應(yīng)的tensor。
image.png
inp = torch.eye(5, requires_grad=True)
out = (inp+1).pow(2)
out.backward(torch.ones_like(inp), retain_graph=True)
print(f"First call\n{inp.grad}")
out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nSecond call\n{inp.grad}")
inp.grad.zero_()
out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nCall after zeroing gradients\n{inp.grad}")