Tensorflow作为现在最负盛名的深度学习框架,其便利程度大大提升,学习门槛大大降低。神经网络的搭建就像搭积木一样,用不同材质的积木,经过合理的组装,即可搭成一个漂亮的模型。本文将介绍如下内容。
- TF的一些基本概念
- TF代码的模块
- TF的一些常用API
1.TF的一些基本概念
TF的最重要的概念只有两个,一个是Tensor
,一个是Op
,它们共同组成了Graph
。
我们用管道来类比
Graph
—– 水管图
Op
—– 水管的结点
Tensor
—– 水管
Data
—- 水
Data
,就是实实在在的数据,一般用的是numpy里面的ndarray。
Tensor
,名词翻译叫做张量,它是存储数据的东西,只有一个外壳,规定了数据的shape
(形状),dtype
(数据类型)等。我们用水管来类比它,水管里本身没有水的,它起到的作用是规范水的形状,(比如某个节点比较脆弱,不能一次接太多的水,那么我们会把水管变得细长,这样可以使单位流量变小),然后把水运往各种结点。
Op
,就是operation,它是用来改变数据的操作,数学上叫做映射,也就是我们熟知的f()。比如我们把两股水混合在一起(add操作),把两股水并排在一起(concat操作),把水变成激活饮料(加激活函数)等等。所以我们把Op
比作水管的结点。
Graph
由注水口,水管,水管结点以及出水口(即最后一个结点)共同组成了Graph
,这就是一个完整的水管网络。也就是为什么TF的名字叫做Tensorflow。
作为一个水管网络,那么我们肯定要先把水管网络修建好,才能往里面注水对不对,不然边修边注入,不就漏了吗?这就是图计算和我们平时顺序编程的最大不同。为什么这么设计呢?这涉及到一些更深层次的问题,在此不再展开。
2.TF代码的模块
TF代码一般分为九大模块:
超参数的设置:
这里的超参数,是人为给定的,而不是机器学习的。比如初始的learning rate,网络迭代的step数等等。
数据的读取:
我们往往在构建网络之前,先将数据读入缓存,在网络搭建好之后从注水口注入。一般呢,我们会构建一个迭代器,每次喂入batch_size大小的数据给网络。为什么这么做呢,因为一般来说数据集少则几百M,多则上百G,很难一次读入。利用Iterater,可以分批读入,这样就可以训练了。但是mnist数据集不同,它很小,所以可以一次读入。迭代器的构建先不慌掌握。我们新建一个
data.py
,把mnist数据读出来解析完毕之后,返回trainset和labelset即可。模型的搭建
一般我们会另外建一个文件,如
model.py
,专门用来写模型结构。因为在完成一个task的时候,我们不可能只局限于一个model,可能需要搭建多个model。所以另开一个文件。通常我们会把输入tensor(注水口,即tf.placeholder)传入model,返回的是输出tensor,也就是最后一个结点。loss的设置
有些代码会把loss和模型写在一块,但是我觉得这样耦合度还是高了点,因为一个模型完全可以用不同的loss,所以最好单独写。这个loss也就是损失函数。
optimizer的设置
在训练的时候,有了loss作为指示器,表示模型训练的好坏程度,那么optimizer就是起到了根据loss来调整model参数的作用。所以我们常常会看到这样一句,tf.train.XXXXOptimizer(learning_rate).minimize(loss),这个函数返回的是一个op,我们通过run这个op来使optimizer发挥作用。
session的设置
session,即是会话。什么是会话呢,就是把用户的所有东西收集到一起的环境,以后用户执行的操作,都在这个环境里。这样做的好处是什么呢?打个比方,我买了一堆东西放到了一个屋子,并且标明这是我自己的屋子。那么以后我进这个屋子,不用看都知道,里面的东西肯定都是我的,不存在我会用到别人东西的情况。TF对于会话的定义非常简单,也就是sess = tf.Session(),以后run某些Op的时候,就用sess.run(Op)就可以了。顺便解释一下这个sess.run()函数。这个函数里面最重要的两个参数要掌握,一个是
fetch
,一个是feed_dict
。fetch
得到的是一个list,list里面放的是Op,也就是出水口,有几个出水口,那么sess.run()就会返回多少个数据。TF采用的是栈式存储。这个怎么说呢?我们直接举例。比如我想要一号出水口出的水,那么我就从这个出水口钻进去,沿着一路往前爬,直到爬到进水口为止。这个过程可能不会用到全部的水管,只会用到需要用到的水管。那么有时候我想得到中间的Op结点的结果验证一下怎么办呢,直接把中间的Op加入fetch即可。feed_dict
得到的是一个dict,这个就是纯粹的进水口啦。也就是用tf.placeholder()定义的。我们把数据直接灌入进水口即可。Saver的设置
一个模型训练起来有时候要花上几天,那么我们当然希望把权重参数都保存起来。这样的话导入模型之后不需要重新训练直接就能上手。所以训练好了需要save,开始训练需要load。这个用法先不赘述,以后单开一章讲。
summary的设置
TF提供了一个非常强大的可视化界面,tensorboard,方便我们观察指标结果。这个用法先不赘述,以后单开一章讲。
训练
一般训练的代码如下:
for step in range(train_steps): #打算训练train_steps轮次
... = sess.run(fetch=[...],feed_dict={...:...,})
if step % num_summary == 0 : # 每训练num_summary轮,即添加结果进入summary
...
if step % num_save == 0 : # 每训练num_save轮,即保存权重。
...
以上大概就是一个TF-project的全部流程。对照我之前写的那个用mnist做数据集的代码看一下,用实例加强记忆。