我问自己同样的问题,想知道为什么不改变。通过查看 original paper(第 2 页),可以看到算法需要 self._lr 步长(在论文中使用 alpha 设计),但从未更新。我们还看到每个t 步骤都会更新一个alpha_t,并且应该对应于self._lr_t 属性。但事实上,正如您所观察到的,在训练期间的任何时候评估 self._lr_t 张量的值总是会返回初始值,即 _lr。
因此,据我了解,您的问题是如何获取 TensorFlow 的 AdamOptimizer 的 alpha_t,如本文第 2 节和相应的 TF v1.2 API page 中所述:
alpha_t = alpha * sqrt(1-beta_2_t) / (1-beta_1_t)
背景
正如您所观察到的,_lr_t 张量在训练过程中并没有改变,这可能会导致优化器不适应的错误结论(这可以通过切换到 vanilla 来轻松测试 em> GradientDescentOptimizer 与 alpha 相同)。而且,事实上,其他值确实会发生变化:快速查看优化器的 __dict__ 会发现以下键:['_epsilon_t', '_lr', '_beta1_t', '_lr_t', '_beta1', '_beta1_power', '_beta2', '_updated_lr', '_name', '_use_locking', '_beta2_t', '_beta2_power', '_epsilon', '_slots']。
通过培训检查他们,我注意到只有_beta1_power、_beta2_power 和_slots 得到更新。
进一步检查the optimizer's code,在第 211 行,我们看到以下更新:
update_beta1 = self._beta1_power.assign(
self._beta1_power * self._beta1_t,
use_locking=self._use_locking)
这基本上意味着_beta1_power,即initialized with _beta1,将在每次迭代后乘以_beta_1_t,即is also initialized with beta_1_t。
但令人困惑的部分来了:_beta1_t 和 _beta2_t 永远不会更新,因此它们在整个训练过程中有效地保持初始值(_beta1和_beta2),相互矛盾论文的符号与_lr 和lr_t 类似。 我想这是有原因的,但我个人不知道为什么,无论如何这是实现的受保护/私有属性(因为它们以下划线开头)并且不属于公共接口(它们甚至可能在 TF 版本之间发生变化)。
所以经过这个小背景我们可以看到_beta_1_power和_beta_2_power是对当前训练步取幂的原始beta值,也就是等同于论文中beta_t所指的变量。回到论文第 2 节中alpha_t 的定义,我们看到,有了这些信息,它应该很容易实现:
解决方案
optimizer = tf.train.AdamOptimizer()
# rest of the graph...
# ... somewhere in your session
# note that a0 comes from a scalar, whereas bb1 and bb2 come from tensors and thus have to be evaluated
a0, bb1, bb2 = optimizer._lr, optimizer._beta1_power.eval(), optimizer._beta2_power.eval()
at = a0* (1-bb2)**0.5 /(1-bb1)
print(at)
变量at 保存当前训练步骤的alpha_t。
免责声明
我找不到一种仅使用优化器界面来获取此值的更简洁的方法,但如果它存在,请告诉我!我想没有,这实际上质疑了绘制alpha_t 的有用性,因为它不依赖于数据。
此外,为了完成这些信息,论文的第 2 部分还给出了权重更新的公式,这更能说明问题,但情节也更密集。对于一个非常漂亮和好看的实现,您可能需要查看您链接的帖子中的this nice answer。
希望对您有所帮助!干杯,
安德烈斯