Tensorflow学习笔记(三)

经过前两节,已经大致了解了tensorflow的基本思想和一些基础的计算API,本节我们将以深度神经网络为例,深度剖析tensorflow的使用技巧。

神经网络层结构

如果一个样本包含维,即,其标签为,我们希望建立一个神经网络,通过来预测其标签,以一个多层全连接的神经网络为例,其每层变换定义方式如下:
\begin{align} {\bf x}_{layer1}&=f_1({\bf w}_1{\bf x}+{\bf b}_1)\\ {\bf x}_{layer2}&=f_2({\bf w}_2{\bf x}_{layer1}+{\bf b}_2)\\ \vdots\\ {\bf x}_{layer(k)}&=f_2({\bf w}_k{\bf x}_{layer(k-1)}+{\bf b}_k) \end{align}
其中是第隐层的待学习的权重矩阵,其中表示第层输出向量的维度,同时它又是第层输入向量的维度。特别地,输入样本层的维度为。由于线性分类器在面对一些复杂的分类任务时表达能力不够,所以神经网络引入了非线性变换(通常是元素级的操作,即对向量的每个元素取函数值),常使用的非线性变换包括sigmoid函数、tanh函数和relu函数。
于是可以撰写如下代码:

import tensorflow as tf
input = tf.constant([0.3,0.5,0.7,0.2])
w1 = tf.Variable(tf.random_normal(shape=[4,3], stddev=0.1),name='w1')
biases1 = tf.Variable(tf.random_normal(shape=[1,3], stddev=0.1),name='1')
w1 = tf.Variable(tf.random_normal(shape=[3,5], stddev=0.1),name='w1')
biases1 = tf.Variable(tf.random_normal(shape=[1,5], stddev=0.1),name='1')
x1 = tf.nn.relu(tf.matmul(x, w1)+biases1)
x2 = tf.nn.relu(tf.matmul(x1, w2)+biases2)

上面代码中将得到x1是一个3维行向量,x2时一个5维行向量,即通过两层变换,原来的输入x从4维行向量变成了5维行向量。如果有多个输入(即一个batch),则x为维张量,输出x2则变为维张量(由于加法的向量列可以自动维度展开适应,所以不用改代码)。

损失函数

在上一步得到x2之后,我们得到了样本x的一个新的表达,现在需要建立一个损失函数(loss function)来刻画这个表达的合理性,loss函数是x2和样本标签y的函数,那么根据是分类任务还是回归任务可以定义不同损失函数:

  1. 分类任务的交叉熵损失函数
    对于分类任务来说,如果一个样本属于第类(共类),则其标签为,为第个元素为而其余元素为的单位向量。
    在定义交叉熵之前,需要将神经网络输出的x2之后再加入称为softmax的一层,其将x2转为维非负向量,且所有元素相加为,其本质是将x2映射为其为个类分别的概率。首先将x2采用线性变换映射为维向量,然后使用softmax函数得到概率分布

    当转化为概率后,我们使用交叉熵来定义其损失函数。可以证明最小化交叉熵等价于极大似然估计。对于两个分布p,q,其交叉熵定义为

    于是对于一个样本的输出和其向量化的标签(若第类则其余为0),其交叉熵为

    于是在tensorflow中可以使用如下代码计算交叉熵
import tensorflow as tf
## 该函数输出softmax化后的概率向量
def soft_max(tensor):
    ##这一步将所有z_i同时减去最大的,方式指数运算溢出
    minus_maximum = tensor - tf.reduce_max(tensor)
    return tf.exp(minus_maximum)/tf.reduce_sum(tf.exp(minus_maximum))

def cross_entropy(_y, y):
     ##计算交叉熵: _y是softmax输出层的向量,y是标签向量
     return -tf.reduce_sum(y*tf.log(tf.clip_by_value(_y, 1e-10, 1)))

z = tf.constant([1, 0.5, 2]) ##设z为神经网络softmax层的输入
y = tf.constant([0,0,1]) ##设y为样本对应的标签向量,属于第3类
tf.InteractiveSession()
print('softmax layer output is:', soft_max(w).eval())
print('cross entropy is:', cross_entropy(soft_max(w), y).eval())
----------
>>softmax layer output is: [0.2312239  0.14024438 0.6285317 ]
>>cross entropy is: 0.10.4643688

