Каковы наилучшие методы для написания пользовательского слоя Keras в отношении уменьшения количества дублирующегося кода, конфигурации и хранилища?

#python #tensorflow #keras

#python #тензорный поток #keras

Вопрос:

Я немного смущен написанием слоя Keras, следуя лучшим методам. Такое ощущение, что есть немного дублирующегося кода и дублирующейся конфигурации.

В частности, моя цель — объединить несколько существующих слоев вместе. Объединение будет использоваться для облегчения обучения передаче и визуальной проверки / отладки модели. Примером кода является:

 import tensorflow.keras as keras

class CategoricalEmbedding(keras.layers.Layer): 
  def __init__(self, vocabulary, embedding_dimensions, embedding_matrix, **kwargs):  
    self.lookup = keras.layers.experimental.preprocessing.IntegerLookup(
      num_oov_indices=1, mask_value=None, vocabulary=vocabulary
    )    
    self.embedding = keras.layers.Embedding(
      len(vocabulary)   1, embedding_dimensions, input_length=1,
      weights=[embedding_matrix]
    )
    super(CategoricalEmbedding, self).__init__(**kwargs)
    
  def call(self, categorical_ids):
    indexes = self.lookup(categorical_ids)
    embeddings = self.embedding(indexes)
    resized = K.squeeze(embeddings, -2)
    return resized
  
  def get_config(self):
    return {
      "vocabulary": self.lookup.get_vocabulary(),
      "embedding_dimensions": self.embedding.output_dim,
      "embedding_matrix": self.embedding.weights[0],
      **super(CategoricalEmbedding, self).get_config()
    }
  

Мои две проблемы с приведенным выше кодом — это требование написать get_config() и дублирующаяся информация, которая уже содержится в weights / config подуровня. В частности, вся информация, необходимая для восстановления CategoricalEmbedding слоя, существует в подуровнях IntegerLookup и Embedding . Ручная запись get_config() может привести к дефектам. Кроме того, IntegerLookup.vocabulary будет сериализован в двух местах — одно в weights / config IntegerLookup и одно в config CategoricalEmbedding . Поскольку vocabulary значения могут составлять миллионы, дополнительные затраты на настройку не являются несущественными.

Другой способ — не используйте Keras Layer, вместо этого используйте Keras Model:

 import tensorflow.keras as keras
    
def categorical_embedding(vocabulary, embedding_dimensions, embedding_matrix, name=None):
  model_name = name if name is not None else "categorical_embedding"
  
  lookup = keras.layers.experimental.preprocessing.IntegerLookup(
    num_oov_indices=1, mask_value=None, vocabulary=vocabulary
  )
  lookup.weights[0].name = "lookup_weights" # fix for serialization issue
  embedding = keras.layers.Embedding(
    len(vocabulary)   1, embedding_dimensions, input_length=1, weights=[embedding_matrix]    
  )
  squeeze = keras.layers.Lambda(lambda net: K.squeeze(net, -2), name="squeeze_to_one_embedding")
  
  return keras.Sequential([lookup, embedding, squeeze], name=model_name)
  

Это лучший способ написать вышеупомянутый слой Keras? Следует ли использовать слой Keras для такой простой композиции? Есть ли лучший способ написать уровень Keras для снижения затрат на код и / или сериализацию / хранение? Следует ли использовать модели Keras таким образом? (Я упускаю что-то фундаментальное?)

Комментарии:

1. Сами вложения могут быть предварительно вычислены с помощью любого из нескольких алгоритмов, а затем использованы в любой заданной модели путем построения слоя встраивания с weights= и trainable=false

2. Отличный момент — я добавил еще большие веса встраивания в пример кода. Инициализация происходит за счет использования предварительно подготовленных вложений word в руководстве по модели Keras .