爲什麼摘抄這一段,因爲我認爲這裏是一個非常有用的部分,看完autograd就想去問答區提問:
然後發現沒有c幣,於是乎暫時作罷,結果發現答案就在下一小節(先看完再想問題,不然浪費了一個好問題),沒辦法我就是這麼熱愛思考的一個人,看完立刻就有問題,等不到再看一段書。
— 我是分界線—
p94:目前,絕大多數函數都可以使用autograd實現反向求導,但如果需要自己寫一個複雜的函數,不支持自動反向求導怎麼辦?答案是寫一個Function,實現它的前向傳播和反向傳播代碼,Function對應於計算圖中的矩形,它接收參數,計算並返回結果。下面給出一個例子:
class Mul(Function):
@staticmethod
def forward(ctx, w, x, b, x_requires_grad = True):
ctx.x_requires_grad = x_requires_grad
ctx.save_for_backward(w,x)
output = w*x+b
return output
@staticmethod
def backward(ctx, grad_output):
w,x = ctx.saved_variables
grad_w = grad_output * x
if ctx.x_requires_grad:
grad_x = grad_output * w
else:
grad_x = None
grad_b = grad_output * 1
return grad_w, grad_x, grad_b, None
對以上代碼的分析如下。
- 自定義的Function需要繼承autograd.Function,沒有構造函數__init__,forward和backward函數都是靜態方法
- forward函數的輸入和輸出都是tensor,backward函數的輸入和輸出都是variable
- backward函數的輸出和forward函數的輸入一一對應,backward函數的輸入和forward函數的輸出一一對應
- backward函數的grad_output參數即t.autograd.backward中的grad_variables
- 如果某一個輸入不需要求導,直接返回None
- 反向傳播可能需要利用前向傳播的某些中間結果,在前向傳播過程中,需要保存中間結果,否則前向傳播結束後這些對象即被釋放
使用Function.apply(variable)即可調用實現的Function
from torch.autograd import Function
class MultiplyAdd(Function):
@staticmethod
def forward(ctx, w, x, b):
print('type in forward', type(x))
ctx.save_for_backward()
output = w*x+b
return output
@staticmethod
def backward(ctx, grad_output):
w,x = ctx.saved_variables
print('type in backward', type(x))
grad_w = grad_output * x
grad_x = grad_output * w
grad_b = grad_output * 1
return grad_w, grad_x, grad_b
x = V(t.ones(1))
w = V(t.rand(1), requires_grad = True)
b = V(t.rand(1), requires_grad = True)
print('forward')
z = MultiplyAdd.apply(w,x,b)
print('backward')
z.backward()
x.grad, w.grad, b.grad
forward函數的輸入是tensor,而backward函數的輸入是variable,這是爲了實現高階求導,backward函數的輸入值是variable,但是在實際使用時autograd.Function會將輸入variable提取爲tensor,並將計算結果的tensor封裝成variable返回,在backward函數中要對variable進行操作,是爲了能夠計算梯度的梯度。
書評
這本書不適合完全沒有基礎的人看,更像是介紹如何使用PyTorch框架的一本書,但是各大框架正在飛速發展,這本書用的版本和接口,很多在PyTorch1.0裏面甚至0.4裏面就已經deprecated(棄用)了。在看過PyTorch的官方Tutorials之後,這本書可以不看的,我看完也沒有太大的收穫,當然還是有的,最大的收穫就是對整個框架的設計邏輯和思路設計有了整體的認識,知識更有體系,想要深入認真玩好這個框架還是看官方的Doc更直接些,只不過作爲第一個入門框架直接上官方Doc可能難度較大。(其實也還好,理解起來也沒有太大問題,系統學一遍只是讓自己更踏實)