事前に訓練された語彙が未知の単語に出会うたびに、正規化された300次元ベクトル(要素の型= tf.float32)を追加する方法について興味があります。事前に訓練されたGloVe Word埋め込みを使用していますが、場合によっては、未知の単語に遭遇したことに気づき、この新たに見つかった未知の単語の正規ランダム化されたWordベクトルを作成したいと思います。
問題は、現在の設定では、 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)
以下のコード例は、embed_tensor
は、次のように単語が埋め込まれるような機能です。
trainable
がFalse
の場合、トレーニング中に埋め込みを固定することができます。trainable
がFalse
の場合、トレーニング中に埋め込みを固定することができます。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)
参考までに、トレーニングデータに存在せず、事前トレーニングされた埋め込みを持たない単語を賢明で非ランダムに表現するには、トレーニングデータ内の低頻度の単語をnkトークン(それはあなたの語彙にありません)そしてunk_embedding
トレーニング可能。このようにして、トレーニングデータでは見えない単語のプロトタイプを学習します。
試したことはありませんが、コードの同じ機械を使用して可能な方法を提供することはできますが、後で考えます。
index_table_from_tensor
メソッドは、すべてのoovワードを事前定義された数のバケットにシャッフルするnum_oov_buckets
パラメーターを受け入れます。
このパラメーターを特定の「十分に大きい」値に設定すると、データがこれらのバケット間で広がることがわかります(各バケットには、ID>最後の語彙内のWordのIDがあります)。
そう、
embedding_init
変数の最後の行(バケットに対応する行)をランダムな値に設定(つまり、assign
)した場合num_oov_buckets
十分に大きくすると、衝突が最小限に抑えられます非常に効率的な方法で求めている動作(の近似値)を取得できます。
ランダムな振る舞いは、ハッシュテーブルのものと同様の理論によって正当化できます。バケットの数が十分に大きい場合、文字列のハッシュ方法は各oov Wordを高い確率で異なるバケットに割り当てます(つまり、同じ衝突を最小限に抑えます)バケット)。各バケットに異なる乱数を割り当てるため、各oov Wordの(ほぼ)異なるマッピングを取得できます。
私がこれについて考えたのは、新しい単語ごとに新しい次元を追加することにより、事前に訓練された埋め込みに新しい単語を取り込むことでした(基本的には、それらのワンホットな性質を維持します)。
新しい単語の数は少ないが重要であると仮定すると、たとえば、埋め込み結果の次元を300から300 +新しい単語の数に増やすことができます。この場合、新しい単語はその次元の1を除くすべてゼロになります。