.backward() 是 PyTorch 中用于自动求导的函数,它的主要作用是计算损失函数对模型参数的梯度,从而实现反向传播算法。
在深度学习中,我们通常使用梯度下降算法来更新模型参数,使得模型能够逐步逼近最优解。
在梯度下降算法中,我们需要计算损失函数关于模型参数的梯度,以便确定参数更新的方向和大小。
这个计算过程就是反向传播算法,而 loss.backward() 就是反向传播算法的实现。
Tensor.backward(gradient=None, retain_graph=None, create_graph=False, inputs=None)[source]
.
当前Variable(理解成函数Y)对leaf variable(理解成变量X=[x1,x2,x3])求偏导。
Computes the gradient of current tensor wrt graph leaves.
计算当前张量相对于图中叶子节点的梯度。The graph is differentiated using the chain rule. If the tensor is non-scalar (i.e. its data has more than one element) and requires gradient, the function additionally requires specifying gradient. It should be a tensor of matching type and location, that contains the gradient of the differentiated function w.r.t. self.
“使用链式法则对图进行微分。如果张量是非标量(即其数据具有多个元素)并且需要梯度,则该函数还需要指定梯度。它应该是相同类型和位置的张量,其中包含相对于自身的微分函数的梯度。”This function accumulates gradients in the leaves - you might need to zero .grad attributes or set them to None before calling it. See Default gradient layouts for details on the memory layout of accumulated gradients.
这个函数在叶子节点中累积梯度,可能需要在调用它之前将 .grad 属性清零或设置为 None。有关累积梯度的内存布局详情,请参阅默认梯度布局。
gradient (Tensor or None)
– 计算图可以通过链式法则求导。如果Tensor是 非标量(non-scalar)的(即是说Y中有不止一个y,即Y=[y1,y2,…]),且requires_grad=True。那么此函数需要指定gradient,它的形状应该和Variable的长度匹配(这个就很好理解了,gradient的长度体与Y的长度一直才能保存每一个yi的梯度值啊),里面保存了Variable的梯度。
原文链接:https://blog.csdn.net/weixin_43763731/article/details/88982979
retain_graph (bool, optional)
– 这个参数默认是False。计算梯度所必要的buffer在经历过一次backward过程后不会被释放。如果你想多次计算某个子图的梯度的时候,设置为True。
create_graph (bool, optional)
– If True, graph of the derivative will be constructed, allowing to compute higher order derivative products. Defaults to False.
inputs (sequence of Tensor)
– Inputs w.r.t. which the gradient will be accumulated into .grad. All other Tensors will be ignored. If not provided, the gradient is accumulated into all the leaf Tensors that were used to compute the attr::tensors.
看到一篇比较清楚地讲解,我把结论写在这里,具体的参看原文:
参考:https://blog.csdn.net/witnessai1/article/details/79763596
Tensor必须是一个一维标量
如:a = v(t.FloatTensor([2, 3]), requires_grad=True)
m = v(t.FloatTensor([[2, 3]]), requires_grad=True)
则不行
会有如下报错:
报错信息:backward只能被应用在一个标量上,也就是一个一维tensor,或者传入跟变量相关的梯度。
特别注意Tensor里面默认的参数requires_grad=False
,requires_grad == True
, 则表示它可以参与求导,也可以从它向后求导。
requires_grad == True
具有传递性:如果:x.requires_grad == True
,y.requires_grad == False
, z=f(x,y)
则z.requires_grad == True
Tensor.backward(parameters)
接受的 参数parameters
必须要和Tensor
的大小一模一样,然后作为Tensor
的系数传回去;
如果Tensor
不是一个一维标量,想要获取对应梯度,需要计算jacobian矩阵。
参考:loss.backward()和torch.autograd.grad的区别
requires_grad == True
)Pytorch中的自动求导机制会根据输入和前向传播过程自动构建计算图(节点就是参与运算的变量,图中的边就是变量之间的运算关系),然后根据计算图进行反向传播,计算每个节点的梯度值。
Pytorch提供了两种求梯度的方法,分别是backward()和torch.autograd.grad()。
不过需要注意的是,这两种梯度方法都会在反向传播求导的时候释放计算图,如果需要再次做自动求导,因为计算图已经不再了,就会报错。如果要在反向传播的时候保留计算图,可以设置retain_graph=True。
参考:https://zhuanlan.zhihu.com/p/33378444
pytorch是动态图机制,所以在训练模型时候,每迭代一次都会构建一个新的计算图。而计算图其实就是代表程序中变量之间的关系。举个列子:
y
=
(
a
+
b
)
(
b
+
c
)
y = (a+b)(b+c)
y=(a+b)(b+c) 在这个运算过程就会建立一个如下的计算图:
注意图中的 leaf_node,叶子结点就是由用户自己创建的Variable变量,在这个图中仅有a,b,c 是 leaf_node。为什么要关注leaf_node?因为在网络backward时候,需要用链式求导法则求出网络最后输出的梯度,然后再对网络进行优化,如下就是网络的求导过程。
x = Variable(torch.FloatTensor([[1, 2]]), requires_grad=True) # 定义一个输入变量
y = Variable(torch.FloatTensor([[3, 4],
[5, 6]]))
loss = torch.mm(x, y) # 变量之间的运算
loss.backward(torch.FloatTensor([[1, 0]]), retain_graph=True) # 求梯度,保留图
print(x.grad.data) # 求出 x_1 的梯度
x.grad.data.zero_() # 最后的梯度会累加到叶节点,所以叶节点清零
loss.backward(torch.FloatTensor([[0, 1]])) # 求出 x_2的梯度
print(x.grad.data) # 求出 x_2的梯度
这里有一点不太理解:为什么loss.backward(torch.FloatTensor([[1, 0]]), retain_graph=True)
是对
x
1
x_1
x1?求导,而loss.backward(torch.FloatTensor([[0, 1]]))
是对
x
2
x_2
x2?求导。
好像有一点明白了,torch.FloatTensor([[1, 0]])
中
x
2
x_2
x2?为0???