函數:\(tensor.backward(params)\)網絡
這個params的維度必定要和tensor
的一致,由於tensor
若是是一個向量y = [y1,y2,y3]
,那麼傳入的params=[a1,a2,a3]
,這三個值是係數,那麼是什麼的係數呢?
假定對x =[ x1,x2]
求導,那麼咱們知道,
\(dy/dx\) 爲:
第一列: \(dy1/dx1,dy2/dx1,dy3/dx1\)
第二列:\(dy1/dx2, dy2/dx2,dy3/dx2\)
從而 \(dy/dx\)是一個3行2列的矩陣,每一列對應了對x1的導數,每一列也就是\(x1\)的梯度向量
而反向計算的時候,並非返回這個矩陣,而是返回這個矩陣每列的和做爲梯度,也就是:\(dy1/dx1+dy2/dx1+dy3/dx1\) 是y對x1的梯度
這就好理解了,係數爲\(params=[a1,a2,a3]\)就對應了這加和的三項!也就是,對\(x1\)的梯度其實是\(a1*dy1/dx1+a2*dy2/dx1+a3*dy3/dx1\)
而輸出y是標量的時候,就不須要了,默認的就是\(1.\)函數
本身重寫backward
函數時,要寫上一個grad_output
參數,這個參數就是上面提到的params
spa
這個grad_output
參數到底是什麼呢?下面做出解釋:
是這樣的,假如網絡有兩層, h = h(x),y = y(h)
你能夠計算\(dy/dx\),這樣,y.backward()
,由於\(dy/dy=1\),那麼,backward
的參數就能夠省略
若是計算h.backward(
),由於你想求的是\(dy/dx\),(這纔是輸出對於輸入的梯度),那麼,計算圖中的y = y(h)
就沒有考慮到
由於\(dy/dx = dy/dh * dh/dx\),h.backward()
求得是\(dh/dx\),那麼你必須傳入以前的梯度\(dy/dh\)才行,也就是說,h.backward(params=dy/dh)
這裏面的參數就是\(dy/dh\)code
這就好理解了,若是咱們本身實現了一層,繼承自Function
,本身實現靜態方法forward
和backward
時,backward
必須有個grad_output
參數,這個參數就是計算圖中輸出對該自定義層的梯度,這樣才能求出對輸入的梯度。繼承
另外,假設定義的層計算出的是y
,調用的就是y.backward(grad_output)
,這個裏面的參數的維度必須和y是相同的。這也就是爲何前面提到對於輸出是多維的,會有個「係數」的緣由,這個係數就是後向傳播時,該層以前的梯度的累積,這樣與本層再累積,才實現了完整的鏈式法則,最終求出out
對input
的梯度。input
另外,自定義實現forward
和backward
時,兩函數的輸入輸出是有要求的,即forward
的輸入必須和~的return
相對應,如forward
的input
有個w
參數,那麼backward
的return
就必須在對應的位置返回grad_w
,由於只有這樣,纔可以對相應的輸入參數梯度降低。io