使用keras tokenizer处理不在训练集中的新单词

时间:2018-01-24 21:55:23

标签: python machine-learning nlp deep-learning keras

我目前正在使用Keras Tokenizer创建一个单词索引,然后将该单词索引与导入的GloVe字典进行匹配,以创建一个嵌入矩阵。然而,我遇到的问题是,这似乎打败了使用单词矢量嵌入的一个优点,因为当使用训练模型进行预测时,如果它遇到了一个不在标记器中的新单词。单词索引它将它从序列中删除。

#fit the tokenizer
tokenizer = Tokenizer()
tokenizer.fit_on_texts(texts)
word_index = tokenizer.word_index

#load glove embedding into a dict
embeddings_index = {}
dims = 100
glove_data = 'glove.6B.'+str(dims)+'d.txt'
f = open(glove_data)
for line in f:
    values = line.split()
    word = values[0]
    value = np.asarray(values[1:], dtype='float32')
    embeddings_index[word] = value
f.close()

#create embedding matrix
embedding_matrix = np.zeros((len(word_index) + 1, dims))
for word, i in word_index.items():
    embedding_vector = embeddings_index.get(word)
    if embedding_vector is not None:
        # words not found in embedding index will be all-zeros.
        embedding_matrix[i] = embedding_vector[:dims]

#Embedding layer:
embedding_layer = Embedding(embedding_matrix.shape[0],
                        embedding_matrix.shape[1],
                        weights=[embedding_matrix],
                        input_length=12)

#then to make a prediction
sequence = tokenizer.texts_to_sequences(["Test sentence"])
model.predict(sequence)

那么有没有一种方法我仍然可以使用标记器将句子转换成数组,并且仍然使用尽可能多的单词GloVe字典,而不仅仅是那些出现在我的训练文本中的单词?

编辑:经过进一步思考,我想一个选项是在令牌器适合的文本中添加一个或多个文本,其中包括手套词典中的键列表。如果我想使用tf-idf,那可能会弄乱一些统计数据。有没有更好的方法来做这个或更好的方法?

3 个答案:

答案 0 :(得分:3)

在Keras令牌生成器中,您具有 oov_token 参数。只需选择您的令牌,未知单词就会拥有该令牌。

tokenizer_a = Tokenizer(oov_token=1)
tokenizer_b = Tokenizer()
tokenizer_a.fit_on_texts(["Hello world"])
tokenizer_b.fit_on_texts(["Hello world"])

输出

In [26]: tokenizer_a.texts_to_sequences(["Hello cruel world"])
Out[26]: [[2, 1, 3]]

In [27]: tokenizer_b.texts_to_sequences(["Hello cruel world"])
Out[27]: [[1, 2]]

答案 1 :(得分:0)

我会尝试另一种方法。主要问题是您的word_index是基于您的训练数据的。试试这个:

#load glove embedding into a dict
embeddings_index = {}
dims = 100
glove_data = 'glove.6B.'+str(dims)+'d.txt'
f = open(glove_data)
for line in f:
    values = line.split()
    word = values[0]
    value = np.asarray(values[1:], dtype='float32')
    embeddings_index[word] = value
f.close()

word_index = {w: i for i, w in enumerate(embeddings_index.keys(), 1)}

#create embedding matrix
embedding_matrix = np.zeros((len(word_index) + 1, dims))
for word, i in word_index.items():
    embedding_vector = embeddings_index.get(word)
    if embedding_vector is not None:
        # words not found in embedding index will be all-zeros.
        embedding_matrix[i] = embedding_vector[:dims]

现在您的embedding_matrix包含了所有GloVe作品。

要标记文本,您可以使用类似以下的内容:

from keras.preprocessing.text import text_to_word_sequence

def texts_to_sequences(texts, word_index):
    for text in texts:
        tokens = text_to_word_sequence(text)
        yield [word_index.get(w) for w in tokens if w in word_index]

sequence = texts_to_sequences(['Test sentence'], word_index)

答案 2 :(得分:0)

我有同样的问题。实际上,在标记化之前,Gloved涵盖了我的数据的大约 90%

我要做的是我从pandas数据框中的文本列中创建了一个单词列表,然后使用enumerate创建了它们的字典。

(就像Keras中的分词器所做的一样,但不更改单词并按频率列出它们)。

然后,只要我的单词在Glove字典中,我都会在Glove中检查单词并将Glove中的向量添加到我的初始权重矩阵中。

我希望解释清楚。这是用于进一步说明的代码:

# creating a vocab of my data
vocab_of_text = set(" ".join(df_concat.text).lower().split())

# creating a dictionary of vocab with index
vocab_of_text = list(enumerate(vocab_of_text, 1))

# putting the index first
indexed_vocab = {k:v for v,k in dict(vocab_of_text).items()}

然后我们将手套用于权重矩阵:

# creating a matrix for initial weights
vocab_matrix = np.zeros((len(indexed_vocab)+1,100))



# searching for vactors in Glove
for i, word in indexed_vocab.items():
    vector = embedding_index.get(word)
    # embedding index is a dictionary of Glove
    # with the shape of 'word': vecor

    if vector is not None:
        vocab_matrix[i] = vector

,然后使其可以嵌入:

def text_to_sequence(text, word_index):
    tokens = text.lower().split()
    return [word_index.get(token) for token in tokens if word_index.get(token) is not None]

# giving ids
df_concat['sequences'] = df_concat.text.apply(lambda x : text_to_sequence(x, indexed_vocab))

max_len_seq = 34

# padding
padded = pad_sequences(df_concat['sequences'] ,
              maxlen = max_len_seq, padding = 'post', 
              truncating = 'post')

也感谢@spadarian的回答。在阅读并实施他的idea.part之后,我可以提出这个建议。