您的位置:首页 > 其它

TensorFlow技术解析与实战 4 基础知识

2017-12-14 19:51 731 查看

4.1 系统架构

     自底向上分为设备层和网络层、数据操作层、图计算层、API层、应用层。



4.2 设计理念

(1)将图的定义和图的运行完全分开。

         编程模式通常分为命令式编程和符号式编程。命令式编程是编写我们理解的通常意义上的程序,很容易理解和调试,按照原有逻辑执行。符号式编程涉及很多的嵌入和优化,不容易理解和调试,但运行速度相对有所提升。现有的深度学习框架中,Torch是典型的命令式的,Caffe、MXNet采用了两种编程模式混合的方法,而TensorFlow完全采用符号式编程。

       符号式计算一般是先定义各种变量,然后建立一个数据流图,在数据流图中规定各个变量之间的计算关系,最后需要对数据流图进行编译,但此时的数据流图还是一个空壳儿,里面没有任何实际数据,只有把需要运算的输入放进去后,才能在整个模型中形成数据流,从而形成输出值。

import tensorflow as tf
t = tf.add(8, 9)
print(t) # 输出 Tensor("Add _ 1:0", shape=(), dtype=int32)
add并没有执行,实际上对应的是Tensorflow API中的一个操作,数据流图中的节点。

(2)TensorFlow中涉及的运算都要放在图中,而图的运行只发生在会话(session)中。开启会话后,就可以用数据去填充节点,进行运算;关闭会话后,就不能进行计算了。因此,会话提供了操作运行和Tensor求值的环境。

import tensorflow as tf
#创建图
a= tf.constant([1.0, 2.0])
b= tf.constant([3.0, 4.0])
c= a * b
# 创建会话
sess = tf.Session()
# 计算 c
print sess.run(c) # 进行矩阵乘法,输出 [3., 8.]
sess.close()


4.3 编程模型

      TensorFlow是用数据流图做计算的,先创建一个数据流图(也称为网络结构图)

      顾名思义,TensorFlow是指”张量的流动“,Tensorflow的数据流图是有节点(node)和边(edge)组成的有向无环图(DAG)

      边有两种连接关系:数据依赖和控制依赖。其中,实线边表示数据依赖,代表数据,即张量(任意维度的数据统称为张量)。虚线称为控制依赖,可以用于控制操作的运行,这被用来确保happens-before关系,这类边上没有数据流过,但源节点必须在目的节点开始执行前完成执行。



     节点又称为算子,它代表一个操作(operation,OP)



     图:把操作任务描述成有向无环图

     会话:启动图的第一步是创建一个Session对象。run()执行图时,传入一些Tensor,这个过程叫填充,返回叫取回。

     设备:指一块用来运算并且拥有自己的地址空间的硬件,如GPU和CPU

with tf.Session() as sess:
# 指定在第二个 gpu 上运行
with tf.device("/gpu:1"):
matrix1 = tf.constant([[3., 3.]])
matrix2 = tf.constant([[2.],[2.]])
product = tf.matmul(matrix1, matrix2)
       变量:一种特殊的数据,它在图中有固定的位置,不像普通张量那样可以流动。tf.placeholder()临时替代任意操作的张量。

       内核:能够运行在特定设备(如CPU、GPU)上的一种对操作的实现。因此,同一个操作可能会对应多个内核。

4.4 常用API

       图、操作和张量


         




   



可视化



 

 

4.5 变量作用域

      有两个作用域,一个是name_scope,另一个是variable_scope。它们究竟有什么区别呢?

              获得变量作用域

              变量作用域的初始化

4.6 批标准化

      为了克服神经网络层数加深导致难以训练而诞生的。DNN随着网络加深,训练起来会越来越困难,收敛速度会很慢,常常会导致梯度弥散问题。

      统计机器学习中有一个ICS(Internal Covariate Shift)理论,这是一个经典假设:源域和目标域的数据分布是一致的。也就是说,训练数据和测试数据是满足相同分布的。这是通过训练数据获得的模型能够在测试集获得好的效果的一个基本保障。

      Covariate Shift是指训练集的样本数据和目标样本集分布不一致时,训练得到的模型无法很好地泛化。它是分布不一致假设之下的一个分支问题,也就是指源域和目标域的条件概率是一致的,但是其边缘概率不同。的确,对于神经网络的各层输出,在经过了层内操作后,各层输出分布就会与对应的输入信号分布不同,而且差异会随着网络深度增大而加大,但是每一层所指向的样本标记仍然是不变的。

       解决思路一般是根据训练样本和目标样本的比例对训练样本做一个矫正。因此,通过引入批标准化来规划化某些层或者所有层的输入,从而固定每层输入信号的均值与方差。

       方法:批标准化一般用在非线性映射(激活函数)之前,对x=Wu+b做规范化,使结果(输出信号各个维度)的均值为0,方差为1。让每一层的输入有一个稳定的分布会有利于网络的训练。

       优点:批标准化通过规范化让激活函数分布在线性区间,结果就是加大了梯度,让模型更加大胆地进行梯度下降,于是有如下优点:加大探索的步长,加快收敛的速度;更容易跳出局部最小值;破坏原来的数据分布,一定程度上缓解过拟合。

       因此,在遇到神经网络收敛速度很慢或梯度爆炸等无法训练的情况下,都可以尝试用批标准化来解决。

Wx _ plus _ b = tf.nn.batch _ normalization(Wx _ plus _ b, fc _ mean, fc _ var, shift, scale, epsilon)

