一、CNN卷积神经网络的经典网络综述
下面图片参照博客:http://blog.csdn.net/cyh_24/article/details/51440344
二、LeNet-5网络
LeNet-5网络是针对灰度图进行训练的,输入图像大小为32*32*1,不包含输入层的情况下共有7层,每层都包含可训练参数(连接权重)。注:每个层有多个Feature Map,每个Feature Map通过一种卷积滤波器提取输入的一种特征,然后每个Feature Map有多个神经元。
1、C1层是一个卷积层(通过卷积运算,可以使原信号特征增强,并且降低噪音)
第一层使用5*5大小的过滤器6个,步长s = 1,padding = 0。即:由6个特征图Feature Map构成,特征图中每个神经元与输入中5*5的邻域相连,输出得到的特征图大小为28*28*6。C1有156个可训练参数(每个滤波器5*5=25个unit参数和一个bias参数,一共6个滤波器,共(5*5+1)*6=156个参数),共156*(28*28)=122,304个连接。
2、S2层是一个下采样层(平均池化层)(利用图像局部相关性的原理,对图像进行子抽样,可以减少数据处理量同时保留有用信息,降低网络训练参数及模型的过拟合程度)。
第二层使用2*2大小的过滤器,步长s = 2,padding = 0。即:特征图中的每个单元与C1中相对应特征图的2*2邻域相连接,有6个14*14的特征图,输出得到的特征图大小为14*14*6。池化层只有一组超参数 f 和 s,没有需要学习的参数。
3、C3层是一个卷积层
第三层使用5*5大小的过滤器16个,步长s = 1,padding = 0。即:由16个特征图Feature Map构成,特征图中每个神经元与输入中5*5的邻域相连,输出得到的特征图大小为10*10*16。C3有416个可训练参数(每个滤波器5*5=25个unit参数和一个bias参数,一共16个滤波器,共(5*5+1)*16=416个参数)。
4、S4层是一个下采样层(平均池化层)
第四层使用2*2大小的过滤器,步长s = 2,padding = 0。即:特征图中的每个单元与C3中相对应特征图的2*2
邻域相连接,有16个5*5的特征图,输出得到的特征图大小为5*5*16。没有需要学习的参数。
5、F5层是一个全连接层
有120个单元。每个单元与S4层的全部400个单元之间进行全连接。F5层有120*(400+1)=48120个可训练参数。
如同经典神经网络,F5层计算输入向量和权重向量之间的点积,再加上一个偏置。
6、F6层是一个全连接层
有84个单元。每个单元与F5层的全部120个单元之间进行全连接。F6层有84*(120+1)=10164个可训练参数。
如同经典神经网络,F6层计算输入向量和权重向量之间的点积,再加上一个偏置。
7、Output输出层
输出层由欧式径向基函数(Euclidean Radial Basis Function)单元组成,每类一个单元,每个有84个输入。
换句话说,每个输出RBF单元计算输入向量和参数向量之间的欧式距离。输入离参数向量越远,RBF输出的越大。
用概率术语来说,RBF输出可以被理解为F6层配置空间的高斯分布的负log-likelihood。
给定一个输式,损失函数应能使得F6的配置与RBF参数向量(即模式的期望分类)足够接近。
总结:
随着网络越来越深,图像的宽度和高度都在缩小,信道数量一直在增加。目前,一个或多个卷积层后边跟一个
池化层,再接上一个全连接层的排列方式很常用。
层(layer)激活后的维度(Activation Shape)激活后的大小(Activation Size)参数w、b(parameters)
Input(32,32,1)10240
CONV1(f=5,s=1)(28,28,6)4704(5*5+1)*6=156
POOL1(14,14,6)11760
CONV2(f=5,s=1)(10,10,16)1600(5*5*6+1)*16=2416
POOL2(5,5,16)4000
FC3(120,1)120120*(400+1)=48120
FC4(84,1)8484*(120+1)=10164
Softmax(10,1)1010*(84+1)=850
三、AlexNet网络的框架介绍
AlexNet网络共有:卷积层 5个,池化层 3个,全连接层:3个(其中包含输出层)。
卷积神经网络的结构并不是各个层的简单组合,它是由一个个“模块”有机组成的,在模块内部,
各个层的排列是有讲究的。比如AlexNet的结构图,它是由八个模块组成的。
1、AlexNet——模块一和模块二
结构类型为:卷积-激活函数(ReLU)-降采样(池化)-标准化
这两个模块是CNN的前面部分,构成了一个计算模块,这个可以说是一个卷积过程的标配,从宏观的角度来看,
就是一层卷积,一层降采样这样循环的,中间适当地插入一些函数来控制数值的范围,以便后续的循环计算。
2、AlexNet——模块三和模块四
模块三和四也是两个same卷积过程,差别是少了降采样(池化层),原因就跟输入的尺寸有关,特征的数据量已经比较小了,
所以没有降采样。
3、AlexNet——模块五
模块五也是一个卷积和池化过程,和模块一、二一样的。模块五输出的其实已经是66的小块儿了。
(一般设计可以到11的小块,由于ImageNet的图像大,所以66也正常的。)
原来输入的227227像素的图像会变成6*6这么小,主要原因是归功于降采样(池化层),
当然卷积层也会让图像变小,一层层的下去,图像越来越小。
4、模块六、七、八
模块六和七就是所谓的全连接层了,全连接层就和人工神经网络的结构一样的,结点数超级多,连接线也超多,
所以这儿引出了一个dropout层,来去除一部分没有足够激活的层。
模块八是一个输出的结果,结合上softmax做出分类。有几类,输出几个结点,每个结点保存的是属于该类别的概率值。
AlexNet总结:
(二)整体架构
1、AlexNet.py文件实现前向传播过程以及网络的参数。
2、train.py文件实现训练的过程。
3、eval.py文件实现测试的过程。
四、应用的基础知识点
1、tf.get_variable函数:获取变量。在训练神经网络时会创建这些变量,在测试时会通过保存的模型加载这些变量的值。而且更方便的是,可以在变量加载时将滑动平均变量重命名,所以可以直接通过同样的名字在训练时使用变量自身,而在测试时使用变量的滑动平均值。
2、name_scope与variable_scope的区别:
name_scope 是给op_name加前缀, variable_scope是给get_variable()创建的变量的名字加前缀。
详见链接:http://blog.csdn.net/u012436149/article/details/53081454
3、sparse_softmax_cross_entropy_with_logits与softmax_cross_entropy_with_logits区别
见链接:https://www.jianshu.com/p/75f7e60dae95
4、Tensorflow中tf.train.exponential_decay函数(指数衰减法)
#!/usr/bin/env python# -*- coding:utf-8 -*-# Author:ZhengzhengLiu #用AlexNet实现电脑破译手语——SIGNG datasets#训练集:1080张图片,每张图片大小为:64*64*3,表示数字0至5,每个数字的图片为180张#测试集:120张图片,每张图片大小为:64*64*3,表示数字0至5,每个数字的图片为20张 #AlexNet网络框架实现前向传播过程及网络的参数 import tensorflow as tf #显示网络每一层结构的函数,展示每一个卷积层或池化层输出Tensor的尺寸def print_acrivations(t): """ 显示每一层的名称(t.op.name)和tensor的尺寸(t.get_shape.as_list()) param : t -- Tensor类型的输入 """ print(t.op.name," ",t.get_shape.as_list()) #配置AlexNet网络的参数NUM_CHANNELS = 3 #图片的通道数 #第一层卷积层的尺寸和深度(卷积核个数)CONV1_SIZE = 11CONV1_DEEP = 96 #第二层卷积层的尺寸和深度(卷积核个数)CONV2_SIZE = 5CONV2_DEEP = 256 #第三层卷积层的尺寸和深度(卷积核个数)CONV3_SIZE = 3CONV3_DEEP = 384 #第四层卷积层的尺寸和深度(卷积核个数)CONV4_SIZE = 3CONV4_DEEP = 256 #第五层卷积层的尺寸和深度(卷积核个数)CONV5_SIZE = 3CONV5_DEEP = 256 #第六、七层全连接层的尺寸FC6_SIZE = 4096FC7_SIZE = 4096 #输出层的尺寸(分类数目)OUTPUT_NODE = 10 def AlexNet(input_tensor,train,regularizer): """ AlexNet网络框架实现前向传播过程 param : input_tensor -- 输入的张量,一般为图片 train -- 用于区分训练和测试过程 regularizer -- 正则化 return: out -- 输出最后一层 """ # 第一个卷积层 with tf.variable_scope("conv1"): # 第一个卷积层,用截断的正态分布函数tf.truncated_normal_initializer 初始化卷积核conv1_weights # 卷积核大小为 11*11*3,个数为96个 conv1_weights = tf.get_variable(name="weight",shape=[CONV1_SIZE,CONV1_SIZE,NUM_CHANNELS,CONV1_DEEP], dtype=tf.float32,initializer=tf.truncated_normal_initializer(stddev=0.1)) # 初始化偏向biases全部为0 conv1_biases = tf.get_variable(name="bias",shape=[CONV1_DEEP], dtype=tf.float32,initializer=tf.constant_initializer(0.0)) # 卷积操作,步长s = 4,padding = "SAME" conv1 = tf.nn.conv2d(input=input_tensor,filter=conv1_weights,strides=[1,4,4,1],padding="SAME") # 将conv和baises加起来并进行relu激活 conv1 = tf.nn.relu(tf.nn.bias_add(conv1,conv1_biases)) # 打印conv1的结构 print_acrivations(conv1) # 卷积层后添加LRN层(除AlexNet其他经典网络基本无LRN层,效果不明显且速度有所降低) lrn1 = tf.nn.lrn(conv1, depth_radius=4, bias=1.0, alpha=0.001 / 9, beta=0.75, name="lrn1") # 最大池化层(尺寸为 3*3,步长s=2*2) pool1 = tf.nn.max_pool(lrn1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding="VALID", name="pool1") # 打印pool1的结构 print_acrivations(pool1) #第二个卷积层,卷积核大小为(5,5,96,256) with tf.variable_scope("conv2"): conv2_weights = tf.get_variable(name="weight",shape=[CONV2_SIZE,CONV2_SIZE,CONV1_DEEP,CONV2_DEEP], dtype=tf.float32,initializer=tf.truncated_normal_initializer(stddev=0.1)) conv2_biases = tf.get_variable(name="bias",shape=[CONV2_DEEP], dtype=tf.float32,initializer=tf.constant_initializer(0.0)) conv2 = tf.nn.conv2d(input=pool1,filter=conv2_weights,strides=[[1,1,1,1]],padding="SAME") conv2 = tf.nn.relu(tf.nn.bias_add(conv2,conv2_biases)) print_acrivations(conv2) lrn2 = tf.nn.lrn(conv2, depth_radius=4, bias=1.0, alpha=0.001 / 9, beta=0.75, name="lrn2") pool2 = tf.nn.max_pool(lrn2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding="VALID", name="pool2") print_acrivations(pool2) # 第三个卷积层,卷积核大小为(3,3,256,384),无LRN与最大池化 with tf.variable_scope("conv3"): conv3_weights = tf.get_variable(name="weight",shape=[CONV3_SIZE,CONV3_SIZE,CONV2_DEEP,CONV3_DEEP], dtype=tf.float32,initializer=tf.truncated_normal_initializer(stddev=0.1)) conv3_biases = tf.get_variable(name="bias",shape=[CONV3_DEEP], dtype=tf.float32,initializer=tf.constant_initializer(0.0)) conv3 = tf.nn.conv2d(input=pool2,filter=conv3_weights,strides=[1,1,1,1],padding="SAME") conv3 = tf.nn.relu(tf.nn.bias_add(conv3,conv3_biases)) print_acrivations(conv3) # 第四个卷积层,卷积核大小为(3,3,384,256),无LRN与最大池化 with tf.variable_scope("conv4"): conv4_weights = tf.get_variable(name="weight",shape=[CONV4_SIZE,CONV4_SIZE,CONV3_DEEP,CONV4_DEEP], dtype=tf.float32,initializer=tf.truncated_normal_initializer(stddev=0.1)) conv4_biases = tf.get_variable(name="bias",shape=[CONV4_DEEP], dtype=tf.float32,initializer=tf.constant_initializer(0.0)) conv4 = tf.nn.conv2d(input=conv3,filter=conv4_weights,strides=[1,1,1,1],padding="SAME") conv4 = tf.nn.relu(tf.nn.bias_add(conv4,conv4_biases)) print_acrivations(conv4) # 第五个卷积层,卷积核大小为(3,3,256,256) with tf.variable_scope("conv5"): conv5_weights = tf.get_variable(name="weight",shape=[CONV5_SIZE,CONV5_SIZE,CONV4_DEEP,CONV5_DEEP], dtype=tf.float32,initializer=tf.truncated_normal_initializer(stddev=0.1)) conv5_biases = tf.get_variable(name="bias",shape=[CONV5_DEEP], dtype=tf.float32,initializer=tf.constant_initializer(0.0)) conv5 = tf.nn.conv2d(input=conv4,filter=conv5_weights,strides=[1,1,1,1],padding="SAME") conv5 = tf.nn.relu(tf.nn.bias_add(conv5,conv5_biases)) print_acrivations(conv5) pool5 = tf.nn.max_pool(conv5,ksize=[1,3,3,1],strides=[1,2,2,1],padding="VALID",name="pool5") print_acrivations(pool5) # 第六层 —— 全连接层及dropout #将第五层输出转化为第六层全连接层输入为向量的格式,即:将矩阵拉成一个向量 #每层输入输出都为一个batch矩阵,得到的维度包含pool5_shape[0] = batch中数据的个数 pool5_shape = pool5.get_shape().as_list() nodes = pool5_shape[1]*pool5_shape[2]*pool5_shape[3] dense = tf.reshape(pool5,shape=[pool5_shape[0],nodes]) #向量化 with tf.variable_scope("fc6"): fc6_weights = tf.get_variable(name="weight",shape=[nodes,FC6_SIZE],dtype=tf.float32, initializer=tf.truncated_normal_initializer(stddev=0.1)) #当给出了正则化生成函数,将当前变量的正则化损失加入名字为losses的集合 #add_to_collection函数将一个张量加入一个集合,自定义的集合losses,不在tensorflow自动管理的集合列表中中 if regularizer != None: tf.add_to_collection("losses",regularizer(fc6_weights)) fc6_biases = tf.get_variable(name="bias",shape=[FC6_SIZE],dtype=tf.float32, initializer=tf.constant_initializer(0.0)) fc6 = tf.nn.relu(tf.add(tf.matmul(dense,fc6_weights),fc6_biases)) #dropout只在训练时使用 if train: fc6 = tf.nn.dropout(fc6,keep_prob=0.7) # 第七层 —— 全连接层及dropout with tf.variable_scope("fc7"): fc7_weights = tf.get_variable(name="weight",shape=[FC6_SIZE,FC7_SIZE],dtype=tf.float32, initializer=tf.truncated_normal_initializer(stddev=0.1)) if regularizer != None: tf.add_to_collection("losses",regularizer(fc7_weights)) fc7_biases = tf.get_variable(name="bias",shape=[FC7_SIZE],dtype=tf.float32, initializer=tf.constant_initializer(0.0)) fc7 = tf.nn.relu(tf.add(tf.matmul(fc6,fc7_weights),fc7_biases)) if train: fc7 = tf.nn.dropout(fc7,keep_prob=0.7) # 第八层 —— 全连接层/输出层 with tf.variable_scope("fc8"): fc8_weights = tf.get_variable(name="weight",shape=[FC7_SIZE,OUTPUT_NODE],dtype=tf.float32, initializer=tf.truncated_normal_initializer(stddev=0.1)) if regularizer != None: tf.add_to_collection("losses",regularizer(fc8_weights)) fc8_biases = tf.get_variable(name="bias",shape=[OUTPUT_NODE],dtype=tf.float32, initializer=tf.constant_initializer(0.0)) fc8 = tf.add(tf.matmul(fc7,fc8_weights),fc8_biases) return fc8
#!/usr/bin/env python# -*- coding:utf-8 -*-# Author:ZhengzhengLiu #AlexNet网络的训练过程import osfrom tensorflow.python.framework import opsimport tensorflow as tffrom SIGNG_AlexNet import * #配置神经网络参数BATCH_SIZE = 32 #一个batch数据的数目TRAINING_EPOCH = 30000 #训练迭代次数LEARNING_RATE_BASE = 0.8 #基础学习率LEARNING_RATE_DECAY = 0.99 #学习率衰减REGULARAZTION_RATE = 0.0001 #描述模型复杂度的正则化在损失函数中的系数MOVING_AVERAGE_DECAY = 0.99 #模型保存的路径和文件名MODEL_SAVE_PATH = "/path/to/model"MODEL_NAME = "model.ckpt" #训练模型def AlexNet_train(X_train,Y_train,X_test,Y_test,learning_rate=LEARNING_RATE_BASE, num_epochs=TRAINING_EPOCH, minibatch_size=BATCH_SIZE, print_cost=True): ops.reset_default_graph() # 在没有tf变量重写的情况下重新运行模型 (m, n_H0, n_W0, n_C0) = X_train.shape n_y = Y_train.shape[1] costs = [] # 列表存放目标函数值 #创建占位符 X = tf.placeholder(dtype=tf.float32,shape=(None,n_H0, n_W0, n_C0),name="X") Y = tf.placeholder(dtype=tf.float32,shape=(None,n_y),name="Y") #正则化 regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE) #前向传播 out = SIGNG_AlexNet.AlexNet(X,regularizer) #变量模拟神经网络中的迭代次数,可用于动态控制衰减率 global_step = tf.Variable(0,trainable=False) #定义损失函数、学习率、滑动平均操作机训练过程 variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step) variable_averages_op = variable_averages.apply(tf.trainable_variables()) cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=out,labels=tf.argmax(Y,1)) cross_entropy_mean = tf.reduce_mean(cross_entropy) cost = cross_entropy_mean + tf.add_n(tf.get_collection("losses")) learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE,global_step, m/BATCH_SIZE,LEARNING_RATE_DECAY) optm = tf.train.AdamOptimizer(learning_rate).minimize(cost,global_step=global_step) with tf.control_dependencies([optm,variable_averages_op]): train_op = tf.no_op(name="train") #初始化tensorflow持久化 saver = tf.train.Saver() with tf.Session() as sees: init = tf.initialize_all_variables() sees.run(init) #循环进行模型训练 for epoch in range(TRAINING_EPOCH): minibatch_cost = 0 num_minibatch = int(m / minibatch) minibatchs = random_mini_batches(X_train, Y_train, minibatch) for minibatch in minibatchs: #选择一个minibatch (minibatch_X,minibatch_Y) = minibatch _,temp_cost,step = sees.run([train_op,cost,global_step], feed_dict={X:minibatch_X,Y:minibatch_Y}) minibatch_cost += temp_cost / num_minibatch # 每 1000 次epoch打印目标函数值cost if print_cost == True and epoch % 1 == 0: costs.append(minibatch_cost) if print_cost == True and epoch % 1000 == 0: print("Cost after epoch %i:%f" % (step, minibatch_cost)) saver.save( sees,os.path.join(MODEL_SAVE_PATH,MODEL_NAME),global_step==global_step ) # 计算准确的预测 correct_predict = tf.equal(tf.argmax(out, 1), tf.argmax(Y, 1)) # 在测试集上计算准确率 accuracy = tf.reduce_mean(tf.cast(correct_predict, tf.float32)) print(accuracy) train_accuracy = accuracy.eval({X: X_train, Y: Y_train}) test_accuracy = accuracy.eval({X: X_test, Y: Y_test}) print("Train Acurracy :" + str(train_accuracy)) print("Test Acurracy :" + str(test_accuracy)) return train_accuracy, test_accuracy #加载数据集X_train_orig,Y_train_orig,X_test_orig,Y_test_orig,classes = load_dataset()#标准化特征值,使得数值在0至1之间X_train = X_train_orig/255X_test = X_test_orig/255Y_train = convert_to_one_hot(Y_train_orig,6).TY_test = convert_to_one_hot(Y_test_orig,6).T #调用构建的模型AlexNet_train(X_train,Y_train,X_test,Y_test)
七、ZFNet
————————————————
版权声明:本文为CSDN博主「loveliuzz」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/loveliuzz/article/details/79131131