from functools import partial from keras.models import Model from keras.layers import Activation from keras.layers import BatchNormalization from keras.layers import Concatenate from keras.layers import Conv2D from keras.layers import Dense from keras.layers import Dropout from keras.layers import GlobalAveragePooling2D from keras.layers import Input from keras.layers import Lambda from keras.layers import MaxPooling2D from keras.layers import add from keras import backend as K def scaling(x, scale): return x * scale def _generate_layer_name(name, branch_idx=None, prefix=None): if prefix is None: return None if branch_idx is None: return '_'.join((prefix, name)) return '_'.join((prefix, 'Branch', str(branch_idx), name)) def conv2d_bn(x,filters,kernel_size,strides=1,padding='same',activation='relu',use_bias=False,name=None): x = Conv2D(filters, kernel_size, strides=strides, padding=padding, use_bias=use_bias, name=name)(x) if not use_bias: x = BatchNormalization(axis=3, momentum=0.995, epsilon=0.001, scale=False, name=_generate_layer_name('BatchNorm', prefix=name))(x) if activation is not None: x = Activation(activation, name=_generate_layer_name('Activation', prefix=name))(x) return x def _inception_resnet_block(x, scale, block_type, block_idx, activation='relu'): channel_axis = 3 if block_idx is None: prefix = None else: prefix = '_'.join((block_type, str(block_idx))) name_fmt = partial(_generate_layer_name, prefix=prefix) if block_type == 'Block35': branch_0 = conv2d_bn(x, 32, 1, name=name_fmt('Conv2d_1x1', 0)) branch_1 = conv2d_bn(x, 32, 1, name=name_fmt('Conv2d_0a_1x1', 1)) branch_1 = conv2d_bn(branch_1, 32, 3, name=name_fmt('Conv2d_0b_3x3', 1)) branch_2 = conv2d_bn(x, 32, 1, name=name_fmt('Conv2d_0a_1x1', 2)) branch_2 = conv2d_bn(branch_2, 32, 3, name=name_fmt('Conv2d_0b_3x3', 2)) branch_2 = conv2d_bn(branch_2, 32, 3, name=name_fmt('Conv2d_0c_3x3', 2)) branches = [branch_0, branch_1, branch_2] elif block_type == 'Block17': branch_0 = conv2d_bn(x, 128, 1, name=name_fmt('Conv2d_1x1', 0)) branch_1 = conv2d_bn(x, 128, 1, name=name_fmt('Conv2d_0a_1x1', 1)) branch_1 = conv2d_bn(branch_1, 128, [1, 7], name=name_fmt('Conv2d_0b_1x7', 1)) branch_1 = conv2d_bn(branch_1, 128, [7, 1], name=name_fmt('Conv2d_0c_7x1', 1)) branches = [branch_0, branch_1] elif block_type == 'Block8': branch_0 = conv2d_bn(x, 192, 1, name=name_fmt('Conv2d_1x1', 0)) branch_1 = conv2d_bn(x, 192, 1, name=name_fmt('Conv2d_0a_1x1', 1)) branch_1 = conv2d_bn(branch_1, 192, [1, 3], name=name_fmt('Conv2d_0b_1x3', 1)) branch_1 = conv2d_bn(branch_1, 192, [3, 1], name=name_fmt('Conv2d_0c_3x1', 1)) branches = [branch_0, branch_1] mixed = Concatenate(axis=channel_axis, name=name_fmt('Concatenate'))(branches) up = conv2d_bn(mixed,K.int_shape(x)[channel_axis],1,activation=None,use_bias=True, name=name_fmt('Conv2d_1x1')) up = Lambda(scaling, output_shape=K.int_shape(up)[1:], arguments={'scale': scale})(up) x = add([x, up]) if activation is not None: x = Activation(activation, name=name_fmt('Activation'))(x) return x def InceptionResNetV1(input_shape=(160, 160, 3), classes=128, dropout_keep_prob=0.8): channel_axis = 3 inputs = Input(shape=input_shape) # 160,160,3 -> 77,77,64 x = conv2d_bn(inputs, 32, 3, strides=2, padding='valid', name='Conv2d_1a_3x3') x = conv2d_bn(x, 32, 3, padding='valid', name='Conv2d_2a_3x3') x = conv2d_bn(x, 64, 3, name='Conv2d_2b_3x3') # 77,77,64 -> 38,38,64 x = MaxPooling2D(3, strides=2, name='MaxPool_3a_3x3')(x) # 38,38,64 -> 17,17,256 x = conv2d_bn(x, 80, 1, padding='valid', name='Conv2d_3b_1x1') x = conv2d_bn(x, 192, 3, padding='valid', name='Conv2d_4a_3x3') x = conv2d_bn(x, 256, 3, strides=2, padding='valid', name='Conv2d_4b_3x3') # 5x Block35 (Inception-ResNet-A block): for block_idx in range(1, 6): x = _inception_resnet_block(x,scale=0.17,block_type='Block35',block_idx=block_idx) # Reduction-A block: # 17,17,256 -> 8,8,896 name_fmt = partial(_generate_layer_name, prefix='Mixed_6a') branch_0 = conv2d_bn(x, 384, 3,strides=2,padding='valid',name=name_fmt('Conv2d_1a_3x3', 0)) branch_1 = conv2d_bn(x, 192, 1, name=name_fmt('Conv2d_0a_1x1', 1)) branch_1 = conv2d_bn(branch_1, 192, 3, name=name_fmt('Conv2d_0b_3x3', 1)) branch_1 = conv2d_bn(branch_1,256,3,strides=2,padding='valid',name=name_fmt('Conv2d_1a_3x3', 1)) branch_pool = MaxPooling2D(3,strides=2,padding='valid',name=name_fmt('MaxPool_1a_3x3', 2))(x) branches = [branch_0, branch_1, branch_pool] x = Concatenate(axis=channel_axis, name='Mixed_6a')(branches) # 10x Block17 (Inception-ResNet-B block): for block_idx in range(1, 11): x = _inception_resnet_block(x, scale=0.1, block_type='Block17', block_idx=block_idx) # Reduction-B block # 8,8,896 -> 3,3,1792 name_fmt = partial(_generate_layer_name, prefix='Mixed_7a') branch_0 = conv2d_bn(x, 256, 1, name=name_fmt('Conv2d_0a_1x1', 0)) branch_0 = conv2d_bn(branch_0,384,3,strides=2,padding='valid',name=name_fmt('Conv2d_1a_3x3', 0)) branch_1 = conv2d_bn(x, 256, 1, name=name_fmt('Conv2d_0a_1x1', 1)) branch_1 = conv2d_bn(branch_1,256,3,strides=2,padding='valid',name=name_fmt('Conv2d_1a_3x3', 1)) branch_2 = conv2d_bn(x, 256, 1, name=name_fmt('Conv2d_0a_1x1', 2)) branch_2 = conv2d_bn(branch_2, 256, 3, name=name_fmt('Conv2d_0b_3x3', 2)) branch_2 = conv2d_bn(branch_2,256,3,strides=2,padding='valid',name=name_fmt('Conv2d_1a_3x3', 2)) branch_pool = MaxPooling2D(3,strides=2,padding='valid',name=name_fmt('MaxPool_1a_3x3', 3))(x) branches = [branch_0, branch_1, branch_2, branch_pool] x = Concatenate(axis=channel_axis, name='Mixed_7a')(branches) # 5x Block8 (Inception-ResNet-C block): for block_idx in range(1, 6): x = _inception_resnet_block(x, scale=0.2, block_type='Block8', block_idx=block_idx) x = _inception_resnet_block(x,scale=1.,activation=None,block_type='Block8',block_idx=6) # 平均池化 x = GlobalAveragePooling2D(name='AvgPool')(x) x = Dropout(1.0 - dropout_keep_prob, name='Dropout')(x) # 全连接层到128 x = Dense(classes, use_bias=False, name='Bottleneck')(x) bn_name = _generate_layer_name('BatchNorm', prefix='Bottleneck') x = BatchNormalization(momentum=0.995, epsilon=0.001, scale=False, name=bn_name)(x) # 创建模型 model = Model(inputs, x, name='inception_resnet_v1') return model