Tensorflow 嵌入层词汇量大小

emv*_*y03 2 python tensorflow word-embedding

我正在学习 Tensorflow,并且遇到了张量流中的嵌入层,用于学习自己的词嵌入。该层采用以下参数:

keras.layers.Embedding(input_dim, 
                       output_dim, 
                       embeddings_initializer='uniform',
                       embeddings_regularizer=None, 
                       activity_regularizer=None, 
                       embeddings_constraint=None, 
                       mask_zero=False, 
                       input_length=None)
Run Code Online (Sandbox Code Playgroud)

“输入暗淡”应该与词汇表(即独特的单词)大小相同。如果我想将词汇量限制为仅前 25000 个最常见的单词 - 我应该怎么做?

我可以简单地将 'input_dim' 更改为 25000 还是我必须浏览我的语料库并用标记替换前 25000 个单词之外的任何单词?

Zab*_*azi 5

实际上,如果你使用tensorflow.keras你必须确保你的语料库中的标记不超过词汇表大小或input_dim嵌入层的大小,否则你会得到错误。

如果您使用keras,那么您只需更改input_dim嵌入层中的 ,而无需更改语料库或标记中的任何内容。keras将用向量替换词汇表标记zero

首先,如果使用tensorflow.keras会出现错误。

张量流

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Embedding, Input
import numpy as np

ip = Input(shape = (3,))
emb = Embedding(1, 2, trainable=True, mask_zero=True)(ip)

model = Model(ip, emb)
input_array = np.array([[5, 3, 1], [1, 2, 3]]) # out of vocabulary

model.compile("rmsprop", "mse")

output_array = model.predict(input_array)

print(output_array)

print(output_array.shape)

model.summary()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

但如果我使用 keras 2.3.1,我不会收到任何错误。

喀拉斯2.3.1

from keras.models import Model
from keras.layers import Embedding, Input
import numpy as np

ip = Input(shape = (3,))
emb = Embedding(1, 2, trainable=True, mask_zero=True)(ip)

model = Model(ip, emb)
input_array = np.array([[5, 3, 1], [1, 2, 3]])

model.compile("rmsprop", "mse")

output_array = model.predict(input_array)

print(output_array)

print(output_array.shape)

model.summary()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

keras 对于嵌入层有不同的实现。为了验证这一点,让我们进入 keras 嵌入层。

https://github.com/keras-team/keras/blob/master/keras/layers/embeddings.py#L16

现在我们只看一下 call 函数。

    def call(self, inputs):
        if K.dtype(inputs) != 'int32':
            inputs = K.cast(inputs, 'int32')
        out = K.gather(self.embeddings, inputs)
        return out
Run Code Online (Sandbox Code Playgroud)

注意:如果您想要 keras 2.3.1 的确切源代码,请前往此处下载源代码: https: //github.com/keras-team/keras/releases

但如果我们转向tensorflow实现,情况就不一样了。

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/ops/embedding_ops.py

只是为了验证一下,调用函数的编写方式不同。

  def call(self, inputs):
    dtype = K.dtype(inputs)
    if dtype != 'int32' and dtype != 'int64':
      inputs = math_ops.cast(inputs, 'int32')
    out = embedding_ops.embedding_lookup(self.embeddings, inputs)
    return out
Run Code Online (Sandbox Code Playgroud)

让我们像以前一样设计一个简单的网络并观察权重矩阵。

from keras.models import Model
from keras.layers import Embedding, Input
import numpy as np

ip = Input(shape = (3,))
emb = Embedding(1, 2, trainable=True, mask_zero=True)(ip)

model = Model(ip, emb)
input_array = np.array([[5, 3, 1], [1, 2, 3]])

model.compile("rmsprop", "mse")

output_array = model.predict(input_array)

print(output_array)

print(output_array.shape)

model.summary()
Run Code Online (Sandbox Code Playgroud)

该模型给出以下输出。

[[[0. 0.]
  [0. 0.]
  [0. 0.]]

 [[0. 0.]
  [0. 0.]
  [0. 0.]]]
(2, 3, 2)
Model: "model_18"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_21 (InputLayer)        (None, 3)                 0         
_________________________________________________________________
embedding_33 (Embedding)     (None, 3, 2)              2         
=================================================================
Total params: 2
Trainable params: 2
Non-trainable params: 0
Run Code Online (Sandbox Code Playgroud)

好的,我们得到了一堆零,但默认的weight_initializer 不是零!

那么,现在让我们观察权重矩阵。

import keras.backend as K

w = model.layers[1].get_weights()
print(w)

Run Code Online (Sandbox Code Playgroud)
[array([[ 0.03680499, -0.04904002]], dtype=float32)]
Run Code Online (Sandbox Code Playgroud)

事实上,它并不全是零。

那么,为什么我们会得到零呢?

让我们更改模型的输入。

由于 input_dim = 1 的词汇表中唯一的单词索引是 0。让我们将 0 作为输入之一传递。

from keras.models import Model
from keras.layers import Embedding, Input
import numpy as np

ip = Input(shape = (3,))
emb = Embedding(1, 2, trainable=True, mask_zero=True)(ip)

model = Model(ip, emb)
input_array = np.array([[5, 0, 1], [1, 2, 0]])

model.compile("rmsprop", "mse")

output_array = model.predict(input_array)

print(output_array)

print(output_array.shape)

model.summary()
Run Code Online (Sandbox Code Playgroud)

现在,我们在传递 0 的位置得到非零向量。

[[[ 0.          0.        ]
  [-0.04339869 -0.04900574]
  [ 0.          0.        ]]

 [[ 0.          0.        ]
  [ 0.          0.        ]
  [-0.04339869 -0.04900574]]]
(2, 3, 2)
Model: "model_19"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_22 (InputLayer)        (None, 3)                 0         
_________________________________________________________________
embedding_34 (Embedding)     (None, 3, 2)              2         
=================================================================
Total params: 2
Trainable params: 2
Non-trainable params: 0
Run Code Online (Sandbox Code Playgroud)

简而言之,Keras 用零向量映射任何词汇表外的单词索引,对于那些位置,前向传递将确保所有贡献为零(尽管偏差可能发挥作用),这是合理的。这有点违反直觉,因为将词汇标记传递给模型似乎是一种开销(而不是仅仅在预处理步骤中删除它们)并且是不好的做法,但这是一个很好的解决方案,可以在不重新计算标记的情况下测试不同的input_dim标记。