Преобразование последовательного уровня API Keras для функционального API - PullRequest
0 голосов
/ 04 ноября 2019

Я борюсь за преобразование слоя Tensorflow Keras, созданного для последовательного API, чтобы использовать его в функциональном API. Сегодня я уже видел много ошибок, поэтому постараюсь сделать описание кратким и кратким:

  1. Я пытаюсь использовать слой DynamicMetaEmbedding, описанный в этой статье Towardsdatascience вфункциональный Keras API. В последовательном API код работает. Это Github-репозиторий , содержащий также соответствующий код.
  2. В конце этого вопроса вы найдете некоторый исходный код для воспроизведения проблемы.
  3. Первая ошибка, с которой вы столкнетесь:
'Tensor' object has no attribute 'input_dim'
Однако после исправления этой ошибки появляется много других. Далее, он будет жаловаться на output_dim, и после исправления этого я заметил, что слой не выполняется должным образом;он запускает только init () . Кроме того, добавление функции build () или compute_output_shape () не помогает. Я полагаю, что фундаментальная проблема здесь заключается в том, что слой DynamicMetaEmbedding не видит входные данные фактически как вложения, а как тензоры.

Спасибо за ваше время и помощь! : -)

Best, Тобиас

Протестировано в Google Colab. Версия Keras: 2.2.5 Версия Tensorflow: 1.15.0

Это код Python для слоя DynamicMetaEmbedding Keras:

from typing import Optional, List

import numpy as np
import tensorflow as tf
class DynamicMetaEmbedding(tf.keras.layers.Layer):
    """
    Applies learned attention to different sets of embeddings matrices per token, to mix separate token
    representations into a joined one. Self attention is word-dependent, meaning each word's representation in the output
    is only dependent on the word's original embeddings in the given matrices, and the attention vector.
    Arguments
    ---------
    - `embedding_matrices` (``List[tf.keras.layers.Embedding]``): List of embedding layers
    - `output_dim` (``int``): Dimension of the output embedding
    - `name` (``str``): Layer name
    Input shape
    -----------
    (batch_size, time_steps)
    Output shape
    ------------
    (batch_size, time_steps, output_dim)
    Examples
    --------
    Create Dynamic Meta Embeddings using 2 separate embedding matrices. Notice it is the user's responsibility to make sure
    all the arguments needed in the embedding lookup are passed to the ``tf.keras.layers.Embedding`` constructors (like ``trainable=False``).
    .. code-block:: python3
        import tensorflow as tf
        import tavolo as tvl
        w2v_embedding = tf.keras.layers.Embedding(num_words,
                                                  EMBEDDING_DIM,
                                                  embeddings_initializer=tf.keras.initializers.Constant(w2v_matrix),
                                                  input_length=MAX_SEQUENCE_LENGTH,
                                                  trainable=False)
        glove_embedding = tf.keras.layers.Embedding(num_words,
                                                    EMBEDDING_DIM,
                                                    embeddings_initializer=tf.keras.initializers.Constant(glove_matrix),
                                                    input_length=MAX_SEQUENCE_LENGTH,
                                                    trainable=False)
        model = tf.keras.Sequential([tf.keras.layers.Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32'),
                                     tvl.embeddings.DynamicMetaEmbedding([w2v_embedding, glove_embedding])])  # Use DME embeddings
    Using the same example as above, it is possible to define the output's channel size
    .. code-block:: python3
        model = tf.keras.Sequential([tf.keras.layers.Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32'),
                                     tvl.embeddings.DynamicMetaEmbedding([w2v_embedding, glove_embedding], output_dim=200)])
    References
    ----------
    `Dynamic Meta-Embeddings for Improved Sentence Representations`_
    .. _`Dynamic Meta-Embeddings for Improved Sentence Representations`:
        https://arxiv.org/abs/1804.07983
    """

    def __init__(self,
                 embedding_matrices: List[tf.keras.layers.Embedding],
                 output_dim: Optional[int] = None,
                 name: str = 'dynamic_meta_embedding',
                 **kwargs):
        """
        :param embedding_matrices: List of embedding layers
        :param output_dim: Dimension of the output embedding
        :param name: Layer name
        """
        super().__init__(name=name, **kwargs)

        # Validate all the embedding matrices have the same vocabulary size
        if not len(set((e.input_dim for e in embedding_matrices))) == 1:
            raise ValueError('Vocabulary sizes (first dimension) of all embedding matrices must match')

        # If no output_dim is supplied, use the maximum dimension from the given matrices
        self.output_dim = output_dim or min([e.output_dim for e in embedding_matrices])

        self.embedding_matrices = embedding_matrices
        self.n_embeddings = len(self.embedding_matrices)

        self.projections = [tf.keras.layers.Dense(units=self.output_dim,
                                                  activation=None,
                                                  name='projection_{}'.format(i),
                                                  dtype=self.dtype) for i, e in enumerate(self.embedding_matrices)]

        self.attention = tf.keras.layers.Dense(units=1,
                                               activation=None,
                                               name='attention',
                                               dtype=self.dtype)

    def compute_mask(self, inputs, mask=None):
        return self.projections[0].compute_mask(
            inputs, mask=self.embedding_matrices[0].compute_mask(inputs, mask=mask))

    def call(self, inputs,
             **kwargs) -> tf.Tensor:
        batch_size, time_steps = inputs.shape[:2]
        batch_size = 64

        # Embedding lookup
        embedded = [e(inputs) for e in self.embedding_matrices]  # List of shape=(batch_size, time_steps, channels_i)
        # Projection
        projected = tf.reshape(tf.concat([p(e) for p, e in zip(self.projections, embedded)], axis=-1),
                               # Project embeddings
                               shape=(batch_size, time_steps, self.n_embeddings, self.output_dim),
                               name='projected')  # shape=(batch_size, time_steps, n_embeddings, output_dim)
        print (projected.shape)
        # Calculate attention coefficients
        alphas = self.attention(projected)  # shape=(batch_size, time_steps, n_embeddings, 1)
        alphas = tf.nn.softmax(alphas, axis=-2)  # shape=(batch_size, time_steps, n_embeddings, 1)

        # Attend
        output = tf.squeeze(tf.matmul(
            tf.transpose(projected, perm=[0, 1, 3, 2]), alphas),  # Attending
            name='output')  # shape=(batch_size, time_steps, output_dim)

        return output

    def get_config(self):
        base_config = super().get_config()
        base_config['embedding_matrices'] = [e.get_config() for e in self.embedding_matrices]
        base_config['output_dim'] = self.output_dim

        return base_config

    @classmethod
    def from_config(cls, config: dict):
        embedding_matrices = [tf.keras.layers.Embedding.from_config(e_conf) for e_conf in
                              config.pop('embedding_matrices')]
        return cls(embedding_matrices=embedding_matrices, **config)

Это пример кода для вызова слоя Keras позжев модели.

from keras.layers import Input, Embedding
from keras.models import Model
MAX_WORDS = 20
vocab_size = 5000
EMBEDDING_DIM = 300
def build_MetaEmbeddings_model():
  sent_inputs = Input(shape=(MAX_WORDS,), dtype="int32")

  embeddings1 = Embedding(input_dim=vocab_size,
                      output_dim=EMBEDDING_DIM,
                      mask_zero=True)(sent_inputs)

  embeddings2 = Embedding(input_dim=vocab_size,
                      output_dim=EMBEDDING_DIM,
                      mask_zero=True)(sent_inputs)

  dme = DynamicMetaEmbedding([embeddings1, embeddings2])
  model = Model(inputs=sent_inputs, outputs=dme)
  return model
model = build_MetaEmbeddings_model()
...