对比前文,更简便的办法是使用.backward()函数进行求导
以代码示例
代码语言:javascript复制x = torch.ones(1)
w = torch.full([1], 2, requires_grad=True)
# 首先构建tensor
# 构建动态图,完成MSE的构建
mse = F.mse_loss(torch.ones(1), x*w)
# 对其求导时直接对设定的loss使用.backward()函数
mse.backward()
# 对设定的loss信息进行向后传递,注意:pytorch在前向传播时会自动记录传播路径
# 会记录路径上所有gradient的方法,使用 参数.grad函数即可输出相应的求导信息
print(w.grad)
输出
代码语言:javascript复制tensor([2.])
这种.backward()方法更为简洁,以后在编写代码时也多采用这种方法。
在此总结两种求导方法
(1).torch.autograd.grad(loss, [w1, w2, ...])
该函数返回的是əloss/əw1, əloss/əw2。
(2) loss.backward()法
直接调用之前的梯度信息
写入w1.grad, w2.grad即可输出
下面介绍经常使用的softmax函数
Softmax(全称:soft version of max)常与crossentropy(交叉熵)搭配连用。
上图中假设有三个输出,分别是2.0、1.0和0.1,如果将数值转移成概率的话,希望概率最大的值作为label。即我们希望将最大值2.0所对应的label作为相应索引输出。那么如何进行按照probilities作为概率输出呢?
按照之前所讲的sigmoid函数压缩成[0~1],但对于分类问题来说,物体均具有概率属性,按此方法输出的所有概率之和无法满足等于1的要求(P(0) P(1) P(2) = 1)。
因此为解决此类问题,这里引入了softmax函数。
这里进行了操作 e2/(e2 e1 e0.1) = 0.7,e1/(e2 e1 e0.1) = 0.2,e0.1/(e2 e1 e0.1)=0.1。
这样每个节点都在0至1之间。另外这里注意,softmax具有差距放大功能。如原2.0与1.0是两倍的关系,经过softmax操作后,变为0.7与0.2,呈3.5倍的关系。
对softmax函数进行求导,首先写出其函数式
进行求导
另eai为g(x),另分母eak为h(x)。
当i与j相等时:
当i与j不相等时:
对以上求导过程进行总结
这里注意,由于pi和pj均在[0,1]范围内。故pi(1-pj)乘积大于0,而-pi*pj的乘积小于0。
这里使用代码举例
代码语言:javascript复制import torch
import torch.nn.functional as F
a = torch.rand(3, requires_grad=True)
print(a)
p = F.softmax(a, dim=0)
# 指定dim维度进行sfotmax操作
print('softmax:', p)
print(torch.autograd.grad(p[1], [a]))
# 注意loss必须为长度为1的值,这里由于p是dim=1,长度为3的值,因此取p[1]。
输出为
代码语言:javascript复制tensor([0.1683, 0.6142, 0.7754], requires_grad=True)
softmax: tensor([0.2274, 0.3552, 0.4174], grad_fn=<SoftmaxBackward>)
(tensor([-0.0808, 0.2290, -0.1483]),)
这里进行了əp1/əai的操作,由于a是[0, 2]的tensor,结果返回了[1, 3]的矩阵。当i=1时,梯度信息为正,这在前文中有所提到。