Tensorflow之一基础篇

《Tensorflow技术解析与实战》基础篇

Tensorflow技术基础篇,本文章内容来源于《Tensorflow技术解析与实战》一书前四章内容整理

一、Tensorflow环境准备

Anaconda里安装Tensorflow;
依赖的其他模块有:numpy,matplotlib,jupyter
scikit-image:有一组图像处理的算法,可以使过滤一张图片变得很简单,非常适用于对图像的预处理。
librosa:用python进行音频特征提取的第三方库,有很多方式可以提取音频特征。
nltk:包含着大量的语料库,可以方便地完成很多自然语言处理的任务,包括分词、词性标注、命名实体识别(NER)及句法分析。
keras:Tensorflow核心中的高级别框架,Tensorflow的默认API
tflearn:支持Tensorflow的第三方框架。

pip install keras --upgrade  #来安装所需要的包

二、可视化Tensorflow

playground教学用神经网络可视化工具;

TensorBoard

Tensorflow自带强大可视化工具,Web应用程序套件。包含7个可视化功能:
SCALARS:展示训练过程中的准确率、损失值、权重/偏置的变化情况;
IMAGES:展示训练过程中记录的图像
AUDIO:展示训练过程中记录的音频
GRAPHS:展示模型的数据流图,以及各个设备上消耗的内存和时间
DISTAIBUTIONS:展示训练过程中记录的数据的分布图
HISTOGRAMS:展示训练过程中记录的数据的柱状图
EMBEDDINGS:展示词向量(Word2Vec)后的投影分布。

使用Tensorboard

执行python文件,(文件定义了日志保存的路径path),生成日志
定位到日志的磁盘下,执行 tensorboard –logdir=path即可
然后打开 http://localhost:6006 就能看到可视化的信息

三、Tensorflow的基础知识

1、Tensorflow系统架构

自底向上:设备层和网络层–>数据操作层–>图计算层–>API层–>应用层。前三层是Tensorflow的核心层。
网络通信层:gRPC 和远程直接数据存取RDMA 都是在分布式运算时需要用到的
设备管理层:Tensorflow分别在CPU,GPU,FPGA等设备上的实现。
使上层只需要处理卷积等逻辑,而不需要关系在硬件上的卷积实现过程。

2、设计理念

Torch是典型的命令式的,Caffe、MXNet采用混合的方法,TF是完全符号式编程。
定义各种变量,建立数据流图,在数据流图中规定各个变量之间的计算关系,最后编译数据流图,当输入数据放进去之后,才能有数据流,形成输出值。
Tensorflow中涉及的运算都要放在图中,而图的运行只发生在会话中,开启会话后,就可以用数据填充节点,进行运算;关闭就停止计算。

3、编程模型

《Tensorflow之一基础篇》
Tensorflow就是指“张量的流动”。Tensorflow的数据流图是由节点和边组成的有向无环图(directed acycline graph,DAG)。Tensorflow是由Tensor和Flow两部分组成,Tensor代表了数据流图的边,Flow代表了数据流图中节点所做的操作。

边及其两种连接关系

  1. 实现边–数据依赖
    张量从前往后完成一次前向传播;残差(ture-predict=error)从后往前流动一遍完成一次反向传播。
  2. 虚线边–控制依赖
    控制操作的运行,被用来确保happens-before关系,这类边上没有数据流过,但源节点必须在目的节点开始执行前完成执行。

节点

又称算子,代表一个操作。类似神经元,施加数学运算,feed in ,push out。
操作和运算的代码保存在tensorflow/python/ops/目录下,阅读运算的源代码都在这里

