Toggle navigation
首页
(current)
问答
文章
话题
商城
登录
注册
【干货】复现ResNet系列模型
卷积神经网络
cnn
ResNet
图像分类
tensorflow
入门
一文搭建ResNet干货教程
# 阅前须知: 为了使本文结构精简,理解简单,所以会尽量少涉及到有关数学公式,降低学习门槛,带领读者快速搭建ResNet-152经典模型并投入训练。 #####本文的最后会放出博主自己复现的ResNet模型,帮助大家投入自己的数据集进行训练。 如读者在阅读时发现有错误的地方欢在评论的地方指出,共同进步 联系邮箱:fffeiyee@163.com > 编译环境:Python3.5 TensorFlow-gpu 1.3.0 ## 一、结构分析 关于ResNet的来源我就不进行赘述了,相信读者都对这个包揽各大图像识别赛事冠军的模型或多或少有一定的了解。  说起卷积模型,LeNet、Inception、Vgg都是我们在学习图像识别领域神经网络的经典模型,以上图片模型就是经典的Vgg-19与34层传统卷积网络、ResNet-34的对比。 从计算量上来讲,Vgg-19的三层全连接神经网络的计算量明显大于传统卷积网络和ResNet,传统卷积网络和ResNet的参数数量相同。  从训练拟合度上讲,论文中分别给出了plain-18、plain-34和resnet-18、resnet-34的对比,我们不难发现plain随着层数的增加,精度并没有得到明显的提升,而resnet不仅随着层数的增加提高了训练精度,且相较同深度的plain而言精度更高 在以往的学习之中,我们知道深度网络随着层数的增加,很容易造成“退化”和“梯度消失”的问题,训练数据的过拟合。但在ResNet中,作者给出了一种解决方案:增加一个identity mapping(恒等映射,由于本文面向读者基础不同,就不加以详述,有能力的同学可以看一下ResNet作者的论文) #### **残差模块**:  上图是一个残差模块的结构示意,残差块想要有效果需要有两层或两层以上的layer,同时,输入x与输出F(x)的维度也须相同。 #### Residual block:  在对于高于50层深度的resnet模型中,为了进一步减少计算量且保证模型精度,作者对残差模块进行了优化,将内部两层3*3layer换成1*1 → 3*3 → 1*1,。首先采用1*1卷积进行深度降维,减少残差模块在深度上的计算量,第二层3*3layer和之前的模块功能一样,提取图像特征,第三层1*1layer用于维度还原。 那么问题又来了,既然已经经过了3*3卷积,那输出维度怎么会一样呢?作者在论文中给出了三种解决方案: 1、维度不足部分全0填充 2、输入输出维度一致时使用恒等映射,不一致时使用线性投影 3、对于所有的block均使用线性投影。 在本文中,我们对模型主要采用全0填充。 好,以上就是简单的理论入门,接下来我们开始着手用TensorFlow对理论进行代码实现。 ## 二、实现规划(ResNet-50-101-152) #### 三种规格模型的结构表:  基本思想是对不同深度的ResNet结构来定义相应的字典。 在本文中,我们的模型搭建方式是以字典的形式进行循环堆砌。 #### 结构字典: > ResNet_demo = { "layer_50":[{"depth": 256,"num_class": 3}, {"depth": 512,"num_class": 4}, {"depth": 1024,"num_class": 6}, {"depth": 2048,"num_class": 3}], "layer_101": [{"depth": 256, "num_class": 3}, {"depth": 512, "num_class": 4}, {"depth": 1024, "num_class": 23}, {"depth": 2048, "num_class": 3}], "layer_152": [{"depth": 256, "num_class": 3}, {"depth": 512, "num_class": 8}, {"depth": 1024, "num_class": 36}, {"depth": 2048, "num_class": 3}] 子类模块规划 在ResNet网络传递的过程中,我们来探讨一些即将遇到的问题: 1.降采样过程 2.通道填充 #### 降采样过程:  降采样过程用于不同类瓶颈模块之间传递的过程,例如上图中粉色卷积层和蓝色卷积层之间的数据交互,蓝色卷积层中的/2就是降采样处理 降采样模块代码实现 def sampling(input_tensor, #Tensor入口 ksize = 1, #采样块大小 stride = 2): #采样步长 data = input_tensor data = slim.max_pool2d(data,ksize,stride = stride) return data 通道填充用于输入数据x与结果数据F(x)生成残差和时造成的通道不匹配问题 通道填充模块代码实现 def highway(input_tensor, # 输入Tensor depth,): # 输出通道 data = input_tensor data = slim.conv2d(data,depth,1,activation_fn=None) data = tf.layers.batch_normalization(data, training=is_train) return data 好的,两个子类问题已经得到解决,下面来对残差模块进行规划实现 #### 残差模块: 因为搭建方向选择layer大于等于50层,所以我们采用论文中给出的第二种残差模块(1*1+3*3+1*1) def bottleneck(input_tensor,output_depth): #取出通道 redepth = input_tensor.get_shape().as_list()[3] # 当通道不相符时,进行全零填充并降采样 if output_depth != redepth: #全零填充 input_tensor = depthFilling(input_tensor,output_depth) #降采样 input_tensor= sampling(input_tensor) data = input_tensor #降通道处理 data = slim.conv2d(inputs = data, num_outputs = output_depth//4, kernel_size = 1,stride = 1) #提取特征 data = slim.conv2d(inputs = data, num_outputs = output_depth//4, kernel_size = 3,stride = 1) #通道还原 data = slim.conv2d(inputs = data, num_outputs = output_depth, kernel_size = 1,stride = 1, activation_fn=None, normalizer_fn=None) #生成残差 data = data + input_tensor data = tf.nn.relu(data) return data 有了残差模块,我们就可以对网络结构进行堆砌了 #### 整体堆砌: #堆叠ResNet模块 def inference(input_tensor, #数据入口 demos, #模型资料(list) num_output, #出口数量 is_train): data = input_tensor #第一层卷积7*7,stride = 2,深度为64 data = conv2d_same(data,64,7,2,is_train,None,normalizer_fn = False) data = slim.max_pool2d(data,3,2,scope="pool_1") with tf.variable_scope("resnet"): # with tf.variable_scope("resnet"): #堆叠总类瓶颈模块 demo_num = 0 for demo in demos: demo_num += 1 print("--------------------------------------------") #堆叠子类瓶颈模块 with tf.variable_scope("num_" + str(demo_num)): for i in range(demo["num_class"]): print(demo_num) if demo_num is not 4: if i == demo["num_class"] - 1: stride = 2 else: stride = 1 else: stride = 1 with tf.variable_scope("bottleneck_" + str(i + 1)): data = bottleneck(data,demo["depth"],stride,is_train) print("--------------------------------------------") data = tf.layers.batch_normalization(data,training=is_train) data = tf.nn.relu(data) #平均池化,也可用Avg_pool函数 data = tf.reduce_mean(data, [1, 2], keep_dims=True,name='nal_pool') #data = slim.avg_pool2d(data,2) print("output : ", data) #最后全连接层 data = slim.conv2d(data,num_output,1,activation_fn=None,scope='final_conv') data_shape = data.get_shape().as_list() nodes = data_shape[1] * data_shape[2] * data_shape[3] data = tf.reshape(data, [-1, nodes]) return data #### inference调用方式: inference(input_tensor, #数据入口 demos, #模型资料(list) num_output, #出口数量 is_train) #是否处于训练模式 ### 参考文献: https://arxiv.org/pdf/1512.03385.pdf http://blog.csdn.net/xxy0118/article/details/78324256 http://blog.csdn.net/mao_feng/article/details/52734438 ### github: 别忘了Star : https://github.com/FeiYee/ResNet-TensorFlow GitHub上的代码有中文注释,看不懂的同学随时可以私我
发表于 2018-11-15 20:52
阅读 ( 287 )
分类:
图像识别
0 推荐
收藏
你可能感兴趣的文章
昂钛客AI深度学习实战课程大纲
183 浏览
tensorflow源码解析之seq2seq.py文件(上)
429 浏览
利用seq2seq的Decoder-Encoder机制实现序列生成模型(下)
747 浏览
关于使用卷机神经网络识别蝴蝶分类与位置的一些问题
522 浏览
生成式对抗网络(GAN)下篇----tensorflow实现
615 浏览
相关问题
CNN人脸识别 TF 损失函数和准确率都非常差 而且在某一位置上下波动
1 回答
Seq2Seq模型预测部分改写
2 回答
tensorflow写的回归LSTM无法进行预测帮我解答下吧。
3 回答
神经网络训练初期验证集准确率为0,后面又上去了,出现这种情况是什么原因?
3 回答
新手 有关Tensorflow使用的问题求解答
2 回答
为什么CIFAR-10模型准确率不提升?
3 回答
0 条评论
请先
登录
后评论
FeiYee
天文爱好者
3 篇文章
作家榜
»
admin
20 文章
整理者
15 文章
swsuh2018
15 文章
LittleMiss
12 文章
随心
8 文章
mrguan
4 文章
智子
4 文章
阿杰
4 文章
×
发送私信
发给:
内容:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!