MNIST手写数字识别

MNIST数据集

MNIST数据集是由0~9的手写数字集组成的数据集,其中包括训练iamge集、训练label集、测试image集、测试label集4个部分。在TensorFlow中,提供了集体数据集。

from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)  # 当本地没有mnist数据集时,则自动下载

数据集中度每个部分均可自行查看其大小

print(mnist.train.images.shape)
print(mnist.train.labels.shape)
print(mnist.train.images[0, :])

在数据集中,所有图片的保存方式是[1, 784]的一维数组形式,label的保存格式为独热表示法,即用一个[1, 10]的一维数组表示0~9的九个数字,且除了被表示数对应下标元素的值为1之外,其他元素均为0。比如,数字5的独热表示法为[0, 0, 0, 0, 0, 1, 0, 0, 0, 0]。
将图片保存为可视的图片,代码如下:

import os
import scipy.misc

save_dir = 'MNIST_data/raw/'
if os.path.exist(save_dir) is False:
	os.makedirs(save_dir)  # 没有save_dir途径时,自动生成该途径

for i in range(20):  # 可视化前20张图片为例
	image_array = mnist.train.images[i, :]  # 去除第i行的所有列
	image = image_array.shape(28, 28)
	filename = save_dir + 'mnist_train_%d.jpg' % i 
	scipy.misc.toimage(image, cmin=0.0, cmax=1.0).save(filename)

手写数字识别

全连接网络识别

在MNIST数据集中,对于label的保存方式为独热表示法,那么,如何对独热表示的值进行处理呢,在此,我们引进一个函数:softmax函数。softmax函数是逻辑函数的一种推广,它可以将n维的每一个数据映射为0~1之间的某一个数。例如,对(a, b, c)使用函数,返回在这里插入图片描述
,其中分别表示abc的概率。在该事例中,softmax函数的返回值是指对图片进行检测,结果为0到9这10个数字分别的概率组成的一个[1, 10]的向量,数值最大的元素对应的下标就是检测的结果。在TensorFlow中,也收入了相关的函数

y=tf.nn.sotfmax(y)

构建网络时,我们的函数值y的结果依赖于输入值x,系数矩阵w和偏执值b,构建函数y=Wx+b,通过每一次的变量更改使都函数计算的y值组件趋近与真值。
训练过程中,就是让softmax(y)计算结过和MNIST数据集中的label的结果尽可能的相似,两者之间的差别定义为训练时的loss,在具体的训练过过程中,用交叉熵来表示两者之间的相似度,当交叉熵越大,则两者的相似程度就越小,即我们训练的过程就是为了减小交叉熵。

cross_entropy = tf.reduce_mean(-tf.reduce_sum(label * tf.log(y)))  # 交叉熵损失(用来衡量y与y_之间的相似性)

对于已经训练好的函数模型来说,我们用测试集的平均数来作为评价标注。在测试集通过训练好的模型时,模型的输入值为test_image,输出结果是prediction,并且是由独热表示法表示的prediction。在评价模型之前,分别取出prediction和test_label中最大项的下标作为结果,并比较这两结果是否相等,相等为Ture,不等为False(及转化为数字为0和1),此时便可用平均数来表示模型的正确率。

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))  # argmax表示取出目标数列中元素最大的下标;equal表示逐项对比两数列,在对应位置,相等返回True,不相等返回False
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))  # cast将True和False对应的转回为0和1

识别代码具体如下:

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

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

x = tf.placeholder(tf.float32, [None, 784])  # x和y_非变量,采用占位的表示法
w = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x, w) + b)

y_ = tf.placeholder(tf.float32, [None, 10])

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y)))  # 交叉熵损失(用来衡量y与y_之间的相似性)
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

# 设置对话框(TensorFlow的基本语法)
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()


# 开始训练,以1000次为例
for _ in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})


# 评价
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}))

输出结果如下:
在这里插入图片描述
这种识别方式的正确率大概在0.90~0.91左右,准确率还是略有差池。

卷积网络识别

与上一种识别方式的不同是,卷积网络识别对图片进行了卷积特征提取,用卷积网络的特点,将输入softmax函数的值进行了一定的处理,使得训练网络的准确率有所提高。
在卷积网络中,网络的输入值不在想前一种方式一样输入的是一维向量,而是一个具体的图片的三维矩阵,在卷积层上通过合适的卷积核在图片上的运动,将原图片映射为feature,再通过池化层,得出一次卷积的结果。
卷积神经网络由两部分组成:一部分卷积部分,一部分全连接部分。
在通常情况下,一次完整的卷积过程通常包括卷积层、激活函数、池化层三个标准部分。(卷积层和池化层的具体运行原理就不做过多解释,可自行查看相关文献,本文以实例的具体实现为主)激活函数的存在是为了防止过拟合状态的出现,这种方式也是神经网络中非常常见的防止过拟合的做法。在MNIST识别网络中,一般会存在两次的卷积过程,卷积过程中的卷积层和池化层的具体实现如下:

