之前已经介绍了使用tensorflow构建线性回归以及用逻辑回归来进行MNIST手写字母识别,这些都属于比较简单的网络结构。当我们需要构建更为复杂的结构时,就需要好好计划编码结构,不然代码混乱不说而且难于调试。这里主要介绍如何高效结构化模型,以word2vec作为例子说明。
关于word2vec的理论知识可以参考cs224n的课件。主要介绍利用tensorflow搭建skip-gram模型。原理可参考:
Word2Vec Tutorial—The Skip-Gram Model
如何结构化Tensorflow模型
tensorflow中模型的结构
第一步,构建计算图
1、为输入和输出定义placeholders
2、定义权重weights
3、定义inference model
4、定义损失函数
5、定义优化器
第二步,计算
1、初次初始化所有模型变量
2、输入训练数据,可能还会涉及随机化数据样本的顺序。
3、对训练数据执行推理模型,从而计算每个训练输入以当前模型参数的输出结果。
4、计算损失
5、调整模型参数使得模型的损失最大或者最小。
Word2Vec, skip-gram model实例
第一步,构建计算图
1、为输入和输出定义placeholders
输入是中心词,输出是目标(上下文)词,我们直接输入这些词的索引而不是one-hot向量,例如:如果中心词是单词表中的第1001个单词,我们输入数字1001。每个样本输入都是一个标量,所以我们以形状[BATCH_SIZE]的占位符定义批量大小为BATCH_SIZE的输入。同样,输出也是用同样的方法定义。
2、定义权重weights
每行对应一个词的表示向量。如果用一个词表示一个大小为EMBED_SIZE的向量,那么嵌入矩阵的形状为[VOCAB_SIZE,EMBED_SIZE]。我们将嵌入矩阵初始化为随机分布的值。
3、定义推理模型
我们的目标是得到词汇表中单词的向量表示,embed_matrix的维度是[VOCAB_SIZE x EMBED_SIZE],embedding矩阵的每一行和该索引出的单词的矢量表示相对应。为了得到批次中所有中心词的表示,我们得到所有相应行的切片嵌入矩阵。Tensorflow为我们提供了一个简单的API:tf.nn.embedding_lookup()。
于是为了得到输入中心词的嵌入矩阵表示,我们这样操作:
4、定义损失函数
对于NCE损失,我们需要隐藏层的权重和偏置来计算。
5、定义优化器
我们使用梯度下降法。
第二步,执行 计算
|
|
Name Scope
给出张量的名称,在Tensorboard中查看
这看起来可读性并不强,节点到处都是。Tensorboard并不知道哪些节点之间关联性比较强并将它们组合在一起。当构建更为复杂的模型时,这看起来会更混乱。实际上我们可以同过name scope的方法指定节点之间的关联关系,这样有着相同name scope的节点会被放置在一起。
这样我们就可以将之前的代码再规范一下:
这样Tensorboard中的图看起来更加直观了,鼠标点击相应的块会出现该块的具体内容。
Tensorboard中有两种类型的边界,一种是实线一种是虚线,实线代表data flow边,而虚线代表控制依赖的边。
此外,为了让代码的复用性更强,我们可以将模型写成一个类,如下所示:
为什么要学习梯度?
从以上例子可以看出 ,我们在构建模型的时候并没有计算梯度,而是Tensorflow自动帮我们求解的,那么我们为什么还要学习梯度呢?因为Tensorflow虽然帮我们计算了梯度,但是它并没有告诉我们函数是否会受到梯度爆炸或者消失的影响,所以我们仍然需要了解梯度下降的工作原理。