TensorFlow实现多层感知机

多层感知机简介

  多层感知机(Multilayer PerceptronMLP)也叫做人工神经网络(Artificial Neural NetworkANN),除了输入和输出层,它中间可以有多个隐层。最简单的MLP只含一个隐层,即三层的结构,如下图所示。可以看到,多层感知机层与层之间是全连接的(全连接是指上一层的任何一个神经元与下一层的所有神经元都有连接)。单层感知器只能学习线性函数,而多层感知器也可以学习非线性函数。

在这里插入图片描述

  Softmax回归可以算是多分类问题logistic回归,它和神经网络的最大区别是没有隐含层。理论上只要隐含节点足够多,即使只有一个隐含层的神经网络也可以拟合任意函数;同时,隐含层数越多,越容易拟合复杂结构。为了拟合复杂函数,需要的隐含节点的数目基本上随着隐含层的数量增多呈指数下降的趋势,也就是说层数越多,神经网络所需要的隐含节点可以越少。层数越深,概念越抽象,需要背诵的知识点就越少。在实际应用中,深层神经网络会遇到许多困难,如过拟合、参数调试、梯度弥散等。
  参数调试问题尤其是SGD(StochasticGradient Descent)的参数,对SGD设置不同的学习率,最后得到的结果可能差异巨大。神经网络的优化通常不是一个简单的凸优化问题,它处处充满了局部最优。有理论表示,神经网络可能有很多个局部最优解都可以达到比较好的分类效果,而全局最优很可能造成过拟合。对于SGD,我们希望一开始学习率大一些,加速收敛,在训练的后期又希望学习率小一些,这样可以低速进入一个局部最优解。不同的机器学习问题的学习率设置也需要针对性的调试,像AdagradAdamAdadelta等自适应的方法可以减轻调试参数的负担。对于这些优化算法,通常我们使用其默认的参数设置就可以得到比较好的效果。
  梯度弥散(Gradient Vanishment)是另一个影响深层神经网络训练的问题,在ReLU激活函数出现之前,神经网络训练是使用Sigmoid作为激活函数。非线性的Sigmoid函数在信号的特征空间映射上,对中央区的信号增益较大,对两侧区的信号增益小。当神经网络层数较多时,Sigmoid函数在反向传播中梯度值会逐渐减小,到达前面几层的梯度值就变得非常小了,在神经网络训练的时候,前面几层的神经网络参数几乎得不到训练更新。直到ReLU(y = max(0, x))的出现才比较完美地解决了梯度弥散的问题。信号在超过某个阈值时,神经元才会进入兴奋和激活的状态,否则会处于抑制状态。ReLU可以很好地反向传递梯度,经过多层的梯度反向传播,梯度依旧不会大幅减小,因此非常适合深层神经网络的训练。ReLU对比于Sigmoid的主要特点有以下几点:

  • 单侧抑制。
  • 相对宽阔的兴奋边界。
  • 稀疏激活性。

  目前,ReLU及其变种EIUPReLURReLU已经成为最主流的激活函数。实践中大部分情况下(包括MLPCNNRNN)将隐含层的激活函数从Sigmoid替换为ReLU都可以带来训练速度和模型准确率的提升。当然神经网络的输出层一般都是Sigmoid函数,因为它最接近概率输出分布。

在这里插入图片描述

TensorFlow实现多层感知机

  在TensorFlow上实现的Softmax回归模型对MNIST数据集取得了92%的正确率,现在我们给神经网络加上一层隐含层,并使用减轻过拟合的Dropout、自适应学习率的Adagrad以及解决梯度弥散问题激活函数ReLU
  首先载入TensorFlow并加载MNIST数据集,创建一个TensorFlow默认的Interactive Session

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
sess = tf.InteractiveSession()

  接下来我们要给隐藏层的参数设置Variable并进行初始化,指定输入节点数in_units和隐含层节点数h1_units。初始化隐含层的权重W1和偏置b1,我们将偏置全部赋值为0,并将权重初始化为截断的正态分布,其标准差为0.1,这一步可以通过tf.truncated_normal实现。因为模型使用的激活函数是ReLU,需要使用正态分布对W1进行初始化,给权重参数增加一些噪声来打破完全对称,并且避免0梯度。在其它一些模型中,有时还需要给偏置初始化一些非零初始值来避免dead neuron(死亡神经元)。对于输出层Softmax,直接将权重W2和偏置b2全部初始化为0即可:

in_units = 784
h1_units = 300

# 对于ReLU激活函数,常用截断正态分布,避免0梯度和完全对称。
# 对于Softmax分类(也就是sigmoid激活),由于对0附近最敏感,所以采用全0初始权重
W1 = tf.Variable(tf.truncated_normal([in_units, h1_units], stddev=0.1))
b1 = tf.Variable(tf.zeros([h1_units], dtype=tf.float32))
W2 = tf.Variable(tf.zeros([h1_units, 10], dtype=tf.float32))
b2 = tf.Variable(tf.zeros([10], dtype=tf.float32))

  接下来为输入x设置placeholder,并为不同的Dropout设置一个输入placeholder,通常在训练时小于1,预测时等于1,所以也把Dropout的比率作为计算图的输入,并定义成一个placeholder

x = tf.placeholder(tf.float32, [None, in_units])
keep_prob = tf.placeholder(tf.float32)

  下面定义模型结构,首先定义一个隐含层hidden1,通过tf.nn.relu(tf.matmul(x, W1) + b1)实现一个激活函数为ReLU的隐含层,这个隐含层的计算公式就是y = relu(W1 * x + b1)。接下来调用tf.nn.dropout实现Dropout功能,随机将一部分神经元节点置为0,这里的keep_prob参数是保留的数据比例而不是置为0的比例,在训练的时候应该是小于1,用以制造随机性,防止过拟合;在预测的时候应该等于1,即全部特征用来预测样本的类别。最后是输出层,也就是softmax

hidden1 = tf.nn.relu(tf.add(tf.matmul(x, W1), b1))
hidden1_drop = tf.nn.dropout(hidden1, keep_prob)
y = tf.nn.softmax(tf.add(tf.matmul(hidden1_drop, W2), b2))

  在优化器选择上,我们选择Adagrad并把学习率设置为0.3,直接使用tf.train.AdagradOptimizer(0.3)就可以了:

y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), axis=1))
train_step = tf.train.AdagradOptimizer(0.3).minimize(cross_entropy)

  训练步骤如下,这里加入keep_prob作为计算图的输入,并且在训练时设为0.75,即保留75%的节点,其余的25%置为0

correct_prediction = tf.equal(tf.argmax(y, axis=1), tf.argmax(y_, axis=1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

tf.global_variables_initializer().run()

for i in range(3000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    train_step.run({x: batch_xs, y_: batch_ys, keep_prob: 0.75})

    if i % 100 == 0:
        print('当前迭代次数{0},当前准确率{1:.3f}'.format(i, accuracy.eval({x: batch_xs, y_: batch_ys, keep_prob: 1.0})))

print(accuracy.eval({x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

最终在测试集上可以得到98%的准确率。
  没有隐含层的Softmax Regression只能直接从图像的像素点推断是哪个数字,而没有特征抽象的过程。多层神经网络依靠隐含层,则可以组合出高阶特征,比如横线、竖线、圆圈等,之后可以将这些高阶特征或者说组件再组合成数字,就能实现精准的匹配和分类。隐含层输出的高阶特征经常是可以复用的,所以每一类的判别、概率输出都共享这些高阶特征,而不是各自连接独立的高阶特征。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值