ResNet残差神经网络原理详解与ResNet50代码实现详解(附keras代码实现详解)

         摘要:

resnet神经网络原理详解

resnet为何由来:

resnet网络模型解释

resnet50具体应用代码详解:

keras实现resnet50版本一:

keras实现resnet50版本二:

参考文献:

摘要:

卷积神经网络由两个非常简单的元素组成,即卷积层和池化层。尽管这种模型的组合方式很简单,但是对于任何特定的计算机视觉问题,可以采用无限种方式设计这些层,并提出新的解决模型。也就是说在当前的研究应用上既有用这些层的通用模式去解决特定问题,又有提出新的模型结构去提高解决问题得效率。因此,该卷积神经网络模型的经典结构为当前问题的解决带来了无限可能。此次博客将主要概述resnet神经网络的由来及原理,并给出详细的代码实现方法。

resnet神经网络原理详解

resnet为何由来:

2014年Karen Simonyan和Andrew Zisserman 发表了题为“ Very Deep Convolutional Networks for Large-Scale Image Recognition ”的论文,试图对深度卷积网络的体系结构设计进行标准化,并开发了更为深入、性能更好的模型VGG。下图为VGG模型结构图,它们以层数命名:分别是16个和19个学习层的VGG-16和VGG-19。最右边的两列表示该架构的VGG-16和VGG-19模型在使用时的配置(过滤器数量不同)。

个人认为VGG模型的设计已成为简单和直接使用卷积神经网络模型结构的登峰造极之作。看了众多关于卷积神经网络的博客及相关论文。其基于卷积神经网络的创新方式无外乎以下几点:

一. 追求实验效果型:

1.使用非常小的卷积滤波器,例如3×3和1×1,步幅为1;2.使用大小为2×2且跨度相同的最大池;3.在使用池化层之前,将卷积层堆叠在一起;4.开发非常深的模型。

二. 追求方法(模型)创新型:

1.各种池化方式,创新特征采样模式,比如动态池等 ,Inception模块等;2.复合RNN(LSTM等其他模型)分段卷积形式,或者是多个点使用误差传递方法 ;3.真正创新各种注意力机制或者损失函数等;4.开发非常深的模型,但是优化于训练时间。可能自己的机器不行的人都这样做。

实践证明,花里胡哨的组合,不如直接加深网络。但是后来发现深度CNN网络达到一定深度后再一味地增加层数并不能带来进一步地分类性能提高,反而会招致网络收敛变得更慢,test dataset的分类准确率也变得更差。排除数据集过小带来的模型过拟合等问题后,仍旧发现过深的网络仍然还会使分类准确度下降(相对于较浅些的网络而言)。正是受制于此不清不楚的问题,VGG网络达到19层后再增加层数就开始导致分类性能的下降。而Resnet网络作者则想到了常规计算机视觉领域常用的residual representation的概念,并进一步将它应用在了CNN模型的构建当中,于是就有了基本的residual learning的block。

resnet网络模型解释

在该论文中,作者提出了一个非常深入的模型,称为“残差网络”(Residual Network,简称ResNet),该模型的一个示例在2015年版ILSVRC挑战赛中获得了成功。

残差指的是什么?
其中ResNet提出了两种mapping:

1. 一种residual mapping,指的就是除了”弯弯的曲线“那部分。而residual mapping指的是“差映射”,也就是H(X) - X,所以残差指的就是F(X):=H(X)-X部分。

2. 另一种是identity mapping,指的就是图2中”弯弯的曲线“。identity mapping顾名思义,就是指本身,也就是公式中的x。

 作者在3.1小结的末尾说:在现实情况下,自身映射一开始就达到最优几乎是不可能的事,但我们的重构将有助于对此问题做预处理。如果优化的函数比起零映射更接近于自身映射的话,网络会更容易学习去确定自身映射的扰动参考,而不是将其作为一个全新的函数去学习。我们通过实验验证(图7),学习的残差函数一半都响应较小,这表明自身映射是更合理的预处理手段。

   所以最后的输出是 y=(H(X)-X)-X=F(x)+x

其实就是在原来网络的基础上,每隔2层(或者3层,或者更多,这篇文章作者只做了2层和3层)的输出F(x)上再加上之前的输入x。这样做,不会增加额外的参数和计算复杂度,整个网络也可以用SGD方法进行端对端的训练,用目前流行的深度学习库(keras等)也可以很容易的实现。

         这种网络的优点有:1. easier to optimize;2.can gain accuracy from increased depth;