其他概念

  1. 图–把操作,数学运算等任务描述成有向无环图
  2. 会话–启动图的第一步创建Session对象;生成一张空图,在会话中添加节点和边,形成图再调用Session对象的run()执行;执行时填充(feed)传入Tensor,返回的结果类型根据输入的类型而定,这个过程叫取回(fetch)。会话是图交互的桥梁,一个会话可以有多个图,会话可以修改图的结构,也可以往图中注入数据进行计算。Session()主要有Extend(在Graph中添加节点和边)和Run(输入计算的节点和填充必要的数据后,进行运算和输出结果)。
    源码在tensorflow/python/client/session.py
  3. 设备–地址空间的硬件GPU和CPU,为了实现分布式执行操作,充分利用资源,可以明确指定操作在哪个设备上执行。
    源代码在tensorflow/python/framework/device.py。
  4. 变量–图中有固定的位置,不像张量可以流动。利用tf.Variable()构造函数,初始值的形状和类型决定了这个变量的形状和类型。tf.placeholder()临时替代任意操作的张量,在调用Session对象的run()方法去执行图时,使用填充数据作为调用的参数,调用结束后,填充数据就消失。
    源代码在tensorflow/tensorflow/python/ops/variables.py
  5. 内核–能够运行在特定设备上的一种对操作的实现,同一个操作可能会对应多个内核。当定义一个操作时,需要把新操作和内核通过注册的方式添加到系统中。

4、常用API

tf.Graph类中包含一系列表示计算的操作对象–tf.Operation,和在操作之间流动的数据张量对象–tf.Tensor
图、操作、张量的API
(1). tf.Graph类

    tf.Graph.__init__()  #创建空图
    tf.Graph.as_default()  #设为默认图
    tf.Graph.device(device_name_or_function)  #定义图运行使用的设备
    tf.Graph.name_scope(name)  #为节点创建层次化的名称

(2). tf.Operation类:代表图的节点,用于计算张量数据。由结点构造其产生,与操作相关的API位于该类中。

    tf.Operation.name  #操作的名称
    tf.Operation.type  #操作的类型,如 MatMul
    tf.Operation.inputs
    tf.Operation.outputs  #操作的输入与输出
    tf.Operation.control_inputs  #操作的依赖
    tf.Operation.run(feed_dict=None, session=None)  #在会话中运行该操作
    tf.Operation.get_attr(name)  #获取操作的属性值

(3). tf.Tensor 类不包含操作输出的值,提供在tf.Session中计算的方法。这样就可以在操作之间构建一个数据流连接。使之能够执行一个表示大量多步计算的图形。与张量相关的 API 均位于 tf.Tensor 类中

    tf.Tensor.dtype   #张量的数据类型
    tf.Tensor.name    #张量的名称
    tf.Tensor.value_index    #张量在操作输出中的索引
    tf.Tensor.graph    #张量所在的图
    tf.Tensor.op    #产生该张量的操作
    tf.Tensor.consumers()    #返回使用该张量的操作列表
    tf.Tensor.eval(feed_dict=None, session=None)    
    #在会话中求张量的值,需要使用 sess.as_default()或者eval(session=sess)
    tf.Tensor.get_shape()    #返回用于表示张量的形状(维度)的类 TensorShape
    tf.Tensor.set_shape(shape)    #更新张量的形状
    tf.Tensor.device    #设置计算该张量的设备

(4).可视化API。通过此来编写可视化程序。

    #创建FileWriter 和事件文件,会在 logdir中创建一个新的事件文件
    tf.summary.FileWriter.add_summary(summary, global_step=None) #将摘要添加到事件文件
    tf.summary.FileWriter.add_event(event) #向事件文件中添加一个事件
    tf.summary.FileWriter.add_graph(graph, global_step=None, graph_def=None) 
    #向事件文件中添加一个图
    tf.summary.FileWriter.get_logdir() #获取事件文件的路径
    tf.summary.FileWriter.flush() #将所有事件都写入磁盘
    tf.summary.FileWriter.close() #将事件写入磁盘,并关闭文件操作符
    tf.summary.scalar(name, tensor, collections=None) #输出包含单个标量值的摘要
    tf.summary.histogram(name, values, collections=None) #输出包含直方图的摘要
    tf.summary.audio(name, tensor, sample_rate, max_outputs=3,
    collections=None) #输出包含音频的摘要
    tf.summary.image(name, tensor, max_outputs=3, collections= None) #输出包含图片的摘要
    tf.summary.merge(inputs, collections=None, name=None) #合并摘要,包含所有输入摘要的值

