pytorch-backword函数的理解
函数:\(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
这个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\)
这就好理解了,如果我们自己实现了一层,继承自Function
,自己实现静态方法forward
和backward
时,backward
必须有个grad_output
参数,这个参数就是计算图中输出对该自定义层的梯度,这样才能求出对输入的梯度。
另外,假设定义的层计算出的是y
,调用的就是y.backward(grad_output)
,这个里面的参数的维度必须和y是相同的。这也就是为什么前面提到对于输出是多维的,会有个“系数”的原因,这个系数就是后向传播时,该层之前的梯度的累积,这样与本层再累积,才实现了完整的链式法则,最终求出out
对input
的梯度。
另外,自定义实现forward
和backward
时,两函数的输入输出是有要求的,即forward
的输入必须和~的return
相对应,如forward
的input
有个w
参数,那么backward
的return
就必须在对应的位置返回grad_w
,因为只有这样,才能够对相应的输入参数梯度下降。