tf.nn.embedding_lookup的作用是什么?CNN文本分类嵌入层实现存疑
嘿,我来帮你拆解一下tf.nn.embedding_lookup到底是怎么工作的,结合你这段CNN文本分类的代码来看就清楚多了!
核心本质:高效的查表操作
简单来说,tf.nn.embedding_lookup就是一个专门查词向量的工具——你可以把它想象成一本“词向量字典”,输入词对应的索引,它就会返回该词对应的embedding向量,完全不用你手动去循环取值,效率很高。
结合你的代码一步步拆解
先把你的代码格式化出来,方便对照:
with tf.device('/cpu:0'), tf.name_scope("embedding"): self.W = tf.Variable(tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0),name="W") self.embedded_chars = tf.nn.embedding_lookup(self.W, self.inputTensor) self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)
self.W:你的可训练词向量字典self.W是一个形状为[vocab_size, embedding_size]的可训练变量:vocab_size是你词汇表的总词数,比如你用了10000个不同的词,这个值就是10000embedding_size是每个词向量的维度,比如常用的128、256维- 初始化时用
tf.random_uniform生成了-1到1之间的随机值,后续训练过程中,模型会不断优化这些向量,让它们更适配你的文本分类任务
self.inputTensor:输入的词索引序列
这个张量是你预处理后的文本输入——比如一段文本被转换成了由词索引组成的序列,举个例子:如果你的文本是“我 爱 机器学习”,对应的词汇表索引是[5, 12, 3, 7],那inputTensor里就会是这样的索引值。它的形状一般是[batch_size, sequence_length],其中batch_size是每次训练的样本数,sequence_length是每个文本的固定长度。tf.nn.embedding_lookup(self.W, self.inputTensor):查字典取词向量
这个函数做的事情非常直白:遍历inputTensor里的每一个索引,把self.W中对应索引的那一行(也就是该词的embedding向量)取出来,最终拼接成一个新的张量。- 比如如果
inputTensor形状是[2, 3](2个样本,每个样本3个词),self.W是[10000, 128],那么输出的embedded_chars形状就是[2, 3, 128]——每个样本的每个词都被替换成了对应的128维词向量。
给你举个更直观的小例子:
假设vocab_size=5,embedding_size=3,self.W的值是:[[0.1, 0.2, 0.3], # 索引0的词向量 [0.4, 0.5, 0.6], # 索引1的词向量 [0.7, 0.8, 0.9], # 索引2的词向量 [1.0, 1.1, 1.2], # 索引3的词向量 [1.3, 1.4, 1.5]] # 索引4的词向量如果
inputTensor是[[1,3], [2,0]](2个样本,每个样本2个词),那么embedding_lookup的输出就是:[[[0.4,0.5,0.6], [1.0,1.1,1.2]], [[0.7,0.8,0.9], [0.1,0.2,0.3]]]- 比如如果
最后一步
tf.expand_dims:适配CNN的输入要求
你后面用tf.expand_dims(self.embedded_chars, -1)给张量增加了一个维度,把embedded_chars从[batch_size, sequence_length, embedding_size]变成[batch_size, sequence_length, embedding_size, 1]。这是因为TensorFlow的卷积层(比如tf.nn.conv2d)要求输入是4维张量(格式为[batch, height, width, channels]),这里把sequence_length当作高度,embedding_size当作宽度,最后新增的1当作通道数,这样才能顺利输入到后续的卷积层做特征提取。
额外补充
self.W是可训练的,训练过程中模型会根据分类任务的损失不断调整这些词向量,让语义相似的词拥有相似的向量,最终提升分类效果。
内容的提问来源于stack exchange,提问作者Bibhu Pala