对于作者提出的网络结构,具体实现存在以下两种情形。

1. 当F和x相同维度时,直接相加(element-wise addition),公式如下:

这种方法不会增加网络的参数以及计算复杂度。

2.  当F和x维度不同时,需要先将x做一个变换(linear projection),然后再相加,公式如下:

网络结构:

下图取自本文,从左至右比较了VGG模型,普通卷积模型和带有残差模块的普通卷积模型(称为残差网络)的体系结构。 

resnet50具体应用代码详解:

keras实现resnet50版本一:

采用keras具体构建resnet50:

# GRADED FUNCTION: ResNet50

def ResNet50(input_shape = (64, 64, 3), classes = 6):
    """
    Implementation of the popular ResNet50 the following architecture:
    CONV2D -> BATCHNORM -> RELU -> MAXPOOL -> CONVBLOCK -> IDBLOCK*2 -> CONVBLOCK -> IDBLOCK*3
    -> CONVBLOCK -> IDBLOCK*5 -> CONVBLOCK -> IDBLOCK*2 -> AVGPOOL -> TOPLAYER

    Arguments:
    input_shape -- shape of the images of the dataset
    classes -- integer, number of classes

    Returns:
    model -- a Model() instance in Keras
    """
    
    # Define the input as a tensor with shape input_shape
    X_input = Input(input_shape)

    
    # Zero-Padding
    X = ZeroPadding2D((3, 3))(X_input)
    
    # Stage 1
    X = Conv2D(filters=64, kernel_size=(7, 7), strides=(2, 2), name="conv",
               kernel_initializer=glorot_uniform(seed=0))(X)
    X = BatchNormalization(axis=3, name="bn_conv1")(X)
    X = Activation("relu")(X)
    X = MaxPooling2D(pool_size=(3, 3), strides=(2, 2))(X)

    # Stage 2
    X = convolutional_block(X, f=3, filters=[64, 64, 256], stage=2, block="a", s=1)
    X = identity_block(X, f=3, filters=[64, 64, 256], stage=2, block="b")
    X = identity_block(X, f=3, filters=[64, 64, 256], stage=2, block="c")
    ### START CODE HERE ###

    # Stage 3 (≈4 lines)
    # The convolutional block uses three set of filters of size [128,128,512], "f" is 3, "s" is 2 and the block is "a".
    # The 3 identity blocks use three set of filters of size [128,128,512], "f" is 3 and the blocks are "b", "c" and "d".
    X = convolutional_block(X, f=3, filters=[128, 128, 512], stage=3, block="a", s=1)
    X = identity_block(X, f=3, filters=[128, 128, 512], stage=3, block="b")
    X = identity_block(X, f=3, filters=[128, 128, 512], stage=3, block="c")
    X = identity_block(X, f=3, filters=[128, 128, 512], stage=3, block="d")
    
    # Stage 4 (≈6 lines)
    # The convolutional block uses three set of filters of size [256, 256, 1024], "f" is 3, "s" is 2 and the block is "a".
    # The 5 identity blocks use three set of filters of size [256, 256, 1024], "f" is 3 and the blocks are "b", "c", "d", "e" and "f".
    X = convolutional_block(X, f=3, filters=[256, 256, 1024], stage=4, block="a", s=2)
    X = identity_block(X, f=3, filters=[256, 256, 1024], stage=4, block="b")
    X = identity_block(X, f=3, filters=[256, 256, 1024], stage=4, block="c")
    X = identity_block(X, f=3, filters=[256, 256, 1024], stage=4, block="d")
    X = identity_block(X, f=3, filters=[256, 256, 1024], stage=4, block="e")
    X = identity_block(X, f=3, filters=[256, 256, 1024], stage=4, block="f")
    

    # Stage 5 (≈3 lines)
    # The convolutional block uses three set of filters of size [512, 512, 2048], "f" is 3, "s" is 2 and the block is "a".
    # The 2 identity blocks use three set of filters of size [256, 256, 2048], "f" is 3 and the blocks are "b" and "c".
    X = convolutional_block(X, f=3, filters=[512, 512, 2048], stage=5, block="a", s=2)
    X = identity_block(X, f=3, filters=[512, 512, 2048], stage=5, block="b")
    X = identity_block(X, f=3, filters=[512, 512, 2048], stage=5, block="c")
    
    # filters should be [256, 256, 2048], but it fail to be graded. Use [512, 512, 2048] to pass the grading
    

    # AVGPOOL (≈1 line). Use "X = AveragePooling2D(...)(X)"
    # The 2D Average Pooling uses a window of shape (2,2) and its name is "avg_pool".
    X = AveragePooling2D(pool_size=(2, 2), padding="same")(X)
    
    ### END CODE HERE ###

    # output layer
    X = Flatten()(X)
    X = Dense(classes, activation="softmax", name="fc"+str(classes), kernel_initializer=glorot_uniform(seed=0))(X)
    
    # Create model
    model = Model(inputs=X_input, outputs=X, name="ResNet50")

    return model

