在mnist数据集上训练神经网络(非CNN)

前言: 接触机器学习和深度学习以来,第一篇博客。本想系统性的写几篇,但限于加班较多,晚上学习,留给写博客的时间不多了,本篇总结是markdown格式的,恰巧现在CSDN博客支持markdown格式的博客了,作为第一篇吧,后续慢慢来。
任务:

使用tensorflow,构造并训练一个神经网络,在mnist数据集上训练神经网络,在测试集上达到超过98%的准确率。

要点提示:

在完成的过程中,综合运用目前学到的基础知识:
- 深度神经网络
- 激活函数
- 正则化
- 初始化
- 摸索一下各个超参数
- 隐层神经元数量
- 学习率
- 正则化惩罚因子
- 最好每隔几个step就对loss、accuracy等进行一次输出,方便有根据地进行调整

1.观查最简陋的模型

"""A very simple MNIST classifier.
See extensive documentation at
https://www.tensorflow.org/get_started/mnist/beginners
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import sys
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
FLAGS = None

# Import data
data_dir = '/tmp/tensorflow/mnist/input_data'
mnist = input_data.read_data_sets(data_dir, one_hot=True)

# Create the model
x = tf.placeholder(tf.float32, [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.matmul(x, W) + b

# Define loss and optimizer
y_ = tf.placeholder(tf.float32, [None, 10])

# The raw formulation of cross-entropy,
#
#   tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(tf.nn.softmax(y)),
#                                 reduction_indices=[1]))
#
# can be numerically unstable.
#
# So here we use tf.nn.softmax_cross_entropy_with_logits on the raw
# outputs of 'y', and then average across the batch.
cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))

train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

sess = tf.Session()
init_op = tf.global_variables_initializer()
sess.run(init_op)

# Train
for _ in range(3000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

# Test trained model
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: mnist.test.images,
                                      y_: mnist.test.labels}))

1.1初次运行,准确率是:0.921

1.2在训练过程中输出准确率和损失

在step为整百时,训练前将此step对应的batch的准确率输出,然后再做训练。根据输出部分log,方便对调优趋势进行判断。log格式如下:

step 400, training accuracy 0.94, cross_entropy 0.247223

1.3简单调整一下学习率,看看变化

最初学习率是0.5,这个学习率直觉有些大;调整为0.3后,准确率是0.9231;调整为0.05后,准确率是0.9142

每次运行,准确率稍有变化,但百分位前的不会变化,结合给的提示,不做其他优化,这个简陋模型,准确率只能在0.92附近。

2.分析确定模型训练的策略

2.1确定训练模型的调整重点及相应的超差范围
1. 增加隐层,需要调整隐层数量(1,2,3)及每层的神经元数量(10-2048)
2. 确定激活函数(sigmoid, tanh, relu)
3. 对权重进行正则化(l1, l2),并调整正则参数
4. 调整权重和偏置的初始化策略(truncated_normal, random_normal, random_uniform),并调整相应参数
5. 调整学习率

2.2整体思路

运用现有知识训练和调参过程中不能盲目,东一榔头西一棒子会降低得到最优模型的效率。因为要用到多个方面的优化措施和相应参数,很容易出现“按住葫芦起来瓢”的现象,所以不能一开始就追求最佳效果,应该将模型调整到大概比较好的效果之后,再进行微调。

3.训练模型

3.1增加隐层

从课程中和对深度学习的了解,隐层对提高准确率起到至关重要的作用,分析一下各隐层的神经元数量与权重和偏置shape的关系:

从10到2048都试了,没有保存相应的结果,但记得2048时,训练一遍需要半个多小时(无gpu,低电压i7cpu),神经元数量在1024和2048时,测试集预测准确率一致在0.96上下;神经元数量取512、256、128时反而效果好一些,接一下来就使用256作为神经元数量。

  • 依次实验隐层数量为1,2,3的情况(此时神经元都设置为256个)
隐层数量loss准确率
10.1521820.9551
20.1556750.9562
30.1557670.9536

发现隐层数量1,2和3时准确率差不多,但3时明显训练速度慢。接下来使用2个隐层对模型进行训练;

  • 调整两个隐层的神经元数量

只加了隐层,未加激活函数,准确率惨不忍睹,准确率仅为0.1多一些,哈哈。激活函数带有“挤压”性质,而且使得神经网络具有的拟合非线性函数的能力,使得其具有强大的表达能力。我们加上激活函数试试看,先看sigmoid的效果:发现加上sigmoid激活函数之后,准确率还是在0.1左右,加上relu激活函数,准确率仍然没有改变,经过查找资料和课程内容的深入理解,是权重矩阵和偏置zero初始化引起的问题。改为使用truncated_normal初始化,使用sigmoid激活函数时,准确率提升至0.89左右;使用relu激活函数,准确率在0.95左右。

PS:隐层调整,费了不少功夫,在这个过程中发现增加step数量有能在一定程度上提高预测准确率,因此将step数量由3000(5 ephochs)增加为了6000(10 ephochs)

3.2确定激活函数
在使用两层隐层,每层神经元数量为256,step数量为6000的情况下,三种激活函数的情况如下:

激活函数loss准确率
sigmoid0.1008850.9673
tanh0.0710790.9829
relu0.05785060.9829

可以看出在使用sigmoid函数时,准确率相对较低,接下来使用relu作为激活函数;

PS:最开始使用的是zero初始化,relu时准确率低的吓人,走了弯路,在群里看到了同学反馈的情况,使用了truncated_normal。

3.3初始化
- truncated_normal:从截断的正态分布中输出随机值
- random_normal:从正态分布中输出随机值
- random_uniform:从均匀分布中返回随机值
在使用以上三个函数进行初始化时,经过多次实验,truncated_normal参数取0.01时效果较好。

3.4正则化

经过前面三步,准确率已经达到了0.982左右,又对模型分别增加了三种正则处理:
- tf.contrib.layers.l2_regularizer
- tf.contrib.layers.l1_regularizer
- tf.nn.l2_loss
正则因子分别从0.1,0.01,0.001,0.0005,0.0001,其中在使用0.1,0.01,0.001时,竟然降低了预测的准确率,使用0.0005和0.0001时也没有提高准确率(实话实说,至少这个模型中是这样)

感觉有可能是step数量较大以及此数据集中测试集和训练集较类似,正则起到的作用较小。

3.5学习率

在未加隐层前,首先试了一下学习率,发现0.3比0.5效果好。

在确定了以上各种措施之后,对学习率在0.01到0.5区间用二分策略,试了较多次,最后发现学习率在0.35时效果最好。

3.6整体微调
在两层隐层的情况下,进行微调:
1. 调整隐层中神经元数量,范围是64-512;
2. 调整初始化函数的参数0.01-0.5
3. 调整正则因子0.01到0.0002
4. 调整学习率0.01到0.5

即使同样的参数,因为初始化具有随机性,最后得到的预测准确率也会在千分位之后有些不同。最好的一次准确率为0.9857,最后稳定在0.984左右。

4.心得体会

  1. 调参是ml和dl的必备技能,就像使用666法则解决问题,分析解决软件中的bug一样,需要练就一个好习惯;
  2. 不能将学习范围限制在课程介绍的内容,就像zero初始化和relu同时使用、nn.l2_loss都是别人说了才知道,自己应该学会去查相关文档和资料;
  3. 在学习过程中不仅要知其然,更要知其所以然,才能让更快更稳定的进步;

如需看最后参数情况,可下载调好参数的模型:最终模型地址

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值