- 深度学习自然语言处理实战
- 开课吧组编 张楠 苏南 王贵阳等编著
- 863字
- 2021-04-22 17:09:13
2.3 PyTorch自动求梯度
深度学习的过程中,在对代价函数(loss)进行优化时需要计算梯度(gradient),Py-Torch提供的autograd(自动求梯度)包能够根据输入的数据和前向传播过程自动构建计算图,并执行反向传播。
2.3.1 基本概念
在PyTorch中,torch.Tensor是autograd包的核心类,如果将其属性.requires_ grad设置为True,它将开始追踪对Tensor的所有操作,即可以利用链式法则(Chain Rule)进行梯度传播(Gradient Propagation)。完成计算后,可以调用.backward()来自动完成所有梯度的计算。这个Tensor的梯度将累积到.grad属性中。例如,如果x是一个Tensor,x.requires_grad=True,然后x.grad是另一个Tensor,x.grad将累计x的所有的梯度。
如果在后期需要停止对Tensor历史记录的追踪,可以调用.detach()函数,它会将Tensor与其计算的历史记录做分离,并防止将来的计算被继续追踪,此时,梯度就不会进行传播了。如果需要设置一些操作代码使其不被跟踪,可以用with torch.no_grad()将具体的代码块包装起来。这种方法在评估(Evaluate)模型时用处很大,这是因为在评估模型的阶段不需要用到可训练参数(require_grad = True)部分的梯度。
Function也是autograd包中很重要的一个类。通过将Tensor和Function进行连接可以构建一个保存整个计算过程历史信息的有向无环图(Directed Acyclic Graph,DAG)。每个Tensor都会有一个.grad_fn属性,这个属性会保存创建该Tensor的Function,即说明这个Tensor是否由某些运算得到。如果是用户自己创建的Tensor,那么.grad_fn属性将是None。
2.3.2 Tensor样例
创建一个Tensor,通过设置requires_grad = True来跟踪与它相关的计算。
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/53_01.jpg?sign=1739644970-WxM0atLi7YWya80x7stNfSZ0MnvJkqz9-0-16a2e4452207e9a037b844ef297f28b3)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/53_02.jpg?sign=1739644970-UwIz7c1LcXxM9qr9XRdnRZ96YLfeJUzb-0-ac79b77e83367cc42c73bced098e30d5)
对Tensor x做加法运算
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/53_03.jpg?sign=1739644970-k4ylGr3xCJCmBUfjQTDJekeKd24S07HR-0-4cc2a5c58955f6777a66e5d52a9c6df6)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/53_04.jpg?sign=1739644970-2Logdy5KERqIVk65G3yaarNhd0rclIRA-0-f1152f39be274b494f475e0b0c65c1f0)
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/54_01.jpg?sign=1739644970-nbL9bjTAImgkXxPnj5Op2Xqgt2Xa498e-0-d29c0a887ab46c2c337e463fb342faf7)
在这里可以看到,Tensor x是直接创建的(又可以称为叶子节点),因此x没有grad fn;Tensor y是通过加法创建出来的,因此y有一个名为<AddBackward0>的grad_fn。
对Tensor y做更复杂的运算,如下所示:
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/54_02.jpg?sign=1739644970-S33HR1xzPVYEpnwakfBNwllbtYLCUfNV-0-21957733b45a45b17e65c381fad252d0)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/54_03.jpg?sign=1739644970-Q605FLEu7fChUXA7rEwSPn2GnYQMXSHb-0-c049878a275eccc54559c51bb129f0b2)
.requires_grad_(...)会改变张量的requires_grad标记。如果没有提供相应的参数,输入的标记默认为False。
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/54_04.jpg?sign=1739644970-OzUSV5Jl1x3vmNIhK7sU3XsXoLTN81Lm-0-e97141db168c4940e4248329fa71d3ae)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/54_05.jpg?sign=1739644970-dgpi7yNJ31U2PVukCPTwpaBwH4WPJeru-0-ecc973562f25beb7a2324f359a9e90b2)
2.3.3 梯度计算
我们根据上述内容建立一个稍微复杂的网络来进行梯度计算。
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_01.jpg?sign=1739644970-m9AFiRNeNxX6oO6dhgcKG012ZtvqEZWs-0-b06f8104c22cd588ce6d24431588831e)
然后进行反向传播
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_02.jpg?sign=1739644970-aSEEoi7cMaFDj81tpHjPNWfrnP5Tw2cc-0-59d5bcca338ff41ab15d2f533dfe4a51)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_03.jpg?sign=1739644970-sKUzKGYQLUqtuPv5gO1pqnwOn3s4Ulv6-0-342975522a338d418ffc8432e361ce88)
下面,我们来计算一个简单的雅可比的梯度。
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_04.jpg?sign=1739644970-5RPdpghdVLAhza75XnRtJEyXgDitGPoQ-0-a2df946bf1997cee532b164b8af40987)
输入的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_05.jpg?sign=1739644970-8Adpp3alleB50uaybNlyAntm7lPOh3Mq-0-0875a2ca6f6f039979e556538f1aab5f)
现在在这种情况下,y不再是一个标量。torch.autograd不能直接计算整个雅可比,但是如果我们只想要雅可比向量积,只需要简单地把向量传递给backward作为参数。
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_06.jpg?sign=1739644970-YHXZPpzCsaGkAphok3YHRY4ogXgI60gA-0-006022d28d3ce393282324576937935a)
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/56_01.jpg?sign=1739644970-6aOdfbkHc6ZJBdozTFzNJJa4A0DEIaJr-0-8e5e7bff7c8d3277f8be6502265eaff4)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/56_02.jpg?sign=1739644970-Fa8UiNvCYd7CNMC2S46jL93PeVeIpSce-0-fa76cb6fae5c05748ea6515e950499cf)
可以通过将代码包裹在with torch.no_grad()中,来停止对从跟踪历史中的.requires_grad=True的张量自动求导。
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/56_03.jpg?sign=1739644970-EZtElIdIi0enptwdZcvIrwmyZ72o6TxU-0-809fe058935a8419bcaaaf68f099bcf8)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/56_04.jpg?sign=1739644970-tDexde5cn18PXO5rqoAq2MdJvARiPVx4-0-c5e9b50aee8ca9537d4d2ba53eb639b0)