【发布时间】:2021-10-10 16:43:01
【问题描述】:
我想为tf.keras(不是独立的keras)制作一个累积的SGD优化器。我在 pypi 上找到了几个独立的keras 累积 SGD 优化器的实现,包括这个one。尽管如此,我正在使用一个使用tf.keras 的项目。正如我所见,将它们混合在一起并不是一个好主意。
问题在于实现这个自定义优化器的文档并不是很直接。基类(我应该继承自)是Optimizer_v2.py,它在评论部分包含有关任务的一些信息。
需要重写的方法是:
- resource_apply_dense (更新变量给定梯度张量是密集的)
-resource_apply_sparse(给定梯度张量的更新变量是稀疏的)
- create_slots(如果您的优化器算法需要额外的变量)
- get_config(优化器的序列化,包含所有超参数)
当然这些只有get_config() 实际存在于基类中。 resource_apply_dense 实际上是 _resource_apply_dense,resource_apply_sparse 是 _resource_apply_sparse,create_slots 甚至在基类中都不存在。在gradient_decent.py 中的SGD 子类中,create_slots 也作为_create_slots 存在。
无论如何,显然文档没有更新(在 git 中也有一个关于此的问题,但我不记得指出与文档缺乏一致性的链接)但这使得整个过程变得困难。例如,在SGD 中,我必须重写_resource_apply_dense() 方法,但我无法理解梯度的计算位置和更新位置。
实际代码如下:
def _resource_apply_dense(self, grad, var, apply_state=None):
var_device, var_dtype = var.device, var.dtype.base_dtype
coefficients = ((apply_state or {}).get((var_device, var_dtype))
or self._fallback_apply_state(var_device, var_dtype))
if self._momentum:
momentum_var = self.get_slot(var, "momentum")
return training_ops.resource_apply_keras_momentum(
var.handle,
momentum_var.handle,
coefficients["lr_t"],
grad,
coefficients["momentum"],
use_locking=self._use_locking,
use_nesterov=self.nesterov)
else:
return training_ops.resource_apply_gradient_descent(
var.handle, coefficients["lr_t"], grad, use_locking=self._use_locking)
显然依赖training_ops.resource_apply_keras_momentum 和training_ops.resource_apply_gradient_descent 来完成实际工作。如何从上述代码中拆分OptimizerV2 中minimize() 方法中提到的两部分? 2部分是:
_compute_gradients() 和 apply_gradients()。
在这个 cmets 中有很多令人困惑的部分,例如在基类中:
许多优化器子类,例如
Adam和Adagrad分配和 管理与要训练的变量相关的其他变量。 这些称为插槽。插槽有名称,您可以询问 它使用的插槽名称的优化器。
尽管如果我声明一个 Adam 优化器并询问插槽名称,我会得到一个空列表 (?)。
optimizer = Adam(lr=1e-3)
optimizer.get_slot_names()
[]
另一个令人困惑的问题是私有方法的使用,不清楚它们何时被调用以及它们的目的是什么。例如_prepare_local() 包含在SGD 中并包含一行:
apply_state[(var_device, var_dtype)]["momentum"] = array_ops.identity(self._get_hyper("momentum", var_dtype))
无论如何,这里的问题是我不知道要遵循哪种方法来创建自定义 tf.keras 优化器。 cmets 中包含的指令似乎与实际实现的子类相矛盾,后者似乎也将肮脏的工作分配给实际的 C++ 函数,但不清楚这是如何完成的或如何(在我的情况下)分离动作(如渐变计算和应用)。那么,是否有人可以就如何进行以及完成这项(相对)简单的任务所遵循的步骤提供任何建议?
顺便说一句,我使用的是 tf 1.15(所以链接来自那里)。
【问题讨论】:
标签: python tensorflow keras