在准备工作完成后,直接打开PyCharm开撸代码,本文提供的代码共19行,本节将对这19行逐一讲解,直至实现全部功能。
1.import tensorflow as tf
没啥说的,加载Tensorflow库,起名叫tf。
2.import tensorflow.examples.tutorials.mnist.input_data as input_data
顾名思义,让Tensorflow加载Mnist数据集,起名叫input_data
3.x = tf.placeholder('float', shape=[None, 28*28])
Python在使用变量时需要先定义,原理上就是在内存上先给他分配一个空间。x就是输入的图片,大小为2828。注意:这里的x还没有形状,只有2828的大小。
4.y_true = tf.placeholder('float', shape=[None, 10])
为Mnist数据集中图片的标签分配内存。
5.conv_relu_pool_1 = tf.nn.max_pool(tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(tf.reshape(x, [-1, 28, 28, 1]),tf.Variable(tf.truncated_normal([5, 5, 1, 6], stddev=0.1)),strides=[1,1,1,1],padding="SAME"),tf.Variable(tf.constant(0.1, shape=[6])))),ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")
将第一个卷积层、激活步骤、池化层连接在一起,起名为conv_relu_pool_1。这句看似很长,但很好理解,并且省去了许多函数定义的可有可无步骤,从里向外理解:
(1)tf.nn.conv2d(tf.reshape(x, [-1, 28, 28, 1]),tf.Variable(tf.truncated_normal([5, 5, 1, 6], stddev=0.1)),strides=[1,1,1,1],padding="SAME")
tf.reshape(x, [-1, 28, 28, 1])表示图片的输入,因为之前的x是没有形状的,所以这里给他转化为长度和高度均为28的形状。[]内有四维参数,分别表示[batch, height, width, channels],channels表示元色的数量,batch是批梯度下降的数量,-1表示自动,[]内四个参数只能有1个-1,且后文会赋值。
tf.Variable(tf.truncated_normal([5, 5, 1, 6], stddev=0.1))代表卷积核,卷积核是从方差为0.1的正态分布中抽取的6个55的向量。
strides=[1,1,1,1]表示卷积的步长,这里的四维对应[batch, height, width, channels]。
padding=“SAME"。padding参数有两种模式:SAME和VALID。SAME与VALID模式的区别:在卷积时,如果卷积存在残余行列时,VALID模式下会自动抛弃剩下没有卷积内容,而SAME模式下会自动边界填充,边界外填充0,满足卷积条件。
(2)tf.Variable(tf.constant(0.1, shape=[6]))
表示偏置常量,初始大小为0.1,有6个,对应6个卷积核,即6张特征图,tf.Variable()表示将该常量转化为变量,因为后期根据学习偏置会改变。
(3)ksize=[1,2,2,1],strides=[1,2,2,1],padding=“SAME”
表示池化单元,池化步长的大小,也对应[batch, height, width, channels],padding意同上。
(4)tf.nn.bias_add()
表示输入与偏置相加。
(5)tf.nn.relu()
表示激活函数,relu()函数大家耳熟能详,就是小于0的值变为0,大于0的值不变。
(6)tf.nn.max_pool
表示最大池化操作。
6.conv_relu_pool_2 = tf.reshape(tf.nn.max_pool(tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv_relu_pool_1,tf.Variable(tf.truncated_normal([5, 5, 6, 16], stddev=0.1)),strides=[1,1,1,1],padding="SAME"),tf.Variable(tf.constant(0.1, shape=[16])))),ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME"), [-1, 7*7*16]) 原理同5.需要注意的是,在该层结束后,需要进行全连接操作,故需要将本层的输出转化为一个“列向量”,故使用
tf.reshape()操作。
7.fc1 = tf.nn.relu(tf.matmul(conv_relu_pool_2, tf.Variable(tf.truncated_normal([784, 120], stddev=0.1)))+tf.Variable(tf.constant(0.1, shape=[120])))
该行为第1全连接层
tf.matmul(conv_relu_pool_2, tf.Variable(tf.truncated_normal([784, 120], stddev=0.1)))表示第2卷积层、激活步骤、池化层步骤的结果与一参数矩阵相乘,tf.matmul()代表矩阵相乘,代表全连接操作。
tf.nn.relu(。。。+tf.Variable(tf.constant(0.1, shape=[120])))表示结果加一个偏置后激活。
8.fc2 = tf.nn.relu(tf.matmul(fc1, tf.Variable(tf.truncated_normal([120, 84], stddev=0.1)))+tf.Variable(tf.constant(0.1, shape=[84])))
该行为第2全连接层,解释同7.
9.fc3 = tf.nn.softmax(tf.matmul(fc2, tf.Variable(tf.truncated_normal([84, 10], stddev=0.1)))+tf.Variable(tf.constant(0.1, shape=[10])))
该行为第3全连接层,解释同7,不过激活函数变为softmax,该激活函数用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,可以看成概率来理解,从而来进行多分类
10.train_step = tf.train.AdamOptimizer(1e-3).minimize(-tf.reduce_sum(y_true*tf.log(fc3)))
该步骤为网络的训练步骤。
-tf.reduce_sum(y_truetf.log(fc3))
tf.log(fc3)涉及到对数似然损失函数,对于用于分类的softmax激活函数,对应的损失函数一般都是用对数似然函数,tf.reduce_sum()表示降维求和,有人会问都是1维降什么维?主要是没有tf.sum()。。。
tf.train.AdamOptimizer(1e-3).minimize是实现Adam算法的优化器。众所周知,y_true与tf.log(fc3)同号时,才算学习正确,所以和即交叉熵越大越好,但是为什么是minimize(-。。。)呢,因为tf.train.AdamOptimizer(1e-3).minimize没给maximize这个函数。。。
11.accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(fc3, 1), tf.argmax(y_true, 1)), 'float'))
tf.equal(tf.argmax(fc3, 1), tf.argmax(y_true, 1))
tf.argmax()方法用于计算张量沿着某一维度的最大值的索引,第二个参数 axis: 指定的维(或轴),取值为0,代表延列取最大值索引,取值为1,表示延行取最大值索引,如果不指定,则默认为按照列计算,取值为2,3,4…是,则为多维函数的相应维度,以此类推。tf.equal()顾名思义,看二者相不相等,反馈是TRUE或FALSE。
tf.cast()转化数据格式,因为下一步要开始计算了。
tf.reduce_mean()表示降维求均值,也就是准确率。
12.mnist = input_data.read_data_sets('MNIST', one_hot=True)
提取mnist,one_hot=True简单理解就是要使用标签。
13.tf.InteractiveSession().run(tf.global_variables_initializer())
Python在变量定义后要对全局的变量进行赋值之后才能运行,这步就是实现这个功能。
14.for i in range(1000):
就是训练1000步。
15.batch = mnist.train.next_batch(60)
一次从样本中选取60个进行训练,正好60*1000=60000,训练集里就是60000个数据。
16.if i%100 == 0:
每100步展示一次结果。
17.print('step {}, training accuracy: {}'.format(i, accuracy.eval(feed_dict={x: batch[0], y_true: batch[1]})))
print(…)很好理解,accuracy.eval(feed_dict={x: batch[0], y_true: batch[1]}),.eval就是运行的意思,feed_dict顾名思义就是“喂_字典”,“喂”就是输入数据,“字典”就是数据的索引,至于x: batch[0], y_true: batch[1],不用想太多,batch[0]就是图片数据,batch[1]就是标签。
18.train_step.run(feed_dict={x: batch[0], y_true: batch[1]})
顾名思义,开始训练。
19.print('test accuracy: {}'.format(accuracy.eval(feed_dict={x: mnist.test.images, y_true:mnist.test.labels})))
计算验证集的准确度。
import tensorflow as tf import tensorflow.examples.tutorials.mnist.input_data as input_data x = tf.placeholder('float', shape=[None, 28*28]) y_true = tf.placeholder('float', shape=[None, 10]) conv_relu_pool_1 = tf.nn.max_pool(tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(tf.reshape(x, [-1, 28, 28, 1]),tf.Variable(tf.truncated_normal([5, 5, 1, 6], stddev=0.1)),strides=[1,1,1,1],padding="SAME"),tf.Variable(tf.constant(0.1, shape=[6])))),ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME") conv_relu_pool_2 = tf.reshape(tf.nn.max_pool(tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv_relu_pool_1,tf.Variable(tf.truncated_normal([5, 5, 6, 16], stddev=0.1)),strides=[1,1,1,1],padding="SAME"),tf.Variable(tf.constant(0.1, shape=[16])))),ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME"), [-1, 7*7*16]) fc1 = tf.nn.relu(tf.matmul(conv_relu_pool_2, tf.Variable(tf.truncated_normal([784, 120], stddev=0.1)))+tf.Variable(tf.constant(0.1, shape=[120]))) fc2 = tf.nn.relu(tf.matmul(fc1, tf.Variable(tf.truncated_normal([120, 84], stddev=0.1)))+tf.Variable(tf.constant(0.1, shape=[84]))) fc3 = tf.nn.softmax(tf.matmul(fc2, tf.Variable(tf.truncated_normal([84, 10], stddev=0.1)))+tf.Variable(tf.constant(0.1, shape=[10]))) train_step = tf.train.AdamOptimizer(1e-3).minimize(-tf.reduce_sum(y_true*tf.log(fc3))) accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(fc3, 1), tf.argmax(y_true, 1)), 'float')) mnist = input_data.read_data_sets('MNIST', one_hot=True) tf.InteractiveSession().run(tf.global_variables_initializer()) for i in range(1000): batch = mnist.train.next_batch(60)#一次从样本中选取60个进行训练 if i%100 == 0: print('step {}, training accuracy: {}'.format(i, accuracy.eval(feed_dict={x: batch[0], y_true: batch[1]}))) train_step.run(feed_dict={x: batch[0], y_true: batch[1]}) print('test accuracy: {}'.format(accuracy.eval(feed_dict={x: mnist.test.images, y_true:mnist.test.labels})))
如有错误与疑问,请不吝赐教,谢谢。