
附课程链接第七讲.卷积神经网络7.2lenet5代码讲解由于个人使用Win7系统并未完全按照课程所讲以下记录的也基本是我的结合课程做的Windows系统PyCharm操作。且本人有python基础故一些操作可能简略。并未完全按照网课。记住编写代码时除注释内容外字符均使用英文格式。一、Lenet神经网络结构为Lenet5神经网络是LeCun等人在1998年提出的。Lenet5使用了6个5×5×1的核对输入的32×32×1的图片进行卷积计算卷积计算后的结果通过激活函数由于不使用零填充、步长为1用此公式计算得到输出尺寸为28。因为用了6个核所以输出深度是6。之后又用2×2的核对28×28×6的图片进行池化操作、步长为2又用公式求得输出尺寸为14。可见通过池化操作减少了75%的操作池化操作不改变输入图片的深度。所以输出是14×14×6。使用16个5×5×6的核核的深度要和输入的深度一致所以核的深度是6这个5×5×6的核对输入图片14×14×6进行卷积计算卷积计算的结果通过激活函数。由于用了16个5×5×6的核输出的深度等于使用卷积核的个数是10×10×16。再用2×2的核对输入的10×10×16的图片进行池化操作池化操作对每个深度分别操作。池化不改变图片的深度输出是5×5×16的图片最后把5×5×16的图片转换成一维数组喂入全连接网络计算分类评估值。上述全过程如下二、对Lenet神经网络微调以适应mnist数据集mnist数据集存放的是28×28×1的灰度图片我们把Lenet5进行更改让其匹配28×28×1的输入图片。微调操作微调后的结构三、代码Lenet神经网络在mnist数据集上的实现主要分为三个部分前向传播过程mnist_lenet5_forward.py、反向传播过程mnist_lenet5_backward.py、测试过程mnist_lenet5_test.py。1、前向传播过程在前向传播过程中搭建了神经网络。 前向传播 importtensorflowastf#在前向传播中首先定义了神经网络的相关参数IMAGE_SIZE28#mnist数据集每张图片分辨率也就是横向和纵向的边长都是28个像素点NUM_CHANNELS1#是灰度图所以通道数是1CONV1_SIZE5#第一层卷积核大小为5CONV1_KERNEL_NUM32#第一层核个数为32CONV2_SIZE5#第二层卷积核大小为5CONV2_KERNEL_NUM64#第二层卷积核个数为64FC_SIZE512#第一层全连接网络有512个神经元OUTPUT_NODE10#第二层全连接网络有10个神经元对应了十分类的输出 权重w生成函数与之前一样 defget_weight(shape,regularizer):#shape表示生成张量的维度regularizer表示正则化权重wtf.Variable(tf.truncated_normal(shape,stddev0.1))#生成去掉过大偏离点的正太分布随机数ifregularizer!None:tf.add_to_collection(losses,tf.contrib.layers.l2_regularizer(regularizer)(w))#如果使用正则化regularizer ! None则把每一个w的正则化计入到总lossesreturnw 偏置b生成函数与之前一样 defget_bias(shape):#shape表示生成张量的维度btf.Variable(tf.zeros(shape))#生成初始值为0的偏置breturnb 卷积层计算函数 defconv2d(x,w):returntf.nn.conv2d(x,w,strides[1,1,1,1],paddingSAME)#给出输入图片x、所用卷积核w#x是对输入的描述是个四阶张量。一阶给出一次喂入多少张图片也就是batch二、三阶分别给出图片行、列分辨率四阶给出输入的通道数。#w是对卷积核的描述也是个四阶张量。一、二阶分别给出图片行、列分辨率。三阶是通道数四阶是有多少个卷积核。#strides为卷积核滑动步长二、三阶表示滑动步长都是1。#使用零填充所以padding SAME。 最大池化层计算函数 defmax_pool_2x2(x):returntf.nn.max_pool(x,ksize[1,2,2,1],strides[1,2,2,1],paddingSAME)#x是对输入的描述是个四阶张量。一阶给出一次喂入多少张图片也就是batch二、三阶分别给出图片行、列分辨率四阶给出输入的通道数。#池化层大小ksize是2*2的。#strides二、三阶表示滑动步长都是1。#使用零填充所以padding SAME。 搭建神经网络描述从输入到输出的数据流 defforward(x,train,regularizer):conv1_wget_weight([CONV1_SIZE,CONV1_SIZE,NUM_CHANNELS,CONV1_KERNEL_NUM],regularizer)#初始化第一层卷积核conv1_bget_bias([CONV1_KERNEL_NUM])#初始化第一层偏置conv1conv2d(x,conv1_w)#执行卷积计算输入是x卷积核是初始化的conv1_wrelu1tf.nn.relu(tf.nn.bias_add(conv1,conv1_b))#对卷积后的输出conv1添加偏置通过激活函数pool1max_pool_2x2(relu1)#将激活后的输出进行最大池化conv2_wget_weight([CONV2_SIZE,CONV2_SIZE,CONV1_KERNEL_NUM,CONV2_KERNEL_NUM],regularizer)#第二层卷积核的深度等于上层卷积核的个数conv2_bget_bias([CONV2_KERNEL_NUM])conv2conv2d(pool1,conv2_w)#第二层的输入是上一层的输出pool1relu2tf.nn.relu(tf.nn.bias_add(conv2,conv2_b))#通过激活函数pool2max_pool_2x2(relu2)#通过最大池化。pool2是第二层卷积的输出。需要把它从三维张量变为二维张量pool_shapepool2.get_shape().as_list()#得到pool2输出矩阵的维度存入list()中nodespool_shape[1]*pool_shape[2]*pool_shape[3]#提取特征的长度pool_shape[1]提取特征的宽度pool_shape[2]提取特征的深度pool_shape[3]#这三个相乘就是所有特征点的个数reshapedtf.reshape(pool2,[pool_shape[0],nodes])#pool_shape[0]是一个batch的值。#将pool2表示成batch行所有特征点作为个数列的二维形状喂入全连接网络中#通过第一层全连接网络fc1_wget_weight([nodes,FC_SIZE],regularizer)fc1_bget_bias([FC_SIZE])fc1tf.nn.relu(tf.matmul(reshaped,fc1_w)fc1_b)#把上层的输出reshaped乘以本层线上的权重加上偏置过激活函数iftrain:fc1tf.nn.dropout(fc1,0.5)#如果是训练阶段则对该层输出使用50%的dropout#通过第二层全连接网络fc2_wget_weight([FC_SIZE,OUTPUT_NODE],regularizer)#初始化第二层全连接网络的wfc2_bget_bias([OUTPUT_NODE])#初始化第二层全连接网络的bytf.matmul(fc1,fc2_w)fc2_b#上层的输出和本层线上的权重相乘加上偏置得到输出yreturny2.反向传播过程在反向传播过程中基本与之前的代码相同。只增加了对输入数据的形状调整。 反向传播 importtensorflowastffromtensorflow.examples.tutorials.mnistimportinput_dataimportmnist_lenet5_forwardimportos#os模块importnumpyasnp BATCH_SIZE100#定义每轮喂入神经网络多少张图片LEARNING_RATE_BASE0.005#最开始的学习率LEARNING_RATE_DECAY0.99#学习率衰减率REGULARIZER0.0001#正则化系数STEPS50000#共训练多少轮MOVING_AVERAGE_DECAY0.99#滑动平均衰减率MODEL_SAVE_PATHmnist_model#模型的保存路径MODEL_NAMEmnist_model#模型保存的文件名train_num_examples60000#对于反向传播而言要训练网络参数defbackward(mnist):#在backward函数中读入mnist x,y_是定义的占位符指定参数为浮点型。由于卷积层输入为四阶张量 x的一阶表示每轮喂入的图片数量 二、三阶分别表示图片的行、列分辨率 四阶表示输入的通道数 xtf.placeholder(tf.float32,[BATCH_SIZE,mnist_lenet5_forward.IMAGE_SIZE,mnist_lenet5_forward.IMAGE_SIZE,mnist_lenet5_forward.NUM_CHANNELS])#给x占位y_tf.placeholder(tf.float32,[None,mnist_lenet5_forward.OUTPUT_NODE])#给y_占位ymnist_lenet5_forward.forward(x,True,REGULARIZER)#True表示训练参数时使用dropout操作global_steptf.Variable(0,trainableFalse)#给轮数计数器赋初值设定为不可训练cetf.nn.sparse_softmax_cross_entropy_with_logits(logitsy,labelstf.argmax(y_,1))# 实现softmax和交叉熵的协同使用cemtf.reduce_mean(ce)losscemtf.add_n(tf.get_collection(losses))#调用包含正则化的损失函数loss#定义指数衰减学习率learning_ratetf.train.exponential_decay(LEARNING_RATE_BASE,global_step,train_num_examples/BATCH_SIZE,LEARNING_RATE_DECAY,staircaseTrue)#定义训练过程train_steptf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_stepglobal_step)#定义滑动平均ematf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)ema_opema.apply(tf.trainable_variables())withtf.control_dependencies([train_step,ema_op]):train_optf.no_op(nametrain)#实例化saversavertf.train.Saver()#tf.compat.v1.train.Saver#在with结构中初始化所有变量withtf.Session()assess:init_optf.global_variables_initializer()sess.run(init_op)ckpttf.train.get_checkpoint_state(MODEL_SAVE_PATH)ifckptandckpt.model_checkpoint_path:saver.restore(sess,ckpt.model_checkpoint_path)#在for循环中迭代STEPS轮foriinrange(STEPS):xs,ysmnist.train.next_batch(BATCH_SIZE)#每次读入BATCH_SIZE组图片和标签#用np.reshape实现了从数据集中取出的xs进行reshape操作reshaped_xsnp.reshape(xs,(BATCH_SIZE,mnist_lenet5_forward.IMAGE_SIZE,mnist_lenet5_forward.IMAGE_SIZE,mnist_lenet5_forward.NUM_CHANNELS))_,loss_value,stepsess.run([train_op,loss,global_step],feed_dict{x:reshaped_xs,y_:ys})#用sess.run把喂入神经网络的x做了同样的修改ifi%1000:#每100轮打印loss值print(After %d training steps(s),loss on training batch is %g.%(step,loss_value))saver.save(sess,os.path.join(MODEL_SAVE_PATH,MODEL_NAME),global_stepglobal_step)#保存模型到当前会话defmain():mnistinput_data.read_data_sets(mnist_work/,one_hotTrue)#mnist input_data.read_data_sets(./data/, one_hotTrue)backward(mnist)if__name____main__:main()3、测试程序在测试程序中会输出识别准确率也仅对x的形状进行了调整。由于测试是使用训练好的网络所以不适用dropout所有神经元都要参加运算。importtime#为了延时导入了time模块importtensorflowastffromtensorflow.examples.tutorials.mnistimportinput_dataimportmnist_lenet5_forwardimportmnist_lenet5_backwardimportnumpyasnp TEST_INTERVAL_SECS5#定义程序循环的间隔时间是5sdeftest(mnist):withtf.Graph().as_default()asg:#绘制计算图中的节点#给输入图像x和y_占位xtf.placeholder(tf.float32,[mnist.test.num_examples,mnist_lenet5_forward.IMAGE_SIZE,mnist_lenet5_forward.IMAGE_SIZE,mnist_lenet5_forward.NUM_CHANNELS])y_tf.placeholder(tf.float32,[None,mnist_lenet5_forward.OUTPUT_NODE])#用前向传播过程计算出y的值ymnist_lenet5_forward.forward(x,False,None)#实例化可还原滑动平均的saver这样所有参数在会话中北加载时会被赋值为各自的滑动平均值ematf.train.ExponentialMovingAverage(mnist_lenet5_backward.MOVING_AVERAGE_DECAY)ema_restoreema.variables_to_restore()savertf.train.Saver(ema_restore)#计算正确率correct_predictiontf.equal(tf.argmax(y,1),tf.argmax(y_,1))accuracytf.reduce_mean(tf.cast(correct_prediction,tf.float32))whileTrue:withtf.Session()assess:#加载训练好的模型ckpt也就是把滑动平均值赋给各个参数ckpttf.train.get_checkpoint_state(mnist_lenet5_backward.MODEL_SAVE_PATH)#如果已有ckpt模型则恢复ifckptandckpt.model_checkpoint_path:#恢复会话saver.restore(sess,ckpt.model_checkpoint_path)#恢复轮数global_stepint(ckpt.model_checkpoint_path.split(/)[-1].split(-)[-1])reshaped_xnp.reshape(mnist.test.images,(mnist.test.num_examples,mnist_lenet5_forward.IMAGE_SIZE,mnist_lenet5_forward.IMAGE_SIZE,mnist_lenet5_forward.NUM_CHANNELS))#计算准确率accuracy_scoresess.run(accuracy,feed_dict{x:reshaped_x,y_:mnist.test.labels})#打印提示print(After %s training step(s),test accuracy %g%(global_step,accuracy_score))#如果没有模型else:print(No checkpoint file found)#模型不存在提示returntime.sleep(TEST_INTERVAL_SECS)defmain():mnistinput_data.read_data_sets(mnist_work/,one_hotTrue)test(mnist)if__name____main__:main()我们运行一下代码看一下使用卷积之后的效果。运行mnist_lenet5_backward.py运行mnist_lenet5_test.py【BUG在运行mnist_lenet5_backward.py时出现了这样的bugerr, “a Variable name or other graph key that is missing”)解决方案我这里报错的原因是原来的文件夹内训练好的模型都还没删除太多了删掉以后就能正常运行了】至此第七讲结束。附助教的Tensorflow笔记7