Niestandardowy optymalizator TensorFlow Keras

30

Załóżmy, że chcę napisać niestandardową klasę optymalizatora zgodną z tf.kerasinterfejsem API (używając wersji TensorFlow> = 2.0). Jestem zdezorientowany co do udokumentowanego sposobu wykonania tej czynności w porównaniu z tym, co zostało zrobione we wdrożeniach.

Dokumentacja tf.keras.optimizers.Optimizer stanów ,

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

Jednak obecna tf.keras.optimizers.Optimizerimplementacja nie definiuje resource_apply_densemetody, ale nie definiują prywatną wyglądające _resource_apply_densemetody niedopałek . Podobnie nie ma metod resource_apply_sparseani create_slotsmetod, ale istnieją kody pośredniczące _resource_apply_sparsemetod i _create_slotswywołanie metod .

Oficjalnych tf.keras.optimizers.Optimizerpodklasy (stosując tf.keras.optimizers.Adamjako przykład), są _resource_apply_dense, _resource_apply_sparse, i _create_slotssposobów, i nie ma takiej metody bez początkowego podkreślenia.

Istnieją podobne metody wiodące podkreślenia w nieznacznie mniej oficjalnych tf.keras.optimizers.Optimizerpodklasy (np tfa.optimizers.MovingAveragez TensorFlow dodatki: _resource_apply_dense, _resource_apply_sparse, _create_slots).

Innym mylącym dla mnie punktem jest to, że niektóre optymalizatory TensorFlow Addons również zastępują apply_gradientsmetodę (np. tfa.optimizers.MovingAverage), Podczas gdy tf.keras.optimizersoptymalizatory nie.

Ponadto zauważyłem, że apply_gradientsmetody tf.keras.optimizers.Optimizermetody połączeń_create_slots , ale podstawa tf.keras.optimizers.Optimizerklasa nie ma _create_slotsmetody. Wygląda więc na to, że należy zdefiniować _create_slotsmetodę w podklasie optymalizatora, jeśli ta podklasa się nie przesłoni .apply_gradients


pytania

Jaki jest prawidłowy sposób na podklasę a tf.keras.optimizers.Optimizer? Konkretnie,

  1. Czy tf.keras.optimizers.Optimizerdokumentacja wymieniona u góry oznacza po prostu zastąpienie wiodących wersji podkreślonych metod, o których wspominają (np. _resource_apply_denseZamiast resource_apply_dense)? Jeśli tak, to czy są jakieś gwarancje API, że te prywatne metody nie zmieniają swojego zachowania w przyszłych wersjach TensorFlow? Jakie są podpisy tych metod?
  2. Kiedy można zastąpić metody apply_gradientsoprócz _apply_resource_[dense|sparse]metod?

Edytować. Otwarty problem w GitHub: # 36449

Artem Mavrin
źródło
1
Może to być coś, co należy zgłosić deweloperom jako problem z dokumentacją. Zdecydowanie wygląda na to, że te metody przesłonięcia powinny zawierać początkowy znak podkreślenia w dokumentacji, ale w każdym razie, jak mówisz, nie ma informacji o ich podpisie i dokładnym celu. Może się również zdarzyć, że nazwy metod bez podkreślenia (i udokumentowane) są planowane do dodania (podobnie jak w przypadku get_config), ale wtedy nie powinny jeszcze pojawić się w dokumentacji publicznej .
jdehesa
W przypadku podpisów zawsze możesz spojrzeć na deklarację _resource_apply_denselub _resource_apply_sparsei zobaczyć ich użycie w zaimplementowanych optymalizatorach. Wydaje mi się, że nie może to być publiczny interfejs API z gwarancjami stabilności, ale powiedziałbym, że korzystanie z nich jest całkiem bezpieczne. Powinny po prostu zapewnić lepsze wytyczne w tym zakresie.
jdehesa
Zgadzam się, że jest to problem z dokumentacją w TensorFlow. Czy stworzyłeś problem w repozytorium tf Github? Jeśli tak, czy możesz udostępnić link tutaj?
jpgard

Odpowiedzi:

3

Zaimplementowałem Keras AdamW we wszystkich głównych wersjach TF i Keras - zapraszam do zapoznania się z optimizers_v2.py . Kilka punktów:

  • Powinieneś dziedziczyć OptimizerV2, czyli tak naprawdę to, co połączyłeś; to najnowsza i aktualna klasa bazowa dla tf.kerasoptymalizatorów
  • Masz rację w (1) - jest to błąd w dokumentacji; metody są prywatne, ponieważ nie są przeznaczone do bezpośredniego użycia przez użytkownika.
  • apply_gradients(lub dowolna inna metoda) jest zastępowana tylko wtedy, gdy domyślna wartość nie spełnia wymagań danego optymalizatora; w połączonym przykładzie jest to tylko jedno-liniowy dodatek do oryginału
  • „Wygląda więc na to, że _create_slotsnależy zdefiniować metodę w podklasie optymalizatora, jeśli podklasa ta nie zastępuje apply_gradients - obie są ze sobą niezwiązane; to przypadek.

  • Jaka jest różnica między _resource_apply_densei _resource_apply_sparse?

Później zajmuje się rzadkimi warstwami - np. Embedding- a wcześniej wszystkim innym; przykładem .

  • Kiedy powinienem użyć _create_slots()?

Podczas definiowania treningów tf.Variable ; przykład: momenty pierwszego i drugiego rzędu wag (np. Adam). Używa add_slot().

Prawie, ilekroć nie używasz _create_slots(); to jak ustawianie atrybutów klasy, ale z dodatkowymi krokami wstępnego przetwarzania, aby zapewnić poprawność użycia. Więc Python int, float, tf.Tensor, tf.Variable, i inni. (Powinienem był użyć go częściej w Keras AdamW).


Uwaga : chociaż moje powiązane optymalizatory działają poprawnie i są tak szybkie jak oryginały, kod postępuje zgodnie z najlepszymi praktykami TensorFlow i wciąż może być szybszy; Nie polecam tego jako „idealnego odniesienia”. Np. Niektóre obiekty Pythona (np. int) Powinny być tensorami; eta_tjest zdefiniowany jako tf.Variable, ale natychmiast zastąpiony jako tf.Tensorw _applymetodach. Niekoniecznie wielka sprawa, po prostu nie miałem czasu na remont.

OverLordGoldDragon
źródło
2
  1. Tak, wygląda to na błąd w dokumentacji. Poprzednie nazwy podkreślenia są poprawnymi metodami zastępowania. Powiązany jest Optymalizator inny niż Keras, który ma te wszystkie zdefiniowane, ale nie zaimplementowane w klasie podstawowej 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. Nie wiem, o apply_dense. Po pierwsze, jeśli go przesłonisz, kod wspomina, że ​​strategia dystrybucji dla repliki może być „niebezpieczna”
    # 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
źródło