web-dev-qa-db-ja.com

Keras埋め込みレイヤーのmask_zeroはどのように機能しますか?

mask_zero=Trueは、入力値が0のときに0を出力するため、次のレイヤーは計算などをスキップできます。

どうやって mask_zero機能しますか?

例:

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)

実際の出力は次のとおりです(数値はランダムです)。

(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]]]

ただし、出力は次のようになると思いました。

[[[ 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

実際には、埋め込みレイヤーに_mask_zero=True_を設定しても、ゼロベクトルは返されません。むしろ、埋め込みレイヤーの動作は変化せず、インデックス0の埋め込みベクトルを返します。これは、埋め込みレイヤーの重みを確認することで確認できます(つまり、前述の例ではm.layers[0].get_weights()になります)。代わりに、RNNレイヤーなどの次のレイヤーの動作に影響します。

埋め込みレイヤーのソースコードを調べると、 _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
_

この出力マスクは、mask引数として、マスキングをサポートする次のレイヤーに渡されます。これは、ベースレイヤーのLayer___call___ メソッドに実装されています。

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

これにより、次のレイヤーはこの入力ステップを無視します(つまり、計算では考慮されません)。これは最小限の例です:

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

ご覧のとおり、2番目と4番目のタイムステップのLSTMレイヤーの出力は、それぞれ1番目と3番目のタイムステップの出力と同じです。つまり、それらのタイムステップはマスクされています。

更新:損失関数は内部的に拡張されて _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)`.
    """
_

モデルのコンパイル時

_weighted_losses = [weighted_masked_objective(fn) for fn in loss_functions]
_

これは、次の例を使用して確認できます。

_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

データの一部が実際にはパディングであり、無視する必要があることをモデルに通知するプロセスは、Maskingと呼ばれます。

Kerasモデルにinput masksを導入するには3つの方法があります。

  1. keras.layers.Maskingレイヤーを追加します。
  2. keras.layers.Embeddingレイヤーをmask_zero=Trueで構成します。
  3. この引数をサポートするレイヤー(RNNレイヤーなど)を呼び出すときに、マスク引数を手動で渡します。

以下に、Input Masksを使用して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)

上記のコードの出力を以下に示します。

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

詳細については、これを参照してください Tensorflowチュートリアル

0