Keras Embedding 层中的 mask_zero 是如何工作的?
How does mask_zero in Keras Embedding layer work?
我认为当输入值为 0 时 mask_zero=True
将输出 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]]]
实际上,为嵌入层设置 mask_zero=True
不会导致 return 零向量。相反,嵌入层的行为不会改变,它会 return 索引为零的嵌入向量。您可以通过检查嵌入层权重来确认这一点(即在您提到的示例中它将是 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
参数传递到支持掩码的后续层。这个已经在base layer的__call__
方法中实现了,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
这使得后面的层忽略(即不在计算中考虑)这个输入步骤。这是一个最小的例子:
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)
如您所见,LSTM 层的第二个和第四个时间步的输出分别与第一个和第三个时间步的输出相同。这意味着这些时间步长已被屏蔽。
更新: 计算损失时也会考虑掩码,因为损失函数在内部增强以支持使用 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
通知模型数据的某些部分实际上是填充并且应该被忽略的过程称为 Masking。
Keras模型中引入input masks
的三种方式:
- 添加一个
keras.layers.Masking
图层。
- 配置一个
keras.layers.Embedding
层mask_zero=True
.
- 在调用支持此参数的层(例如 RNN 层)时手动传递掩码参数。
下面给出的是使用keras.layers.Embedding
引入Input Masks
的代码
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 Tutorial。
我认为当输入值为 0 时 mask_zero=True
将输出 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]]]
实际上,为嵌入层设置 mask_zero=True
不会导致 return 零向量。相反,嵌入层的行为不会改变,它会 return 索引为零的嵌入向量。您可以通过检查嵌入层权重来确认这一点(即在您提到的示例中它将是 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
参数传递到支持掩码的后续层。这个已经在base layer的__call__
方法中实现了,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
这使得后面的层忽略(即不在计算中考虑)这个输入步骤。这是一个最小的例子:
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)
如您所见,LSTM 层的第二个和第四个时间步的输出分别与第一个和第三个时间步的输出相同。这意味着这些时间步长已被屏蔽。
更新: 计算损失时也会考虑掩码,因为损失函数在内部增强以支持使用 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
通知模型数据的某些部分实际上是填充并且应该被忽略的过程称为 Masking。
Keras模型中引入input masks
的三种方式:
- 添加一个
keras.layers.Masking
图层。 - 配置一个
keras.layers.Embedding
层mask_zero=True
. - 在调用支持此参数的层(例如 RNN 层)时手动传递掩码参数。
下面给出的是使用keras.layers.Embedding
Input Masks
的代码
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 Tutorial。