# 也就是在做:

# Wx _ plus _ b = (Wx _ plus _ b - fc _ mean) / tf.sqrt(fc _ var + 0.001)

# Wx _ plus _ b = Wx _ plus _ b * scale + shift

4.7 神经元函数及优化方法

    务必把本届介绍的常用API记熟。

激活函数:它们定义在 tensorflow-1.1.0/tensorflow/python/ops/nn.py

tf.nn.relu()

tf.nn.sigmoid()

tf.nn.tanh()

tf.nn.elu()

tf.nn.bias _ add()

tf.nn.crelu()

tf.nn.relu6()

tf.nn.softplus()

tf.nn.softsign()

tf.nn.dropout() # 防止过拟合,用来舍弃某些神经元

卷积函数:定义在 tensorflow-1.1.0/tensorflow/python/ops 下的 nn_impl.py 和 nn_ops.py 文件中

计算N维卷积的和:

tf.nn.convolution(input, filter, padding, strides=None, dilation _ rate=None, name=None, data _ format=None)

对一个四维的输入数据input和四维的卷积核filter进行操作,然后对输入数据进行一个二维的卷积操作,最后得到卷积之后的结果:

tf.nn.conv2d(input, filter, strides, padding, use _ cudnn _ on _ gpu=None, data _ format= None, name=None)

张量的数据维度是[batch, in_height, in_width, in_channels],卷积核的维度是[filter_height, filter_width, in_channels, channel_multiplier],在通道 in_channels 上面的卷积深度是1,depthwise_conv2d 函数将不同的卷积核独立地应用在 in_channels 的每个通道上(从通道 1到通道 channel_multiplier),然后把所以的结果进行汇总。最后输出通道的总数是 in_channels
* channel_multiplie

tf.nn.depthwise _ conv2d (input, filter, strides, padding, rate=None, name=None, data _ format=None)

用几个分离的卷积核去做卷积。在这个 API 中,将应用一个二维的卷积核,在每个通道上,以深度 channel_multiplier 进行卷积

tf.nn.separable _ conv2d (input, depthwise _ filter, pointwise _ filter, strides, padding, rate=None, name=None, data _ format=None)

计算 Atrous 卷积,又称孔卷积或者扩张卷积

tf.nn.atrous _ conv2d(value, filters, rate, padding, name=None)

在解卷积网络(deconvolutional network)中有时称为“反卷积”,但实际上是 conv2d的转置,而不是实际的反卷积。

tf.nn.conv2d _ transpose(value, filter, output _ shape, strides, padding='SAME', data _ format='NHWC', name=None)

和二维卷积类似。这个函数是用来计算给定三维的输入和过滤器的情况下的一维卷积。不同的是,它的输入是三维,如[batch, in_width, in_channels]。卷积核的维度也是三维,少了一维 filter_height,如 [filter_width, in_channels, out_channels]。stride 是一个正整数,代表卷积核向右移动每一步的长度。

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)

池化函数:定义在 tensorflow-1.1.0/tensorflow/python/ops 下的 nn.py 和 gen_nn_ops.py

计算池化区域中元素的平均值

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)

执行一个 N 维的池化操作

tf.nn.pool(input, window _ shape, pooling _ type, padding, dilation _ rate=None, strides=None, name=None, data _ format=None)

分类函数:定义在 tensorflow-1.1.0/tensorflow/python/ops 的nn.py 和 nn_ops.py 文件

这个函数的输入要格外注意,如果采用此函数作为损失函数,在神经网络的最后一层不需要进行 sigmoid 运算

tf.nn.sigmoid _ cross _ entropy _ with _ logits(logits, targets, name=None)

计算 Softmax 激活

tf.nn.softmax(logits, dim=-1, name=None)

计算 log softmax 激活

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)

优化方法:目前基本都是基于梯度下降的

tf.train.GradientDescentOptimizer

tf.train.AdadeltaOptimizer

tf.train.AdagradOptimizer

tf.train.AdagradDAOptimizer

tf.train.MomentumOptimizer

tf.train.AdamOptimizer

tf.train.FtrlOptimizer

tf.train.RMSPropOptimizer

想要更深入研究各种优化方法,可以参参《An overview of gradient descent optimization algorithms》

4.8 模型的存储与加载:

      提供了以下两种方式来存储和加载模型

(1)生成检查点文件(checkpoint file),扩展名一般为.ckpt,通过在 tf.train.Saver 对象上调用 Saver.save()生成。它包含权重和其他在程序中定义的变量,不包含图结构。如果需要在另一个程序中使用,需要重新创建图形结构,并告诉 TensorFlow 如何处理这些权重。

(2)生成图协议文件(graph proto file),这是一个二进制文件,扩展名一般为.pb,用tf.train.write_graph()保存,只包含图形结构,不包含权重,然后使用 tf.import_graph_def()来加载图形。

4.9 队列和线程

     P100

4.10 加载数据

     tensorFlow作为符号编程框架,需要先构建数据流图,再读取数据,随后进行模型训练。

TensorFlow 官方网站给出了以下读取数据 3 种方法 。

     ● 预加载数据(preloaded data):在 TensorFlow 图中定义常量或变量来保存所有数据。

     ● 填充数据(feeding):Python 产生数据,再把数据填充后端。

     ● 从文件读取数据(reading from file):从文件中直接读取,让队列管理器从文件中读取数据。

4.11 实现一个自定义操作

     
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: