На самом деле, если вы используете tensorflow.keras
, вы должны убедиться, что в вашем корпусе токены не превышают Dictionary_size или input_dim
слоя внедрения, иначе вы получите ошибку.
Если вы используете keras
, вы можете просто изменить input_dim
в слое встраивания, ничего не меняя в корпусе или токенах. keras
заменит лексемы вне словаря вектором zero
.
Прежде всего, возникает ошибка, если вы используете tenorflow.keras.
tensorflow
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()
Но если я использую keras 2.3.1, я не получаю никаких ошибок.
keras 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()
keras имеет разные реализации для слоя встраивания. Чтобы проверить это, давайте go встраиваем слой keras.
https://github.com/keras-team/keras/blob/master/keras/layers/embeddings.py#L16
А пока давайте просто рассмотрим функцию вызова.
def call(self, inputs):
if K.dtype(inputs) != 'int32':
inputs = K.cast(inputs, 'int32')
out = K.gather(self.embeddings, inputs)
return out
NB: Если вам нужен точный исходный код для keras 2.3.1 go здесь и загрузите исходный код: https://github.com/keras-team/keras/releases
Но если мы go реализуем тензорный поток, это другое.
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
Давайте спроектируем простую сеть, например перед и наблюдайте за матрицей весов.
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()
Модель дает следующий результат.
[[[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
Хорошо, мы получаем кучу нулей, но по умолчанию weight_initializer не нули!
Итак, давайте теперь рассмотрим матрицу весов.
import keras.backend as K
w = model.layers[1].get_weights()
print(w)
[array([[ 0.03680499, -0.04904002]], dtype=float32)]
На самом деле, это не все нули.
Итак, почему мы получаем нули?
Давайте изменим наши входные данные на модель.
Поскольку единственный индекс слова в словаре для 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()
Теперь мы получаем ненулевые векторы для позиций, в которые мы передали 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
Короче говоря, Керас сопоставляет любой индекс слова вне словарного запаса с нулевой вектор, и это разумно, так как для этих позиций прямой проход будет гарантировать, что все вклады равны NIL (хотя смещения могут иметь значение). Это немного противоречит интуиции, поскольку передача токенов словаря в модель кажется накладными расходами (а не просто их удаление на этапе предварительной обработки) и плохой практикой, но это хорошее исправление для тестирования различных input_dim
без повторной -счет жетонов.