基于神经网络手写数字识别的简略设计
引用了小哥的代码,我自己照着看了一遍后就写了一下,感觉对于初学者还是比较有益的,感谢https://blog.csdn.net/weixin_46824122/article/details/105417564的贡献!!下面时我自己进行整理了一下后的所写内容,希望对大家有益啦~
1. 代码块
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
mg = tf.Graph()
with mg.as_default():#打开tensorflow中默认的图,在图上进行以下的操作
#手写数字图片数据的读取
#1 准备数据
mnist = input_data.read_data_sets("./MNIST_data", one_hot=True)#读取图片数据
#x y_true 主要目的是占位,为以后的运行会话时,将数据传入
x = tf.placeholder(tf.float32, [None, 784])
y_true = tf.placeholder(tf.int32, [None, 10])
input_X = tf.reshape(x, [-1, 28, 28, 1])#因为输入的图片是[1,784]格式,需要转换为[28,28]的格式的图片(灰度图,二维图)
#2 卷积神经网络
#卷积层——卷积、激活、池化
#刚开始是随机定义卷积核(权重)和偏置的值
conv1_weights = tf.Variable(tf.random_normal([3, 3, 1, 32]))#卷积核大小为3*3*1 32个
conv1_bias = tf.Variable(tf.random_normal([32]))
conv1_x = tf.nn.conv2d(input_X, conv1_weights, [1,1,1,1],padding="SAME")+conv1_bias#参数为输入的图片数据、卷积核、步长、padding值
#padding为SAME时,输出大小为输入大小/步长,取上整
#padding为VALID时,输出大小为(输入大小-卷积核大小+1)/ 步长
relu1_x = tf.nn.relu(conv1_x) #激活函数,relu、tanh等
#池化层参数为输入数据、框大小、步长
pool1_x = tf.nn.max_pool(relu1_x,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")
#第一层卷积层输出结果 28/1 = 28 28/2=14 → 14*14*32
conv2_weights = tf.Variable(tf.random_normal([3,3,32,64]))
conv2_bias = tf.Variable(tf.random_normal([64]))
conv2_x = tf.nn.conv2d(pool1_x,conv2_weights,[1,1,1,1],padding="SAME")+conv2_bias
relu2_x = tf.nn.relu(conv2_x)
pool2_x = tf.nn.max_pool(relu2_x,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")
#第二层卷积层输出结果 14/1 = 14 14/2=7 → 7*7*64
#3 全连接层
#[None,7*7*64] * [7*7*64,10] = [None,10]
x_fc = tf.reshape(pool2_x,shape=[-1,7*7*64])
weights_fc = tf.Variable(tf.random_normal([7*7*64,10]))
bias_fc = tf.Variable(tf.random_normal([10]))
y_predict = tf.matmul(x_fc,weights_fc)+bias_fc#得到的最后的结果
#4 softmax回归函数以及交叉熵损失计算
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=y_predict,labels=y_true))
#利用tensorflow中的损失优化进行训练,0.01为学习率,通过让损失值loss最小化,回归得到最适合的卷积核和偏置
#5 梯度下降法、Adam、Adagrad等方法
train_op = tf.train.AdamOptimizer(0.01).minimize(loss)
#得出每次训练的结果与真实数据y_true是否相同,判断相同个数
equal_list = tf.equal(tf.argmax(y_true,1),tf.argmax(y_predict,1))
#算出准确率即结果的平均值
accuracy = tf.reduce_mean(tf.cast(equal_list,tf.float32))
#初始化所有的变量
init_op = tf.global_variables_initializer()
#保存训练模型
saver = tf.train.Saver()
#开启会话去训练
with tf.Session(graph=mg) as sess:
sess.run(init_op)#进行初始化操作
#记录准确率
acc = []
#循环训练100次
for i in range(100):
#每次训练从所有数据中拿出500个作为一次,然后下次训练就拿出后面500个,如果到最后了还没结束,就重新打乱所有的键值再重新取值
mnist_x,mnist_y = mnist.train.next_batch(500)
mnist_x *=255 #由于数据是经过归一化的,像素值为0-1 所以需要✖255
#开始运行训练
#将数据“喂”进去,train_op即损失优化的最后结果保存在_里面
_,ac = sess.run([train_op,accuracy],feed_dict={x:mnist_x,y_true:mnist_y})
print("训练第%d步的准确率为:%f,损失为:%f"%(i+1,
#输出的准确率、损失值都需要重新sess.run一下,不然输出不了
sess.run(accuracy,feed_dict={x:mnist_x,y_true:mnist_y}),
sess.run(loss, feed_dict={x: mnist_x, y_true: mnist_y})
))
acc.append(ac) #将ac加入到acc数组中
plt.plot(acc) #用图形表示变化
plt.show()
#将模型保存起来
saver.save(sess,r"model_ckpt\second.ckpt")
2 整理的相关一些知识点
👉 Padding=”SAME” Padding=”VALID”
从程序中可以看出我的输入是553,过滤器是333,padding设置的值是SAME,所以我一开始预想的是输出557(有7个过滤器),可是最后程序运行的结果是337,和我预想的不一致,原来tensorflow官网定义的padding如下:
padding = “SAME”输入和输出大小关系如下:
输出大小等于输入大小除以步长向上取整,s是步长大小;
padding = “VALID”输入和输出大小关系如下:
输出大小等于输入大小减去滤波器大小加上1,最后再除以步长(f为滤波器的大小,s是步长大小)。
因此还是上述的那个例子,我的输入是553,滤波器是333,padding= “SAME”,步长s = 2,因此根据公式我的输出是(5/2=2.5),2.5向上取整是3,因此符合上述程序输出的结果,如果我将padding的值改成“VALID”,则最后的输出结果是
(5-3+1)/2=1.5,1.5向上取整是2,因此输出应该是227。
👉 tf.argmax() tf.agrmin()
axis = 0:
axis=0时比较每一列的元素,将每一列最大元素所在的索引记录下来,最后输出每一列最大元素所在的索引数组。
axis = 1:
axis=1的时候,将每一行最大元素所在的索引记录下来,最后返回每一行最大元素所在的索引数组。
👉 tf.cast(x,tf.float32)
数据类型转换。
👉 mnist.train.next_batch
是专门用于由tensorflow提供的MNIST教程的函数。它的工作原理是在开始时将训练图像和标签对随机化,并在每次调用该函数时选择每个随后的batch_size张图像。一旦到达末尾,图像标签对将再次随机分配,并重复该过程。仅在使用所有可用对后,才重新组合和重复整个数据集。
👉 tf.Graph().as_default()
表示实例化了一个类,一个用于 tensorflow 计算和表示用的数据流图,通俗来讲就是:在代码中添加的操作(画中的结点)和数据(画中的线条)都是画在纸上的“画”,而图就是呈现这些画的纸,你可以利用很多线程生成很多张图,但是默认图就只有一张。
tf.Graph().as_default() 表示将这个类实例,也就是新生成的图作为整个 tensorflow 运行环境的默认图,如果只有一个主线程不写也没有关系,tensorflow 里面已经存好了一张默认图,可以使用tf.get_default_graph() 来调用(显示这张默认纸),当你有多个线程就可以创造多个tf.Graph(),就是你可以有一个画图本,有很多张图纸,这时候就会有一个默认图的概念了。
适合小白哦~~~有错误的地方欢迎批评指正!!!!
爱你三千遍!!!!~~