热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

(数据科学学习手札36)tensorflow实现MLP

一、简介我们在前面的数据科学学习手札34中也介绍过,作为最典型的神经网络,多层感知机(MLP)结构简单且规则,并且在隐层设计的足够完善时,可以拟合任意连续函数,而除了利用前面介绍的sklear

一、简介

  我们在前面的数据科学学习手札34中也介绍过,作为最典型的神经网络,多层感知机(MLP)结构简单且规则,并且在隐层设计的足够完善时,可以拟合任意连续函数,而除了利用前面介绍的sklearn.neural_network中的MLP来实现多层感知机之外,利用tensorflow来实现MLP更加形象,使得使用者对要搭建的神经网络的结构有一个更加清醒的认识,本文就将对tensorflow搭建MLP模型的方法进行一个简单的介绍,并实现MNIST数据集的分类任务;

 

二、MNIST分类

   作为数据挖掘工作中处理的最多的任务,分类任务占据了机器学习的大半江山,而一个网络结构设计良好(即隐层层数和每个隐层神经元个数选择恰当)的多层感知机在分类任务上也有着非常优越的性能,依然以MNIST手写数字数据集作为演示,上一篇中我们利用一层输入层+softmax搭建的分类器在MNIST数据集的测试集上达到93%的精度,下面我们使用加上一层隐层的网络,以及一些tricks来看看能够提升多少精度;

网络结构:

  这里我们搭建的多层前馈网络由784个输入层神经元——200个隐层神经元——10个输出层神经元组成,而为了减少梯度弥散现象,我们设置relu(非线性映射函数)为隐层的激活函数,如下图:

这种激活函数更接近生物神经元的工作机制,即在达到阈值之前持续抑制,在超越阈值之后开始兴奋;而对输出层,因为对数据做了one_hot处理,所以依然使用softmax进行处理;

Dropout:  

  过拟合是机器学习尤其是神经网络任务中经常发生的问题,即我们的学习器将训练集的独特性质当作全部数据集的普遍性质,使得学习器在训练集上的精度非常高,但在测试集上的精度却非常低(这里假设训练集与测试集数据分布一致),而除了随机梯度下降的一系列方法外(如上一篇中我们提到的在每轮训练中使用全体训练集中一个小尺寸的训练批来进行本轮的参数调整),我们可以使用类似的思想,将神经网络某一层的输出节点数据随机丢弃一部分,即令这部分被随机选中的节点输出值令为0,这样做等价于创造出很多新样本,通过增大样本量,减少特征数量来防止过拟合,dropout也算是一种bagging方法,可以将每次丢弃节点输出视为对特征的一次采样,相当于我们训练了一个ensemble的神经网络模型,对每个样本都做特征采样,并构成一个融合的神经网络

 学习效率:

  因为神经网络的训练通常不是一个凸优化问题,它充满了很多局部最优,因此我们通常不会采用标准的梯度下降算法,而是采用一些有更大可能跳出局部最优的算法,常用的如SGD,而SGD本身也不稳定,其结果也会在最优解附近波动,且设置不同的学习效率可能会导致我们的网络落入截然不同的局部最优之中,对于SGD,我们希望开始训练时学习率大一些,以加速收敛的过程,而后期学习率低一些,以更稳定地落入局部最优解,因此常使用Adagrad、Adam等自适应的优化方法,可以在其默认参数上取得较好的效果;

  下面。就结合上述策略,利用tensorflow搭建我们的多层感知机来对MNIST手写数字数据集进行训练:

 

2.1 风格一

  先使用朴素的风格来搭建网络,首先还是照例从tensorflow自带的数据集中提取出mnist数据集:

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

'''导入MNIST手写数据'''
mnist = input_data.read_data_sets('MNIST_data/', one_hot = True)

  接着使用交互环境下会话的方式,将生成的第一个会话作为默认会话:

'''注册默认的session,之后的运算都会在这个session中进行'''
sess = tf.InteractiveSession()

  接着初始化输入层与隐层间的784x300个权值、隐层神经元的300个bias、隐层与输出层之间的300x10个权值、输出层的10个bias,其中为了避免隐层的relu激活时陷入0梯度的情况,对输入层和隐层间的权值初始化为均值为0,标准差为0.2的正态分布随机数,对其他参数初始化为0:

'''定义输入层神经元个数'''
in_units = 784

'''定义隐层神经元个数'''
h1_units = 300

