前一节介绍了一些最基本的概念和使用方法。因为我个人的最终目的还是在深度学习上,所以一些深度学习和机器学习模块是必须要了解的,这其中包括了tf.train 、tf.contrib.learn、还有如训练神经网络必备的tf.nn等API。这里准备把常用的API和使用方法按照使用频次进行一个排列,可以当做一个以后使用参考。这一节介绍的内容可以有选择的看。而且最全的信息都在TensorFlow的API里面了,但是里面的方法函数千千万,所以主要都是根据其Python API Guide中的内容所写。
train提供了一系列帮助模型训练类和函数。其内容大致可以分为以下几类:1、Optimizer类(优化器),2、GradientComputation梯度计算,3、Gradient Clipping梯度剪切(截断),4、Decaying thelearning rate学习率降低方法,5、Moving Averages滑动平均,6、Coordinator and QueueRunne协调器和队列运行器, 7、Distributed execution分布执行 8、Training Hooks本意是“钩子”的意思应该是相当于流程控制吧这个可以看知乎这里。上面就是train的几个大类别,但我们真正常用的也并不是所有,这里先记录一下常用的一些类别和其方法。这里有人把所有train函数的使用做了一个汇总,有点多所以还是捡重要的说。
这个是最常用的了,其中包含了一个tf.train.Optimizer的基本的优化类和对应的一些常用的子类,如梯度下降、动量更新等等(常用:GradientDescentOptimizer, AdagradOptimizer, or MomentumOptimizer)。这里有两种使用方法,可以想象的是我们通常流程都是得到一个损失函数-->计算梯度--->得到梯度值-->梯度下降,这里的方法使我们既可以用函数直接得到一个梯度下降的Operation,也可以按照上面的步骤建立多个Operation达到优化的目的。
这里用官方API中的例子,假设已经有了一个损失函数Loss:
# Create an optimizerwith the desired parameters.建立一个梯度下降的Operation
opt =GradientDescentOptimizer(learning_rate=0.1)
# Add Ops to thegraph to minimize a cost by updating a list of variables.
# "cost" isa Tensor, and the list of variables contains tf.Variable
# objects.利用上面的优化器加入一个最小化代价函数的Operation
opt_op =opt.minimize(cost, var_list=
在训练过程中只要run上面的这个opt_op(优化操作)的Operation就可以了。
还可以分开计算,上面是用了minimize()把计算梯度和把梯度应用在变量上两个步骤合在了一起,也可以分成三步做,这主要用在梯度检测上,可以看每一步的梯度计算情况:
# Create anoptimizer.一样需要建立一个优化器
opt =GradientDescentOptimizer(learning_rate=0.1)
# Compute thegradients for a list of variables.计算列表中变量的梯度,注意返回值是一个元组列表
grads_and_vars =opt.compute_gradients(loss, )
# grads_and_vars is alist of tuples (gradient, variable). Dowhatever you
# need to the'gradient' part, for example cap them, etc.把得到的元组列表转换成可用的结构,这个怎么转的不太清楚求指教
capped_grads_and_vars= [(MyCapper(gv[0]), gv[1]) for gv in grads_and_vars]
# Ask the optimizerto apply the capped gradients.
opt.apply_gradients(capped_grads_and_vars)
这里的minimize()和compute_gradients计算还有一些可选项称为Gating Gradients,这个可以控制梯度及计算的方式,默认是GATE_OP也就是对于每个Op确保在这个操作被执行时所有被使用的变量的梯度已经计算好了。更细致的介绍如下:
**GATE_NONE :并行地计算和应用梯度。提供最大化的并行执行,但是会导致有的数据结果没有再现性。比如两个matmul操作的梯度依赖输入值,使用GATE_NONE可能会出现有一个梯度在其他梯度之前便应用到某个输入中,导致出现不可再现的(non-reproducible)结果
**GATE_OP: 对于每个操作Op,确保每一个梯度在使用之前都已经计算完成。这种做法防止了那些具有多个输入,并且梯度计算依赖输入情形中,多输入Ops之间的竞争情况出现。
**GATE_GRAPH: 确保所有的变量对应的所有梯度在他们任何一个被使用前计算完成。该方式具有最低级别的并行化程度,但是对于想要在应用它们任何一个之前处理完所有的梯度计算时很有帮助的。
最常用的优化方法就是上面提到的那些,还有下面这些:
这个一般没必要单独用,因为上面的优化器已经用到了这些函数,大致是计算梯度或hessians的一些函数
用来在图中加入梯度截断,这个主要用于梯度消失或是梯度爆炸的情况,可以增加一些泛化性能增加稀疏性,和nn中的dropout的原理是类似的。这个以后再考虑吧
这个很常用,方法也就这几个看看博客什么的就知道怎么回事了,以指数衰减为例:其计算公式如下
decayed_learning_rate= learning_rate *
decay_rate ^(global_step / decay_steps)
我们需要的就是给定一个递增的变量global_step和一个衰减率decay_rate和一个衰减周期decay_steps。下面以简单的代码为例:
...
global_step =tf.Variable(0, trainable=False)
starter_learning_rate= 0.1
learning_rate =tf.train.exponential_decay(starter_learning_rate, global_step,
100000, 0.96, staircase=True)
# Passing global_stepto minimize() will increment it at each step.
learning_step = (
tf.train.GradientDescentOptimizer(learning_rate)
.minimize(...my loss...,global_step=global_step)
)
这个的意思是在这10000个步骤中每次衰减率为0.96,这里也有一个例子可以参考一下(程序写的一般)。
还有一些滑动平均和并行化的方法,后面用到会在整理。
这个是一些在基本的TensorFlow基础上由第三方开发的一些API,可以看成是一些高等级的TensorFlow库(比如原来的Keras现在就直接包含在这里面了,还有一些传统机器学习用的一些包),里面有很多东西挺有用的不过东西太多了而且有的东西还不是很完善还有很多重复的内容,在TensorFlow的contrib地址有详细介绍,github地址在此。
这里东西很多,都是一些可以简化tensorflow的一些API如:
写着写着突然发现了好多东西其实要直接去github对应的地方去看,那里面介绍的比较清楚。这里tf.contrib.learn(其地址如下),先放下这是不是TFLearn。因为感觉内容比较多,所以决定用单独的章节带着例子介绍这些contrib中的内容。
这里是包括一些神经网络常用的层。
首先提供了一些常用的非线性激活函数,如tf.nn.relu(feature, name=None)输入一个tensor返回一个tensor。可以分为非线性平滑的激活函数(sigmoid,tanh, elu, softplus, and softsign)和不是处处可微的(relu, relu6, crelu and relu_x)。
这里很特殊的把dropout也放在这里面了。还有一个要注意的地方,就是sigmoid和tanh不在这里面,而是直接调用就可以(tf.sigmoid、tf.tanh),还有一个tf.nn.bias_add(value,bias,data_format=None,name=None)也被放到了这个类别里,这个和tf.add很像但是偏差固定是一维的。
这里面针对generic vs. specific filters(普遍和特殊滤波器的权衡)产生了三类不同的卷积方式:
**conv2d: Arbitrary filters that can mixchannels together.任意卷积核同时在不同通道上进行卷积
**depthwise_conv2d:Filters that operate on each channelindependently.卷积核在每个通道上独立工作
**separable_conv2d: A depthwise spatial filterfollowed by a pointwise filter.没懂
上面这三个目前不是很懂。
我们都知道卷积有步长stride参数,这里假设输入的x的维度为[batch,in_height,in_weight,channel]的格式,这里注意TensorFlow的维度是可选的下面介绍函数的时候会介绍到,而且这里定义的stride是四维的因为通常理解的卷积核滑动步长都是二维的在长宽两个维度,这里的height和weight方向的滑动步长由strides[1]和strides[2]两位决定,而其余两位都是0。
还有一个卷积上的问题是padding补零问题。tf.nn的卷积提供了两种不同的补零方法:‘SAME’和‘VALID’,其中valid就是不补零,而且还会截断一些数据防止出现不能滑动的情况(其实可以看成是补零的反面:删数据),而‘SAME’是通过补零使数据恰好能够进行卷积,而且TensorFlow和其他框架不同其他框架定义补零时候上下或补零数量一致的,但在TensorFlow中可出现上下共补5个0(上面2个,下面3个)的情况。不过不知道为什么没有输入输出尺寸相同的那种补零方式。
上面都是笼统的说的,现在用一个例子来分析一下。我们最常用的函数就是tf.nn.conv2d,用于计算给定四维输入和四维卷积核的二维卷积(也就是我们图片上常用的那种)主要构造函数如下:
例子1、tf.nn.conv2d
conv2d(
input,输入数据共四个维度,维度的构成有下面的data_format决定
filter,卷积核四维,维度构成总是[filter_height高, filter_width宽, in_channels输入通道数, out_channels输入通道数]
strides,上面介绍过,是一个int列表长度为4,其维度构成也是由data_format决定的
padding,补零格式
use_cudnn_on_gpu=None,是不是用gpu训练
data_format=None,数据格式
name=None 这个Operation的名字
)
这里说一下data_format这是一个string格式的总共有:"NHWC", "NCHW"两种,其中默认的是"NHWC"也就是数据按照[batch, height, width, channels]的格式输入的,而'NCHW'顾名思义是按照[batch, channels, height, width]输入的。默认情况下输入是[batch, in_height, in_width, in_channels],卷积核是[filter_height, filter_width, in_channels,out_channels]
例2、tf.nn.conv3d
为了和上面的2d作对比,这里举一个conv3d的例子,文档中说Conv3D是一种交叉互相换的形式。
conv3d(
input,输入格式为[batch, in_depth, in_height, in_width, in_channels]
filter,[filter_depth, filter_height,filter_width, in_channels, out_channels]
strides,这里要求strides[0] = strides[4] = 1.和cov2d一样,都有两个是1
padding,
name=None
)
例3、tf.nn.depthwise_conv2d
上面没弄懂的这里详细解释一下。这个和tf.nn.conv2d的区别在于conv2的卷积核的输入通道数与数据的通道数是一样的,也就是每个卷积核同时作用于所有层然后累加得出一个输出层的的结果,而这里的depthwise_conv2d每个卷积核的输入维度是1也就是说不同的卷积核作用在每个输入通道上,按照输入的通道数一层一层处理。更通俗的说就是我们假设有4个输入通道数是1的卷积核,然后把这4个卷积核一层一层的作用在一个3通道的输入数据上,这样就得到了一个12个输出,把这12个输出并起来就可以了。
depthwise_conv2d(
input,设输入是[batch,in_height, in_width, in_channels]
filter,尺寸是[filter_height, filter_width, in_channels, channel_multiplier].
strides,[1, stride, stride, 1]
padding,
rate=None,
name=None,
data_format=None
)
这里有两个图帮助理解,第一个是conv2,第二个是depthwise_conv2d,图片来自一个blog突然找不到了。
(3)反向传播
因为还有反向传播过程,所以还有两个函数用于得到反向传播的结果,但是tensorflow是隐形的进行反向传播,所以这个暂时不用了解
这里定义了一些池化方法,大致有2种:平均池化,最大池化。目前通常用最大池化,tf.nn还提供了带有返回argmax最大值位置的池化方法。以最大池化为例:
max_pool(
value,尺寸如下[batch, height, width, channels],而且要类型为tf.float32
ksize,池化的尺寸也是一个4维的第一位和最后一位为1
strides,
padding,
data_format='NHWC',
name=None
)
这是用在图像预处理上的一种非线性滤波方法,具体原理不是很了解,有机会再看吧。
这个非常重要,是能够让神经元避免出现饱和而且能够增加模型的泛化能力。最简单的是L2-norm,在深度学习图像中用的最多的目前应该是batch_normalization,这里的L2-norm其实就是output = x / sqrt(max(sum(x**2), epsilon))这样一个表达式。因为用的多所以把batch_norm的正则化函数写在这:
batch_normalization(
x,
mean,均值
variance,方差
offset,偏移量
scale,尺度
variance_epsilon,用于避免除零
name=None
)
可以看出这个还要自己输入均值和方差,还是比较麻烦的,均值方差可以用tf.nn.normalize_moments计算,不过还是后面直接用API比较好。
Loss用于计算两个tensor之间的误差,这里的损失是指的回归中会用到的,只有两个:L2损失output = sum(t ** 2) / 2(不过不知道为什么只有一个输入,这个有点没用),还有一个是tf.nn.log_poisson_loss计算泊松损失,这个不是很了解,不过这个需要输入的确实是两个tensor并计算一种损失。
这里面都是一些分类需要用到的损失函数。
(1) 首先第一个就是tf.nn.softmax,这个就是计算一个tensor的softmax输出,输入为[batchsize,feature],输出为[batchsize,num_classes]
(2) 这里重点介绍一下tf.nn.softmax_cross_entropy_with_logits,计算logits和labels之间的softmax cross entropy。
softmax_cross_entropy_with_logits(
_sentinel=None,
labels=None,logits:就是神经网络最后一层的输出,如果有batch的话,它的大小就是[batchsize,num_classes],单样本的话,大小就是num_classes
logits=None,logits:labels:实际的标签,和logits的尺寸相同
dim=-1,
name=None
)
这里简单的说一下计算流程,首先根据权重得到softmax的输出值,然后计算softmax输出值与真实标签之间的交叉熵误差,具体公式见这里。
(3)还有计算logsoftmax的函数tf.nn.log_softmax
计算公式为logsoftmax = logits -log(reduce_sum(exp(logits), dim)) ,这里的reduce_sum()是求和的operat。
很常用这里其实是提供的一个lookup embedding的函数tf.nn.embedding_lookup,函数的用法主要是选取一个张量里面索引对应的元素。具体的内容可以百度一下。
还有一些其他的内容:
(1)Recurrent Neural Networks 提供了几个方法用于帮助rnn构建,需要结合tf.contrib.rnn
(2)Connectionist Temporal Classification:这个主要用在Seq2Seq的问题通常结合LSTM+CTC,这里有个介绍
(3)Evaluation:用于估计网络的性能,包括两个方法:tf.nn.top_k(计算前k个最大值)和tf.nn.in_top_k(判断目标是不是前k个值中的一个)
(4)Candidate Sampling:这是一种采样方法,具体的含义见这里,主要用在语义及相关分析上