Python 自定义TensorFlow Keras优化器

Python 自定义TensorFlow Keras优化器,python,tensorflow,deep-learning,tf.keras,tensorflow2.x,Python,Tensorflow,Deep Learning,Tf.keras,Tensorflow2.x,假设我想编写一个符合tf.kerasAPI(使用TensorFlow版本>=2.0)的定制优化器类。我对文档化的方法与实现中的方法感到困惑 tf.keras.Optimizer.Optimizer的文档 ###编写一个定制的优化器。 如果您打算创建自己的优化算法,只需从 该类并重写以下方法: -资源应用密度(给定梯度张量为密度的更新变量) -资源应用稀疏(给定梯度张量为稀疏的更新变量) -创建\u插槽(如果优化器算法需要其他变量) 但是,当前的tf.keras.optimizers.Optim

假设我想编写一个符合
tf.keras
API(使用TensorFlow版本>=2.0)的定制优化器类。我对文档化的方法与实现中的方法感到困惑

tf.keras.Optimizer.Optimizer的文档

###编写一个定制的优化器。
如果您打算创建自己的优化算法,只需从
该类并重写以下方法:
-资源应用密度(给定梯度张量为密度的更新变量)
-资源应用稀疏(给定梯度张量为稀疏的更新变量)
-创建\u插槽(如果优化器算法需要其他变量)
但是,当前的
tf.keras.optimizers.Optimizer
实现并没有定义
resource\u apply\u density
方法,而是定义了一个私有外观。类似地,没有
资源\u应用\u稀疏
创建\u插槽
方法,但有a和a

在官方的
tf.keras.optimizers.Optimizer
子类(以
tf.keras.optimizers.Adam
为例)中,有、和方法,并且没有不带前导下划线的方法

在稍微不太正式的
tf.keras.optimizers.Optimizer
子类(例如,TensorFlow插件中的
tfa.optimizers.MovingAverage
)中有类似的主要下划线方法

另一个让我感到困惑的地方是,一些TensorFlow插件优化器还覆盖了
apply_gradients
方法(例如,),而
tf.keras.optimizers
优化器则没有

此外,我注意到
tf.keras.Optimizer.Optimizer方法的
apply_gradients
方法,但是基本
tf.keras.Optimizer.Optimizer
类没有
\u create_slot
方法。 因此,如果优化器子类不覆盖
应用梯度,则必须在优化器子类中定义
\u create\u slots
方法


问题 子类化a
tf.keras.optimizers.Optimizer
的正确方法是什么?具体来说,

  • 顶部列出的
    tf.keras.optimizers.Optimizer
    文档是否仅仅意味着覆盖它们提到的方法的主要下划线版本(例如,
    \u resource\u apply\u dense
    而不是
    resource\u apply\u dense
    )?如果是这样的话,是否有API保证这些私有外观的方法在TensorFlow的未来版本中不会改变它们的行为?这些方法的特征是什么
  • 除了
    \u apply\u resource\uu[dense | sparse]
    方法之外,什么时候可以覆盖
    应用梯度

  • 编辑。在GitHub上打开的问题:

  • 是的,这看起来是一个文档错误。前面的下划线名称是要重写的正确方法。相关的是非Keras优化器,它定义了所有这些,但没有在基类中实现
  • 我不知道如何应用。首先,如果您重写它,代码会提到每副本分发策略可能是“危险的”

  • 更新:TF2.2迫使我清理所有实现—因此现在它们可以用作TF最佳实践的参考。还添加了一个关于
    \u get\u hyper
    \u set\u hyper
    的章节


    我已经在所有主要的TF和Keras版本中实现了——我邀请您进行检查。有几点:

    • 您应该继承,这实际上是您链接的内容;它是
      tf.keras
      优化器的最新基类
    • 您在(1)中的回答是正确的-这是一个文档错误;这些方法是私有的,因为它们不是用户直接使用的
    • apply_gradients
      (或任何其他方法)只有在默认值不能实现给定优化器所需的功能时才被覆盖;在您的链接示例中,它只是原始版本的一个单行插件
    • “因此,似乎必须在优化器子类中定义
      \u create\u slots
      方法,如果该子类不覆盖
      apply\u gradients
      ”——这两个方法是不相关的;这是巧合

    • \u resource\u apply\u density
      \u resource\u apply\u sparse
      之间有什么区别
    后者处理稀疏层,例如
    嵌入
    ,前者处理其他所有内容

    • 我应该什么时候使用
      \u create\u slots()
    定义可训练的
    tf.变量时
    s;示例:权重的一阶和二阶矩(例如Adam)。它使用



    vs:它们支持设置和获取Python文本(
    int
    str
    等)、可调用项和张量。它们的存在主要是为了方便:通过
    \u set\u hyper
    设置的任何内容都可以通过
    \u get\u hyper
    检索,避免重复样板代码。我专门对此进行了问答。

    这可能是作为文档问题向开发人员报告的内容。最明显的是,那些要重写的方法应该在文档中包含初始下划线,但是在任何情况下,就像您所说的,都没有关于它们的签名和确切用途的信息。也可能是计划添加不带下划线的方法名(并记录在案)(如使用
    get\u config
    ),但它们还不应该出现在中。对于签名,您可以随时查看或的声明,并在实现的优化器中查看它们的用法。我认为,虽然它可能不是具有稳定性保证的公共API,但我认为使用它们是非常安全的。他们应该在这方面提供更好的指导。我同意这是TensorFlow的文档问题。您是否在tf Github回购协议中为此创建了一个问题?如果是,你能在这里分享这个链接吗?
      def _create_slots(self, var_list):
        """Create all slots needed by the variables.
        Args:
          var_list: A list of `Variable` objects.
        """
        # No slots needed by default
        pass
    
      def _resource_apply_dense(self, grad, handle):
        """Add ops to apply dense gradients to the variable `handle`.
        Args:
          grad: a `Tensor` representing the gradient.
          handle: a `Tensor` of dtype `resource` which points to the variable
           to be updated.
        Returns:
          An `Operation` which updates the value of the variable.
        """
        raise NotImplementedError()
    
      def _resource_apply_sparse(self, grad, handle, indices):
        """Add ops to apply sparse gradients to the variable `handle`.
        Similar to `_apply_sparse`, the `indices` argument to this method has been
        de-duplicated. Optimizers which deal correctly with non-unique indices may
        instead override `_resource_apply_sparse_duplicate_indices` to avoid this
        overhead.
        Args:
          grad: a `Tensor` representing the gradient for the affected indices.
          handle: a `Tensor` of dtype `resource` which points to the variable
           to be updated.
          indices: a `Tensor` of integral type representing the indices for
           which the gradient is nonzero. Indices are unique.
        Returns:
          An `Operation` which updates the value of the variable.
        """
        raise NotImplementedError()
    
        # TODO(isaprykin): When using a DistributionStrategy, and when an
        # optimizer is created in each replica, it might be dangerous to
        # rely on some Optimizer methods.  When such methods are called on a
        # per-replica optimizer, an exception needs to be thrown.  We do
        # allow creation per-replica optimizers however, because the
        # compute_gradients()->apply_gradients() sequence is safe.