'''为输入层与隐层神经元之间的连接权重初始化持久的正态分布随机数,这里权重为784乘300,300是隐层的尺寸'''
W1 = tf.Variable(tf.truncated_normal([in_units, h1_units],mean=0,stddev=0.2))

'''为隐层初始化bias,尺寸为300'''
b1 = tf.Variable(tf.zeros([h1_units]))

'''初始化隐层与输出层间的权重,尺寸为300X10'''
W2 = tf.Variable(tf.zeros([h1_units, 10]))

'''初始化输出层的bias'''
b2 = tf.Variable(tf.zeros([10]))

  接着我们定义自变量、隐层神经元dropout中的保留比例keep_prob的输入部件:

'''定义自变量的输入部件,尺寸为 任意行X784列'''
x = tf.placeholder(tf.float32, [None, in_units])

'''为dropout中的保留比例设置输入部件'''
keep_prob = tf.placeholder(tf.float32)

  接着定义隐层relu激活部分的计算部件、隐层dropout部分的操作部件、输出层softmax的计算部件:

'''定义隐层求解部件'''
hidden1 = tf.nn.relu(tf.matmul(x, W1) + b1)

'''定义隐层dropout操作部件'''
hidden1_drop = tf.nn.dropout(hidden1, keep_prob)

'''定义输出层softmax计算部件'''
y = tf.nn.softmax(tf.matmul(hidden1_drop, W2) + b2)

  还有样本真实分类标签的输入部件以及loss_function部分的计算组件:

'''定义训练label的输入部件'''
y_ = tf.placeholder(tf.float32, [None, 10])

'''定义均方误差计算部件,这里注意要压成1维'''
loss_function = tf.reduce_mean(tf.reduce_sum((y_ - y)**2, reduction_indices=[1]))

  这样我们的网络结构和计算部分全部搭建完成,接下来至关重要的一步就是定义优化器的组件,它会完成自动求导调整参数的工作,这里我们选择自适应的随机梯度下降算法Adagrad作为优化器,学习率尽量设置小一些,否则可能会导致网络的测试精度维持在一个很低的水平不变即在最优解附近来回震荡却难以接近最优解(亲测):

'''定义优化器组件,这里采用AdagradOptimizer作为优化算法,这是种变种的随机梯度下降算法'''
train_step = tf.train.AdagradOptimizer(0.18).minimize(loss_function)

  接下来就到了正式的训练过程了,我们激活当前会话中所有计算部件,并定义训练步数为15000步,每一轮迭代选择一个批量为100的训练批来进行训练,dropout的keep_prob设置为0.76,并在每50轮训练完成后将测试集输入到当前的网络中计算预测精度,注意在正式预测时dropout的keep_prob应设置为1.0,即不进行特征的丢弃:

'''激活当前session中的全部部件'''
tf.global_variables_initializer().run()

'''开始迭代训练过程,最大迭代次数为3001次'''
for i in range(15000):
    '''为每一轮训练选择一个尺寸为100的随机训练批'''
    batch_xs, batch_ys = mnist.train.next_batch(100)
    '''将当前轮迭代选择的训练批作为输入数据输入train_step中进行训练'''
    train_step.run({x: batch_xs, y_: batch_ys, keep_prob:0.76})
    '''每500轮打印一次当前网络在测试集上的训练结果'''
    if i % 50 == 0:
        print('',i,'轮迭代后:')
        '''构造bool型变量用于判断所有测试样本与其真是类别的匹配情况'''
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
        '''将bool型变量转换为float型并计算均值'''
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
        '''激活accuracy计算组件并传入mnist的测试集自变量、标签及dropout保留比率,这里因为是预测所以设置为全部保留'''
        print(accuracy.eval({x: mnist.test.images,
                             y_: mnist.test.labels,
                             keep_prob: 1.0}))

  经过全部迭代后,我们的多层感知机在测试集上达到了0.9802的精度表现如下图:

  事实上在训练到10000轮左右的时候我们的多层感知机就已经到达这个精度了,说明此时的网络已经稳定在当前的最优解中,后面的训练过程只是在这个最优解附近微弱的震荡而已,所以实际上可以设置更小的迭代轮数;

 

2.2 风格二

   除了上述的将网络结构部件的所有语句一条一条平铺直叙般编写的风格外,还有一种以自编函数来快捷定义网络结构的编程风格广受欢迎,如下:

  在添加神经层的时候,我们可以事先编写自编函数如下:

 

