2024/06/18
之前写过一篇 的优化器 的源码解读,这次来看一看 的优化器源码。
药师:【TensorFlow】优化器AdamOptimizer的源码分析?zhuanlan.zhihu.com的优化器基本都继承于 "class Optimizer",这是所有 optimizer 的 base class,本文尝试对其中的源码进行解读。
总的来说,PyTorch 中 Optimizer 的代码相较于 TensorFlow 要更易读一些。下边先通过一个简单的例子看一下,PyTorch 中是如何使用优化器的。
首先,在创建优化器对象的时候,要传入网络模型的参数,并设置学习率等优化方法的参数。然后使用函数将梯度置为零。接着调用函数来进行反向传播计算梯度。最后使用优化器的函数来更新参数。
以 PyTorch 中的 SGD Optimizer 为例,下边是 函数。 网络模型的参数被传进来后,用表示;其余参数被打包进字典中命名为。再通过来将和传给父类的函数。
这样做的好处就是,我可以把子类中一些相同的处理操作集中写到父类的初始化函数中去,这样所有子类只需要调用就好了。例如 SGD 类的其他函数中所用到的 就是在父类的函数中创建的。
其中第十行中的的作用在于当字典里的 key 被查找但不存在时,返回的不是而是一个默认值,此处返回的默认值会是个空字典。最后一行调用的,其中是个字典,Key 就是,Value 就是。
函数的主要作用是将放进中。首先要将网络参数重新组织放到列表中。接着将中的键值对遍历放到字典中。之后对和中的元素进行判断,确保没有重复的参数。最后将字典放进列表中。( 注:是在函数中创建的 )
接下来看一下函数。优化器 SGD 中的 函数如下所示。 可以看到,操作很简单,就是将所有参数的梯度置为零。的作用是 是列表,其中的元素是字典。
更新参数主要是靠 函数,在父类 的 函数中只有一行代码 。SGD 中的实现如下所示。正如前边介绍的,网络模型参数和优化器的参数都保存在列表 的元素中,该元素以字典形式存储和访问具体的网络模型参数和优化器的参数。所以,可以通过两层循环访问网络模型的每一个参数 。获取到梯度之后,根据优化器参数设置是否使用 或者再对参数进行调整。最后一行 的作用是对参数进行更新。
PyTorch 中的 Adam Optimizer 和 SGD Optimizer 的主要区别也是 函数不同。Adam Optimizer 中的 函数如下所示。其中,对于每个网络模型参数都使用和来保存 梯度 和 梯度的平方 的移动平均值。第一次更新的时候没有,即,所以两个数值都需要使用来初始化为
值得注意的是,Adam Optimizer 只能处理 dense gradient,要想处理 sparse gradient 需要使用 SparseAdam Optimizer 。
另外,我收集了一些 PyTorch 实现的 Optimizer,欢迎大家来一起维护。
https://github.com/201419/Optimizer-PyTorch?github.com