Простая реализация будет:
def most_similar(emb_layer, pos_word_idxs, neg_word_idxs=[], top_n=10):
weights = emb_layer.weights[0]
mean = []
for idx in pos_word_idxs:
mean.append(weights.value()[idx, :])
for idx in neg_word_idxs:
mean.append(weights.value()[idx, :] * -1)
mean = tf.reduce_mean(mean, 0)
dists = tf.tensordot(weights, mean, 1)
best = tf.math.top_k(dists, top_n)
# Mask words used as pos or neg
mask = []
for v in set(pos_word_idxs + neg_word_idxs):
mask.append(tf.cast(tf.equal(best.indices, v), tf.int8))
mask = tf.less(tf.reduce_sum(mask, 0), 1)
return tf.boolean_mask(best.indices, mask), tf.boolean_mask(best.values, mask)
Конечно, вам нужно знать индексы слов. Я предполагаю, что у вас есть word2idx
отображение, поэтому вы можете получить их так: [word2idx[w] for w in pos_words]
.
Чтобы использовать это:
# Assuming the first layer is the Embedding and you are interested in word with idx 10
idxs, vals = most_similar(model.layers[0], [10])
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
idxs = sess.run(idxs)
vals = sess.run(vals)
Некоторые потенциальные улучшения для этой функции:
- Убедитесь, что он возвращает
top_n
слов (после маски он возвращает меньше слов)
gensim
использует нормализованные вложения (L2_norm)