Otimizador TensorFlow Keras personalizado


30

Suponha que eu queira escrever uma classe de otimizador personalizada que esteja em conformidade com a tf.kerasAPI (usando a versão TensorFlow> = 2.0). Estou confuso sobre a maneira documentada de fazer isso versus o que é feito nas implementações.

A documentação para tf.keras.optimizers.Optimizer estados ,

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

No entanto, a atual tf.keras.optimizers.Optimizerimplementação não definir um resource_apply_densemétodo, mas não definir uma procura privada- _resource_apply_densestub método . Da mesma forma, não há resource_apply_sparseou create_slotsmétodos, mas há um _resource_apply_sparsestub de método e uma _create_slotschamada de método .

Em oficiais tf.keras.optimizers.Optimizersubclasses (utilizando tf.keras.optimizers.Adamcomo exemplo), existem _resource_apply_dense, _resource_apply_sparsee _create_slotsmétodos, e não existem tais métodos sem o sublinhado.

Existem métodos similares-sublinhado em ligeiramente-menos-oficiais tf.keras.optimizers.Optimizersubclasses (por exemplo, tfa.optimizers.MovingAveragea partir de TensorFlow Complementos: _resource_apply_dense, _resource_apply_sparse, _create_slots).

Outro ponto de confusão para mim é que alguns dos otimizadores do TensorFlow Addons também substituem o apply_gradientsmétodo (por exemplo, tfa.optimizers.MovingAverage), enquanto os tf.keras.optimizersotimizadores não.

Além disso, notei que o apply_gradientsmétodo do tf.keras.optimizers.Optimizermétodo chama_create_slots , mas a tf.keras.optimizers.Optimizerclasse base não possui um _create_slotsmétodo. Portanto, parece que um _create_slotsmétodo deve ser definido em uma subclasse do otimizador se essa subclasse não for substituída apply_gradients.


Questões

Qual é a maneira correta de subclassificar a tf.keras.optimizers.Optimizer? Especificamente,

  1. A tf.keras.optimizers.Optimizerdocumentação listada na parte superior significa simplesmente substituir as versões com sublinhado dos métodos mencionados (por exemplo, em _resource_apply_densevez de resource_apply_dense)? Em caso afirmativo, existem garantias de API sobre esses métodos de aparência privada que não alterem seu comportamento em versões futuras do TensorFlow? Quais são as assinaturas desses métodos?
  2. Quando alguém substituiria apply_gradientsalém dos _apply_resource_[dense|sparse]métodos?

Editar. Problema aberto no GitHub: # 36449


11
Isso pode ser algo a ser relatado como um problema de documentação para os desenvolvedores. Definitivamente, parece que esses métodos a serem substituídos devem incluir o sublinhado inicial na documentação, mas, em qualquer caso, como você diz, não há informações sobre a assinatura e o objetivo exato. Também pode ser que nomes de métodos sem sublinhado (e documentados) estejam planejados para serem adicionados (como em get_config), mas ainda não devem aparecer na documentação pública .
jdehesa 24/01

Para as assinaturas, você sempre pode examinar a declaração de _resource_apply_denseou _resource_apply_sparsee ver seu uso nos otimizadores implementados. Embora possa não ser, penso eu, API pública com garantias de estabilidade, eu diria que é bastante seguro usá-las. Eles apenas devem fornecer uma melhor orientação nesse aspecto.
jdehesa 24/01

Concordo que este é um problema de documentação do TensorFlow. Você criou um problema para isso no repositório tf Github? Se sim, você poderia compartilhar o link aqui?
jpgard

Respostas:


3

Eu implementei o Keras AdamW em todas as principais versões do TF & Keras - convido você a examinar optimizers_v2.py . Vários pontos:

  • Você deve herdar OptimizerV2, que é realmente o que você vinculou; é a classe base mais recente e atual para tf.kerasotimizadores
  • Você está correto em (1) - este é um erro de documentação; os métodos são privados, pois não devem ser usados ​​diretamente pelo usuário.
  • apply_gradients(ou qualquer outro método) será substituído apenas se o padrão não atingir o necessário para um determinado otimizador; no seu exemplo vinculado, é apenas um complemento de uma linha do original
  • "Portanto, parece que um _create_slotsmétodo deve ser definido em uma subclasse otimizadora se essa subclasse não for substituída apply_gradients" - as duas não são relacionadas; é coincidência.

  • Qual é a diferença entre _resource_apply_densee _resource_apply_sparse?

Ultimamente lida com camadas esparsas - por exemplo Embedding- e antiga com todo o resto; exemplo .

  • Quando devo usar _create_slots()?

Ao definir s treináveis tf.Variable ; exemplo: momentos de primeira e segunda ordem dos pesos (por exemplo, Adam). Ele usa add_slot().

Praticamente, sempre que não estiver usando _create_slots(); é como definir atributos de classe, mas com etapas extras de pré-processamento para garantir a correção no uso. Então, Python int, float, tf.Tensor, tf.Variable, e outros. (Eu deveria ter usado mais no Keras AdamW).


Nota : enquanto meus otimizadores vinculados funcionam corretamente e são tão rápidos quanto os originais, o código segue as práticas recomendadas do TensorFlow e ainda pode ser mais rápido; Eu não o recomendo como a "referência ideal". Por exemplo, alguns objetos Python (por exemplo int) devem ser tensores; eta_té definido como a tf.Variable, mas imediatamente substituído como a tf.Tensorem _applymétodos. Não é necessariamente um grande negócio, apenas não tive tempo para renovar.


2
  1. Sim, isso parece ser um erro de documentação. Os nomes de sublinhado anteriores são os métodos corretos para substituir. Relacionado é o Optimizador que não é Keras, que tem tudo isso definido, mas não implementado na classe 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. Eu não sei apply_dense. Por um lado, se você o substituir, o código menciona que um DistributionStrategy por réplica pode ser "perigoso"
    # 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.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.