# D:/workplace/python # -*- coding: utf-8 -*- # @File :resnetV1.py # @Author:Guido LuXiaohao # @Date :2020/4/8 # @Software:PyCharm """ ResNet v1 This is a revised implementation from Cifar10 ResNet example in Keras: (https://github.com/keras-team/keras/blob/master/examples/cifar10_resnet.py) [a] Deep Residual Learning for Image Recognition https://arxiv.org/pdf/1512.03385.pdf """ from __future__ import print_function import keras from keras.layers import Dense, Conv2D, BatchNormalization, Activation from keras.layers import AveragePooling2D, Input, Flatten from keras.optimizers import Adam from keras.callbacks import ModelCheckpoint, LearningRateScheduler from keras.callbacks import ReduceLROnPlateau from keras.preprocessing.image import ImageDataGenerator from keras.regularizers import l2 from keras import backend as K from keras.models import Model from nets.attention_module.se_cbam import attach_attention_module # 先定义一个神经层,再通过堆叠来完成,分为两个函数 def resnet_layer(inputs, num_filters=16, # 输出通道数/深度 kernel_size=3, strides=1, activation='relu', batch_normalization=True, conv_first=True): """2D Convolution-Batch Normalization-Activation stack builder # Arguments inputs (tensor): input tensor from input image or previous layer图像数据或者前一层神经网络的张量 num_filters (int): Conv2D number of filters二维卷积核的个数 kernel_size (int): Conv2D square kernel dimensions卷积核的大小 strides (int): Conv2D square stride dimensions卷积核的滑动步长 activation (string): activation name激活函数 batch_normalization (bool): whether to include batch normalization是否使用批量归一化 conv_first (bool): conv-bn-activation (True) or bn-activation-conv (False) # Returns x (tensor): tensor as input to the next layer """ # 实例化一个卷积对象 conv = Conv2D(num_filters,# 输出空间的维度(即卷积中滤波器的输出数量) #conv2d_ ,conv2d_13,conv2d_23 kernel_size=kernel_size, strides=strides, padding='same',#padding设置为SAME,则说明输入图片大小和输出图片大小是一致的,如果是VALID则图片经过滤波器后可能会变小 kernel_initializer='he_normal', kernel_regularizer=l2(1e-4))#该层权重矩阵的每个系数都会使网络总损失增加1e-4*weight_coefficient_value x = inputs # 定义卷积、批量标准化、激活 if conv_first: x = conv(x) if batch_normalization: x = BatchNormalization()(x) if activation is not None: x = Activation(activation)(x) else: if batch_normalization: x = BatchNormalization()(x) if activation is not None: x = Activation(activation)(x) x = conv(x) return x def resnet_v1(input_shape, depth, num_classes=10, attention_module=None): """ResNet Version 1 Model builder [a] Stacks of 2 x (3 x 3) Conv2D-BN-ReLU Last ReLU is after the shortcut connection. At the beginning of each stage, the feature map size is halved (downsampled) by a convolutional layer with strides=2, while the number of filters is doubled. Within each stage, the layers have the same number filters and the same number of filters. Features maps sizes: stage 0: 32x32, 16 stage 1: 16x16, 32 stage 2: 8x8, 64 The Number of parameters is approx the same as Table 6 of [a]: ResNet20 0.27M ResNet32 0.46M ResNet44 0.66M ResNet56 0.85M ResNet110 1.7M # Arguments input_shape (tensor): shape of input image tensor depth (int): number of core convolutional layers num_classes (int): number of classes (CIFAR10 has 10) # Returns model (Model): Keras model instance """ if (depth - 2) % 6 != 0: #depth=20 raise ValueError('depth should be 6n+2 (eg 20, 32, 44 in [a])') # Start model definition. num_filters = 16 num_res_blocks = int((depth - 2) / 6) # 每个残差堆叠层含有的残差模块3 inputs = Input(shape=input_shape) # 这部分返回一个张量,形状为input_shape, 要指定input_shape x = resnet_layer(inputs=inputs) # 其余都用自定义参数 # Instantiate the stack of residual units实例化残差单元模块 for stack in range(3): # 定义了三个残差堆叠层 for res_block in range(num_res_blocks): # num_res_blocks = 3 strides = 1 if stack > 0 and res_block == 0: # first layer but not first stack 每个残差堆叠层的第一个残差模块,但不是第一个堆叠 strides = 2 # downsample 在conv3_1, conv4_1下采样 y = resnet_layer(inputs=x, num_filters=num_filters, strides=strides) # 有activation y = resnet_layer(inputs=y, num_filters=num_filters, activation=None) if stack > 0 and res_block == 0: # first layer but not first stack # linear projection residual shortcut connection to match # changed dims x = resnet_layer(inputs=x, num_filters=num_filters, kernel_size=1, strides=strides,#strides=1 activation=None, batch_normalization=False) #以上为原来的resnet,下面是添加attention_module # attention_module if attention_module is not None: y = attach_attention_module(y, attention_module) # net:y x = keras.layers.add([x, y]) # add_2:Add 将输入feature和经过res_block的feature相加 x = Activation('relu')(x) # activation_4:Activation num_filters *= 2 # Add classifier on top. # v1 does not use BN after last shortcut connection-ReLU x = AveragePooling2D(pool_size=8)(x) #average_pooling2d_1:AveragePooling2D y = Flatten()(x) #flaten_1:Flatten outputs = Dense(num_classes, #dense19:Dense activation='softmax', kernel_initializer='he_normal')(y) #he_normal 它从[-limt,limt]的均匀分布中抽取样本,其中limit=sqrt(6 / fan_in), 其中`fan_in`是权值张量中输入单位个数 # Instantiate model. model = Model(inputs=inputs, outputs=outputs) return model """ 一般情况下, 输入的图片矩阵以及后面的卷积核, 特征图矩阵都是方阵, 这里设输入矩阵大小为 w, 卷积核大小为 k, 步幅为 s, 补零层数为 p, 则卷积后产生的特征图大小计算公式为: w'=(w+2p-k)/s+1 """ """ resnet 每个 stack 中都含有 3 个残差模块res_block,每个模块的卷积核都是 3X3 大小的,pad 为 1,stride 为 1。 Con4_x 的输出通过 global_average_pooling 映射到 64 个 1X1 大小的 feature map,最后再通过含有 10 个神经元的全连接层输出分类结果。 """