_tf.keras
_ APIに準拠するカスタムオプティマイザークラスを記述したいとします(TensorFlowバージョン> = 2.0を使用)。これを行うための文書化された方法と実装で何が行われるかについて混乱しています。
_tf.keras.optimizers.Optimizer
_のドキュメント states 、
_ ### 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
_メソッドを定義していませんが、doesプライベートな外観の __resource_apply_dense
_メソッドスタブを定義しています 。同様に、_resource_apply_sparse
_または_create_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
_サブクラス(たとえば、TensorFlowアドオンの_tfa.optimizers.MovingAverage
_: __resource_apply_dense
_ 、 __resource_apply_sparse
_ 、 __create_slots
_ )。
私にとってもう1つの混乱点は、TensorFlow Addonsオプティマイザの一部alsoが_apply_gradients
_メソッドをオーバーライドすることです(たとえば、 _tfa.optimizers.MovingAverage
_ )、一方、_tf.keras.optimizers
_オプティマイザーはそうしません。
さらに、_apply_gradients
_メソッドの_tf.keras.optimizers.Optimizer
_メソッド が__create_slots
_ を呼び出していることに気付きましたが、基本の_tf.keras.optimizers.Optimizer
_クラスには__create_slots
_メソッド。したがって、サブクラスが__create_slots
_をオーバーライドしない場合、オプティマイザーサブクラスで_apply_gradients
_メソッドmustが定義されているようです。
_tf.keras.optimizers.Optimizer
_をサブクラス化する正しい方法は何ですか?具体的には
tf.keras.optimizers.Optimizer
_のドキュメントは、それらが言及しているメソッドの先行アンダースコアバージョンをオーバーライドすることを単に意味しますか(たとえば、__resource_apply_dense
_ではなく_resource_apply_dense
_)。もしそうなら、これらのプライベートに見えるメソッドがTensorFlowの将来のバージョンでそれらの振る舞いを変更しないことについてのAPI保証はありますか?これらのメソッドのシグネチャは何ですか?apply_gradients
_メソッドに加えて、いつ__apply_resource_[dense|sparse]
_をオーバーライドしますか?編集。GitHubで未解決の問題: #36449
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()
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.