Пользовательский оптимизатор 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_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подклассах (например, tfa.optimizers.MovingAverageот TensorFlow Addons: _resource_apply_dense, _resource_apply_sparse, _create_slots).

Еще один неприятный момент для меня заключается в том, что некоторые оптимизаторы аддонов TensorFlow также переопределяют apply_gradientsметод (например, tfa.optimizers.MovingAverage), а tf.keras.optimizersоптимизаторы - нет.

Более того, я заметил, что apply_gradientsметод вызываетtf.keras.optimizers.Optimizer метод , но базовый класс не имеет метода. Таким образом, кажется, что метод должен быть определен в подклассе оптимизатора, если этот подкласс не переопределяет ._create_slotstf.keras.optimizers.Optimizer_create_slots_create_slotsapply_gradients


Вопросов

Как правильно подкласс tf.keras.optimizers.Optimizer? В частности,

  1. Означает ли tf.keras.optimizers.Optimizerдокументация, перечисленная вверху, просто переопределение версий методов, которые они упоминают (например, _resource_apply_denseвместо resource_apply_dense)? Если да, есть ли какие-либо гарантии API относительно того, что эти приватно выглядящие методы не изменят свое поведение в будущих версиях TensorFlow? Каковы подписи этих методов?
  2. Когда можно переопределить apply_gradientsв дополнение к _apply_resource_[dense|sparse]методам?

Редактировать. Открытый вопрос на GitHub: # 36449

Артем Маврин
источник
1
Это может быть чем-то, что нужно сообщить разработчикам как проблема с документацией. Похоже, что эти методы для переопределения должны включать в документ начальное подчеркивание, но в любом случае, как вы говорите, нет информации об их подписи и точном назначении. Также может быть так, что имена методов без подчеркивания (и задокументированные) планируется добавить (например, с помощью get_config), но тогда они еще не должны появляться в общедоступной документации .
Идеша
Для сигнатур вы всегда можете посмотреть на объявление _resource_apply_denseили _resource_apply_sparse, и увидеть их использование в реализованных оптимизаторах. Я думаю, что публичного API с гарантиями стабильности может и не быть, я бы сказал, что использовать его довольно безопасно. Они просто должны дать лучшее руководство в этом аспекте.
jdehesa
Я согласен, что это проблема с документацией TensorFlow. Вы создали проблему для этого в репозитории Tf Github? Если да, не могли бы вы поделиться ссылкой здесь?
jpgard

Ответы:

3

Я реализовал Keras AdamW во всех основных версиях TF & Keras - я приглашаю вас ознакомиться с optimizer_v2.py . Несколько моментов:

  • Вы должны наследовать OptimizerV2, что на самом деле то, что вы связали; это самый последний и актуальный базовый класс для tf.kerasоптимизаторов
  • Вы правы в (1) - это ошибка документации; методы являются частными, так как они не предназначены для непосредственного использования пользователем.
  • apply_gradients(или любой другой метод) переопределяется, только если значение по умолчанию не выполняет то, что необходимо для данного оптимизатора; в вашем связанном примере это просто однострочное дополнение к оригиналу
  • «Таким образом, кажется, что _create_slotsметод должен быть определен в подклассе оптимизатора, если этот подкласс не переопределяет apply_gradients» - эти два не связаны; это случайно.

  • В чем разница между _resource_apply_denseи _resource_apply_sparse?

Последние имеют дело с разреженными слоями - например Embedding- и бывшими со всем остальным; пример .

  • Когда я должен использовать _create_slots()?

При определении обучаемых tf.Variable с; пример: весовые коэффициенты первого и второго порядка (например, Адам). Это использует add_slot().

  • Когда я должен использовать _set_hyper()?

В значительной степени, когда не используется _create_slots(); это похоже на настройку атрибутов класса, но с дополнительными шагами предварительной обработки, чтобы гарантировать правильность использования. Так Python int, float, tf.Tensor, tf.Variable, и другие. (Я должен был использовать это больше в Keras AdamW).


Примечание : хотя мои связанные оптимизаторы работают правильно и работают примерно так же быстро, как и оригиналы, код соответствует лучшим методам TensorFlow и все еще может быть быстрее; Я не рекомендую это как "идеальную ссылку". Например, некоторые объекты Python (например int) должны быть тензорами; eta_tопределяется как a tf.Variable, но сразу же переопределяется как tf.Tensorin в _applyметодах. Не обязательно большое дело, просто не было времени на ремонт.

OverLordGoldDragon
источник
2
  1. Да, это похоже на ошибку документации. Предыдущие имена подчеркивания являются правильными методами для переопределения. С этим связан не оптимизатор Keras, в котором все это определено, но не реализовано в базовом классе 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. Я не знаю о apply_dense. Во-первых, если вы переопределите это, в коде упоминается, что для каждой реплики 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.
Тайлер
источник