@TOC

一、求导

在pytorch中有自动求导功能,张量tensor中有一个参数requires_grad,当我们创建一个tensor时设置其为True时即标记为自动求导,此时这个张量参与的运算会被跟踪记录,其默认值是false

需要注意的是,这个requires_grad是具有传递性的,用图和代码举个例子:

pytorch的backword中传入一个负数 pytorch backward()_反向传播


再用代码演示一次:

x = torch.ones(2,2,requires_grad=True) #requires_grad默认是false
y = torch.ones(2,2)
z = torch.ones(2,2)
print(x.requires_grad)
print(y.requires_grad)
print(z.requires_grad)
z = x*y
print(z.requires_grad)
print(z)

结果:
True
False
False
True

二.反向传播

反向传播用的是高数中的链式法则,不显示地把各个变量梯度求出来,而是动态的计算,其实我觉得这个才是求导,反向传播就是把前面节点的梯度(偏导)求出来,这里的节点指的是两个变量运算后得到的另一个变量,如上图的变量z。在pytorch中有自带的反向传播函数.backward()。

需要特别注意的是,这个.backward()函数其实是有参数的,这个参数也是一个tensor,在官网给的资料和大部分其他人的说明中,这个参数的说明是这样的:当得到的output是一个标量(即只有一个确切的值,不是向量)时,可以不填,等于torch.Tensor(1),但是当output是矢量(即是向量或者说数组)时,我们就要自己设定一个了,这个参数的设置一般和输出大小相同。到这并没有清晰的解释为什么要是相同的。我的一个比较形象的理解是:因为这个是反向传播,求的是梯度,根据梯度的定义就是找到一个方向使得值变化最大,当结果是标量时,只有一个维度的方向可以走,而当结果是二维或者三维时,就可以在二维和三维方向上去找一个变化方向了。

权值更新

我们可以使用自己手写的更新代码:

learning_rate = 0.01
  for f in net.parameters():
  f.data.sub_(f.grad.data * learning_rate)

当然我们也可以使用torch自带的更新函数

criterion = nn.MSELoss() #做一个损失函数
target = torch.randn(10) # a dummy target, for example 随便设置的正确标记
target = target.view(1, -1) # make it the same shape as output
optimizer = optim.SGD(net.parameters(), lr=0.01)#创建torch自带的更新器(或者叫优化器),这里选择的方法是随机梯度下降,然后设置步长为0.01
# in your training loop:
optimizer.zero_grad()  # zero the gradient buffers
output = net(input)
loss = criterion(output, target)#计算损失
loss.backward()#反向传播
optimizer.step()#更新

总的来说分为:
1.指定损失函数
2.创建优化器并设置优化方法和学习率
3.导数清零(这一步可以放在前面,主要是怕上一次的导数计算积累)
4.计算损失
5.反向传播
6.更新