def conve2d(x, w):
    conve = tf.nn.conv2d(x, w, strides=[1, 1, 1, 1], padding='SAME')
    return conve


def pool_(x):
    pill = tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    return pool

在经过卷积网络的特征提取后,再将提取的feature输入到全连接层。注意全连接的输入值是一个一维数组,所为,在输入全连接层之前,要对feature进行降维处理。全连接层中,也包括了两层网络,经过第一层,在第二层中将数据划分为10 类,以此来表示每个数字对应的概率。全连接层实现如下:

image_fc1 = tf.nn.relu(tf.matmul(feature, w_fc1) + b_fc1)
keep_drop = tf.placeholder(tf.float32)  
h_fc1_drop = tf.nn.dropout(image_fc1, keep_drop)

其中,设置keep_drop也是为了防止在全连接层中出现过过拟合现象才设置的全连接层中每一个神经元打开的概率。(注意,这里的激活函数在训练和预测是的计算参数不同,训练时,激活函数的参数为0.5,而在与测试参数为1)。

其与训练过程和上一种方法基本类似,就不做重复阐述了。
识别网络实现如下:

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

mnist = input_data.read_data_sets('E:/pyCharm/pycharm.lianxi/DeepLearn/mnist/MNIST_data/', one_hot=True)  # 这里的地址可以更具你自己MNIST数据具体所在地址进行更改,此处只是举例

x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])

image = tf.reshape(x, [-1, 28, 28, 1])

def weight(shape):
    w = tf.truncated_normal(shape, stddev=0.1)  # 生成正太分布
#    w = tf.constant(0.1, shape=shape)
    return tf.Variable(w)


def bias(shape):
    b = tf.constant(0.1, shape=shape)
    return tf.Variable(b)


def conve2d(x, w):
    conve = tf.nn.conv2d(x, w, strides=[1, 1, 1, 1], padding='SAME')
    return conve


def pool_(x):
    pill = tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    return pill

# conv1
w_conve1 = weight([5, 5, 1, 32])
b_conve1 = bias([32])
conve1 = tf.nn.relu(conve2d(image, w_conve1) + b_conve1)
pool1 = pool_(conve1)


# conv2
w_conve2 = weight([5, 5, 32, 64])
b_conve2 = bias([64])
conve2 = tf.nn.relu(conve2d(pool1, w_conve2) + b_conve2)
pool2 = pool_(conve2)


# fc1
feature = tf.reshape(pool2, [-1, 7 * 7 * 64])  # -1表示行数更具pool2自动生成
w_fc1 = weight([7 * 7 * 64, 1024])
b_fc1 = bias([1024])
image_fc1 = tf.nn.relu(tf.matmul(feature, w_fc1) + b_fc1)
keep_drop = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(image_fc1, keep_drop)


w_fc2 = weight([1024, 10])
b_fc2 = bias([10])
image_fc2 = tf.matmul(image_fc1, w_fc2) + b_fc2


cress_loss = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=image_fc2)
)  # 此处是将wx+b直接进行了交叉熵处理,与上一种方法的代码不一样的是没有再将wx+b进行softmax函数处理,但并不意味这没有sotfmax这个过程,只是该函数已经内部包括了这一步而已
train_step = tf.train.AdamOptimizer(1e-4).minimize(cress_loss)

correct_prediction = tf.equal(tf.argmax(image_fc2, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())


for i in range(10000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys, keep_drop: 0.5})
    if i % 100 == 0:
    procession = sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels, keep_drop: 1})
    print('第{}次, 准确率为{}'.format(i, procession))

运行结果为:
在这里插入图片描述
此处因为有一定的运行时间,展示一部分运行结果。随着训练词数的增加,可以明显看出,运用卷积神经网络对mnist数据集进行识别的准确率要比全连接网络的准确率高的多(比较这只是迭代600次就已经达到了0.96的准确率,事实上,可以达到0.99以上)。

提示:在代码部分定义weigth的函数中,我们采取了以正态分布式生成系数的初始值,经过小编亲自尝试,这样生产的系数矩阵在迭代训练的过程中表现的效果要比直接适用于和bias一样的初始化方式好得多,所以,我们就采用正太分布的系数初始化。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值