Tensorflow(二)MNIST数据集分类

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Bazingaea/article/details/83788821

1.获取数据集

有两种方式可以得到数据集,第一是直接通过mnist = input_data.read_data_sets('MNIST_data',one_hot = True)进行联网下载,但这个方法可能很慢或者连接不到服务器,所以推荐使用第二个,在MNIST 直接下载数据,然后放在当前路径下的‘MNIST_data’文件夹中,下载以后不需要解压,直接压缩包放进去就好,它会自动解压获取数据的。

这个数据集是包含了0-9这10个数字的很多图片,我们要做的就是给出一张图片上面有数字,分析出这个数字是0-9中的哪一个。

one-hot的意思就是,输出值y应该是一个这样的形式【0,1,2,3,4,5,6,7,8,9】,每一个位置对应一个数字,得到的预测值只有一位为1,其他都是0,也就是说,如果预测值是【1,0,0,0,0,0,0,0,0,0】代表这个数字为0。预测值和给定的y值都是这种形式

2.softmax

softmax是一个激活函数,用在多分类问题的最后一层,最后一层使用这个函数以后得到的yhat并不是最终的预测值,以数据集分类例子来说,他是由10个小数组成的向量,并且这10个数的和为1,这10个数分别代表了最后这张图片是哪个数字的几率。选择最大的一项作为1,其他项都为0,最终得到预测值。

3.关于数据维度的问题

上面在讲向量的时候我都说的比较模糊,没有说明到底是行向量还是列向量,在之前吴恩达老师深度学习的课程中,神经网络中各层数据和参数的维度是这样定义的:(这是简化示例图,为了方便说明w和b的维度,下面代码展示的并没有隐藏层)

但这个数据集获取到的数据定义形式,也就是X和Y正好是反着来的,如果想要按照这个模型来,把获取到的数据转置即可,但这里为了以后增加改进方便,用了数据原始的格式。

注意数据的格式会引起两个问题,第一是参数值的维度,第二是向前传播是矩阵乘法的顺序

4.代码

首先导入需要用到的包:

import tensorflow as tf
#mnist是tensorflow中一个实例,使用input_data来下载/引入数据
from tensorflow.examples.tutorials.mnist import input_data

得到并且分析数据:

#获取所有的数据,包括train-set test-set
mnist = input_data.read_data_sets('MNIST_data',one_hot = True)

执行这条命令就会得到:

Extracting MNIST_data\train-images-idx3-ubyte.gz
Extracting MNIST_data\train-labels-idx1-ubyte.gz
Extracting MNIST_data\t10k-images-idx3-ubyte.gz
Extracting MNIST_data\t10k-labels-idx1-ubyte.gz

它会自动解压压缩包,得到里面的数据,我们可以分析一下里面数据的格式

#训练数据的样本个数
mnist.train.num_examples  #55000

#看看训练集x和y的维度,其中images为X ,labels为Y
print(mnist.train.images.shape)   #(55000, 784)
print(mnist.train.labels.shape)   #(55000, 10)

#测试集
print(mnist.test.images.shape)   #(10000, 784)
print(mnist.test.labels.shape)   #(10000, 10)

当数据很多的时候,可以使用Mini-batch gradient descent来训练模型,也就是分批次的训练数据,每一次迭代将数据分别n_batch个组,每个组有batch_size个数据,用batch_size个数据对模型进行训练。

#定义批次和一共有多少批次
batch_size = 100
n_batch = mnist.train.num_examples // batch_size

使用tensorflow的一大好处就是,它只需要实现向前传播和计算cost值,向后传播和更新参数它会自动帮你完成。

#定义两个占位符
#占位符就是,它并没有真实的数据,但给了下面代码使用数据的机会,等在session中再通过feed-dict来把数据喂给模型
x = tf.placeholder(tf.float32,[None,784])
y = tf.placeholder(tf.float32,[None,10])


#向前传播
w = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([1,10]))
prediction = tf.nn.softmax(tf.matmul(x,w)+b)

#计算代价值
cost = tf.reduce_mean(tf.square(y-prediction))

#以梯度下降的方式,目标是减少cost值训练一个神经网络 学习因子为0.2
train = tf.train.GradientDescentOptimizer(0.2).minimize(cost)

