欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-08 09:42:08
...

前言: 接触机器学习和深度学习以来,第一篇博客。本想系统性的写几篇,但限于加班较多,晚上学习,留给写博客的时间不多了,本篇总结是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的关系:

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

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

  • 依次实验隐层数量为1,2,3的情况(此时神经元都设置为256个)
隐层数量 loss 准确率
1 0.152182 0.9551
2 0.155675 0.9562
3 0.155767 0.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 准确率
sigmoid 0.100885 0.9673
tanh 0.071079 0.9829
relu 0.0578506 0.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左右。

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

4.心得体会

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

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