【问题标题】:Using keras tokenizer for new words not in training set对不在训练集中的新词使用 keras 分词器
【发布时间】:2018-07-04 01:52:18
【问题描述】:

我目前正在使用 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 可能会弄乱一些统计数据。是否有更好的方法或其他更好的方法?

【问题讨论】:

  • 这是基于词的分词的常见问题。一种方法是忽略这些词,因为它正在发生。有时,一个更可取的选择是有一个表示“看不见的词”的标记。此外,还有一些方法可以说明如何从已见词中组合未见词的嵌入(查看“词汇外嵌入”)。最后,有些人使用字符 n-gram 的嵌入而不是词嵌入来实际解决该问题(尤其是在诸如 Twitter 等具有大量且不断变化的词汇表的场景中)。
  • 嗨@JARS,您能否提供一些链接或示例,说明您所说的“最后,有些人使用嵌入字符n-gram...”?我没有发现任何更清楚的信息可以提供帮助。
  • @KleysonRios,您可以使用子词模型,例如 fastTextBPEngram2vec

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


【解决方案1】:

在 Keras Tokenizer 中,您有 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]]

【讨论】:

    【解决方案2】:

    我会尝试不同的方法。主要问题是您的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)
    

    【讨论】:

      【解决方案3】:

      我遇到了同样的问题。事实上,在标记化之前,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()}
      

      然后我们使用 Glove 作为权重矩阵:

      # 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之后,我可以想出这个。

      【讨论】:

        猜你喜欢
        • 2021-03-29
        • 2019-11-14
        • 2021-11-23
        • 2019-10-27
        • 1970-01-01
        • 1970-01-01
        • 2021-10-16
        • 1970-01-01
        • 2020-11-30
        相关资源
        最近更新 更多