在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 | 准确率 |
---|---|---|
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左右。
4.心得体会
- 调参是ml和dl的必备技能,就像使用666法则解决问题,分析解决软件中的bug一样,需要练就一个好习惯;
- 不能将学习范围限制在课程介绍的内容,就像zero初始化和relu同时使用、nn.l2_loss都是别人说了才知道,自己应该学会去查相关文档和资料;
- 在学习过程中不仅要知其然,更要知其所以然,才能让更快更稳定的进步;
如需看最后参数情况,可下载调好参数的模型:最终模型地址
下一篇: TensorFlow学习笔记——图像增强
推荐阅读
-
Keras : 利用卷积神经网络CNN对图像进行分类,以mnist数据集为例建立模型并预测
-
CNN 卷积神经网络实践(基于Mnist数据集)
-
在mnist数据集上训练神经网络(非CNN)
-
Pytorch:卷积神经网络CNN,使用重复元素的网络(VGG)训练MNIST数据集99%以上正确率
-
tensorflow使用卷积神经网络训练mnist数据集代码及结果
-
【深度学习】5:CNN卷积神经网络原理、识别MNIST数据集
-
TensorFlow——CNN卷积神经网络处理Mnist数据集
-
PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)
-
两层卷积神经网络训练mnist数据集
-
深度学习笔记---简单三层CNN的自制框架实现以及对MNIST数据集的训练实现