カスタムTensorFlow Kerasオプティマイザー


30

tf.kerasAPIに準拠するカスタムオプティマイザークラスを記述したいとします(TensorFlowバージョン> = 2.0を使用)。これを行うための文書化された方法と実装で何が行われるかについて混乱しています。

ドキュメントtf.keras.optimizers.Optimizer の状態

  ### Write a customized optimizer.
  If you intend to create your own optimization algorithm, simply inherit from
  this class and override the following methods:

    - resource_apply_dense (update variable given gradient tensor is dense)
    - resource_apply_sparse (update variable given gradient tensor is sparse)
    - create_slots (if your optimizer algorithm requires additional variables)

ただし、現在のtf.keras.optimizers.Optimizer実装はresource_apply_denseメソッドを定義していませんが、プライベートなメソッドのスタブを定義してます。同様に、何も存在しない、または方法が、ある方法スタブメソッド呼び出しが_resource_apply_denseresource_apply_sparsecreate_slots_resource_apply_sparse_create_slots

公式にtf.keras.optimizers.Optimizerサブクラス(使用tf.keras.optimizers.Adam例として)がある_resource_apply_dense_resource_apply_sparseおよび_create_slots方法は、先頭の下線なしのそのような方法は存在しません。

やや少ない公式で同様のリーディングアンダースコアの方法があるtf.keras.optimizers.Optimizer(例えば、サブクラスtfa.optimizers.MovingAverage:TensorFlowアドオンからは_resource_apply_dense_resource_apply_sparse_create_slots)。

私にとってもう1つの混乱点は、TensorFlowアドオンオプティマイザーの一部apply_gradientsメソッド(たとえば、tfa.optimizers.MovingAverage)をオーバーライドするのに対し、tf.keras.optimizersオプティマイザーはオーバーライドしないことです。

また、メソッド呼び出しapply_gradientstf.keras.optimizers.Optimizerメソッドがを呼び出し_create_slotsていることに気づきましたが、基本tf.keras.optimizers.Optimizerクラスには_create_slotsメソッドがありません。したがって、サブクラスがをオーバーライドしない場合、オプティマイザーサブクラスで_create_slotsメソッドを定義する必要があるようapply_gradientsです。


ご質問

aをサブクラス化する正しい方法は何tf.keras.optimizers.Optimizerですか?具体的には

  1. tf.keras.optimizers.Optimizer上部にリストされているドキュメントは、それらが言及するメソッドの先頭のアンダースコアバージョンをオーバーライドすることを単に意味しますか(たとえば、_resource_apply_denseではなくresource_apply_dense)?もしそうなら、これらのプライベートに見えるメソッドがTensorFlowの将来のバージョンでそれらの振る舞いを変更しないことについてのAPI保証はありますか?これらのメソッドのシグネチャは何ですか?
  2. メソッドapply_gradientsに加えていつオーバーライド_apply_resource_[dense|sparse]するのですか?

編集。GitHubで未解決の問題:#36449


1
これは、ドキュメントの問題として開発者に報告する必要があるかもしれません。間違いなく、オーバーライドするこれらのメソッドの最初のアンダースコアをドキュメントに含める必要があるように見えますが、いずれにしても、あなたの言うように、その署名と正確な目的に関する情報はありません。また、アンダースコアのない(およびドキュメント化された)メソッド名が(と同様にget_config)追加される予定である場合もありますが、それらはまだパブリックドキュメントに表示されません。
jdehesa

シグネチャについては、常に_resource_apply_denseまたはの宣言を_resource_apply_sparse確認し、実装されたオプティマイザでの使用法を確認できます。安定性が保証されたパブリックAPIではないかもしれませんが、それらを使用することはかなり安全だと思います。彼らはこの面でより良いガイダンスを提供するべきです。
jdehesa

これはTensorFlowのドキュメントの問題であることに同意します。この問題をtf Githubリポジトリで作成しましたか?もしそうなら、ここでリンクを共有してもらえますか?
jpgard

回答:


3

私が実装しましたKeras AdamWをすべての主要なTF&Kerasのバージョンでは-私は検討することを勧めoptimizers_v2.py。いくつかのポイント:

  • 継承する必要OptimizerV2があります。これは実際にリンクしたものです。それは最新かつ現在の基本クラスですtf.kerasオプティマイザの
  • あなたは(1)で正しい-これはドキュメントの誤りです。これらのメソッドはプライベートであり、ユーザーが直接使用するためのものではありません。
  • apply_gradients(またはその他のメソッド)は、デフォルトが特定のオプティマイザに必要なものを達成しない場合にのみオーバーライドされます。あなたのリンクされた例では、それはオリジナルへのワンライナーのアドオンです
  • 「そのため、_create_slotsサブクラスがオーバーライドしない場合、オプティマイザサブクラスでメソッドを定義する必要があるようですapply_gradients」-2つは無関係です。偶然です。

  • 違いは何である_resource_apply_denseとは_resource_apply_sparse

Latterはスパースレイヤーを扱いEmbeddingます。

  • いつ使用すべき_create_slots()ですか?

トレーニング可能なを 定義するときtf.Variable; 例:重みの1次および2次モーメント(例:Adam)。使用しadd_slot()ます。

ほとんど、使用しないときはいつでも_create_slots(); これはクラス属性の設定に似ていますが、使用法の正確さを保証するための追加の前処理ステップがあります。だから、Pythonのint, floattf.Tensortf.Variable、&他。(Keras AdamWではもっと使用するべきでした)。


:リンクされたオプティマイザは正しく動作し、元のオプティマイザとほぼ同じ速さですが、コードはTensorFlowのベストプラクティスに従っており、それでもなお高速です。「理想的なリファレンス」としてはお勧めしません。例えば、いくつかのPythonオブジェクト(例えばint)はテンソルでなければなりません。eta_tはとして定義されてtf.Variableいますが、すぐにtf.Tensorin _applyメソッドとしてオーバーライドされます。必ずしも大したことではなく、改修する時間がなかっただけです。


2
  1. はい、これはドキュメントのエラーのようです。上記のアンダースコア名は、オーバーライドする正しい方法です。関連するのは、これらがすべて定義されているが、基本クラスhttps://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/training/optimizer.pyに実装されていない非Kerasオプティマイザーです
  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()
  1. 知りませんapply_dense。1つには、オーバーライドすると、レプリカごとのDistributionStrategyが「危険」である可能性があることをコードが述べている
    # 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.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.