Keras中Embedding层masking与Concatenate层不可调和的矛盾
问题描述
我在用Keras的Embedding层做nlp相关的实现时,发现了一个神奇的问题,先上代码:
a = Input(shape=[15]) # None*15
b = Input(shape=[30]) # None*30
emb_a = Embedding(10, 5, mask_zero=True)(a) # None*15*5
emb_b = Embedding(20, 5, mask_zero=False)(b) # None*30*5
cat = Concatenate(axis=1)([emb_a, emb_b]) # None*45*5
model = Model(inputs=[a, b], outputs=[cat])
print model.summary()
我有两个Embedding层,当其中一个设置mask_zero=True
,而另一个为False时,会报如下错误。
ValueError: Dimension 0 in both shapes must be equal, but are 1 and 5.
Shapes are [1] and [5]. for 'concatenate_1/concat_1' (op: 'ConcatV2')
with input shapes: [?,15,1], [?,30,5], [] and with computed input tensors: input[2] = <1>.
什么意思呢?是说在concatenate时发现两个矩阵的第三维一个是1,一个是5,这就很神奇了,加了个mask_zero=True
还会改变矩阵维度的吗?
寻找问题根源
为了检验Embedding层输出的正确性,我把代码改成了:
a = Input(shape=[30])
...
cat = Concatenate(axis=2)([emb_a, emb_b])
运行成功了,并且summary显示两个Embedding层输出矩阵的第三维都是5。
这就很奇怪了,明明没有改变维度,为什么会报那样的错误?
然后我仔细追溯了一下前面的各项error,发现这么一句:
File ".../keras/layers/merge.py", line 374, in compute_mask
concatenated = K.concatenate(masks, axis=self.axis)
难道是mask的拼接有问题?
于是我修改了/keras/layers/merge.py
里的Concatenate
类的compute_mask
函数(sudo vim
就可以修改),在返回前输出一下masks:
def compute_mask(self, inputs, mask=None):
...
for x in masks:
print x
return ...
Tensor("concatenate_1/ExpandDims:0", shape=(?, 30, 1), dtype=bool)
Tensor("concatenate_1/Cast:0", shape=(?, 30, 5), dtype=bool)
发现了!有一个叫concatenate_1/ExpandDims:0
的mask它的第三维度是1!
那么这个ExpandDims
是什么鬼,观察一下compute_mask
代码,发现了:
...
elif K.ndim(mask_i) < K.ndim(input_i):