'''自定义神经层添加函数'''
def add_layer(inputs, in_size, out_size, activation_function=None):

    '''定义权重项'''
    Weights = tf.Variable(tf.random_normal([in_size,out_size]))

    '''定义bias项'''
    biases = tf.Variable(tf.zeros([1,out_size]) + 0.1)

    '''权重与输入值的矩阵乘法+bias项'''
    Wx_plus_b = tf.matmul(inputs, Weights) + biases

    '''根据激活函数的设置来处理输出项'''
    if activation_function is None:
        outputs = Wx_plus_b
    else:
        outputs = activation_function(Wx_plus_b)
    return outputs

 

这样就可以用一个函数来代替数条语句,下面我们用这种风格来实现前面同样的功能:

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


'''导入MNIST手写数据'''
mnist = input_data.read_data_sets('MNIST_data/', one_hot = True)

'''自定义神经层添加函数'''
def add_layer(inputs, in_size, out_size, activation_function=None):

    '''定义权重项'''
    Weights = tf.Variable(tf.truncated_normal([in_size,out_size],mean=0, stddev=0.2))

    '''定义bias项'''
    biases = tf.Variable(tf.zeros([1,out_size]) + 0.1)

    '''权重与输入值的矩阵乘法+bias项'''
    Wx_plus_b = tf.matmul(inputs, Weights) + biases

    '''根据激活函数的设置来处理输出项'''
    if activation_function is None:
        outputs = Wx_plus_b
    else:
        outputs = activation_function(Wx_plus_b)
    return outputs

'''创建样本数据和dropout参数的输入部件'''
x = tf.placeholder(tf.float32, [None, 784])
y = tf.placeholder(tf.float32, [None, 10])
keep_prob = tf.placeholder(tf.float32)

'''利用自编函数来生成隐层的计算部件,这里activation_function设置为relu'''
l1 = add_layer(x, 784,300, activation_function=tf.nn.relu)

'''对l1进行dropout处理'''
l1_dropout = tf.nn.dropout(l1,keep_prob)

'''利用自编函数对dropout后的隐层输出到输出层输出创建计算部件,这里将activation_function改成softmax'''
prediction = add_layer(l1_dropout, 300, 10, activation_function=tf.nn.softmax)

'''根据均方误差构造loss function计算部件'''
loss = tf.reduce_mean(tf.reduce_sum((prediction - y)**2, reduction_indices=[1]))

'''定义优化器部件'''
train_step = tf.train.AdagradOptimizer(0.3).minimize(loss)

'''激活所有部件'''
init = tf.global_variables_initializer()

'''创建新会话'''
sess = tf.Session()

'''在新会话中激活所有部件'''
sess.run(init)

'''10001次迭代训练,每200次输出一次当前网络在测试集上的精度'''
for i in range(10001):
    '''每次从训练集中抽出批量为200的训练批进行训练'''
    x_batch,y_batch = mnist.train.next_batch(200)
    '''激活sess中的train_step部件'''
    sess.run(train_step, feed_dict={x:x_batch, y:y_batch, keep_prob:0.75})
    '''每200次迭代打印一次当前精度'''
    if i %200 == 0:
        print('',i,'轮迭代后:')
        '''创建精度计算部件'''
        whether_correct = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))
        accuracy = tf.reduce_mean(tf.cast(whether_correct, tf.float32))
        '''在sess中激活精度计算部件来计算当前网络的精度'''
        print(sess.run(accuracy, feed_dict={x:mnist.test.images,
                                            y:mnist.test.labels,
                                            keep_prob:1.0}))

同样的,在10000次迭代后,我们的单隐层前馈网络取得了0.98的精度:

 

   以上就是关于tensorflow搭建MLP模型的基本内容,如有笔误,望指出。


推荐阅读
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • Opencv提供了几种分类器,例程里通过字符识别来进行说明的1、支持向量机(SVM):给定训练样本,支持向量机建立一个超平面作为决策平面,使得正例和反例之间的隔离边缘被最大化。函数原型:训练原型cv ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 都会|可能会_###haohaohao###图神经网络之神器——PyTorch Geometric 上手 & 实战
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了###haohaohao###图神经网络之神器——PyTorchGeometric上手&实战相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
  • Python入门后,想要从事自由职业可以做哪方面工作?1.爬虫很多人入门Python的必修课之一就是web开发和爬虫。但是这两项想要赚钱的话 ... [详细]
  • keras归一化激活函数dropout
    激活函数:1.softmax函数在多分类中常用的激活函数,是基于逻辑回归的,常用在输出一层,将输出压缩在0~1之间,且保证所有元素和为1,表示输入值属于每个输出值的概率大小2、Si ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
author-avatar
AA一缕阳光
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有