实际上,在tensorflow中,这一类交叉熵以及softmax函数都不用自己写,有可供使用的api在tf.nn中,只需要简单的一行代码

cross_entropy = tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=w)
  1. 回归和自定义损失函数
    回归常用最小均方误差,代码也很简单
mse = tf.reduce_mean(tf.square(y_ - y))

同样我们还可以自定义其他的损失函数,比如我们希望当小于标签的时候惩罚为,大于惩罚为,那么如下代码可以实现该损失函数

v1 = tf.constant([2.0, 3, 4])  ##value
v2 = tf.constant([2.4, 2.5, 5]) ##label
loss = tf.reduce_sum(tf.where(tf.greater(v1, v2), (v1-v2)*2, (v2-v1)*3))
  1. 引入正则项Regularizer
    如果引入正则项,其中是训练参数,可以使用如下代码
loss_with_regularizer=loss+tf.contrib.layers.l2_regularizer(lambda)(w)
  1. 使用collection来构建带正则项的损失函数
    在简单的神经网络中,3中的方式就可以很好滴计算正则化的损失函数了,但是当神经网络的层数增多时,每一层都会有一个w,这样方式就可能导致loss的定义很长,可读性差。更主要的是,当网络结构复杂之后定义网络结构的部分和计算损失函数的的部分可能不在同一个函数中,这样通过变量这种方式来计算损失函数就不方便了。为了解决这个问题,可以使用TensorFlow提供的集合(collection)。
import tensorflow as tf

def get_weight(shape, lambda):
    var = tf.Variable(tf.random_normal(shape), dtype=tf.float32)
    tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(lambda)(var))
    return var

x = tf.placeholder(tf.float32, shape=[None, 2])
y_ = tf.placeholder(tf.float32, shape=[None, 1])
batch_size = 8
layer_dimension = [2, 10, 10, 10, 1]
n_layers = len(layer_dimension)

cur_layer = x
in_dimension = layer_dimension[0]

for i in range(1, n_layers):
    out_dimension = layer_dimension[I]
    weight = get_weight([in_dimension, outdimension], 0.001)
    bias = tf.Variable(tf.constant(0.1, shape=[out_dimension]))
    cur_layer = tf.nn.relu(tf.matmul(cur_layer, weight) + bias)
    in_dimension = layer_dimension[I]

mes_loss= tf.reduce_mean(tf.square(y_-cur_layer))
tf.add_to_collection('losses', mes_loss)
loss = tf.add_n(tf.get_collection('losses'))

训练: 优化算法

在前面已经定义了网络结构和输出的损失函数,现在的目标是希望通过迭代来逐渐更新参数来减小损失函数。在深度学习中最常用的优化算法是随机梯度下降(SGD),但其有一些变种,比如说Nesterov和Momenta,另外步长的调节也有讲究,也有一些自适应步长算法如ADAM和RMSProp算法。值得庆幸的是,常用的优化器tensorflow都提供了api,而且传入损失函数能够实现自动求导(自动进行反向传播算法)。本节先介绍如何使用内置的优化算法,自定义的优化算法(如果有空)将在后续研究介绍。tf.train里面包括很多优化器,其中Optimizer是一个基类,在此之上定义了很多个优化器

基类Optimizer (learning rate, ...params)
GradientDescentOptimizer
AdagradOptimizer
AdagradDAOptimizer
MomentumOptimizer
AdamOptimizer
FtrlOptimizer
RMSPropOptimizer

  • 定义衰减学习率
decayed_learning_rate =\
learning_rate*decay_rate^(global_step/deca_steps)

也可以使用tf.train自带的指数衰减步长

global_step = tf.Variable(0, trainable=False)
learning_rate = tf.train.exponential_decay(0.1, global_step, 100, 0.96, staircase = True)
  • 进行一次训练迭代
learning_step = tf.train.GradientDescentOptimizer(learning_rate)\
.minimize(...my loss..., global_step = global_step)

滑动平均模型

ExponentialMovingEverage,通过引入影子变量,使得在开始的时候鼓励模型更新,而在之后不鼓励更新,防止噪声干扰。具体应用见下一节。

你可能感兴趣的:(Tensorflow学习笔记(三))