理解tensorflow中的`tf.nn.nce_loss()`

Gab*_*Chu 20 python tensorflow

我试图了解Tensorflow中的NCE损失函数.NCE丢失用于word2vec任务,例如:

# 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.
# tf.nce_loss automatically draws a new sample of the negative labels each
# time we evaluate the loss.
loss = tf.reduce_mean(
    tf.nn.nce_loss(weights=nce_weights,
                   biases=nce_biases,
                   labels=train_labels,
                   inputs=embed,
                   num_sampled=num_sampled,
                   num_classes=vocabulary_size))
Run Code Online (Sandbox Code Playgroud)

更多细节请参考Tensorflow word2vec_basic.py

  1. NCE函数中的输入和输出矩阵是什么?

在word2vec模型中,我们感兴趣的是为单词构建表示.在训练过程中,给定一个滑动窗口,每个单词将有两个嵌入:1)当单词是中心单词时; 2)当单词是上下文单词时.这两个嵌入分别称为输入和输出向量.(输入和输出矩阵的更多解释)

在我看来,输入矩阵是embeddings和输出矩阵nce_weights.这样对吗?

  1. 什么是最终嵌入?

根据s0urcer关于的一篇文章nce,它说最终的嵌入矩阵只是输入矩阵.虽然,有些人说,final_embedding=input_matrix+output_matrix.哪个是对的/更常见的?

dro*_*lei 14

让我们看一下word2vec示例中的相对代码(examples/tutorials/word2vec).

embeddings = tf.Variable(
    tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))
embed = tf.nn.embedding_lookup(embeddings, train_inputs)
Run Code Online (Sandbox Code Playgroud)

这两行创建嵌入表示.embeddings是一个矩阵,其中每一行代表一个单词向量.embedding_lookup获取对应的向量的快速方法train_inputs.在word2vec示例中,train_inputs由一些int32数字组成,表示id目标词.基本上,它可以通过隐藏层功能放置.

# 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]))
Run Code Online (Sandbox Code Playgroud)

这两行创建参数.它们将在培训期间由优化器更新.我们可以tf.matmul(embed, tf.transpose(nce_weights)) + nce_biases用来获得最终的输出分数.换句话说,分类中的最后一个内积层可以用它代替.

loss = tf.reduce_mean(
      tf.nn.nce_loss(weights=nce_weights,     # [vocab_size, embed_size]
                   biases=nce_biases,         # [embed_size]
                   labels=train_labels,       # [bs, 1]
                   inputs=embed,              # [bs, embed_size]
                   num_sampled=num_sampled, 
                   num_classes=vocabulary_size))
Run Code Online (Sandbox Code Playgroud)

这些线条创造nce loss,@ garej给出了非常好的解释.num_samplednce算法中的负采样数.


为了说明其用法nce,我们可以在mnist示例(examples/tutorials/mnist/mnist_deep.py)中应用它,并执行以下两个步骤:

1.用隐藏图层输出替换嵌入.隐藏层的维度是1024和num_output是10.最小值num_sampled为1.请记住删除最后一个内积层deepnn().

y_conv, keep_prob = deepnn(x)                                            

num_sampled = 1                                                          
vocabulary_size = 10                                                     
embedding_size = 1024                                                    
with tf.device('/cpu:0'):                                                
  embed = y_conv                                                         
  # 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])) 
Run Code Online (Sandbox Code Playgroud)

2.创建损失和计算输出.计算输出后,我们可以用它来计算精度.请注意,此处的标签不是softmax中使用的单热矢量.标签是培训样本的原始标签.

loss = tf.reduce_mean(                                   
    tf.nn.nce_loss(weights=nce_weights,                           
                   biases=nce_biases,                             
                   labels=y_idx,                                  
                   inputs=embed,                                  
                   num_sampled=num_sampled,                       
                   num_classes=vocabulary_size))                  

output = tf.matmul(y_conv, tf.transpose(nce_weights)) + nce_biases
correct_prediction = tf.equal(tf.argmax(output, 1), tf.argmax(y_, 1))
Run Code Online (Sandbox Code Playgroud)

当我们设定时num_sampled=1,val精度将在周围结束98.8%.如果我们设置num_sampled=9,我们可以获得与softmax训练的val精度几乎相同的val精度.但请注意,nce不同于softmax.

培训的完整代码mnistnce,可以发现在这里.希望它有所帮助.