DenseNet的几个优点:
1、减轻了vanishing-gradient(梯度消失) (每一层都直接连接input和loss,因此就可以减轻梯度消失现象)
2、加强了feature的传递
3、更有效地利用了feature
4、一定程度上较少了参数数量
1)密集连接:
若你有L层,那么就会有L个连接,但是在DenseNet中,会有L(L+1)/2个连接。简单讲,就是每一层的输入来自前面所有层的输出。(这里不同于resnet中的权值和操作,采用了concat操作)
一个局域block(前向特征融合):
def conv_block(x, growth_rate, name): #一个局部的特征融合,将block输入与block输出进行concat bn_axis = 3 if K.image_data_format() == 'channels_last' else 1 x1 = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name=name + '_0_bn')(x) x1 = layers.Activation('relu', name=name + '_0_relu')(x1) x1 = layers.Conv2D(2 * growth_rate, 1, use_bias=False, name=name + '_1_conv')(x1) x1 = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name=name + '_1_bn')(x1) x1 = layers.Activation('relu', name=name + '_1_relu')(x1) x1 = layers.Conv2D(growth_rate, 3, padding='same', use_bias=False, name=name + '_2_conv')(x1) x = layers.Concatenate(axis=bn_axis, name=name + '_concat')([x, x1])
2)
bottleneck layer的提出:也就是每个dense block的3*3卷积前面都包含了一个1*1的卷积操作(降维,减少参数~)+ 密集连接= 减少参数量且通道融合
3)DenseNet-C的提出,新增加了Translation layer,该层的1*1卷积的输出channel默认是输入channel的一半
附上所有代码:
# -*- coding: utf-8 -*- from __future__ import print_function import numpy as np import warnings from keras.models import Model from keras import layers from keras.layers import Flatten from keras.layers import Dense from keras.layers import Input from keras.layers import Conv2D from keras.layers import MaxPooling2D from keras.layers import GlobalMaxPooling2D from keras.layers import GlobalAveragePooling2D from keras.preprocessing import image from keras.utils import layer_utils from keras import backend as K from keras.engine.topology import get_source_inputs import cfg def basemodel(input_tensor=None, input_shape=None, pooling=None): if input_tensor is None: img_input = Input(shape=input_shape) else: if not K.is_keras_tensor(input_tensor): img_input = Input(tensor=input_tensor, shape=input_shape) else: img_input = input_tensor bn_axis = 3 if K.image_data_format() == 'channels_last' else 1 x = layers.ZeroPadding2D(padding=((1, 1), (1, 1)))(img_input) x = layers.Conv2D(64, 3, strides=2, use_bias=False, name='conv1/conv')(x) x = layers.BatchNormalization( axis=bn_axis, epsilon=1.001e-5, name='conv1/bn')(x) x = layers.Activation('relu', name='conv1/relu')(x) x = layers.ZeroPadding2D(padding=((1, 1), (1, 1)))(x) x = layers.MaxPooling2D(3, strides=2, name='pool1')(x) #128 x = dense_block(x, 3, name='conv2') #密集连接 x = transition_block(x, 0.5, name='pool2') #池化 x = dense_block(x, 6, name='conv3') x = transition_block(x, 0.5, name='pool3') x = dense_block(x, 12, name='conv4') x = transition_block(x, 0.5, name='pool4') # x = dense_block(x, 4, name='conv5') x = layers.BatchNormalization( axis=bn_axis, epsilon=1.001e-5, name='bn')(x) x = layers.Activation('relu', name='relu')(x) if input_tensor is not None: inputs = get_source_inputs(input_tensor) else: inputs = img_input model = Model(inputs, x, name='basemodel_dense') return model def dense_block(x, blocks, name): """A dense block. # Arguments x: input tensor. blocks: integer, the number of building blocks. name: string, block label. # Returns output tensor for the block. """ for i in range(blocks): x = conv_block(x, 16, name=name + '_block' + str(i + 1)) return x def transition_block(x, reduction, name): #等同于进行一次池化,减少通道数 """A transition block. # Arguments x: input tensor. reduction: float, compression rate at transition layers. name: string, block label. # Returns output tensor for the block. """ bn_axis = 3 if K.image_data_format() == 'channels_last' else 1 x = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name=name + '_bn')(x) x = layers.Activation('relu', name=name + '_relu')(x) x = layers.Conv2D(int(K.int_shape(x)[bn_axis] * reduction), 1, use_bias=False, name=name + '_conv')(x) x = layers.AveragePooling2D(2, strides=2, name=name + '_pool')(x) return x def conv_block(x, growth_rate, name): #一个局部的特征融合,将block输入与block输出进行concat bn_axis = 3 if K.image_data_format() == 'channels_last' else 1 x1 = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name=name + '_0_bn')(x) x1 = layers.Activation('relu', name=name + '_0_relu')(x1) x1 = layers.Conv2D(2 * growth_rate, 1, use_bias=False, name=name + '_1_conv')(x1) x1 = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name=name + '_1_bn')(x1) x1 = layers.Activation('relu', name=name + '_1_relu')(x1) x1 = layers.Conv2D(growth_rate, 3, padding='same', use_bias=False, name=name + '_2_conv')(x1) x = layers.Concatenate(axis=bn_axis, name=name + '_concat')([x, x1]) return x if __name__ == '__main__': input_img = Input(name='input_img', shape=(cfg.max_train_img_size, cfg.max_train_img_size, cfg.num_channels), dtype='float32') basemodel = basemodel(input_tensor=input_img) basemodel.summary()
Resnet和densenet的区别: