TensorFlow实现多层感知机

一、感知机的简介

前面我们实现了一个softmax regression,也可以说是一个多分类问题的logistic regression。它和传统意义上的神经网络最大的区别就是没有隐藏层。在一个神经网络中,包含输入层、隐含层和输出层。隐含层是模型的黑箱部分,不被显露出来。有了隐含层,隐含层就有了一些特殊的属性,比如引入非线性的隐含层后,理论上只要隐含节点足够多,即使只有一个隐含层的神经网络也可以拟合任意函数。隐含层越多,越容易拟合复杂函数。基本上想要拟合一个复杂的函数,隐含节点的数目,随着隐含层数量的增多呈指数下降趋势,也就是说层数越多,神经网络所需要的隐含节点可以越少。但是在实际应用中,使用层数较深的网络遇到很多困难,比如容易过拟合,参数难以调试,梯度弥散等等。

过拟合是机器学习中一个常见的问题,它是指模型预测准确率在训练集上升高,但是在测试集上反而下降了,这意味着模型的泛化性不好,模型只是记住了当前数据的特征,不具备推广能力。我们可以使用“dropout”来解决过拟合的问题。这事Hinton教授团队提出的一个方法,基本思路是在训练神经网络时,将神经网络的某一层的输出节点数据随机丢失一部分。相当于把一个图片的部分点删除掉,此时还是可以识别出图片的。这种做法实质上等于创造出了很多新的随机样本,通过增大样本量、减少特征数来防止过拟合。

参数难以调试也是神经网络的另一大痛点。我们使用的SGD算法更新权重。但是设置不同的学习速率,最后得到的结果也可能不同。神经网络通常不是一个凸优化的问题,它处处充满了局部最优。SGD本身不是一个比较稳定的算法,结果可能会在最优解附近波动,而不同的学习速率可能导致神经网络落入截然不同的局部最优之中。理论表明,神经网络可能有很多个局部最优解都可以达到比较好的分类效果,而全局最优反而容易是过拟合的解。对于SGD一开始我们可能希望学习速率大一点,可以加速收敛,但是训练的后期又希望学习速率小一点,可以比较稳定地落入一个局部最优解。SGD需要对学习速率、Momentum、Nesterov等参数进行比较复杂的调试。当参数调试的合适时,网络可以达到好的效果。而有一些机器学习算法如Adagrad、Adam等自适应算法可以减轻调试参数的负担,只需要使用默认的参数就可以达到很好的效果。

梯度弥散是另一个影响深层神经网络的问题。早期的神经网络都使用sigmoid作为激活函数。sigmoid函数具有限制性,输出数值在0-1,最符合概率输出的定义。非线性的sigmoid函数在信号的特征空间映射上,对中央区的信号增益较大,对两侧区的信号增益小。因此,在训练神经网络时,可以将重要特征置于中央区,将非重要特征置于两侧区。但是sigmoid激活当神经网络层数较多时,sigmoid函数在反向传播中梯度值会逐渐减小,经过多层的传递后会呈指数级急剧较小,因此梯度值在传递到前面几层时就变得非常小了,基本起不到训练的作用。

针对这三种问题,我们使用dropout、Adagrad、ReLU解决。在早期的神经网络的致命缺点是不能解决异或问题,因为其是线性的。当引入了隐含层并使用非线性的激活函数后,我们可以使用曲线划分两类样本,可以轻松解决异或问题。神经网络的隐含层越多,就可以对原有特征进行抽象的变换,模型的拟合能力就越强。这就是多层神经网络(或多层感知机)的功能所在。

二、TensorFlow实现多层感知机

  1. 准备数据:将我们要用到的数据准备好
  2. 定义占位变量:占位变量是给输入X和标签y_和keep_prob占位。当我们训练模型的时候,在将数据传入到模型中
  3. 初始化权重:初始化W1和b1,W2和b2,.W1初始化标准差为0.1的正太分布,b1为1,W2和b2都为0
  4. 计算输出值:此步相当于前向传播计算出预测值,先计算隐藏层的值,在经过dropout,最后计算输出层softmax值
  5. 计算损失值:损失值是训练算法的重要部分。我们的目的就是获取损失值最小时的权重
  6. 建立优化器:调用优化器,最小化损失值,使用Adagrad优化器
  7. 获取准确率:通过输入测试集数据。验证模型准确率
# 导入数据集
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
# 创建默认的sess
sess = tf.InteractiveSession()

# 初始化权重
in_units = 784    # 输入层节点
h1_units = 300    # 隐藏层节点
# 第一层参数
W1 = tf.Variable(tf.truncated_normal([in_units, h1_units], stddev=0.1))
b1 = tf.Variable(tf.zeros([h1_units]))
# 第二层参数
W2 = tf.Variable(tf.zeros([h1_units, 10]))
b2 = tf.Variable(tf.zeros([10]))

# 定义placeholder
X = tf.placeholder(tf.float32, [None, in_units])
keep_prob = tf.placeholder(tf.float32)
y_ = tf.placeholder(tf.float32, [None, 10])

# 定义模型结构
hidden1 = tf.nn.relu(tf.matmul(X, W1) + b1)
hidden1_drop = tf.nn.dropout(hidden1, keep_prob)
y = tf.nn.softmax(tf.matmul(hidden1_drop, W2) + b2)

# 定义损失,优化损失
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))

train_step = tf.train.AdagradOptimizer(0.3).minimize(cross_entropy)

# 迭代进行训练
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})
    
# 计算准确率
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(accuracy.eval({X: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

结果:0.9785

最终,在测试集上的结果大约是98%的准确率。多层神经网络依靠隐含层,则可以组合出高阶特征,比如横线、竖线、圆圈等,之后可以将这些高阶特征或者说组件在组合成数字,就能实现精准的匹配和分类。隐含层输出的高阶特征经常是可以复用的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值