![PyTorch计算机视觉实战:目标检测、图像处理与深度学习](https://wfqqreader-1252317822.image.myqcloud.com/cover/947/50417947/b_50417947.jpg)
1.4.1 梯度下降的代码
下面将给出梯度下降的Python实现代码。
下列代码可以从本书GitHub存储库(https://tinyurl.com/mcvp-packt)Chapter01文件夹中的Gradient_descent.ipynb获得。
1.定义前馈网络并计算均方误差损失值,正如我们在1.3.5节中所做的那样:
![](https://epubservercos.yuewen.com/37D997/29686491107405206/epubprivate/OEBPS/Images/32_02.jpg?sign=1739045263-G7lFDlj9SlzVBOXcCMuJrz6XydqMtmyP-0-ffb157d525dc7d1f6d09a42f6b1835c6)
2.将每个权重和偏置项增加一个非常小的量(0.0001),并对每个权重和偏置项更新一次,计算总体误差损失的平方值。
❍ 在下面的代码中,创建了一个名为update_weights的函数,它通过执行梯度下降过程来更新权重。函数的输入是网络的输入变量inputs、期望的outputs、weights(在模型训练开始时进行随机初始化),以及模型的学习率lr(有关学习率的更多内容见后面的章节):
![](https://epubservercos.yuewen.com/37D997/29686491107405206/epubprivate/OEBPS/Images/33_01.jpg?sign=1739045263-DYIfl3kVqVnFlXBHRc3t2jSqWiJs6rKl-0-aecd7bcb6d3529edf3510f3a31983233)
❍ 确保对权重列表进行了deepcopy操作。由于权重将在后面的步骤中被操纵,deepcopy确保了我们可以在不干扰实际权重的情况下使用多个权重副本。创建作为函数输入传递的原始权重集的三个副本——original_weights、temp_weights和updated_weights:
![](https://epubservercos.yuewen.com/37D997/29686491107405206/epubprivate/OEBPS/Images/33_02.jpg?sign=1739045263-NgbSyhr9KiiLYuIrPYRM7C8dlslLc2rm-0-cca12b1a14c614dd1788586fb5c6012e)
❍ 通过feed_forward函数传递inputs、outputs和original_weights,使用原始的权重集计算损失值(original_loss):
![](https://epubservercos.yuewen.com/37D997/29686491107405206/epubprivate/OEBPS/Images/33_03.jpg?sign=1739045263-uzGbfA5ycbm24C6Sy0LerN8hH6XYcMhU-0-542eb099336f3005bc0297f46b677e1f)
❍ 循环遍历网络的所有层:
![](https://epubservercos.yuewen.com/37D997/29686491107405206/epubprivate/OEBPS/Images/33_04.jpg?sign=1739045263-J4oRgXiQyC2IOJLDcXpZ0uDlzOhP1b6d-0-b932445c30fe88c7aa02753e79c7c725)
❍ 在神经网络中总共有四个参数列表:两个连接输入层和隐藏层的权重与偏置参数列表,另外两个连接隐藏层和输出层的权重与偏置参数列表。现在,我们循环遍历所有单独的参数,因为每个列表有不同的形状,利用np.ndenumerate循环遍历给定列表中的每个参数:
![](https://epubservercos.yuewen.com/37D997/29686491107405206/epubprivate/OEBPS/Images/33_05.jpg?sign=1739045263-AK4VY0yK0LkBM08LVc2eH5GKitJ3DrqR-0-c2a6aac12ea1dede6e187f3d7a37ac6a)
❍ 现在将原始权重集存储在temp_weights中。选择其在第i层存在的指标权重,并将其增加一个较小的量。最后,用神经网络的新权重集计算新的损失:
![](https://epubservercos.yuewen.com/37D997/29686491107405206/epubprivate/OEBPS/Images/33_06.jpg?sign=1739045263-4fTOuYpwE1FX1qBZBKbIGovBEw6J33tE-0-ae3c6543e75e5a7d56cacd84b409cb2f)
在上述代码的第一行中,将temp_weights重置为原始的权重集,正如在每次迭代中那样更新不同的参数,由此计算出在给定轮内对参数进行少量更新时得到的新的损失。
❍ 计算由于权重变化而产生的梯度(损失值的变化):
![](https://epubservercos.yuewen.com/37D997/29686491107405206/epubprivate/OEBPS/Images/33_07.jpg?sign=1739045263-9iY7HDLZyJGZ2bRsQKwyEHor4yTJGq4V-0-dadf948a24beb73b5da1cad2386dcb85)
通过非常小的增量更新一个参数,然后计算相应的梯度,这个过程相当于一个微分过程。
❍ 最后,更新updated_weights对应层和index中的参数。更新后的权重值将按梯度值的比例减小。此外,我们还引入了一种机制,通过使用学习率lr(关于学习率的更多信息,见1.6节)来缓慢地建立信任,而不是将其完全减小为梯度值:
![](https://epubservercos.yuewen.com/37D997/29686491107405206/epubprivate/OEBPS/Images/34_01.jpg?sign=1739045263-1zu9fvOfImA8y4Pz0bCKAMW7fUbPdcs2-0-04e36c59552d0787dddeb5c7ed42135e)
❍ 一旦更新了所有层的参数值和层内的索引,我们就返回更新后的权重值updated_weights:
![](https://epubservercos.yuewen.com/37D997/29686491107405206/epubprivate/OEBPS/Images/34_02.jpg?sign=1739045263-3JtvWLyxsproMRwkX8KWHNQcHgTGiChL-0-a5634f6df6fa4d5096b845cd3745bc2f)
神经网络的另一个参数是在计算损失值时需要考虑的批大小(batch size)。
前面使用所有数据点来计算损失(均方误差)值。然而在实践中,当有成千上万(或者在某些情况下数百万)的数据点时,使用较多数据点计算损失值,其增量贡献将遵循收益递减规律,因此我们将使用比数据点总数要小得多的批大小进行模型训练。在一轮的训练中,每次使用一个批次数据点进行梯度下降(在前向传播之后),直到用尽所有的数据点。
训练模型时典型的批大小是32和1024之间的任意数。
在本节中,我们了解了当权重值发生少量变化时,如何基于损失值的变化更新权重值。在下一节中,将学习如何在不计算梯度的情况下更新权重。