实验内容:
1. 编写TensorFlow框架的CNN网络,利用数据流编程的方法编写2层卷积网络和全连接层等。对MNIST手写数字数据集读取和划分为测试集和训练集,定义网络的输入和输出参数的类型大小,定义损失函数、优化器最小化损失函数、正确率。最后输出模型在测试集上的正确率。
(1)参考人工智能教学实训系统,理解原理。
(2)在(1)的基础上,要求,将填充padding设置为1,步长strids设置为2,卷积核大小为3*3,然后训练网络,最终输出模型再测试集上的准确率。
实验报告要求:
实验代码:
(完整代码,适当注释)伪代码
线性回归伪代码如下:
输入:数据集D,交叉验证参数k
输出结果:参数w
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import time
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
learning_rate = 1e-4
keep_prob_rate = 0.9
max_epoch = 2000
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 2,2, 1], padding='SAME')
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
def compute_accuracy(v_xs, v_ys):
global prediction
y_pre = sess.run(prediction, feed_dict={xs: v_xs, keep_prob: 1})
correct_prediction = tf.equal(tf.argmax(y_pre, 1), tf.argmax(v_ys, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
result = sess.run(accuracy, feed_dict={xs: v_xs, ys: v_ys, keep_prob: 1})
return result
xs = tf.placeholder(tf.float32, [None, 784], name='x_input')
ys = tf.placeholder(tf.float32, [None, 10], name='y_input')
keep_prob = tf.placeholder(tf.float32)
x_image = tf.reshape(xs, [-1, 28, 28, 1])
# 卷积层 1
W_conv1 = weight_variable([3, 3, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
# 卷积层 2
W_conv2 = weight_variable([3, 3, 32, 64]) # patch 5x5, in size 32, out size 64
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
# 全连接层 1
W_fc1 = weight_variable([2*2 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 2*2 * 64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
prediction = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
cross_entropy = tf.reduce_mean(-tf.reduce_sum(ys * tf.log(prediction),
reduction_indices=[1]))
train_step = tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
print("step 0, test accuracy %g" %compute_accuracy(
mnist.test.images, mnist.test.labels))
start = time.time()
for i in range(max_epoch):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={xs: batch_xs, ys: batch_ys, keep_prob: keep_prob_rate})
if (i+1) % 50 == 0:
print("步骤 %d, test 准确率 %g" % ((i+1), compute_accuracy(
mnist.test.images, mnist.test.labels)))
end = time.time()
print('******************************************************')
print("运行时间:%.2f秒" % (end - start))
- 首先加载数据
上面使用内置函数加载tensorflow的默认图片数据
里面包括60000张数据,即为60000*784(28*28 图片的长和宽分别有28个像素)
其中训练集有55000张 测试集有10000张,验证集有5000张。
其中的10表示0-9,因为数字有0-9,数组上面分别表示相应的概率。只要数字下标概率哪个比较大,就表示当前的图片是数字几。
这里定义了初始权重,采用的是普通正态分布,
tf.truncated_normal(shape, mean, stddev)
截断的产生正态分布的随机数,即随机数与均值的差值若大于两倍的标准差,则重新生成。
shape,生成张量的维度
mean,均值
stddev,标准差
这里维度则由传入的参数决定,stddev=0.1则表示标准差为0.1
这里则表示 维度为shape,默认填充用0.1填充,这里定义的偏置函数,所以默认偏置设置为0.1
这里定义了卷积的函数,x表示因变量。W表示函数的参数。strides=[1, 2,2, 1]则表示步长为上下步长2的卷积,后面padding=”SAME”则表示使用零填充,目的是防止某些数据读取不到,因为可能会发生数组越界,我们用0填充的话,不影响原来的数据,也保证的数据的公平。即都可以学习到。
这里定义了池化的的函数。其中的参数 ksize 表示滑动窗口为2*2的。因为不在batch和channels上做池化,所以这两个维度设为了1。同理strides=[1, 2, 2, 1],则表示步长为2*2并且不在batch和channels做池化。padding: 填充的方法,SAME或VALID,SAME表示添加全0填充,VALID表示不添加。这里则表示填充0
函数传入的是v_xs, v_ys。
V_xs为测试的图片x
v_ys则为测试的图片的y值,即为真实值
这里定义了计算预测率的函数。首先global prediction 声明全局变量。Prediction是我们通过cnn学习出来的参数值,将x输入进去然后得出预测值correct_prediction,然后再通过tf.reduce_mean降维度得到平均值,最终返回result拿到准确率。
Xs表示加载因变量x 是55000*784的
Ys表示加载真实值y是555000*10的
keep_prob 我的理解是这里生成一个变量然后后面的有进行用到
x_image:则表示转换成图片的维度,前面-1表示任意多张图片。然后图片维度是28*28的。后面的1表示单通道。因为是黑白图片,后面可以直接用plt进行画图直接将图片画出来。
好下面进行卷积层1
首先生成一个W_conv1= weight_variable([3, 3, 1, 32]) 这里呢我们就是想一张图片卷积32次,然后的卷积核的大小为3*3,图片为单通道1.所以即为3,3,1,32。
然后生成偏置变量b_conv1。因为卷积个数为32次,所以这里的维度应该为32
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
这里我们用relu的激活函数,然后进行计算卷积核大小。
h_pool1 = max_pool_2x2(h_conv1)下面调用函数进行池化。
下面是卷积层1的维度分析:
1.首先一张图片的维度为28*28,然后想卷积32次,假设一张图片,那么卷积后的维度则应该为
【28+2-3/2+1】 取整得到14所以此时一张图片的维度为14*14*32
2.下面进行池化,由于我们进行的是最大池化,并且窗口大小为2*2,步长为2*2所以计算得到出维度应该降为原来的一半即一张图片的维度为 7*7*32
下面是卷积层2的维度分析:
1.首先通过卷积层一后一张图片的维度为7*7*32,那么卷积后的维度则应该为
【7+2-3/2+1】 取整得到3所以此时一张图片的维度为3*3*32
2.下面进行池化,由于我们进行的是最大池化,并且窗口大小为2*2,步长为2*2所以计算得到出维度应该降为原来的一半即一张图片的维度为 2*2*32
下面是连接层1的维度分析:
1. h_pool2_flat = tf.reshape(h_pool2, [-1, 2*2 * 64])这里通过reshape函数将 卷积层2后的图片维度 转换成 (*)*256的其中-1表示可以有多张图片。
然后再下面通过激活函数relu和交叉熵损失函数。维度为(*)*256
下面是连接层2的维度分析:
1.初始w 1024*10 因为连接层的维度为-1* 1024 那么矩阵相乘后得到的则为-1*10其中-1表示多张图片,10表示数字0-9,从而将多维的展开成一维的。
2.其中softmax即为做归一化处理,即将数据转化成(0,1)的数值,这样可以加快计算,也有利于数据的处理。
下面则是定义交叉熵损失函数,以及用adam优化器进行梯度下降。这里计算得到了交叉熵函数,我们最终使用梯度下降的方法来求解交叉熵函数的最小值,不断迭代更新w从而得到最佳的权重w。
这里则是通过主函数进行计算预测的准确率。有了解到tensorflow是通过图来进行计算的,
with tf.Session() as sess:
加载自变量x数据
以及加载因变量y的真实值
其中keep_prob_rate这里则为防止过拟合的意思。这里我设置成0.9
通过查官网上了解到的解释是:
意思是每个元素被保留的概率,那么 keep_prob:1就是所有元素全部保留的意思。
一般在大量数据训练时,为了防止过拟合,添加Dropout层,设置一个0~1之间的小数。
其中max_epoch表示学习的次数。这里可以设置为3000次,即梯度下降迭代3000次。
实验结果:
实验反思或感想:本次实验设置两个卷积层和两个连接层,本实验的基本原理是将一张图片(28*28)首先卷积32次得到28*28*32,1次卷积后后14*14*32,2次卷积后为7*7*32,连接一次为-1*(256),连接两次后为-1*(10),其中的-1表示为多张图片。最终得到一个一维张量,然后再判断0-9哪个下表的数组的概率大,就可以判断出本张图片是数字几。
每一步骤都要加激活函数,relu,因为不加激活函数的话,我们永远进行的是线性操作,那么我觉得人工神经网络存在的意义就不是很大,即他就和线性回归基本一样了。正因为激活函数的存在,我们划分的分界线就可以是曲线了,从而更能体现人工神经网络的价值所在。
实际上则为 先将图片的局部特征提取出来,最终再拟合成一维张量。
然后呢,最终得到一个交叉熵的损失函数,其中的因变量是w,我们通过求解梯度下降的方法来求解交叉熵函数的最小值,不断迭代更新w,这样我们通过3000次的更新后就基本得到了比较的w的参数。