我试图了解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))
更多详情,请参阅Tensorflow word2vec_basic.py
在word2vec模型中,我们有兴趣为单词构建表示。在训练过程中,给定一个滑动窗口,每个单词将有两个嵌入:1)当单词是中心单词时; 2)当单词是上下文单词时。这两个嵌入分别称为输入和输出向量。 (more explanations of input and output matrices)
在我看来,输入矩阵是embeddings
,输出矩阵是nce_weights
。是不是?
根据post s0urcer也与nce
有关,它说最终的嵌入矩阵只是输入矩阵。同时,some others saying,final_embedding=input_matrix+output_matrix
。哪个是对的/更常见的?
答案 0 :(得分: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)
这两行创建嵌入表示。 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]))
这两行创建参数。它们将在培训期间由优化器更新。我们可以使用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))
这些行创建nce loss
, @garej 给出了非常好的解释。 num_sampled
是指nce
算法中的负抽样数。
为了说明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]))
<强> 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))
当我们设置num_sampled=1
时,val准确度将以98.8%
左右结束。如果我们设置num_sampled=9
,我们可以获得与softmax训练的val精度几乎相同的val精度。但请注意,nce
与softmax
不同。
可以找到mnist
的完整培训代码nce
here。希望它有所帮助。
答案 1 :(得分:2)
embeddings
Tensor是您的最终输出矩阵。它将单词映射到向量。在单词预测图中使用它。
输入矩阵是从训练文本生成的一批centre-word : context-word
对(train_input
和train_label
)。
虽然nce_loss
op的确切工作原理尚不清楚,但基本思路是它使用单层网络(参数nce_weights
和nce_biases
)来映射输入向量(使用embeddings
op从embed
中选择)到输出词,然后将输出与训练标签(训练文本中的相邻单词)以及随机子样本进行比较(num_sampled
)词汇表中的所有其他单词,然后修改输入向量(存储在embeddings
中)和网络参数以最小化错误。
答案 2 :(得分:1)
NCE功能中的输入和输出矩阵是什么?
以跳过的克模型为例:
the quick brown fox jumped over the lazy dog
输入和输出对是:
(quick, the), (quick, brown), (brown, quick), (brown, fox), ...
有关详细信息,请参阅the tutorial。
最终的嵌入是什么?
您应该提取的最终嵌入通常是输入和隐藏图层之间的{w} 。
一个热矢量[0,0,0,1,0]是上图中的输入层,输出是字嵌入[10,12,19],W(在上图中)是中间的矩阵。
有关详细说明,请阅读this tutorial。
答案 3 :(得分:1)
1)简而言之,它一般是正确的,但对于所讨论的功能只是部分正确。见tutorial:
噪声对比估计损失定义为a 逻辑回归模型。为此,我们需要定义权重和 词汇表中每个单词的偏见(也称为
output weights
而不是与input embeddings
)。
因此,nce_loss
函数的输入为output weights
,input embeddings
的部分为<{1}}。
2)&#39;决赛&#39;嵌入(又名Word向量,又名单词的向量表示)就是你所说的input matrix
。嵌入是该矩阵的字符串(向量),对应于每个单词。
警告事实上,由于NN环境中的输入和输出概念用法,这个术语令人困惑。嵌入矩阵不是NN的输入,因为NN的输入在技术上是输入层。您可以在培训过程中获得此矩阵的最终状态。尽管如此,这个矩阵应该在编程中初始化,因为算法必须从该矩阵的某个随机状态开始,以便在训练期间逐步更新它。
权重也是如此 - 它们也要初始化。它发生在以下行:
nce_weights = tf.Variable(
tf.truncated_normal([50000, 128], stddev=1.0 / math.sqrt(128)))
每个嵌入向量可以乘以权重矩阵的向量(以字符串到列的方式)。所以我们将在NN output layer
中得到标量。此标量的范数被解释为目标词(来自输入层)将伴随与output layer
中的标量位置对应的标签[或上下文]字的概率。
所以,如果我们说的是函数的输入(参数),那么两个矩阵都是这样的:权重和嵌入式的批量大小提取:
tf.nn.nce_loss(weights=nce_weights, # Tensor of shape(50000, 128)
biases=nce_biases, # vector of zeros; len(128)
labels=train_labels, # labels == context words enums
inputs=embed, # Tensor of shape(128, 128)
num_sampled=num_sampled, # 64: randomly chosen negative (rare) words
num_classes=vocabulary_size)) # 50000: by construction
此nce_loss
函数输出batch_size的向量 - 在TensorFlow示例中为shape(128,)
张量。
然后reduce_mean()
将此结果减少为采用这128个值的平均值的标量,这实际上是进一步最小化的目标。
希望这有帮助。
答案 4 :(得分:0)
从论文 有效地学习单词嵌入与噪声对比估计 :
NCE基于将密度估计减少到概率二元分类。基本思想是训练逻辑回归分类器 区分来自数据分布的样本和来自某些“噪声”分布的样本
我们可以发现,在字嵌入中,NCE实际上是负抽样。 (关于这两者之间的区别,请参阅论文: 关于噪声对比度估计和负采样的注意事项 )
因此,您无需输入噪音分布。而且从引用中,你会发现它实际上是一个逻辑回归:权重和偏见是逻辑回归所需要的。如果您熟悉word2vec,那只是添加偏见。