一、前言
本篇应该是爬虫获取20分类数据集使用不同网络模型分类的最后一篇,本篇主要讲ResNet的网络架构及实现,具体如何更改相应的文件位置请参考上一篇 ,经过不断的测试与训练博主发现一个不小的问题,就是网络训练了很久都不能拟合实际效果,一开始是以为每个epoch迭代速度慢的原因,后来经过排查发现,实际是因为参数初始化的值与零相近的结果。在链式法则中,这样的参数初始化的值易陷入梯度弥散的情况。相关修改已写入码云中。码云链接 。数据集和网络的梳理见链接07-vgg16-TensorFlow 20 classification of flower identification
二、介绍
ResNet的层数从GoogLeNet的22层增加到了152层,其主要的创新之处在于使用了残差网络,该创新点主要是为了解决当网络层次加深时网络无法训练的问题。
ResNet在网络中加入了恒等映射层y=x层,其主要作用是使得网络随深度的变化而不会产生权重衰减和梯度衰减或者消失。相当于在网络的中间开辟了多个通道使得输入与输出的层数间隔的均值减小,残差结构的优化的具体实现方式即在原来的拟合输出H(x)编程输出和输入的差值H(x)-x,其中H(x)是某一层原始的期望映射输出,x是输入。
二层残差学习单元,其包括两个3*3大小的卷积层并使用relu的激活方式激活,三层残差学习单元,其将二层残差学习单元中的一个3*3大小的卷积和分解为两个1*1大小的卷积层,放在3*3的卷积层前后,执行先降维再升维的操作。本篇将使用三层残差学习单元来构建此网络模型。
三、具体实现过程
1.定义全局变量

c=0

2.定义卷积层,里面使用到全局变量

def conv(net,kernel_size,out_channels,strides=[1,1,1,1]):
    in_channels=net.get_shape()[-1]
    global  c
    with tf.variable_scope('c%d'%c):
        net=tf.nn.conv2d(net,filter=get_variable('w',[kernel_size[0],kernel_size[1],in_channels,out_channels]),strides=strides,padding='SAME')
        net=tf.nn.bias_add(net,bias=get_variable('b',[out_channels]))
        net=tf.nn.relu(net)
    c+=1
    return net

3.定义残差升维神经元

#定义残差升维神经元
def Res_Unit_increase(net):
    out_channels=int(net.get_shape()[-1])/2
    #1*1降维
    out_net=conv(net,kernel_size=[1,1],out_channels=out_channels)
    #3*3卷积
    out_net=conv(out_net,kernel_size=[3,3],out_channels=out_channels)
    #1*1升维
    out_net=conv(out_net,kernel_size=[1,1],out_channels=out_channels*4)
    #net升维
    net=conv(net,kernel_size=[1,1],out_channels=out_channels*4)
    return net+out_net

4.定义残差同维神经元

def Res_Unit_same(net):
    out_channels=int(net.get_shape()[-1])/4
    #1*1降维
    out_net=conv(net,kernel_size=[1,1],out_channels=out_channels)
    #3*3卷积
    out_net=conv(out_net,kernel_size=[3,3],out_channels=out_channels)
    #1*1升维
    out_net=conv(out_net,kernel_size=[1,1],out_channels=out_channels*4)
    return out_net+net

5.定义5次同残差

def Res_five_same(net):
    out_net=Res_Unit_same(net)
    out_net=Res_Unit_same(out_net)
    out_net=Res_Unit_same(out_net)
    out_net=Res_Unit_same(out_net)
    out_net=Res_Unit_same(out_net)
    return out_net

6.定义残差网络结构

def Res_Net(x,y):
    conv1_out = 64
    with tf.variable_scope('input'):
        network = tf.reshape(x, shape=[-1, 224, 224, 3], name='input')
    with tf.variable_scope('conv1-64'):
        network = tf.nn.conv2d(network, filter=get_variable('w', [7, 7, 3, conv1_out]), strides=[1, 1, 1, 1],
                               padding='SAME')
        network = tf.nn.bias_add(network, bias=get_variable('b', [conv1_out]))
        network = tf.nn.relu(network)
    with tf.variable_scope('max_pool_1'):
        network=tf.nn.max_pool(network,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
    with tf.variable_scope('conv2-64'):
        out_channels=network.get_shape()[-1]
        network=conv(network,kernel_size=[1,1],out_channels=out_channels)
    with tf.variable_scope('max_pool_2'):
        network=tf.nn.max_pool(network,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
    #每个resnet相当于3层网络
    #56*56*64
    with tf.variable_scope('resnet1'):
        network=Res_Unit_same(network)
    #56*56*64  5层
    with tf.variable_scope('max_pool_3'):
        network=tf.nn.max_pool(network,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
    #28*28*64
    with tf.variable_scope('resnet2-6'):
        network=Res_five_same(network)
    #28*28*64  20层
    with tf.variable_scope('resnet7'):
        network=Res_Unit_increase(network)
    #28*28*128 21层
    with tf.variable_scope('max_pool_4'):
        network=tf.nn.max_pool(network,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
    #14*14*128
    with tf.variable_scope('resnet8-12'):
        network=Res_five_same(network)
    #14*14*128 36层
    with tf.variable_scope('resnet13-17'):
        network=Res_five_same(network)
    #14*14*128 51层
    with tf.variable_scope('resnet18'):
        network=Res_Unit_increase(network)
    #14*14*256 52层
    with tf.variable_scope('max_pool_5'):
        network = tf.nn.max_pool(network, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    #7*7*256
    with tf.variable_scope('resnet19-23'):
        network=Res_five_same(network)
    #7*7*256 67层
    with tf.variable_scope('resnet24-28'):
        network=Res_five_same(network)
    #7*7*256 82层
    with tf.variable_scope('resnet29-33'):
        network=Res_five_same(network)
    #7*7*256 97层
    with tf.variable_scope('resnet34'):
        network=Res_Unit_increase(network)
    #7*7*512 100层
    with tf.variable_scope('avg_pool_1'):
        network=tf.nn.avg_pool(network,ksize=[1,7,7,1],strides=[1,7,7,1],padding='VALID')
    #1*1*512

    with tf.variable_scope('fc_1'):
        image_shape = network.get_shape()
        print(image_shape)
        network = tf.reshape(network, shape=(-1, image_shape[3]))
        network = tf.add(tf.matmul(network, get_variable('w', [image_shape[3],20]), ),get_variable('b', [20]))
    return tf.nn.softmax(network)

四、分析与总结

1.本结构使用100层的ResNet的网络结构,具体调通代码的过程和上一篇 一模一样,这么就不赘述了,附上本次开始运行时的贴图。

resnet网络计算FPS resnet20_TensorFlow


2.代码中有部分做出了修正,比如说为了保证数据集的泛化能力和鲁棒性,在训练的时候使用了随机的index索引信息,具体方式见码云

3.欢迎大家的交流与指正,下一篇预计会写关于RNN或者LSTM的分类网络模型代码,是不是很期待呢?