Optimiseur TensorFlow Keras personnalisé

30

Supposons que je veuille écrire une classe d'optimiseur personnalisée conforme à l' tf.kerasAPI (en utilisant la version TensorFlow> = 2.0). Je suis confus quant à la façon documentée de le faire par rapport à ce qui est fait dans les implémentations.

La documentation pour les tf.keras.optimizers.Optimizer états ,

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

Cependant, le courant tf.keras.optimizers.Optimizermise en œuvre ne définit pas une resource_apply_denseméthode, mais elle ne définit un privé à la recherche _resource_apply_densestub de la méthode . De même, il n'y a pas resource_apply_sparseou create_slotsméthodes, mais il y a un _resource_apply_sparsebout de méthode et un _create_slotsappel de méthode .

Dans officielles tf.keras.optimizers.Optimizersous - classes ( en utilisant tf.keras.optimizers.Adamcomme exemple), il existe _resource_apply_dense, _resource_apply_sparseet les _create_slotsméthodes, et il n'y a pas de telles méthodes sans le trait de soulignement de premier plan.

Il existe des méthodes d' avant-underscore similaires légèrement moins officielles tf.keras.optimizers.Optimizersous - classes (par exemple, tfa.optimizers.MovingAveragede tensorflow addons: _resource_apply_dense, _resource_apply_sparse, _create_slots).

Un autre point de confusion pour moi est que certains des optimiseurs TensorFlow Addons remplacent également la apply_gradientsméthode (par exemple, tfa.optimizers.MovingAverage), contrairement aux tf.keras.optimizersoptimiseurs.

De plus, j'ai remarqué que la apply_gradientsméthode des appels de tf.keras.optimizers.Optimizerméthode , mais la classe de base n'a pas de méthode. Il semble donc qu'une méthode doit être définie dans une sous-classe d'optimiseur si cette sous-classe ne remplace pas ._create_slotstf.keras.optimizers.Optimizer_create_slots_create_slotsapply_gradients


Des questions

Quelle est la bonne façon de sous-classer a tf.keras.optimizers.Optimizer? Plus précisément,

  1. La tf.keras.optimizers.Optimizerdocumentation répertoriée en haut signifie-t-elle simplement remplacer les versions de soulignement principal des méthodes qu'elles mentionnent (par exemple, _resource_apply_denseau lieu de resource_apply_dense)? Dans l'affirmative, existe-t-il des garanties API quant à ces méthodes d'apparence privée ne modifiant pas leur comportement dans les futures versions de TensorFlow? Quelles sont les signatures de ces méthodes?
  2. Quand remplacerait-on apply_gradientsen plus des _apply_resource_[dense|sparse]méthodes?

Éditer. Problème ouvert sur GitHub: # 36449

Artem Mavrin
la source
1
Cela peut être quelque chose à signaler en tant que problème de documentation aux développeurs. Il semble que ces méthodes à remplacer devraient inclure le trait de soulignement initial dans la documentation, mais dans tous les cas, comme vous le dites, il n'y a aucune information sur leur signature et leur objectif exact. Il est également possible que des noms de méthode sans soulignement (et documentés) soient prévus (comme avec get_config), mais ils ne devraient pas encore apparaître dans la documentation publique .
jdehesa
Pour les signatures, vous pouvez toujours consulter la déclaration de _resource_apply_denseou _resource_apply_sparse, et voir leur utilisation dans les optimiseurs implémentés. Bien que ce ne soit pas, je pense, une API publique avec des garanties de stabilité, je dirais que c'est assez sûr de les utiliser. Ils devraient juste fournir une meilleure orientation à cet égard.
jdehesa
Je reconnais qu'il s'agit d'un problème de documentation avec TensorFlow. Avez-vous créé un problème pour cela dans le repo tf Github? Si oui, pourriez-vous partager le lien ici?
jpgard

Réponses:

3

J'ai implémenté Keras AdamW dans toutes les principales versions de TF et Keras - je vous invite à examiner optimizers_v2.py . Plusieurs points:

  • Vous devez hériter OptimizerV2, qui est en fait ce que vous avez lié; c'est la classe de base la plus récente et actuelle pour les tf.kerasoptimiseurs
  • Vous avez raison en (1) - c'est une erreur de documentation; les méthodes sont privées, car elles ne sont pas destinées à être utilisées directement par l'utilisateur.
  • apply_gradients(ou toute autre méthode) n'est remplacée que si la valeur par défaut n'accomplit pas ce qui est nécessaire pour un optimiseur donné; dans votre exemple lié, c'est juste un addon à une ligne à l'original
  • "Il semble donc qu'une _create_slotsméthode doit être définie dans une sous-classe d'optimiseur si cette sous-classe ne remplace pas apply_gradients" - les deux ne sont pas liées; c'est une coïncidence.

  • Quelle est la difference entre _resource_apply_denseet _resource_apply_sparse?

Ces dernières traitent des couches clairsemées - par exemple Embedding- et les premières de tout le reste; exemple .

  • Quand dois-je utiliser _create_slots()?

Lors de la définition entraînables tf.Variable s; exemple: poids des moments du premier et du second ordre (par exemple Adam). Il utilise add_slot().

À peu près, chaque fois que vous n'utilisez pas _create_slots(); c'est comme définir des attributs de classe, mais avec des étapes de prétraitement supplémentaires pour garantir l'exactitude de l'utilisation. Alors Python int, float, tf.Tensor, tf.Variable, et d' autres. (J'aurais dû l'utiliser plus dans Keras AdamW).


Remarque : alors que mes optimiseurs liés fonctionnent correctement et sont à peu près aussi rapides que les originaux, le code suit les meilleures pratiques TensorFlow et peut toujours être plus rapide; Je ne le recommande pas comme «référence idéale». Par exemple, certains objets Python (par exemple int) devraient être des tenseurs; eta_test définie comme une tf.Variable, mais est immédiatement remplacée par une méthode tf.Tensorin _apply. Pas forcément un gros problème, je n'ai tout simplement pas eu le temps de rénover.

OverLordGoldDragon
la source
2
  1. Oui, cela semble être une erreur de documentation. Les noms de soulignement précédents sont les méthodes correctes à remplacer. L'optimiseur non Keras est associé à tous ces éléments, mais non implémenté dans la classe de base https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/training/optimizer.py
  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. Je ne sais pas apply_dense. D'une part, si vous le remplacez, le code mentionne qu'une DistributionStrategy par réplique peut être "dangereuse"
    # 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
la source