一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - 解決Keras中Embedding層masking與Concatenate層不可調和的問題

解決Keras中Embedding層masking與Concatenate層不可調和的問題

2020-06-19 10:23蕉叉熵 Python

這篇文章主要介紹了解決Keras中Embedding層masking與Concatenate層不可調和的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

問題描述

我在用Keras的Embedding層做nlp相關的實現時,發現了一個神奇的問題,先上代碼:

?
1
2
3
4
5
6
7
8
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層輸出的正確性,我把代碼改成了:

?
1
2
3
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:

?
1
2
3
4
5
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代碼,發現了:

?
1
2
3
4
5
...
elif K.ndim(mask_i) < K.ndim(input_i):
 # Mask is smaller than the input, expand it
 masks.append(K.expand_dims(mask_i))
...

意思是當mask_i的維度比input_i的維度小時,擴展一維,這下知道第三維的1是怎么來的了,那么可以預計compute_mask函數輸入的mask尺寸應該是(None, 30),輸出一下試試:

?
1
2
3
def compute_mask(self, inputs, mask=None):
 print mask
 ...

[<tf.Tensor 'embedding_1/NotEqual:0' shape=(?, 30) dtype=bool>, None]

果然如此,總結一下問題的所在:

Embedding層的輸出會比輸入多一維,但Embedding生成的mask的維度與輸入一致。在Concatenate中,沒有mask的Embedding輸出被分配一個與該輸出相同維度的全1的mask,比有mask的Embedding的mask多一維。

提出解決方案

那么,Embedding層的mask到底是如何起作用的呢?是直接在Embedding層中起作用,還是在后續的層中起作用呢?縱觀embeddings.py,mask_zero只在compute_mask函數被用到:

?
1
2
3
4
5
def compute_mask(self, inputs, mask=None):
 if not self.mask_zero:
  return None
 else:
  return K.not_equal(inputs, 0)

可見,Embedding層的mask是記錄了Embedding輸入中非零元素的位置,并且傳給后面的支持masking的層,在后面的層里起作用。

一種最簡單的解決方案:

給所有參與Concatenate的Embedding層都設置mask_zero=True。

但是,我想到了一種更靈活的解決方案:

修改embedding.py的compute_mask函數,使得輸出的mask從2維變成3維,且第三維等于output_dim。

?
1
2
3
4
5
6
7
8
9
10
import tensorflow as tf
...
def compute_mask(self, inputs, mask=None):
 if not self.mask_zero:
  return None
 else:
  mask = K.repeat(K.not_equal(inputs, 0), self.output_dim) # [?,output_dim,n]
  mask = tf.transpose(mask, [0,2,1]) # [?,n,output_dim]
  return mask
...

驗證解決方案

為了驗證這個改動是否正確,我需要設計幾個小實驗。

實驗一:mask的正確性

我把輸出的mask做了改動,不知道mask是否是正確的。

如下所示,數據是一個帶有3個樣本、樣本長度最長為3的補零padding過的矩陣,我分別讓Embedding層的mask_zero為False和True(為True時input_dim=|va|+2所以是5)。然后分別將Embedding的輸出在axis=1用MySumLayer進行求和。為了方便觀察,我用keras.initializers.ones()把Embedding層的權值全部初始化為1。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# data
data = np.array([[1,0,0],
     [1,2,0],
     [1,2,3]])
init = keras.initializers.ones()
 
# network
a = Input(shape=[3]) # None*3
emb1 = Embedding(4, 5, embeddings_initializer=init, mask_zero=False)(a) # None*3*5
emb2 = Embedding(5, 5, embeddings_initializer=init, mask_zero=True)(a) # None*3*5
sum1 = MySumLayer(axis=1)(emb1) # None*5
sum2 = MySumLayer(axis=1)(emb2) # None*5
model = Model(inputs=[a], outputs=[sum1, sum2])
 
# prediciton
out = model.predict(data)
for x in out:
 print x

結果如下:

?
1
2
3
4
5
6
7
[[3. 3. 3. 3. 3.]
 [3. 3. 3. 3. 3.]
 [3. 3. 3. 3. 3.]]
 
[[1. 1. 1. 1. 1.]
 [2. 2. 2. 2. 2.]
 [3. 3. 3. 3. 3.]]

這個結果是正確的,這里解釋一波:

(1)當mask_True=False時,輸入矩陣中的0也會被認為是正確的index,從而從權值矩陣中抽出第0行作為該index的Embedding,而我的權值都是1,因此所有Embedding都是1,對axis=1求和,實際上是對word length這一軸求和,輸入的word length最長為3,以致于輸出矩陣的元素都是3.

(2)當mask_True=True時,輸入矩陣中的0會被mask掉,而這個mask的操作是體現在MySumLayer中的,將輸入(3, 3, 5)與mask(3, 3, 5)逐元素相乘,再相加。第一個樣本只有一項非零,第二個有兩項,第三個三項,因此MySumLayer輸出的矩陣,各行元素分別是1,2,3.

另外附上MySumLayer的代碼,它的功能是指定一個axis將Tensor進行求和:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from keras import backend as K
from keras.engine.topology import Layer
import tensorflow as tf
 