(5). 变量作用域 variable_scope示例
name_scope主要是给variable_name或者op_name加前缀name_scope是给op_name加前缀

5、批标准化(BN)

为了克服神经网络层数加深导致难以训练而诞生的,网络深度加深,训练起来会很困难,收敛速度会很慢,会导致梯度弥散问题
用在激活函数之前,对x=Wu+b做规范化,是结果均值为0,方差为1。

6、神经元函数及优化方法

激活函数

TensorFlow 中有如下激活函数,它们定义在tensorflow/python/ops/nn.py 文件中,这里包括平滑非线性的激活函数,如 sigmoid、tanh、elu、softplus 和 softsign,也包括连续但不是处处可微的函数 relu、relu6、crelu 和 relu_x,以及随机正则化函数 dropout。
1. sigmoid 输出映射(0,1),单调连续,适合用于输出层,易求导;软饱和性,落入饱和区,导数会接近于0,易产生梯度消失
2. tanh 也是软饱和性,收敛比sigmoid快,同样无法解决梯度消失问题
3. relu 最受欢迎。解决梯度消失问题,收敛更快,提供神经网络的稀疏表达能力。部分输入落入硬饱和区,导致权重无法更新,神经元死亡。
4. dropout 一个神经元是否被抑制以概率keep_prob决定。

几种激活函数的选择:当输入数据特征相差明显时,用 tanh 的效果会很好,且在循环过程中会不断扩大特征效果并显示出来。当特征相差不明显时,sigmoid 效果比较好。同时,用 sigmoid 和 tanh 作为激活函数时, 需要对输入进行规范化,否则激活后的值全部都进入平坦区,隐层的输出会全部趋同,丧失原有的特征表达。而 relu 会好很多,有时可以不需要输入规范化来避免上述情况。因此,现在大部分的卷积神经网络都采用 relu 作为激活函数。大概有 85%~90%的神经网络会采用 ReLU,10%~15%的神经网络会采用 tanh,尤其用在自然语言处理上。

卷积函数

构建神经网络的重要支架
卷积函数定义在 tensorflow/python/ops 下的 nn_impl.py 和 nn_ops.py 文件中。

tf.nn.convolution(input, filter, padding, strides=None, dilation_rate=None, name=None, data_format=None)
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format= None, name=None)
tf.nn.depthwise_conv2d (input, filter, strides, padding, rate=None, name=None, data_format=None)
tf.nn.separable_conv2d (input, depthwise_filter, pointwise_filter, strides, padding, rate=None, name=None, data_format=None)
tf.nn.atrous_conv2d(value, filters, rate, padding, name=None) tf.nn.conv2d_transpose(value, filter, output_shape, strides, padding='SAME', data_format='NHWC', name=None)
tf.nn.conv1d(value, filters, stride, padding, use_cudnn_on_gpu=None, data_format= None, name=None)
tf.nn.conv3d(input, filter, strides, padding, name=None) tf.nn.conv3d_transpose(value, filter, output_shape, strides, padding='SAME', name=None)

简单积累,使用时再涉及具体用法

池化函数

一般在卷积函数的下一层。

tf.nn.avg_pool(value, ksize, strides, padding, data_format='NHWC', name=None)
tf.nn.max_pool(value, ksize, strides, padding, data_format='NHWC', name=None)
tf.nn.max_pool_with_argmax(input, ksize, strides, padding, Targmax=None, name=None)
tf.nn.avg_pool3d(input, ksize, strides, padding, name=None)
tf.nn.max_pool3d(input, ksize, strides, padding, name=None)
tf.nn.fractional_avg_pool(value, pooling_ratio, pseudo_random=None, overlapping=None,
deterministic=None, seed=None, seed2=None, name=None)
tf.nn.fractional_max_pool(value, pooling_ratio, pseudo_random=None, overlapping=None,
deterministic=None, seed=None, seed2=None, name=None)
tf.nn.pool(input, window_shape, pooling_type, padding, dilation_rate=None, strides=None,
name=None, data_format=None)

