Benutzerdefinierter TensorFlow Keras-Optimierer

30

Angenommen, ich möchte eine benutzerdefinierte Optimierungsklasse schreiben, die der tf.kerasAPI entspricht (mit TensorFlow-Version> = 2.0). Ich bin verwirrt über die dokumentierte Vorgehensweise im Vergleich zu den Implementierungen.

Die Dokumentation für tf.keras.optimizers.Optimizer Staaten ,

  ### 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)

Doch die aktuelle tf.keras.optimizers.Optimizerist die Umsetzung eine nicht definieren resource_apply_denseMethode, aber es hat definiert einen privaten aussehende _resource_apply_denseMethode Stummel . Ebenso gibt es keine resource_apply_sparseoder create_slotsMethoden, aber es gibt einen _resource_apply_sparseMethodenstub und einen _create_slotsMethodenaufruf .

In offiziellen tf.keras.optimizers.OptimizerUnterklassen (unter Verwendung tf.keras.optimizers.Adamals ein Beispiel), gibt es _resource_apply_dense, _resource_apply_sparseund _create_slotsMethoden, und es gibt keine solche Methoden ohne den führenden Unterstrich.

Es gibt ähnliche leading-Unterstreichungsverfahren in etwas weniger amtlichen tf.keras.optimizers.OptimizerSubklassen (zB tfa.optimizers.MovingAveragevon TensorFlow Addons: _resource_apply_dense, _resource_apply_sparse, _create_slots).

Ein weiterer verwirrender Punkt für mich ist, dass einige der TensorFlow Addons-Optimierer die Methode ebenfalls überschreiben apply_gradients(z. B. tfa.optimizers.MovingAverage), während die tf.keras.optimizersOptimierer dies nicht tun.

Außerdem bemerkte ich , dass die apply_gradientsMethode der tf.keras.optimizers.OptimizerMethode Anrufe_create_slots , aber die tf.keras.optimizers.OptimizerBasisklasse keine hat _create_slotsMethode. Es scheint also, dass eine _create_slotsMethode in einer Optimierer-Unterklasse definiert werden muss , wenn diese Unterklasse nicht überschreibt apply_gradients.


Fragen

Was ist der richtige Weg, um eine Unterklasse a tf.keras.optimizers.Optimizer? Speziell,

  1. Bedeutet die oben tf.keras.optimizers.Optimizeraufgeführte Dokumentation lediglich, die führenden Unterstrichversionen der von ihnen erwähnten Methoden zu überschreiben (z. B. _resource_apply_denseanstelle von resource_apply_dense)? Wenn ja, gibt es API-Garantien dafür, dass diese privat aussehenden Methoden ihr Verhalten in zukünftigen Versionen von TensorFlow nicht ändern? Was sind die Signaturen dieser Methoden?
  2. Wann würde man apply_gradientszusätzlich zu den _apply_resource_[dense|sparse]Methoden überschreiben ?

Bearbeiten. Geöffnetes Problem auf GitHub: # 36449

Artem Mavrin
quelle
1
Dies kann den Entwicklern als Dokumentationsproblem gemeldet werden. Es sieht definitiv so aus, als ob diese Methoden zum Überschreiben den ersten Unterstrich in die Dokumentation aufnehmen sollten, aber auf jeden Fall gibt es, wie Sie sagen, keine Informationen über ihre Signatur und ihren genauen Zweck. Es kann auch sein, dass Methodennamen ohne Unterstrich (und dokumentiert) hinzugefügt werden sollen (wie bei get_config), aber dann sollten sie noch nicht in der öffentlichen Dokumentation erscheinen .
Jdehesa
Für die Signaturen können Sie immer die Deklaration von _resource_apply_denseoder _resource_apply_sparseeinsehen und deren Verwendung in implementierten Optimierern sehen. Ich denke, es ist zwar keine öffentliche API mit Stabilitätsgarantien, aber ich würde sagen, es ist ziemlich sicher, sie zu verwenden. Sie sollten in dieser Hinsicht nur eine bessere Anleitung geben.
Jdehesa
Ich bin damit einverstanden, dass dies ein Dokumentationsproblem mit TensorFlow ist. Haben Sie im tf Github Repo ein Problem dafür erstellt? Wenn ja, können Sie den Link hier teilen?
jpgard

Antworten:

3

Ich habe Keras AdamW in allen wichtigen TF- und Keras-Versionen implementiert. Ich lade Sie ein, optimizers_v2.py zu untersuchen . Mehrere Punkte:

  • Sie sollten erben OptimizerV2, was eigentlich das ist, was Sie verlinkt haben; Es ist die neueste und aktuelle Basisklasse für tf.kerasOptimierer
  • Sie sind in (1) richtig - dies ist ein Dokumentationsfehler; Die Methoden sind privat, da sie nicht direkt vom Benutzer verwendet werden sollen.
  • apply_gradients(oder eine andere Methode) wird nur überschrieben, wenn die Standardeinstellung nicht die Anforderungen für einen bestimmten Optimierer erfüllt. In Ihrem verknüpften Beispiel handelt es sich nur um ein Einzeiler-Addon zum Original
  • "Es scheint also, dass eine _create_slotsMethode in einer Optimierer-Unterklasse definiert werden muss, wenn diese Unterklasse nicht überschreibt apply_gradients" - die beiden sind nicht miteinander verbunden. es ist zufällig.

  • Was ist der Unterschied zwischen _resource_apply_denseund _resource_apply_sparse?

Letzteres befasst sich mit spärlichen Schichten - zB Embedding- und erstere mit allem anderen; Beispiel .

  • Wann soll ich verwenden _create_slots()?

Bei der Definition von trainierbaren tf.Variable s; Beispiel: Momente erster und zweiter Ordnung der Gewichte (z. B. Adam). Es verwendet add_slot().

Ziemlich genau, wenn man es nicht benutzt _create_slots(); Es ist wie beim Festlegen von Klassenattributen, jedoch mit zusätzlichen Vorverarbeitungsschritten, um die Richtigkeit der Verwendung sicherzustellen. So Python int, float, tf.Tensor, tf.Variable, und andere. (Ich hätte es mehr in Keras AdamW verwenden sollen).


Hinweis : Während meine verknüpften Optimierer ordnungsgemäß funktionieren und ungefähr so ​​schnell wie die Originale sind, folgt der Code den besten TensorFlow-Praktiken und kann immer noch schneller sein. Ich empfehle es nicht als "ideale Referenz". ZB sollten einige Python-Objekte (z. B. int) Tensoren sein; eta_twird als a definiert tf.Variable, aber sofort als tf.Tensorin- _applyMethoden überschrieben . Nicht unbedingt eine große Sache, hatte nur keine Zeit zu renovieren.

OverLordGoldDragon
quelle
2
  1. Ja, dies scheint ein Dokumentationsfehler zu sein. Die vorhergehenden Unterstrichnamen sind die richtigen Methoden zum Überschreiben. Verwandt ist das Nicht-Keras-Optimierungsprogramm, in dem diese alle definiert, jedoch nicht in der Basisklasse https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/training/optimizer.py implementiert sind
  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. Ich weiß es nicht apply_dense. Zum einen wird im Code erwähnt, dass eine DistributionStrategy pro Replikat "gefährlich" sein kann, wenn Sie sie überschreiben.
    # 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.
Tyler
quelle