![深度学习自然语言处理实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/461/37323461/b_37323461.jpg)
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=1738891946-UWNDAOto1EusI6q41k7Dx9cC4vkEIamy-0-27a7ca10538c9c31fff8384f8525ace3)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/53_02.jpg?sign=1738891946-94H9gZgef2i372TCghaD7TyL3AIV4ast-0-3a5ff8a1048ce58518b32ddbef8ee20d)
对Tensor x做加法运算
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/53_03.jpg?sign=1738891946-dSzigXGyTStfphA2dlIsC7ax35hheaxt-0-e220736f1a05a48f00293eabb5c99c10)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/53_04.jpg?sign=1738891946-mIUVyX9RcjCwCbiR7qpcuUVopYuAQEhs-0-3f684de85ead3eef6dea57208711b658)
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/54_01.jpg?sign=1738891946-8piiQjmyJkrJQf9O5ZudisR2QNeF4TrB-0-a0f15083d26b6c20bbf626893b30007b)
在这里可以看到,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=1738891946-nyZrog1PZMWt2yuSX8tlg8ExIM2mpQR1-0-4ff50235bfdc91e4c85c664a3311f955)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/54_03.jpg?sign=1738891946-ddQzmp7Mgmx0jTAhTwOHe77HUcKUqbGZ-0-fe61af74635a20e76c5d8bfd906acfb1)
.requires_grad_(...)会改变张量的requires_grad标记。如果没有提供相应的参数,输入的标记默认为False。
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/54_04.jpg?sign=1738891946-0oaiFBhPrxX45h71nDctYAHTilPOglnV-0-0b3ebbf5ce899c8408dbb86cc1ddedcc)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/54_05.jpg?sign=1738891946-4gZx0B5yQ3HmMvxiiOPbm3oxV4EbvE3Y-0-d7282f98aa71e9487df67e728acee938)
2.3.3 梯度计算
我们根据上述内容建立一个稍微复杂的网络来进行梯度计算。
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_01.jpg?sign=1738891946-4zaCYfs4QoaMybSyysbZPXVFUCUEKRut-0-17eb2588000a43329fcd05ded240b0d2)
然后进行反向传播
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_02.jpg?sign=1738891946-jXaI9fUgMokPVvpgfOtKz3F374nlcv3s-0-91ec142c530c636b4fe962cdc5ea7b33)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_03.jpg?sign=1738891946-2NyjsgOfduLxhuI2c44xbfes5sVzVOjE-0-bfe02b3c733701e3bd8f3441fa7f2e32)
下面,我们来计算一个简单的雅可比的梯度。
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_04.jpg?sign=1738891946-9EUNW5F5aXOrAbwOgfZLz5dWjcERqVOR-0-62e7c8893061f674b97a5eb18968f3ab)
输入的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_05.jpg?sign=1738891946-4qccNkqsCJpBwl91rJV8DU0mVhitVrwS-0-28d2ee14a8935a2cd576abfc4f4c98e2)
现在在这种情况下,y不再是一个标量。torch.autograd不能直接计算整个雅可比,但是如果我们只想要雅可比向量积,只需要简单地把向量传递给backward作为参数。
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/55_06.jpg?sign=1738891946-jRMuZe0XYJXaOl0bRiOGXgGlTCqGiAm9-0-1116369b00b702ad1977fa6896398f94)
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/56_01.jpg?sign=1738891946-WSAcOwvS77I4zKFumJuBGYcQohTUE213-0-1825e8dbc2d21a6a0c16e64f6ecbde68)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/56_02.jpg?sign=1738891946-9YewFQhKfD7brFAxNQsZh6QTf6FWiYGD-0-2bd1368fb50df49c5c7fa94a9007fbf1)
可以通过将代码包裹在with torch.no_grad()中,来停止对从跟踪历史中的.requires_grad=True的张量自动求导。
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/56_03.jpg?sign=1738891946-dYdmzgzAZd4vCnMiyaXYW0CteWAzK3Up-0-5369c2822a079e56e6f2f0e6042330bb)
输出的结果为
![](https://epubservercos.yuewen.com/BA58E3/19773740808833006/epubprivate/OEBPS/Images/56_04.jpg?sign=1738891946-4iq5cBJqqy53Xw0ckp2I24bOHYAoVH5B-0-e91f2c31eedf2943d6078ff09e50151e)