池化操作是利用一个矩阵窗口在张量上进行扫描,将每个矩阵窗口中的值通过取最大值或平均值来减少元素个数。每个池化操作矩阵窗口大小是由ksize指定,并且根据步长strides决定移动步长

分类函数

TensorFlow 中常见的分类函数主要有sigmoid_cross_entropy_with_logits、softmax、log_softmax、softmax_cross_entropy_with_logits 等,它们也主要定义在 tensorflow-1.1.0/tensorflow/python/ops 的nn.py 和 nn_ops.py 文件中。

tf.nn.sigmoid_cross_entropy_with_logits(logits, targets, name=None)
tf.nn.softmax(logits, dim=-1, name=None)
tf.nn.log_softmax(logits, dim=-1, name=None)
tf.nn.softmax_cross_entropy_with_logits(logits, labels, dim=-1, name=None)
tf.nn.sparse_softmax_cross_entropy_with_logits(logits, labels, name=None) 

用到时再补充具体用法

优化方法

目前加速训练的优化方法基本都是基于梯度下降的,只是细节上有些差异。梯度下降是求函数极值的一种方法,学习到最后就是求损失函数的极值问题。
TensorFlow提供了很多优化器(optimizer)

class tf.train.GradientDescentOptimizer
class tf.train.AdadeltaOptimizer
class tf.train.AdagradOptimizer
class tf.train.AdagradDAOptimizer
class tf.train.MomentumOptimizer
class tf.train.AdamOptimizer
class tf.train.FtrlOptimizer
class tf.train.RMSPropOptimizer

这 8 个优化器对应 8 种优化方法,分别是梯度下降法(BGD 和 SGD)、Adadelta 法、Adagrad法(Adagrad 和 AdagradDAO)、Momentum 法(Momentum 和 Nesterov Momentum)、Adam、Ftrl 法和 RMSProp 法,其中 BGD、SGD、Momentum 和 Nesterov Momentum 是手动指定学习率的,其余算法能够自动调节学习率。

7、模型存储与加载

TensorFlow 的 API 提供了以下两种方式来存储和加载模型。
(1)生成检查点文件(checkpointfile),扩展名一般为.ckpt,通过在tf.train.Saver对象上调用Saver.save()生成。它包含权重和其他在程序中定义的变量,不包含图结构。如果需要在另一个程序中使用,需要重新创建图形结构,并告诉 TensorFlow 如何处理这些权重。
(2)生成图协议文件(graphprotofile),这是一个二进制文件,扩展名一般为.pb,用tf.train.write_graph()保存,只包含图形结构,不包含权重,然后使用 tf.import_graph_def()来加载图形。

8、队列和线程

TensorFlow 中的其他组件一样,队列(queue)本身也是图中的一个节点,是一种有状态的节点,其他节点,如入队节点(enqueue)和出队节点(dequeue),可以修改它的内容。例如,入队节点可以把新元素插到队列末尾,出队节点可以把队列前面的元素删除。

9、加载数据

TensorFlow 作为符号编程框架,需要先构建数据流图,再读取数据,随后进行模型训练。TensorFlow官方网站给出了以下读取数据 3 种方法。
● 预加载数据(preloaded data):在 TensorFlow 图中定义常量或变量来保存所有数据。
● 填充数据(feeding):Python 产生数据,再把数据填充后端。
● 从文件读取数据(reading from file):从文件中直接读取,让队列管理器从文件中读取数据。

四、小结

TensorFlow的基础知识,包括系统架构、设计理念、基本概念,以及常用的API、神经元函数和神经网络,还介绍了存储与加载模型的方法以及线程和队列的知识(这些内容很有利于在第14章对分布式的理解),最后介绍了自定义操作的方法。本章是最重要的!!!!

点赞