TensorFlow学习笔记(4)——深层神经网络

1 深度学习与深层神经网络

维基百科对深度学习的精确定义为“一类通过多层非线性变换对高复杂性数据建模算法的合集”。可见深度学习的两个重要特性:多层和非线性。

1 非线性模型的局限性

一个线性模型中通过输入得到输出的函数被称为一个线性变换,线性模型的最大特点是任意线性模型的组合仍是线性模型。而前向传播算法完全符合其定义。因此只通过线性变换,任意层的全连接神经网络和单层神经网络的表达能力没有任何区别,且都是线性模型,而线性模型能解决的问题太有限,只能解决线性可分问题。

2 激活函数实现去线性化

如果将每个神经元(节点)的输出通过一个非线性函数,那么整个网络的模型就不再是线性的了。这个非线性函数就是激活函数。
TF目前提供7种非线性激活函数,包括tf.nn.relu、tf.sigmoid、tf.tanh是其中比较常用的几个。同时支持使用自己定义的激活函数。

3 多层网络解决异或运算

加入隐藏层后,异或问题可以得到很好的解决。这个特征对于不易提取特征向量的问题有很大帮助。

2 损失函数定义

神经网络模型的效果和优化目标是通过损失函数(loss function)来定义的。

1 经典损失函数

交叉熵是判断一个输出向量和期望向量距离的评判方法之一。交叉熵刻画的是两个概率分布之间的距离。
1.分类问题->输出n个结点->交叉熵,原来的神经网络输出被当做置信度生成新的输出,其满足概率分布的所有要求,用交叉熵计算预测的概率分布和真实答案的概率分布之间的距离
2.回归问题(预测)->1个结点->均方误差
此外,还可以根据问题来自定义损失函数,总之损失函数是希望答案朝着正确的方向发展,所以如果偏离某一方向,可以给其更大的惩罚,这样会使得得到的值离期望的答案更近。不同的损失函数对于相同的神经网络产生重要影响。

3 神经网络优化算法

梯度下降算法主要用于优化单个参数的取值,而反向传播算法给出了一个高效的方式在所有参数上使用梯度下降算法。这里只介绍基本概念和主要思想略去数学推导和证明。
要寻找使J(A)最小的A,目前没有通用方法对任意损失函数直接求解最佳的参数取值,梯度下降算法迭代更新参数A,不断沿着梯度的反方向让参数朝着总损失更小的方向更新。
参数更新的公式为:
An+1=AnηJ(An)An
其中,η是学习率,就是每次更新的幅度。
一般随机生成参数的初始值。

神经网络的优化过程分两个阶段,第一个阶段,先通过前向传播得到预测值,再和真实值比较,得到差距;第二个阶段用反向传播算法计算损失函数对每一个参数的梯度,再根据梯度和学习率使用梯度下降算法更新每一个参数。

注意:
梯度下降算法不能保证全局最优解,参数的初始值很大程度上影响最后的结果。只有当损失函数为凸函数时才能保证全局最优解。
还有一个问题是梯度下降算法计算时间过长,因此采用随机梯度下降算法,每次计算一个batch的数据,保证该batch的均值约等于总体的均值更好。

4 进一步优化

1 学习率的设置

学习率决定了参数每次更新的幅度。幅度过大会导致参数在极优值两侧来回波动。既不能过大也不能过小。TF提供了灵活的学习率设置方法——指数衰减法。可以先使用较大的学习率快速得到一个比较优的解,随着迭代的继续逐步减小学习率,使得模型在训练后期更加稳定。

2 过拟合问题

我们想让模型尽可能对未知数据进行判断而不是尽量模拟训练数据的行为。
过拟合指的是,一个模型过为复杂后,他可以很好的记忆每一个训练数据中随机噪音的部分而忘记了要去学习训练数据中通用的趋势。对于未知数据的判断很差。避免过拟合问题可以采用正则化。
正则化的思想是在损失函数中加入刻画模型复杂程度的指标。
假设优化的损失函数为J(A),则优化时不是直接优化J(A),而是优化J(A)+λR(w)。R(w)刻画的是模型的复杂程度,而λ表示模型复杂损失在总损失中的比例。A表示所有参数,包括权重w和偏置b。一般来说模型复杂度只有w决定。
L1正则化:

R(w)=w1=iwi

L2正则化:
R(w)=w22=iw2i

基本思想都是希望通过限制权重大小使模型不能任意你和训练数据中的随机噪音。
区别:
L1会让参数变得稀疏。L2不会。
L1计算公式不可导,L2可导。
实践中可以同时使用:
R(w)=iαwi+(1α)w2i

TF支持优化带正则项的损失函数。

3滑动平均模型

使得模型在测试数据中更健壮。
TF中提供了tf.train.ExponentialMovingAverage来实现滑动平均模型。
初始化ExponentialMovingAverage时,需要提供一个衰减率decay,用于控制模型更新的速度。越大模型越稳定。
ExponentialMovingAverage对于每个变量会维护一个影子变量,这个影子变量的初始值就是相应变量的初始值,每次变量更新,影子变量的值会更新为:

shadow_variable=decay×shadow_variable+(1decay)×variable

附:神经网络样例程序解决二分类问题

import tensorflow as tf
from numpy.random import RandomState

# 定义训练数据batch的大小
batch_size = 8

# 定义神经网络的参数
w1 = tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2 = tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))

# 在shape的一个维度上使用None可以方便使用不同的batch大小
x = tf.placeholder(tf.float32,shape=(None,2),name='x-input')
y_ = tf.placeholder(tf.float32,shape=(None,1),name='y-input')

# 定义神经网络前向传播的过程
a = tf.matmul(x,w1)
y = tf.matmul(a,w2)

# 定义损失函数和反响传播算法
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y,1e-10,1.0)))
train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)

# 通过随机数生成一个模拟数据集
rdm = RandomState(1)
dataset_size = 128
X = rdm.rand(dataset_size,2)

# 定义规则来给出样本的标签,x1+x2<1的样例都被认为是正样本,其他为负样本,0:负样本,1:正样本
Y = [[int(x1+x2<1)] for (x1,x2) in X]
# 创建一个会话来运行TensorFlow程序
with tf.Session() as sess:
    # 初始化变量
    init_op = tf.global_variables_initializer()
    sess.run(init_op)

    print(sess.run(w1))
    print(sess.run(w2))

    # 设定训练的轮数
    STEPS = 5000

    for i in range(STEPS):
        # 每次选取batch_size 个样本进行训练
        start = (i * batch_size)% dataset_size
        end = min(start+batch_size,dataset_size)

        # 通过选取的样本训练神经网络并更新参数
        sess.run(train_step,feed_dict={x:X[start:end],y_:Y[start:end]})
        if i % 1000 == 0:
            total_cross_entropy = sess.run(cross_entropy,feed_dict={x:X,y_:Y})
            print("After %d trainint step(s),cross entropy on all data is %g" % (i,total_cross_entropy))

    print(sess.run(w1))
    print(sess.run(w2))

没有更多推荐了,返回首页