该网络包括五个卷积层和三个全连接层,输入图像经过卷积操作和全连接层的操作,最后输入具有1000个节点的softmax分类器完成图像分类。
该网络通过使用线性整流函数ReLU作为激活函数,引入局部响应归一化缓解梯度消失问题;使用数据增强和Dropout技术大大缓解了过拟合问题。
实验过程
论文中是使用了ImageNet数据集进行训练和测试的,由于设备计算能力有限,我自己选择的了用mnist数据集进行试验,相应的稍微更改了一下网络结构。
训练集:mnist数据集是一组28*28的灰度图像,训练数据集包含 60,000 个样本, 测试数据集包含 10,000 样本。
#coding:utf-8
import tensorflow as tf
#import tensorflow.compat.v1 as tfc
#import tensorflow_datasets
#mnist = tensorflow_datasets.load('mnist')
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data',one_hot=True)
sess = tf.InteractiveSession() #在运行之前先定义一些操作,Session必须在所有操作全部定义完才能是运行
#初始化权值和偏重
def weight_variabe(shape):
initial = tf.truncated_normal(shape, stddev=0.1)#产生截断的正态分布张量,shape表示产生的张量维度,mean为均值,stddev为标准差
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.1, shape = shape)
return tf.Variable(initial)
#卷积和池化层实现 卷积核3 步长1 池化3,步长2
def conv2d(x,W):
return tf.nn.conv2d(x,W, strides = [1,1,1,1], padding = 'SAME')
def max_pool_3x3(x):
return tf.nn.max_pool(x,ksize = [1,3,3,1],strides = [1,2,2,1], padding = 'SAME')
#LRN 局部响应归一化层
def norm(x,lsize = 4):
#return tf.nn.lrn(x,lsize,bias = 1.0,aplha = 0.001/9.0 ,beta = 0.75)
return tf.nn.lrn(x,lsize,bias = 1.0, beta = 0.75)
#构建卷积层
#placeholder 在tf暂时储存变量
x = tf.placeholder(tf.float32, [None,784]) #这里我们给它分配一个 [None, 784] 的形状,
# 其中 784 是单个展平的 28 x 28 像素 MNIST 图像的维度,
# None 表示对应于批量大小的第一个维度可以是任何大小。
y_ = tf.placeholder(tf.float32,[None,10]) #10种分类结果
keep_prob = tf.placeholder(tf.float32)
x_image = tf.reshape(x,[-1,28,28,1]) #这里是将一组图像矩阵x重建为新的矩阵,其中-1表示a由实际情况来定
#第二三维是指图像的大小
#灰度图对应1,rgb图对应3.
W_conv1 = weight_variabe([3,3,1,64]) # 前两位3 3表示网格大小,第三位1表示输入通道数目
#第四位64表示输出通道数目(也可以理解为使用的卷积核个数、得到的特征图张数)
b_conv1 = bias_variable([64]) #每个输出通道都有一个偏置项,因此偏置项个数为364
h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1) + b_conv1) #使用Relu进行第一次卷积
h_pool1 = max_pool_3x3(h_conv1) #使用3x3的网格最大池化(第一次)
h_norm1 = norm(h_pool1, lsize=4)
W_conv2 = weight_variabe([3,3,64,128])
b_conv2 = bias_variable([128])
h_conv2 = tf.nn.relu(conv2d(h_norm1,W_conv2) + b_conv2) #第二次卷积
h_pool2 = max_pool_3x3(h_conv2) #第二次池化
h_norm2 = norm(h_pool2, lsize=4)
W_conv3 = weight_variabe([3,3,128,256])
b_conv3 = bias_variable([256])
h_conv3 = tf.nn.relu(conv2d(h_pool2,W_conv3) + b_conv3) #第三次卷积
h_pool3 = max_pool_3x3(h_conv3) #第三次池化
h_norm3 = norm(h_pool3, lsize=4)
#实现全连接和Dropout
W_fc1 = weight_variabe([4*4*256,1024]) #加入一个有1024个神经元的全连接层
b_fc1 = bias_variable([1024])
h_norm3_flat = tf.reshape(h_norm3,[-1,4*4*256]) #将池化后的结果reshape成一个一维向量
h_fc1 = tf.nn.relu(tf.matmul(h_norm3_flat,W_fc1) + b_fc1) #在与其权重相乘,加上偏置项,再通过一个ReLU激活函数
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob) #防止过拟合的方法dropout:
# 完全随机选取经过神经网络流一半的数据来训练,在每次训练过程中用0来替代被丢掉的激活值,其它激活值合理缩放。
W_fc2 = weight_variabe([1024,1024])
b_fc2 = bias_variable([1024])
h_fc2 = tf.nn.relu(tf.matmul(h_fc1_drop,W_fc2) + b_fc2)
h_fc2_drop = tf.nn.dropout(h_fc2 , keep_prob)
#实现Readout层
W_fc3 = weight_variabe([1024,10])
b_fc3 = bias_variable([10])
y_conv = tf.matmul(h_fc2_drop,W_fc3) +b_fc3
#参数训练与模型评估
cross_entropy = tf.reduce_mean( #计算交叉熵的代价函数
tf.nn.softmax_cross_entropy_with_logits(labels = y_,logits=y_conv)
)
#使用优化算法使得代价函数最小化
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
#找出预测正确的标签
correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
#得出通过正确个数除以总数得出准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
sess.run(tf.global_variables_initializer())
for i in range(20000):
batch = mnist.train.next_batch(50)
if i%100 == 0:
train_accuracy = accuracy.eval(feed_dict={
x:batch[0] , y_:batch[1] , keep_prob:1.0
})
print('step %d,training accuracy %g'%(i ,train_accuracy))
train_step.run(feed_dict = {x:batch[0], y_:batch[1] , keep_prob : 0.5})
print('test accuracy %g'% accuracy.eval(feed_dict = {
x:mnist.test.images, y_:mnist.test.labels , keep_prob:1.0
}))
sess.close()
LeNet和AlexNet的对比:
本周复现了两个模型,在大结构上,其实两个模型十分相似,但是有一些细节上的差距,对后面的网络结构影响有深刻的意义。
在AlexNet之前,CNN普遍使用平均池化,AlexNet全部使用最大池化,避免平均池化的模糊化效果。并且AlexNet中提出让步长比池化核的尺寸小,这样池化层的输出之间会有重叠和覆盖,提升了特征的丰富性。
AlexNet 优势在于:网络增大(5个卷积层+3个全连接层+1个softmax层),同时解决过拟合(使用了dropout,LRN等技术),并且利用多GPU加速计算(在自己试验是没法实现,所以忽略了这条).。
遇到的问题及解决方法:
①运行代码过程出现的问题,由于TensorFlow版本问题,网上公开的代码在2.0版本的TensorFlow中已经不适用,需要进行语法修改或者版本切换。
②在真正跑代码的过程中发现,虽然已经明白了模型训练的流程,但是面对实际的代码还是无从下手,甚至不知道代码的含义。所以我在跑代码的过程中,不只是单纯的copy网上的代码跑出结果,也会深究每行代码的作用,关键函数的参数含义,并且在注释上一一标注出来。
参考文章:
https://blog.youkuaiyun.com/qq_31278903/article/details/90671908