class MySumLayer(Layer):
 def __init__(self, axis, **kwargs):
  self.supports_masking = True
  self.axis = axis
  super(MySumLayer, self).__init__(**kwargs)
 
 def compute_mask(self, input, input_mask=None):
  # do not pass the mask to the next layers
  return None
 
 def call(self, x, mask=None):
 
  if mask is not None:
   # mask (batch, time)
   mask = K.cast(mask, K.floatx())
   if K.ndim(x)!=K.ndim(mask):
    mask = K.repeat(mask, x.shape[-1])
    mask = tf.transpose(mask, [0,2,1])
   x = x * mask
   return K.sum(x, axis=self.axis)
  else:
   return K.sum(x, axis=self.axis)
 
 def compute_output_shape(self, input_shape):
  # remove temporal dimension
  if self.axis==1:
   return input_shape[0], input_shape[2]
  if self.axis==2:
   return input_shape[0], input_shape[1]

實驗二:一個mask_zero=True和一個mask_zero=False的Embedding是否能夠拼接

?
1
2
3
4
5
6
7
8
a = Input(shape=[3]) # None*3
b = Input(shape=[4]) # None*4
emba = Embedding(4, 5, embeddings_initializer=init, mask_zero=False)(a) # None*3*5
embb = Embedding(6, 5, embeddings_initializer=init, mask_zero=True)(b) # None*4*5
cat = Concatenate(axis=1)([emba, embb]) # None*7*5
 
model = Model(inputs=[a,b], outputs=[cat])
print model.summary()

沒有報錯!而且輸出的shape正是(None, 7, 5)。

實驗三:兩個mask_zero=True的Embedding拼接是否會報錯

?
1
2
3
4
5
6
7
8
a = Input(shape=[3]) # None*3
b = Input(shape=[4]) # None*4
emba = Embedding(4, 5, embeddings_initializer=init, mask_zero=True)(a) # None*3*5
embb = Embedding(6, 5, embeddings_initializer=init, mask_zero=True)(b) # None*4*5
cat = Concatenate(axis=1)([emba, embb]) # None*7*5
 
model = Model(inputs=[a,b], outputs=[cat])
print model.summary()

沒有報錯!

實驗四:兩個mask_zero=True的Embedding拼接結果是否正確

如下所示,第一個矩陣是一個帶有4個樣本、樣本長度最長為3的補零padding過的矩陣,第二個矩陣是一個帶有4個樣本、樣本長度最長為4的補零padding過的矩陣。為什么這里要求樣本個數一致呢,因為一般來說需要這種拼接操作的都是同一批樣本的不同特征。兩者的Embedding都設置mask_zero=True,在axis=1拼接后,用MySumLayer在axis=1加起來。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# data
data1 = np.array([[1,0,0],
     [1,2,0],
     [1,2,3],
     [1,2,3]])
data2 = np.array([[1,0,0,0],
     [1,2,0,0],
     [1,2,3,0],
     [1,2,3,4]])
init = keras.initializers.ones()
 
# network
a = Input(shape=[3]) # None*3
b = Input(shape=[4]) # None*4
emba = Embedding(4, 5, embeddings_initializer=init, mask_zero=True)(a) # None*3*5
embb = Embedding(6, 5, embeddings_initializer=init, mask_zero=True)(b) # None*3*5
 
cat = Concatenate(axis=1)([emba, embb])
su = MySumLayer(axis=1)(cat)
 
model = Model(inputs=[a,b], outputs=[su])
 
# prediction
print model.predict([data1, data2])

輸出如下

?
1
2
3
4
[[2. 2. 2. 2. 2.]
 [4. 4. 4. 4. 4.]
 [6. 6. 6. 6. 6.]
 [7. 7. 7. 7. 7.]]

這個結果是正確的,解釋一波,其實兩個矩陣橫向拼接起來是下面這樣的,4個樣本分別有2、4、6、7個非零index,而Embedding層權值都是1,所以最終輸出的就是上面這個樣子。

?
1
2
3
4
5
# index
1 0 0 1 0 0 0
1 2 0 1 2 0 0
1 2 3 1 2 3 0
1 2 3 1 2 3 4

至此,問題成功解決了。

以上這篇解決Keras中Embedding層masking與Concatenate層不可調和的問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/songbinxu/article/details/80242211

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 成人在线免费播放 | 无遮18禁在线永久免费观看挡 | 狠狠色96视频| a级亚洲片精品久久久久久久 | 大学生按摩黄a级中文片 | 日韩一卡2卡3卡新区网站 | 青草热久精品视频在线观看 | 国产拍拍视频一二三四区 | 欧美一级欧美三级在线 | 亚洲一区二区三区深夜天堂 | 清纯唯美 亚洲 | 天堂俺去俺来也www久久婷婷 | 高清毛片aaaaaaaaa片 | 美女视频ww8888网网 | 国产福利片在线 | 欧美最猛性xxxxx短视频 | 91精品导航在线观看 | 日韩精品一区二区三区中文字幕 | 调教扩张宫颈女人惨叫 | 欧洲久久 | 国产一区二区视频免费 | 999精品视频在线观看热6 | 亚洲午夜精品久久久久久抢 | 高h喷水荡肉爽文np肉色文 | 精品国产免费观看一区高清 | 天天操天天草 | 91九色丨porny丨制服 | 乌克兰肥熟 | 糖心vlog网页版 | 精品无码久久久久久久久 | 俺去啦最新地址 | 亚洲第一综合天堂另类专 | 国产亚洲精品自在线亚洲情侣 | 91麻豆精品国产自产在线 | 香蕉精品高清在线观看视频 | 色帝国亚洲欧美在线蜜汁tv | 午夜精品国产自在现线拍 | 久久青青草原 | 荷兰艾优apiyoo | 日韩在线毛片 | 亚洲精品在线免费 |