这种实现方式比较麻烦,因为除了上述核心模型实现代码之外,还需要定义恒等块和卷积块。因此,如果我们在不需要更改模型的情况下,就是说直接应用resnet50去解决问题,可以通过leras库直接调用resnet50模型即可。只需要我们在输入输出等做好预处理即可。因此,详细解释keras实现resnet50快捷方式。

keras实现resnet50版本二:

首先导入包,通过keras包导入resnet50模型: from keras.applications.resnet50 import ResNet50

但是,我们要采用resnet50解决自己定义的图像处理(分类)问题,所以可以不必导入:decode_predictions函数。

其次,读取数据集:如果大家数据集的存储形式和我这种结构相似(如下图所示)。可以采用生成器函数进行直接读取。

数据集读取代码:

test_datagen = ImageDataGenerator(
    rescale=1. / 255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2)
test_generator = test_datagen.flow_from_directory(
    testset_dir,#目录
    target_size=(img_width, img_height),#目标大小(target_size):整数的元组(高度、宽度)。默认值:(256,256)。将调整找到的所有图像的尺寸。实现对图片的尺寸转换,是预处理中比较常用的方法
    batch_size=batch_size,
    shuffle=False)#返回值一个产生(x,y)元组的目录迭代器(DirectoryIterator)。其中x是包含一批(batch_size,* target_size,channels)类型的图像的numpy数组,y是对应标签的numpy数组。

读取完数据集后,便可以直接调用模型进行训练模型。其代码实现非常简单,如下所示:

from keras.applications.resnet50 import ResNet50
from PIL import Image, ImageEnhance

model = ResNet50(weights=None,classes=6)#训练模型input_shape, num_classes,
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')
history = model.fit_generator(train_generator,steps_per_epoch=len(train_generator),epochs=n_epochs,verbose=1, validation_data=test_generator, validation_steps=len(test_generator))

model.save('resnet50_model.h5')

这样,基本就能通过传入的数据,训练自己的resnet50。但是,在测试结果输出时,需要加一个decode_predictions函数,(这个函数类似于ont_hot转为二进制的函数,目的是为了找到预测图片样本标签)因为用的自己的数据集,所以要自己定义这个decode_predictions函数。以检测训练好的模型输出预测结果。decode_predictions实现代码如下,以本文这个数据集为例:

def decode_predictions_custom(preds, top=5):
    #CLASS_CUSTOM = ["cardboard","paper ","glass","metal"," plastic","trash"]
    CLASS_CUSTOM = ["0","1","2","3","4","5"]
    results = []
    for pred in preds:
        top_indices = pred.argsort()[-top:][::-1]
        result = [tuple(CLASS_CUSTOM[i]) + (pred[i]*100,) for i in top_indices]
        results.append(result)
    return results

至此,采用简单的方法已基本实现resnet50这个深度残差模型,但是,自己的电脑训练起来还是比较费劲,相当费劲。所以大家可以自行去实现一下。

参考文献:

原始论文可下载链接:Deep Residual Learning for Image Recognition, 2016https://sse.tongji.edu.cn/yingshen/course/PR2017Fall/readings/Deep%20Residual%20Learning%20for%20Image%20Recognition.pdf
A Simple Guide to the Versions of the Inception Network, 2018.
CNN Architectures: LeNet, AlexNet, VGG, GoogLeNet, ResNet and more., 2017.
Gradient-based learning applied to document recognition, (PDF) 1998.
ImageNet Classification with Deep Convolutional Neural Networks, 2012.
Very Deep Convolutional Networks for Large-Scale Image Recognition, 2014.
 

原创文章 54 获赞 252 访问量 20万+

猜你喜欢

转载自blog.csdn.net/weixin_40651515/article/details/105822437