我训练了一个Bi-LSTM模型以在一组句子上找到NER。为此,我使用了出现的不同单词,并在单词和数字之间进行了映射,然后使用这些数字创建了Bi-LSTM模型。然后,我创建并腌制该模型对象。
现在,我得到了一组新句子,其中包含训练模型尚未看到的某些单词。因此,这些单词到目前为止还没有数值。因此,当我在以前的现有模型上对其进行测试时,会出现错误。无法找到单词或特征,因为这些单词或特征的数字值不存在。
为避免此错误,我为看到的所有新单词赋予了一个新的整数值。
但是,当我加载模型并对其进行测试时,会出现以下错误:
InvalidArgumentError: indices[0,24] = 5444 is not in [0, 5442) [[Node: embedding_14_16/Gather = Gather[Tindices=DT_INT32, Tparams=DT_FLOAT, validate_indices=true,
_device="/job:localhost/replica:0/task:0/device:CPU:0"](embedding_14_16/embeddings/read, embedding_14_16/Cast)]]
训练数据包含5445个单词,包括填充单词。因此= [0,5444]
5444是我为测试语句中的填充指定的索引值。不清楚为什么要假设索引值在[0,5442)之间。
我已使用以下链接上提供的基本代码:https://www.kaggle.com/gagandeep16/ner-using-bidirectional-lstm
代码:
input = Input(shape=(max_len,))
model = Embedding(input_dim=n_words, output_dim=50
, input_length=max_len)(input)
model = Dropout(0.1)(model)
model = Bidirectional(LSTM(units=100, return_sequences=True, recurrent_dropout=0.1))(model)
out = TimeDistributed(Dense(n_tags, activation="softmax"))(model) # softmax output layer
model = Model(input, out)
model.compile(optimizer="rmsprop", loss="categorical_crossentropy", metrics=["accuracy"])
#number of epochs - Also for output file naming
epoch_num=20
domain="../data/Laptop_Prediction_Corrected"
output_file_name=domain+"_E"+str(epoch_num)+".xlsx"
model_name="../models/Laptop_Prediction_Corrected"
output_model_filename=model_name+"_E"+str(epoch_num)+".sav"
history = model.fit(X_tr, np.array(y_tr), batch_size=32, epochs=epoch_num, validation_split=0.1, verbose=1)
max_len
是句子中单词的总数,n_words
是词汇量。在模型中,填充使用以下代码完成,其中n_words=5441
:
X = pad_sequences(maxlen=max_len, sequences=X, padding="post", value=n_words)
新数据集中的填充
max_len = 50
# this is to pad sentences to the maximum length possible
#-> so all records of X will be of the same length
#X = pad_sequences(maxlen=max_len, sequences=X, padding="post", value=res_new_word2idx["pad_blank"])
#X = pad_sequences(maxlen=max_len, sequences=X, padding="post", value=5441)
不确定这些填充中的哪个正确?
但是,词汇表仅在训练数据中包含单词。当我说:
p = loaded_model.predict(X)
对于包含初始词汇中不存在的单词的文本句子,如何使用predict
?
答案 0 :(得分:1)
您可以使用Keras Tokenizer
类及其方法轻松地标记化和预处理输入数据。在实例化时指定vocab的大小,然后在训练数据上使用其fit_on_texts()
方法以根据给定的文本构建词汇表。之后,您可以使用其text_to_sequences()
方法将每个文本字符串转换为单词索引列表。好处是,仅考虑词汇表中的单词,而忽略所有其他单词(您可以通过将oov_token=1
传递给Tokenizer
类将这些单词设置为一个):
from keras.preprocessing.text import Tokenizer
# set num_words to limit the vocabulary to the most frequent words
tok = Tokenizer(num_words=n_words)
# you can also pass an arbitrary token as `oov_token` argument
# which will represent out-of-vocabulary words and its index would be 1
# tok = Tokenizer(num_words=n_words, oov_token='[unk]')
tok.fit_on_texts(X_train)
X_train = tok.text_to_sequences(X_train)
X_test = tok.text_to_sequences(X_test) # use the same vocab to convert test data to sequences
您可以选择使用pad_sequences
函数用零填充或截断它们以使它们具有相同的长度:
from keras.preprocessing.sequence import pad_sequences
X_train = pad_sequences(X_train, maxlen=max_len)
X_test = pad_sequences(X_test, maxlen=max_len)
现在,如果您没有使用oov令牌,那么vocab的大小将等于n_words+1
,或者如果您没有使用它,则其n_words+2
将会相等。然后,您可以将正确的数字作为其input_dim
参数(第一个位置参数)传递给嵌入层:
Embedding(correct_num_words, embd_size, ...)