![PyTorch深度学习应用实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/410/52842410/b_52842410.jpg)
3-3 自动微分
反向传导时,会更新每一层的权重,这时就轮到偏微分运算派上用场,所以,深度学习框架的第二项主要功能就是自动微分(Automatic Differentiation)。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P44_25830.jpg?sign=1739139817-rpkREsunfp6hNWuJWXagLUzQjDOYcfbN-0-39a4e1ccd0fe52131d77b7637a08374b)
图3.9 神经网络权重求解过程
下列程序代码请参考【03_02_自动微分.ipynb】。
(1)变量y会对x自动微分,代码如下。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P45_3069.jpg?sign=1739139817-73PBrz4nCUpoSZKfw1yVWdL1S3ReHrWe-0-f4dce49155e3aa4d69c035c4012e1ba6)
变量x要参与自动微分,须指定参数requires_grad=True。
设定y是x的多项式,y.grad_fn可取得y的梯度函数。
执行y.backward(),会进行反向传导,即偏微分。
通过x.grad可取得梯度,若有多个变量也是如此。
执行结果中x^2对x自动偏微分,得2x,因x=4,故x梯度=8。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P45_3083.jpg?sign=1739139817-akXiDKlX7sdpinHTvZqN6gEBkMAWUbAU-0-4cb9acbde6758c79c9200a1fb6d1d740)
(2)下列程序代码可取得自动微分相关的属性值。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P45_3086.jpg?sign=1739139817-Dfsk9pCtODlRaD5Reaslk1h6hahJ0LZ0-0-ac60346a95d1b3eed84c98ec5c48e250)
执行结果。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P45_3093.jpg?sign=1739139817-bGBdwmvdFfk0vNn51atT49qjHK1cHtBA-0-dc7c7c9c6314e221743ecc24c8d8bc3a)
(3)来看一个较复杂的例子,以神经网络进行分类时,常使用交叉熵(Cross Entropy)作为损失函数,下图表达Cross Entropy=CE(y, wx+b)。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P46_25835.jpg?sign=1739139817-iLPfBApdpCdyDUoisdb8QCDFpedw78BT-0-9c732ff2f728b3d17450be1b6a0af561)
图3.10 交叉熵(Cross Entropy)运算图
PyTorch会依据程序,建构运算图(Computational Graph),描述梯度下降时,变量运算的顺序如下所示,先算x,再算z,最后计算loss。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P46_3165.jpg?sign=1739139817-NFMRirtHQOgE7W8QDlYq2JEKdQvFLQ3J-0-243ac1c6897f6c368cddf7d65834adf8)
torch.nn.functional.binary_cross_entropy_with_logits是PyTorch提供的交叉熵函数。
执行结果:
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P46_3172.jpg?sign=1739139817-RUkRU62J75vC0RlMWIQzc9yAjURmmzly-0-9979ddfe7f4080050631457298dc7e83)
(4)自动微分中,z是w、b的函数,而loss又是z的函数,故只要对loss进行反向传导即可。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P46_3175.jpg?sign=1739139817-kNzYGYqJM7nSsGTQbO4Qdfl8QuYxvLSC-0-6fb93410c5298af91e147917877b19ab)
执行结果中,w、b梯度分别为:
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P46_3182.jpg?sign=1739139817-nJ78usN5UaWbW2hRZCwNMUXKlW5uESZF-0-980f9b41976559765ec058e03a703481)
(5)TensorFlow使用常数(Constant)及变量(Variable),而PyTorch自v0.4.0起已弃用Variable,直接使用tensor即可,但网络上依然常见Variable,特此说明,详情请参阅本章参考文献[1]。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P46_3185.jpg?sign=1739139817-i4l9fxfsPEEnn5ogQSNSr3Rqoe9vGayK-0-698d63d61edd7aac87a1bf50cfb7e0e6)
上例以torch.ones替代Variable。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P46_3192.jpg?sign=1739139817-zc3jT7bf6NTIWvR55n3MSaQSpERAGLp8-0-1002e4fb038d31228169880a15ee0b29)
(6)模型训练时,会反复执行正向/反向传导,以找到最佳解,因此,梯度下降会执行很多次,这时要注意两件事:
· y.backward执行后,预设会将运算图销毁,y.backward将无法再执行,故要保留运算图,须加参数retain_graph=True。
· 梯度会不断累加,因此,执行y.backward后要重置(Reset)梯度,指令如下:x.grad.zero_()
(7)不重置梯度代码如下:
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P47_3214.jpg?sign=1739139817-smYlzV4ryuPK5Ka32EmxDs7ZJPLES7ry-0-bb146db34fda974dfc087a280df018b8)
执行结果:
一次梯度下降=75.0;
二次梯度下降=150.0;
三次梯度下降=225.0。
二次、三次梯度下降应该都是75,结果都累加。
(8)使用x.grad.zero_()梯度重置代码如下。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P47_3221.jpg?sign=1739139817-rPqqzTIXFbNyKDBYrgI9SYQL4uxD6Grm-0-be0c7a8ace7b4ce6838c0498c95850f8)
(9)多个变量梯度下降。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P47_3228.jpg?sign=1739139817-CEtaYmwxF4HujRWmNYlc5Uu76YPVvhm0-0-5fbdd92c130d1de9dc53d0396de97693)
执行结果:z=6*(x^5)=18750。
接着改写【02_02_梯度下降法.ipynb】,将改用PyTorch函数微分。
(1)只更动微分函数:原来是自己手动计算,现改用自动微分。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P47_3236.jpg?sign=1739139817-D6QkjzDnwUoQx3ofIobwURZgztP5teAL-0-c8101bf357aee33f8cf581be0b63a318)
执行结果:与【02_02_梯度下降法.ipynb】相同。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P48_3256.jpg?sign=1739139817-vU11FrNSMuG1hnPubqJ4FxudKn74cpFY-0-2c9d85d38ae40fb38387216989dd5e99)
(2)再将函数改为2x4-3x2+2x-20。要缩小学习率(0.001),免得错过最小值,同时增大执行周期数(15000)。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P48_3259.jpg?sign=1739139817-2gfknr3tAWmF2LynDfINtPAnFtgE35t7-0-df62e5b92656842d5b4abbdb63de13a6)
执行结果:与【02_02_梯度下降法.ipynb】相同。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P48_3266.jpg?sign=1739139817-XnrxNrFFvadKSlD2Ji4C2vmPtUVnpnxw-0-dfa82b47133a183034b4cdf862cecd8d)
最后来操作一个完整范例,使用梯度下降法对线性回归求解,方程式如下,求w、b的最佳解。
y=wx+b
下列程序代码请参考【03_03_简单线性回归.ipynb】。
(1)载入套件。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P48_3269.jpg?sign=1739139817-74LxFBwDkhs795L9OhVcH2sznX3ZsZlg-0-e34d9122a6ba1c202ce5d5a4f39876fd)
(2)定义训练函数:
· 刚开始w、b初始值均可设为任意值,这里使用正态分布之随机数。
· 定义损失函数=MSE,公式见11行。
· 依照2-3-3节证明,权重更新公式如下:
新权重=原权重-学习率(learning_rate)×梯度(gradient)
· 权重更新必须“设定不参与梯度下降”才能运算,参见第14~18行。
· 每一训练周期的w、b、损失函数都存储至数组,以利后续观察,参见第22~24行。要取得w、b、损失函数的值,可以使用.item()转为常数,也可以使用.detach().numpy()转为NumPy数组,detach作用是将变量脱离梯度下降的控制。
· 记得梯度重置,包括w、b。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P49_3289.jpg?sign=1739139817-Ls0J5oOdyo7EoNSTkGgMUecTXyeLTCAX-0-2f9a88ed10199886a37f021af85a65ae)
(3)产生线性随机数据100笔,介于0~50。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P49_3296.jpg?sign=1739139817-E9PnqCIK7cFdbkKbFAqcGbWW64S6wGzp-0-a7238d45a1462ea79b53a294c25845b5)
(4)执行训练。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P49_3303.jpg?sign=1739139817-nFCyfOYGeUm01Q5OPlCUluxOVr6BsXDt-0-977fbfb0ce7ea49f962a9ea3d2e028fd)
执行结果:w=0.942326545715332, b=1.1824959516525269。
(5)执行训练100000次。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P49_3310.jpg?sign=1739139817-RjZdxbezMSNOzhE2T8vXfCMb2JnAPcHL-0-0d95a286a8f6cda77c42540d49036cdc)
执行结果有差异:w=0.8514814972877502, b=4.500218868255615。
(6)以NumPy验证。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P49_3317.jpg?sign=1739139817-A6uYi7r5Zz8xAA8JVIwTq8s7lwcGqa8W-0-746c25cb7335e9c2960d0fa70e12a72a)
执行结果:w=0.8510051491073364, b=4.517198474698629。结果与梯度下降法训练100000次较相近,显示梯度下降法收敛较慢,需要较多执行周期的训练,这与默认的学习率(lr)有关,读者可以调整反复测试。所以说深度学习必须靠试验与经验,才能找到最佳参数值。
(7)训练100次的模型绘图验证。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P50_3339.jpg?sign=1739139817-smYeH3ZpUXnb2LzhKmHm2rSuBQjybspj-0-98411e1a6a9b65a7c059ac0a90c5b7d8)
执行结果:虽然训练次数不足,但回归线也确实在样本点的中线。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P50_3346.jpg?sign=1739139817-fwnM6qCzJoUHnplALgNEglrhn0qSyfv1-0-881bb28279eafedb70c73ac0ae45ce51)
(8)NumPy模型绘图验证。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P50_3349.jpg?sign=1739139817-7ugX4ymFJ6yasH7m0Wj30ZsT95KCV2hI-0-f066df0e69fce2588c33b0f46acd2d96)
执行结果:回归线在样本点的中线。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P50_3356.jpg?sign=1739139817-HJ89hEIoTsKPoYn6WcoZ2iT3i772o69e-0-20e7868c6caf1f53239f6c97c5c8a10a)
(9)损失函数绘图验证。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P50_3359.jpg?sign=1739139817-FKqFzL6fScsYj5gdbmvV47ztWQmhLb9u-0-93b11be93f55d891bad5b445687c6299)
执行结果:大约在第10个执行周期后就收敛了。
![](https://epubservercos.yuewen.com/128DEE/31397898903670606/epubprivate/OEBPS/Images/Figure-P50_3366.jpg?sign=1739139817-CVkWTUR0M5tBH86ltoZFZCn6Laug4Sv1-0-f2ff926814cb048eb603dfd5d165a8a3)
有了PyTorch自动微分的功能,反向传导变得非常简单,若要改用其他损失函数,只须修改一下公式,其他程序代码都照旧就可以了。这一节模型训练的程序架构非常重要,只要熟悉每个环节,后续复杂的模型也可以运用自如。