通常,backward ) )函数是传递参数的,虽然不知道backward应该传递的参数的详细含义,但没关系。 生命在辛苦。 试着辛苦一下吧。 嘿嘿。
对标量的自动诱导
首先,如果out.backward ()的out是标量(神经网络有一个样本,这个样本有两个属性,神经网络有一个输出) )
导入种子
from torch.autogradimportvariable
a=variable (torch.tensor ([ 2,3 ],requires_grad=True ) ) ) ) ) ) ) ) ) )。
b=a 3
c=b * 3
out=c.mean ()
out.backward (
打印(input : ) )
打印(a.data ) )。
打印(输出: ) )
print(out.data.item ) )
打印(inputgradientsare : ) )
打印(a.grad ) )。
执行结果:
构建了这样的函数
所以,寻求其指引也很容易。
这是自动导出标量的结果。
向向量自动求导
如果out.backward () (out为向量) (或称为1xN矩阵),请自动引导向量以查看发生了什么。
首先构建这样的模型。 (神经网络有一个样本,这个样本有两个属性,相当于神经网络有两个输出。 )
导入种子
from torch.autogradimportvariable
a=variable(torch.tensor([2.4.] )、requires_grad=True ) ) )。
b=torch.zeros (1,2 ) ) ) ) ) ) ) ) b ) ) ) ) ) ) ) )。
b [ 0,0 ]=a [ 0,0 ] * * 2
b [ 0,1 ]=a [ 0,1 ] * * 3
out=2 * b
#其参数传递与out维相同的矩阵
out.backward (torch.float tensor ([1.1.] ) )
打印(input : ) )
打印(a.data ) )。
打印(输出: ) )
是打印(out.data )
打印(inputgradientsare : ) )
打印(a.grad ) )。
模型也很简单,out导出的雅可比应该如下。
因为a1=2,a2=4,所以上面的矩阵应该是:
执行结果:
嗯,确实是8和96,但是仔细想想,和我们想要的雅可比矩阵的形状也不一样啊。 是backward自动省略了0吗?
试着继续吧。 这次在前面的模型的基础上做如下稍微的变更。
导入种子
from torch.autogradimportvariable
a=variable(torch.tensor([2.4.] )、requires_grad=True ) ) )。
b=torch.zeros (1,2 ) ) ) ) ) ) ) ) b ) ) ) ) ) ) ) )。
b [ 0,0 ]=a [ 0,0 ] * * 2a [ 0,1 ]
b [ 0,1 ]=a [ 0,1 ] * * 3a [ 0,0 ]
out=2 * b
#其参数传递与out维相同的矩阵
out.backward (torch.float tensor ([1.1.] ) )
打印(输入: ) )
打印(a.data ) )。
打印(输出: ) )
是打印(out.data )
打印(inputgradientsare : ) )
打印(a.grad ) )。
这种型号的雅可比应该如下所示。
运行一下吧:
等等,什么事? 一般不是这样的
还是? 我是谁? 我已经在哪里了? 为什么给我两个数,而且82=10,962=98? 都是加2吗? 想想看。 刚才在我们backward上传递的参数是[ [ 1,1 ] ],是安装了这个关系并对应合计的吗? 换个参数试试吧。 在程序中,只有传入的参数是[]
1 , 2 ] ]:import torch
from torch.autograd import Variable
a = Variable(torch.Tensor([[2.,4.]]),requires_grad=True)
b = torch.zeros(1,2)
b[0,0] = a[0,0] ** 2 + a[0,1]
b[0,1] = a[0,1] ** 3 + a[0,0]
out = 2 * b
#其参数要传入和out维度一样的矩阵
out.backward(torch.FloatTensor([[1.,2.]]))
print('input:')
print(a.data)
print('output:')
print(out.data)
print('input gradients are:')
print(a.grad)
嗯,这回可以了解了,我们传入的参数,是对原来模型正常求导出来的雅克比矩阵进行线性操作,可以把我们传进的参数(设为arg)看成一个列向量,那么我们得到的结果就是:
在这个题目中,我们得到的实际是:
看起来一切完美的解释了,但是就在我刚刚打字的一刻,我意识到官方文档中说k.backward()传入的参数应该和k具有相同的维度,所以如果按上述去解释是解释不通的。哪里出问题了呢?
仔细看了一下,原来是这样的:在对雅克比矩阵进行线性操作的时候,应该把我们传进的参数(设为arg)看成一个行向量(不是列向量),那么我们得到的结果就是:
也就是:
这回我们就解释的通了。
现在我们来输出一下雅克比矩阵吧,为了不引起歧义,我们让雅克比矩阵的每个数值都不一样(一开始分析错了就是因为雅克比矩阵中有相同的数据),所以模型小改动如下:
import torch
from torch.autograd import Variable
a = Variable(torch.Tensor([[2.,4.]]),requires_grad=True)
b = torch.zeros(1,2)
b[0,0] = a[0,0] ** 2 + a[0,1]
b[0,1] = a[0,1] ** 3 + a[0,0] * 2
out = 2 * b
#其参数要传入和out维度一样的矩阵
out.backward(torch.FloatTensor([[1,0]]),retain_graph=True)
A_temp = copy.deepcopy(a.grad)
a.grad.zero_()
out.backward(torch.FloatTensor([[0,1]]))
B_temp = a.grad
print('jacobian matrix is:')
print(torch.cat( (A_temp,B_temp),0 ))
如果没问题的话咱们的雅克比矩阵应该是 [ [ 8 , 2 ] , [ 4 , 96 ] ]
好了,下面是见证奇迹的时刻了,不要眨眼睛奥,千万不要眨眼睛… 3 2 1 砰…
好了,现在总结一下:因为经过了复杂的神经网络之后,out中每个数值都是由很多输入样本的属性(也就是输入数据)线性或者非线性组合而成的,那么out中的每个数值和输入数据的每个数值都有关联,也就是说【out】中的每个数都可以对【a】中每个数求导,那么我们backward()的参数[k1,k2,k3…kn]的含义就是:
也可以了解成每个out分量对an求导时的权重。
对矩阵自动求导
现在,如果out是一个矩阵呢?
下面的例子也可以了解为:相当于一个神经网络有两个样本,每个样本有两个属性,神经网络有两个输出。
import torch
from torch.autograd import Variable
from torch import nn
a = Variable(torch.FloatTensor([[2,3],[1,2]]),requires_grad=True)
w = Variable( torch.zeros(2,1),requires_grad=True )
out = torch.mm(a,w)
out.backward(torch.FloatTensor([[1.],[1.]]),retain_graph=True)
print("gradients are:{}".format(w.grad.data))
如果前面的例子了解了,那么这个也很好了解,backward输入的参数k是一个2x1的矩阵,2代表的就是样本数量,就是在前面的基础上,再对每个样本进行加权求和。结果是:
如果有兴趣,也可以拓展一下多个样本的多分类问题,猜一下k的维度应该是【输入样本的个数 * 分类的个数】
好啦,纠结我好久的pytorch自动求导原理算是彻底搞懂啦~~~
以上这篇浅谈Pytorch中的自动求导函数backward()所需参数的含义就是小编共享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持乐购源码。