#预测计算准确度
#equal比较两个参数大小是否一样,一样返回true,不一样是false ,得到的其实是true和false的向量
#argmax求y中最大值在哪个位置,1表示对哪个维度找最大值,1表示对应10的那一维
correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))

#把预测值转化为浮点 ,true变成1.0 false变成0.0 ,再求平均值,
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))


#开始训练
with tf.Session() as sess:
    #前面定义的变量,就需要先初始化变量
    sess.run(tf.global_variables_initializer())

    for i in range(100): #迭代100次
        for batch in range(n_batch):  #分批次迭代
            #获取本批次的数据
            batch_xs,batch_ys = mnist.train.next_batch(batch_size)
            sess.run(train,feed_dict={x:batch_xs,y:batch_ys})
        
        #每迭代一次使用test集测试一下准确度
        acc = sess.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels})
        print('after ',i, 'the accuracy is ',acc)
after  0 the accuracy is  0.8299
after  10 the accuracy is  0.9061
after  20 the accuracy is  0.9133
after  31 the accuracy is  0.9188
after  40 the accuracy is  0.9197
after  50 the accuracy is  0.9212
after  60 the accuracy is  0.9234
after  70 the accuracy is  0.9241
after  80 the accuracy is  0.9243
after  90 the accuracy is  0.9257
after  99 the accuracy is  0.9258

5.后记

对于第一次接触tensorflow的我,这个过程还是显得很神奇的,感觉不用自己实现反向传播,工作量就少了一大半,而且它的先定义placeholder然后再feed data的机制真的灰常巧妙!!很有种定义函数中参数的感觉。tensorflow中的变量定义了以后,其实是没有值得,比如输入w得到的是 : <tf.Variable 'Variable_8:0' shape=(784, 10) dtype=float32_ref>

并不是它初始化的值,在session中run过以后,才会赋予它我们所期望的值。

这里没有设置隐藏层,隐藏层的变化也是针对向前传播的,其他的其实都和这个一样。

 

关于代价函数:

在这里用到的代价函数是二次代价函数,也就是用真实值-预测值取平方,使用交叉熵的代价函数其实更好,也可以提升准确率,

交叉熵的代价函数就是 y*log(y-hat),真实值乘以预测值求log,因为真实值其实是one-hot的形式,所以除了一项为1,其他项都是0,那么这个代价函数也就是 y为1的位置,对应y-hat相同位置的的概率值求对数。

上面两个代价函数都要取负数,而且说的只是当个样本,对于多个样本的情况需要把所有代价相加然后取均值

tf中也有内置函数可以直接实现交叉熵的计算:

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y,logits = prediction))

使用drop_out:

#drop_our初始化参数 为1.0代表所有的神经元都是工作的
#stddev表示数据的方差为0.1
w1 = tf.Variable(tf.truncated_normal([784,2000],stddev = 0.1))
b1 = tf.Variable(tf.zeros([1,2000])+0.1)
A1 = tf.nn.tanh(tf.matmul(x,w1)+b1)
A1_drop = tf.nn.dropout(A1,keep_prob)


w2 = tf.Variable(tf.truncated_normal([2000,20],stddev = 0.1))
b2 = tf.Variable(tf.zeros([1,20])+0.1)
A2 = tf.nn.tanh(tf.matmul(A1_drop,w2)+b2)
A2_drop = tf.nn.dropout(A2,keep_prob)

w3 = tf.Variable(tf.truncated_normal([20,10],stddev = 0.1))
b3 = tf.Variable(tf.zeros([1,10])+0.1)
A3 = tf.nn.tanh(tf.matmul(A2_drop,w3)+b3)
A3_drop = tf.nn.dropout(A3,keep_prob)

w4 = tf.Variable(tf.truncated_normal([10,10],stddev = 0.1))
b4 = tf.Variable(tf.zeros([1,10])+0.1)
prediction = tf.nn.softmax(tf.matmul(A3_drop,w4)+b4)

在session中训练迭代的时候添加keep_drop参数:

sess.run(train,feed_dict={x:batch_xs,y:batch_ys,keep_prob:0.8})

预测训练集和测试集的时候要关闭drop out:

 train_acc = sess.run(accuracy,feed_dict={x:mnist.train.images,y:mnist.train.labels,keep_prob:1.0})
 test_acc = sess.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels,keep_prob:1.0})

猜你喜欢

转载自blog.csdn.net/Bazingaea/article/details/83788821