基于Keras的ResNet实现

本文详细介绍了如何基于Keras实现ResNet深度学习网络,重点讨论了ResNet中的Identity块和convolutional块,并展示了构建ResNet50模型的步骤。文章通过手势识别的应用展示了模型的效果。
摘要由CSDN通过智能技术生成

本文是吴恩达《深度学习》第四课《卷积神经网络》第二周课后题第二部分的实现。

0.ResNet简介

目前神经网络变得越来越复杂,从几层到几十层甚至一百多层的网络都有。深层网络的主要的优势是可以表达非常复杂的函数,它可以从不同抽象程度的层里学到特征,比如在比较低层次里学习到边缘特征而在较高层里可以学到复杂的特征。然而使用深层网络并非总是奏效,因为存在一个非常大的障碍——梯度消失:在非常深层的网络中,梯度信号通常会非常快的趋近于0,这使得梯度下降的过程慢得令人发指。具体来说就是在梯度下降的过程中,从最后一层反向传播回第一层的每一步中都要进行权重矩阵乘积运算,这样一来梯度会呈指数级下降到0值。(在极少的情况下还有梯度爆炸的问题,就是梯度在传播的过程中以指数级增长到溢出)

因此在训练的过程中,你会发现如下图所示的问题,随着层数的增加,梯度下降的0的速率增快。

因此,通过不断加深网络虽然可以表达任何复杂的函数,但实际上随着网络层数的增多我们越发的难以训练网络,直到Residual Network的提出,使得训练更深层的网络成为可能。

本文所需的第三方库如下,所需的数据及辅助程序可点击此处下载。

import numpy as np
from keras import layers
from keras.layers import Input, Add, Dense, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D, AveragePooling2D, MaxPooling2D, GlobalMaxPooling2D
from keras.models import Model, load_model
from keras.preprocessing import image
from keras.utils import layer_utils
from keras.utils.data_utils import get_file
from keras.applications.imagenet_utils import preprocess_input
import pydot
from IPython.display import SVG
from keras.utils.vis_utils import model_to_dot
from keras.utils import plot_model
from resnets_utils import *
from keras.initializers import glorot_uniform
import scipy.misc
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow

import keras.backend as K
K.set_image_data_format('channels_last')
K.set_learning_phase(1)

1.数据分析

本次准备处理的数据集是手势数字集,如下图

X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()
X_train = X_train_orig / 255
X_test = X_test_orig / 255
Y_train = convert_to_one_hot(Y_train_orig, 6).T
Y_test = convert_to_one_hot(Y_test_orig, 6).T

print ("number of training examples = " + str(X_train.shape[0]))
print ("number of test examples = " + str(X_test.shape[0]))
print ("X_train shape: " + str(X_train.shape))
print ("Y_train shape: " + str(Y_train.shape))
print ("X_test shape: " + str(X_test.shape))
print ("Y_test shape: " + str(Y_test.shape))
number of training examples = 1080
number of test examples = 120
X_train shape: (1080, 64, 64, 3)
Y_train shape: (1080, 6)
X_test shape: (120, 64, 64, 3)
Y_test shape: (120, 6)

 2.Residual模块

在ResNet中最重要的模块就是“shortcut”或“skip connection”,正是因为这个模块的引入才使得更深层网络成为可能。

左图显示的是网络的主路,右图引入shortcut使得梯度可以直接反向传播到前层。引入skip connection不会影响网络表现,而且有助于效率的提升,因为新增的层可能会学到更多的有效信息,想了解具体细节可以参看吴恩达老师的视频教程。

残差块主要有两种类型,主要区别在于输入/输出是否是相同维度,下面来分别实现。

2.1.Identity块

identity块是ResNet中的标准模块,该模块的特点是输入激活值(a[l])与输出激活值(a[l+2])是相同维度。为了具体说明identity块是怎么实现的,见下图。

图中,下部回路表示网络传播的主路径,上部表示shortcut其跳过了三层隐藏层向后传播。每层中都有CONV2D和RELU操作,为了加快训练,还增加了Batch Norm层,这虽然使执行过程变得复杂,但是不要担心,这在Keras中只需一行代码。该模块实现起来可分四步来实现,如下:

(1)主路组件一

  • CONV2D:F1过滤器shape为(1,1),strides=(1,1),padding=“valid”,name='conv_name_base+ '2a', seed=0;
  • Batch Norm: 对channel标准化,name = bn_name_base + '2a'
  • RELU

(2)主路组件二

  • CONV2D:F1过滤器shape为(f,f),strides=(1,1),padding=“same”,name='conv_name_base+ '2b', seed=0;
  • Batch Norm: 对channel标准化,name = bn_name_base + '2b'
  • RELU

(3)主路组件三

  • CONV2D:F1过滤器shape为(1,1),strides=(1,1),padding=“valid”,name='conv_name_base+ '2c', seed=0;
  • Batch Norm: 对channel标准化,name = bn_name_base + '2c'

(4)求和激活

  • 将shortcut和主路值相加到一起,然后应用RELU函数激活。
def identity_block(X, f, filters, stage, block):

    conv_name_base = 'res' + str(stage) + block + '_branch'
    bn_name_base = 'bn' + str(stage) + block + '_branch'

    F1, F2, F3 = filters

    X_shortcut = X

    X = Conv2D(filters = F1, kernel_size = (1,1), strides = (1,1), padding = 'valid', name = conv_name_base + '2a', kernel_initializer = glorot_uniform(seed = 0))(X)
    X = BatchNormalization(axis = 3, name = bn_name_base + '2a')(X)
    X = Activation('relu')(X)

  
  • 18
    点赞
  • 164
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值