如何在Tensorflow中添加未知单词的新嵌入(训练和预设测试)

问题描述 投票:19回答:3

我很好奇每当遇到预训练词汇表未知的单词时,我如何添加正常随机化的300维向量(元素'type = tf.float32)。我正在使用经过预先训练的GloVe单词嵌入,但在某些情况下,我意识到我遇到了未知单词,我想为这个新发现的未知单词创建一个正常随机化的单词向量。

问题是,在我目前的设置中,我使用tf.contrib.lookup.index_table_from_tensor根据已知词汇从单词转换为整数。这个函数可以创建新的标记,并为一些预定义数量的词汇表单词哈希,但是我的embed不会包含这个新的未知哈希值的嵌入。我不确定我是否可以简单地将随机嵌入添加到embed列表的末尾。

我也想以有效的方式做到这一点,因此预先建立的张量流函数或涉及张量流函数的方法可能是最有效的。我定义了一些预先知道的特殊标记,例如句末标记和默认的未知作为空字符串(“在索引0处”),但是它在学习各种不同的未知单词方面的能力有限。我目前使用tf.nn.embedding_lookup()作为最后嵌入步骤。

我希望能够为训练数据中的每个未知单词添加新的随机300d向量,并且我还想为测试期间可能遇到的训练中未见的任何未知标记添加预先制作的随机单词向量。这样做最有效的方法是什么?

def embed_tensor(string_tensor, trainable=True):
    """    
    Convert List of strings into list of indicies then into 300d vectors
    """
    # ordered lists of vocab and corresponding (by index) 300d vector
    vocab, embed = load_pretrained_glove()

    # Set up tensorflow look up from string word to unique integer
    vocab_lookup = tf.contrib.lookup.index_table_from_tensor(
        mapping=tf.constant(vocab),
        default_value = 0)
    string_tensor = vocab_lookup.lookup(string_tensor)

    # define the word embedding 
    embedding_init = tf.Variable(tf.constant(np.asarray(embed),
                                 dtype=tf.float32),
                                 trainable=trainable,
                                 name="embed_init")

    # return the word embedded version of the sentence (300d vectors/word)
    return tf.nn.embedding_lookup(embedding_init, string_tensor)
python tensorflow nlp
3个回答
10
投票

下面的代码示例调整您的embed_tensor函数,使得嵌入的单词如下:

  • 对于具有预训练嵌入的单词,使用预训练嵌入初始化嵌入。如果trainableFalse,嵌入可以在训练期间保持固定。
  • 对于训练数据中没有预训练嵌入的单词,嵌入是随机初始化的。如果trainableFalse,嵌入可以在训练期间保持固定。
  • 对于测试数据中未出现在训练数据中并且没有预训练嵌入的单词,使用单个随机初始化的嵌入向量。此向量无法训练。
import tensorflow as tf
import numpy as np

EMB_DIM = 300
def load_pretrained_glove():
    return ["a", "cat", "sat", "on", "the", "mat"], np.random.rand(6, EMB_DIM)

def get_train_vocab():
    return ["a", "dog", "sat", "on", "the", "mat"]

def embed_tensor(string_tensor, trainable=True):
  """
  Convert List of strings into list of indices then into 300d vectors
  """
  # ordered lists of vocab and corresponding (by index) 300d vector
  pretrained_vocab, pretrained_embs = load_pretrained_glove()
  train_vocab = get_train_vocab()
  only_in_train = list(set(train_vocab) - set(pretrained_vocab))
  vocab = pretrained_vocab + only_in_train

  # Set up tensorflow look up from string word to unique integer
  vocab_lookup = tf.contrib.lookup.index_table_from_tensor(
    mapping=tf.constant(vocab),
    default_value=len(vocab))
  string_tensor = vocab_lookup.lookup(string_tensor)

  # define the word embedding
  pretrained_embs = tf.get_variable(
      name="embs_pretrained",
      initializer=tf.constant_initializer(np.asarray(pretrained_embs), dtype=tf.float32),
      shape=pretrained_embs.shape,
      trainable=trainable)
  train_embeddings = tf.get_variable(
      name="embs_only_in_train",
      shape=[len(only_in_train), EMB_DIM],
      initializer=tf.random_uniform_initializer(-0.04, 0.04),
      trainable=trainable)
  unk_embedding = tf.get_variable(
      name="unk_embedding",
      shape=[1, EMB_DIM],
      initializer=tf.random_uniform_initializer(-0.04, 0.04),
      trainable=False)

  embeddings = tf.concat([pretrained_embs, train_embeddings, unk_embedding], axis=0)

  return tf.nn.embedding_lookup(embeddings, string_tensor)

仅供参考,对于未在训练数据中出现并且没有预训练嵌入的单词具有合理的非随机表示,您可以考虑将训练数据中低频率的单词映射到unk标记(即不在你的词汇中)并使unk_embedding可训练。通过这种方式,您可以学习训练数据中看不到的单词的原型。


3
投票

我从未尝试过,但我可以尝试使用相同的代码机制提供一种可能的方式,但我会在以后再考虑它。

index_table_from_tensor方法接受一个num_oov_buckets参数,该参数将您所有的oov单词混洗到预定义数量的桶中。

如果将此参数设置为某个“足够大”值,您将看到您的数据在这些存储桶之间传播(每个存储桶都有一个ID>最后一个词汇表单词的ID)。

所以,

  • if(在每次查找时)你设置(即assign)你的embedding_init变量的最后一行(那些对应于桶)变量为随机值
  • 如果你使num_oov_bucketsenough大,碰撞将被最小化

你可以以非常有效的方式获得一个(近似)你所要求的行为。

随机行为可以通过类似于哈希表的理论来证明:如果桶的数量足够大,则字符串的哈希方法将每个oov字分配给具有高概率的不同桶(即,最小化与相同的桶的冲突)桶)。因为,您要为每个不同的存储桶分配不同的随机数,您可以获得每个oov字的(几乎)不同的映射。


0
投票

我对此有一个想法是通过为每个新单词添加一个新维度来捕获新单词到预训练嵌入(基本上保持它们的单一性质)。

假设新单词的数量很少,但它们很重要,例如,您可以将嵌入结果的维度从300到300 +新单词的数量增加,其中每个新单词除了1的维度外都会得到全零。

© www.soinside.com 2019 - 2024. All rights reserved.