自动微分
我们知道在pytorch是支持自动微分的,也就是自动求导数,在深度学习框架中,我们一般会求loss函数关于可学习参数的偏导数。
import torch |
如果我们将来需要计算关于某个 变量 的偏导数,例如:中,则我们使用
x.requires_grad_(True) |
or
x=torch.arange(4.0,requires_grad=True) |
两种方式来给打上变量标记,这里变量的意思表示,未来我们希望修改的值。
深度学习框架中的变量
我们知道,深度学习中我们需要更新参数,这里参数其实就是变量,而样本却不是变量。
很多深度学习任务可以表示为下面的数学形式:
这里我们的loss
函数是关于和的函数,但是这里并不是变量,或者说我们不希望更新。
才是变量,我们希望迭代更新,使得其逼近,这里我们可以采用很多优化方法,最常见的就是梯度下降法,这时我们自然要求,loss
函数关于的偏导数:。
反向传播和梯度清零
我们定义了变量后,我们只要是对变量进行的计算,都会自动求偏导数
import torch |
这里y是使用x计算的,那么在计算y的同时,就会在y中存储一个梯度计算方法。
若我们希望查看此时y关于x的偏导数,则需要
y.backward() |
即先反向传播计算出偏导数,并将偏导数累加在x中,这时我们采用x.grad
就能查看x
中累加的梯度。
而在实际应用中,我们有时候不希望梯度累加,这时候我们就需要梯度清零。
x.grad.zero_() |
注意:
- 当x刚被初始化时,无法使用
x.grad.zero_()
,因为此时其梯度为none
- 梯度清零清除的是x中的累积梯度,而不会清除y中的梯度计算方法
import torch |
上面若不使用x.grad.zero_()
则第二个输出为tensor([2.,2.,2.,2.])
,并且在使用x.grad.zero_()
后,z仍然可以使用反向传播,来计算梯度累加在x上。
深度学习框架下的梯度清零
在深度学习任务中,我们常常会分批次进行梯度下降(stochastic gradient descent),这里就要求我们在计算每一批次后梯度清零。
num_epochs = 3 |
例如上面中X,y就是训练集中的一个批次,我们在进行梯度下降前是需要使用梯度清零的。
with torch.no_grad() 和 x.detach()
import torch |
有时我们需要获得,tensor的值而不需要其梯度,我们可以采用x.detach()
。
在不需要计算梯度时,我们可以使用with torch.no_grad():
来临时禁用梯度,在深度学习框架中,这点非常常见,因为只有在训练模型中的推理过程中我们才需要计算梯度,在其它任何时候,只要是关于变量的计算,我们都不希望其发生自动微分,例如:模型验证阶段,模型部署后
# 假设 model 是训练好的神经网络,X 是输入数据 |