web-dev-qa-db-fra.com

Comment fonctionne mask_zero dans la couche Keras Embedding?

J'ai pensé mask_zero=True affichera des 0 lorsque la valeur d'entrée est 0, donc les couches suivantes pourraient ignorer le calcul ou quelque chose.

Comment mask_zero travaux?

Exemple:

data_in = np.array([
  [1, 2, 0, 0]
])
data_in.shape
>>> (1, 4)

# model
x = Input(shape=(4,))
e = Embedding(5, 5, mask_zero=True)(x)

m = Model(inputs=x, outputs=e)
p = m.predict(data_in)
print(p.shape)
print(p)

La sortie réelle est: (les nombres sont aléatoires)

(1, 4, 5)
[[[ 0.02499047  0.04617121  0.01586803  0.0338897   0.009652  ]
  [ 0.04782704 -0.04035913 -0.0341589   0.03020919 -0.01157228]
  [ 0.00451764 -0.01433611  0.02606953  0.00328832  0.02650392]
  [ 0.00451764 -0.01433611  0.02606953  0.00328832  0.02650392]]]

Cependant, je pensais que la sortie serait:

[[[ 0.02499047  0.04617121  0.01586803  0.0338897   0.009652  ]
  [ 0.04782704 -0.04035913 -0.0341589   0.03020919 -0.01157228]
  [ 0 0 0 0 0]
  [ 0 0 0 0 0]]]
17
crazytomcat

En fait, la définition de mask_zero=True Pour la couche d'intégration n'entraîne pas le retour d'un vecteur nul. Au contraire, le comportement de la couche d’incorporation ne changerait pas et renverrait le vecteur d’incorporation avec un index zéro. Vous pouvez le confirmer en vérifiant les poids de la couche d'intégration (c'est-à-dire que dans l'exemple que vous avez mentionné, ce serait m.layers[0].get_weights()). Au lieu de cela, cela affecterait le comportement des couches suivantes telles que les couches RNN.

Si vous inspectez le code source de la couche Embedding, vous verrez une méthode appelée compute_mask :

def compute_mask(self, inputs, mask=None):
    if not self.mask_zero:
        return None
    output_mask = K.not_equal(inputs, 0)
    return output_mask

Ce masque de sortie sera transmis, en tant qu'argument mask, aux couches suivantes qui prennent en charge le masquage. Ceci a été implémenté dans la méthode __call__ de la couche de base, Layer:

# Handle mask propagation.
previous_mask = _collect_previous_mask(inputs)
user_kwargs = copy.copy(kwargs)
if not is_all_none(previous_mask):
    # The previous layer generated a mask.
    if has_arg(self.call, 'mask'):
        if 'mask' not in kwargs:
            # If mask is explicitly passed to __call__,
            # we should override the default mask.
            kwargs['mask'] = previous_mask

Et cela fait que les couches suivantes ignorent (c'est-à-dire ne prennent pas en compte dans leurs calculs) ces étapes d'entrée. Voici un exemple minimal:

data_in = np.array([
  [1, 0, 2, 0]
])

x = Input(shape=(4,))
e = Embedding(5, 5, mask_zero=True)(x)
rnn = LSTM(3, return_sequences=True)(e)

m = Model(inputs=x, outputs=rnn)
m.predict(data_in)

array([[[-0.00084503, -0.00413611,  0.00049972],
        [-0.00084503, -0.00413611,  0.00049972],
        [-0.00144554, -0.00115775, -0.00293898],
        [-0.00144554, -0.00115775, -0.00293898]]], dtype=float32)

Comme vous pouvez le voir, les sorties de la couche LSTM pour les deuxième et quatrième pas de temps sont identiques à la sortie des premier et troisième pas de temps, respectivement. Cela signifie que ces pas de temps ont été masqués.

Mise à jour: Le masque sera également pris en compte lors du calcul de la perte car les fonctions de perte sont augmentées en interne pour prendre en charge le masquage à l'aide de weighted_masked_objective :

def weighted_masked_objective(fn):
    """Adds support for masking and sample-weighting to an objective function.
    It transforms an objective function `fn(y_true, y_pred)`
    into a sample-weighted, cost-masked objective function
    `fn(y_true, y_pred, weights, mask)`.
    # Arguments
        fn: The objective function to wrap,
            with signature `fn(y_true, y_pred)`.
    # Returns
        A function with signature `fn(y_true, y_pred, weights, mask)`.
    """

lors de la compilation du modèle :

weighted_losses = [weighted_masked_objective(fn) for fn in loss_functions]

Vous pouvez le vérifier en utilisant l'exemple suivant:

data_in = np.array([[1, 2, 0, 0]])
data_out = np.arange(12).reshape(1,4,3)

x = Input(shape=(4,))
e = Embedding(5, 5, mask_zero=True)(x)
d = Dense(3)(e)

m = Model(inputs=x, outputs=d)
m.compile(loss='mse', optimizer='adam')
preds = m.predict(data_in)
loss = m.evaluate(data_in, data_out, verbose=0)
print(preds)
print('Computed Loss:', loss)

[[[ 0.009682    0.02505393 -0.00632722]
  [ 0.01756451  0.05928303  0.0153951 ]
  [-0.00146054 -0.02064196 -0.04356086]
  [-0.00146054 -0.02064196 -0.04356086]]]
Computed Loss: 9.041069030761719

# verify that only the first two outputs 
# have been considered in the computation of loss
print(np.square(preds[0,0:2] - data_out[0,0:2]).mean())

9.041070036475277
16
today

Le processus d'information du modèle qu'une partie des données est en fait un remplissage et doit être ignoré est appelé Masquage .

Il existe trois façons d'introduire input masks dans les modèles Keras:

  1. Ajoutez un keras.layers.Masking calque.
  2. Configurer un keras.layers.Embedding calque avec mask_zero=True.
  3. Passez un argument de masque manuellement lors de l'appel des couches qui prennent en charge cet argument (par exemple, les couches RNN).

Ci-dessous, le code à introduire Input Masks en utilisant keras.layers.Embedding

import numpy as np

import tensorflow as tf

from tensorflow.keras import layers

raw_inputs = [[83, 91, 1, 645, 1253, 927],[73, 8, 3215, 55, 927],[711, 632, 71]]
padded_inputs = tf.keras.preprocessing.sequence.pad_sequences(raw_inputs,
                                                              padding='post')

print(padded_inputs)

embedding = layers.Embedding(input_dim=5000, output_dim=16, mask_zero=True)
masked_output = embedding(padded_inputs)

print(masked_output._keras_mask)

La sortie du code ci-dessus est illustrée ci-dessous:

[[  83   91    1  645 1253  927]
 [  73    8 3215   55  927    0]
 [ 711  632   71    0    0    0]]

tf.Tensor(
[[ True  True  True  True  True  True]
 [ True  True  True  True  True False]
 [ True  True  True False False False]], shape=(3, 6), dtype=bool)

Pour plus d'informations, reportez-vous à cette Tensorflow Tutorial .

0