张量流word2vec例子中权重和偏差的目的是什么?

时间:2016-06-23 04:40:20

标签: machine-learning tensorflow deep-learning

我试图理解word2vec example如何运作,并且不能真正理解传递给nse_loss函数的权重和偏差的目的是什么。函数有两个变量输入:权重(加偏差)和嵌入。

# Look up embeddings for inputs.
embeddings = tf.Variable(
    tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))
embed = tf.nn.embedding_lookup(embeddings, train_inputs)

# Construct the variables for the NCE loss
nce_weights = tf.Variable(
    tf.truncated_normal([vocabulary_size, embedding_size],
                        stddev=1.0 / math.sqrt(embedding_size)))
nce_biases = tf.Variable(tf.zeros([vocabulary_size]))

两者都是随机初始化的(据我所知),两者都会在学习期间受到更新。

# Compute the average NCE loss for the batch.
loss = tf.reduce_mean(
  tf.nn.nce_loss(nce_weights, nce_biases, embed, train_labels,
                 num_sampled, vocabulary_size))

我认为他们俩都应该代表训练有素的模特。然而,重量和偏差以后从未用于相似性计算。相反,只使用一个组件:

# Compute the cosine similarity between minibatch examples and all embeddings.
norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True))
normalized_embeddings = embeddings / norm
valid_embeddings = tf.nn.embedding_lookup(
  normalized_embeddings, valid_dataset)
similarity = tf.matmul(
  valid_embeddings, normalized_embeddings, transpose_b=True)

那么模型的第二个组成部分呢?为什么重量和偏差被忽略了?

谢谢。

3 个答案:

答案 0 :(得分:3)

在word2vec中你想要的是单词的向量表示。为了做到这一点,你可以使用神经网络等。所以你有输入神经元,输出和隐藏层。你学习矢量表示的方法是有一个隐藏层,其中神经元的数量与你在矢量中想要的尺寸相同。每个字有一个输入,每个字有一个输出。然后你训练网络来学习输出的输入,但在中间你有一个较小的层,你可以把它看作矢量的输入编码。所以这里有权重和偏见。但是你以后不需要它们,你用于测试的是一个包含单词和代表该单词的向量的字典。这比运行神经网络以获得表示更快。这就是你以后再也看不到的原因。

关于余弦距离的最后一个代码是知道哪些向量与计算向量相关。你有一些单词(向量)你做了一些操作(比如:国王 - 男人+女人),然后你有一个你想在结果中转换的向量。这是在所有向量之间运行的余弦函数(皇后将与操作的结果向量具有最小距离)。

总而言之,您不会在验证阶段看到重量和偏差,因为您不需要它们。您可以使用在培训中创建的词典。

UPDATE s0urcer更好地解释了如何创建矢量表示。

网络的输入层和输出层代表单词。如果单词不存在则表示值为0,如果单词存在则表示值为1。第一个位置是一个词,第二个是另一个,等等。你有输入/输出神经元作为单词。

中间层是上下文,或者是单词的矢量表示。

现在,您使用句子或连续单词组训练网络。从这个组中,您只需一个字并将其设置在输入中,其他字则是网络的输出。因此,网络基本上会学习一个单词在其上下文中与其他单词的关联。

要获取每个单词的向量表示,请将该单词的输入神经元设置为1,并查看上下文层(中间层)的值。这些值是向量的值。由于除了单词1之外,所有输入都是0,因此这些值是输入神经元与上下文的连接的权重。

您之后不会使用该网络,因为您不需要计算上下文层的所有值,这将会更慢。您只需要在字典中查看该单词的值是什么。

答案 1 :(得分:3)

skip-gramm的想法是根据他们的背景来比较单词。因此,如果它们出现在相同的背景下,我们会认为它们是平等的NN的第一层表示单词矢量编码(基本上称为嵌入)。第二层代表上下文。每次我们只取一行(Ri)的第一层(因为输入向量总是看起来像0,...,0,1,0,...,0)并将它乘以第二层的所有列(Cj, j = 1..num的单词),该产品将是NN的输出。如果单词i和j经常出现在附近(在相同的上下文中),我们训练神经网络具有最大输出分量Ri * Cj。在训练的每个循环期间,我们仅调整一个Ri(再次因为选择输入矢量的方式)并且所有Cj,j = 1..w。当训练结束时,我们抛出第二层的矩阵,因为它代表上下文。我们只使用第一层的矩阵来表示单词的矢量编码。

答案 2 :(得分:1)

权重和偏见在这里更新:

_, loss_val = session.run([optimizer, loss], feed_dict=feed_dict)

优化器执行以下操作 - 计算渐变,然后执行更新步骤。

相似性是在不同的位置调用单独的计算,并用于验证结果。在以下代码部分中会发生这种情况:

if step % 10000 == 0: sim = similarity.eval()

嵌入的验证依赖于相似性嵌入。