使用Tensorflow和预训练的FastText获取未知词汇的嵌入。

10

我正在使用一个预训练好的fasttext模型(https://github.com/facebookresearch/fastText/blob/master/pretrained-vectors.md)

我使用Gensim加载fasttext模型,它可以为任何单词输出向量,无论是已知的还是未知的(超出词汇表范围)。

from gensim.models.wrappers import FastText
en_model = FastText.load_fasttext_format('../wiki.en/wiki.en')
print(en_model['car'])
print(en_model['carcaryou'])
在tensorflow中,我知道可以使用以下代码获取已训练单词的可训练嵌入:

在tensorflow中,我知道可以使用以下代码获取已经看过的单词的可训练嵌入:

# Embedding layer
embeddings = tf.get_variable('embedding_matrix', [vocab_size, state_size], Trainable=True)
rnn_inputs = tf.nn.embedding_lookup(embeddings, x)

已知单词的索引很容易获取。然而,对于那些未见过的单词,FastText会基于子单词模式“预测”它们的潜在向量。未知单词没有任何索引。

在这种情况下,我该如何使用tensorflow来处理fasttext中的已知单词和未知单词?


你可以使用tf.cond来检测单词是否已知(请参阅tf.lookup获取相关工具),并结合tf.py_func在单词未知时调用FastText吗? - Alexandre Passos
@AlexandrePassos 是的。我认为这是可行的。但是,如果我想要已知和未知单词的嵌入都可以训练,该怎么办?对于这些未知单词,我需要将它们的嵌入存储在某个地方。我说得对吗? - Munichong
我也在苦苦寻找答案。@Munichong,你解决了吗? - user1669710
@user1669710 不好意思... - Munichong
1个回答

3
我发现一种使用tf.py_func的解决方法:
def lookup(arr):
    global model
    global decode

    decoded_arr = decode(arr)
    new_arr = np.zeros((*arr.shape, 300))
    for s, sent in enumerate(decoded_arr):
        for w, word in enumerate(sent):
            try:
                new_arr[s, w] = model.wv[word]
            except Exception as e:
                print(e)
                new_arr[s, w] = np.zeros(300)
    return new_arr.astype(np.float32)

z = tf.py_func(lookup, [x], tf.float32, stateful=True, name=None)

这段代码是有效的(使用法语,抱歉但不要紧)。
import tensorflow as tf
import numpy as np
from gensim.models.wrappers import FastText

model = FastText.load_fasttext_format("../../Tracfin/dev/han/data/embeddings/cc.fr.300.bin")
decode = np.vectorize(lambda x: x.decode("utf-8"))

def lookup(arr):
    global model
    global decode

    decoded_arr = decode(arr)
    new_arr = np.zeros((*arr.shape, 300))
    for s, sent in enumerate(decoded_arr):
        for w, word in enumerate(sent):
            try:
                new_arr[s, w] = model.wv[word]
            except Exception as e:
                print(e)
                new_arr[s, w] = np.zeros(300)
    return new_arr.astype(np.float32)

def extract_words(token):
    # Split characters
    out = tf.string_split([token], delimiter=" ")
    # Convert to Dense tensor, filling with default value
    out = tf.reshape(tf.sparse_tensor_to_dense(out, default_value="<pad>"), [-1])
    return out


textfile = "text.txt"
words = [
    "ceci est un texte hexabromocyclododécanes intéressant qui mentionne des",
    "mots connus et des mots inconnus commeceluici ou celui-là polybromobiphényle",
]

with open(textfile, "w") as f:
    f.write("\n".join(words))

tf.reset_default_graph()
padded_shapes = tf.TensorShape([None])
padding_values = "<pad>"

dataset = tf.data.TextLineDataset(textfile)
dataset = dataset.map(extract_words, 2)
dataset = dataset.shuffle(10000, reshuffle_each_iteration=True)
dataset = dataset.repeat()
dataset = dataset.padded_batch(3, padded_shapes, padding_values)
iterator = tf.data.Iterator.from_structure(
    dataset.output_types, dataset.output_shapes
)
dataset_init_op = iterator.make_initializer(dataset, name="dataset_init_op")
x = iterator.get_next()
z = tf.py_func(lookup, [x], tf.float32, stateful=True, name=None)
sess = tf.InteractiveSession()
sess.run(dataset_init_op)
y, w = sess.run([x, z])
y = decode(y)

print(
    "\nWords out of vocabulary: ",
    np.sum(1 for word in y.reshape(-1) if word not in model.wv.vocab),
)
print("Lookup worked: ", all(model.wv[y[0][0][0]] == w[0][0][0]))

输出:

Words out of vocabulary:  6
Lookup worked:  True

我没有尝试优化任何东西,特别是查找循环,欢迎评论


这是一个绕过 tf.nn.embedding_lookup 的解决方案。这意味着,如果至少知道一些字符 n-gram,则可以为每个单词获取一个向量。但嵌入不可训练(OP在评论中提到的),即使是已知单词的嵌入也是如此。 - lenz
嗨,我正在尝试在我的代码中使用 Ted 的解决方案。稍作修改后它可以单独工作,但当我用它来替换代码中的 tf.nn.embedding_lookup 部分时,就会出错。 - user4343712

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接