def darknet4det4(input_shape, output_channels): inputs = Input(shape=(input_shape[0], input_shape[1], 3)) darknet = Model(inputs, darknet_body(inputs)) # downsample subsample_x = compose( DarknetConv2D_BN_Leaky(1024, (3, 3), strides=(1, 1)), DarknetConv2D_BN_Leaky(512, (3, 3), strides=(1, 1)), DarknetConv2D_BN_Leaky(512, (3, 3), strides=(2, 2), padding='SAME') )(darknet.output) _, y4 = make_last_layers(subsample_x, 512, output_channels, output_layer_name="output4") x, y1 = make_last_layers(darknet.output, 512, output_channels, output_layer_name='output1') # print(type(x)) # upsmaple x = compose( DarknetConv2D_BN_Leaky(256, (1, 1)), UpSampling2D(2))(x) x = Concatenate()([x, darknet.layers[152].output]) x, y2 = make_last_layers(x, 256, output_channels, output_layer_name='output2') # upsample x = compose( DarknetConv2D_BN_Leaky(128, (1, 1)), UpSampling2D(2))(x) x = Concatenate()([x, darknet.layers[92].output]) x, y3 = make_last_layers(x, 128, output_channels, output_layer_name='output3') # order in descending feature size return Model(inputs, [y3, y2, y1, y4])
def make_last_layers(x, num_filters, out_filters, output_layer_name=None): '''6 Conv2D_BN_Leaky layers followed by a Conv2D_linear layer''' x = compose( DarknetConv2D_BN_Leaky(num_filters, (1, 1)), DarknetConv2D_BN_Leaky(num_filters * 2, (3, 3)), DarknetConv2D_BN_Leaky(num_filters, (1, 1)), DarknetConv2D_BN_Leaky(num_filters * 2, (3, 3)), DarknetConv2D_BN_Leaky(num_filters, (1, 1)))(x) y = compose( DarknetConv2D_BN_Leaky(num_filters * 2, (3, 3)), DarknetConv2D(out_filters, (1, 1), name=output_layer_name))(x) return x, y
def DarknetConv2D_BN_Leaky(*args, **kwargs): """Darknet Convolution2D followed by BatchNormalization and LeakyReLU.""" no_bias_kwargs = {'use_bias': False} no_bias_kwargs.update(kwargs) return compose( DarknetConv2D(*args, **no_bias_kwargs), BatchNormalization(), LeakyReLU(alpha=0.1))
def downsample(input_channels, times): downconvs_ops = [ ResnetConv2D( input_channels * pow(2, i + 1), (3, 3), strides=(2, 2), ) for i in range(times) ] return compose(*downconvs_ops)
def darknet4det3(input_shape, output_channels): """Create YOLO_V3 model CNN body in Keras.""" inputs = Input(shape=(input_shape[0], input_shape[1], 3)) darknet = Model(inputs, darknet_body(inputs)) x, y1 = make_last_layers(darknet.output, 512, output_channels, output_layer_name='output1') x = compose( DarknetConv2D_BN_Leaky(256, (1, 1)), UpSampling2D(2))(x) x = Concatenate()([x, darknet.layers[152].output]) x, y2 = make_last_layers(x, 256, output_channels, output_layer_name='output2') x = compose( DarknetConv2D_BN_Leaky(128, (1, 1)), UpSampling2D(2))(x) x = Concatenate()([x, darknet.layers[92].output]) x, y3 = make_last_layers(x, 128, output_channels, output_layer_name='output3') return Model(inputs, [y1, y2, y3])
def make_predict_head(y, num_filters, output_channels, name=None): y = compose( Conv2D_BN_Leaky(num_filters, kernel_size=(1, 1), strides=(1, 1)), Conv2D_BN_Leaky(num_filters * 2, kernel_size=(1, 1), strides=(1, 1)), # Conv2D_BN_Leaky(num_filters, kernel_size=(1, 1), strides=(1, 1)), ResnetConv2D(output_channels, kernel_size=(1, 1), strides=(1, 1), name=name))(y) # print(y) return y
def resblock_body(x, num_filters, num_blocks): '''A series of resblocks starting with a downsampling Convolution2D''' # Darknet uses left and top padding instead of 'same' mode x = ZeroPadding2D(((1, 0), (1, 0)))(x) x = DarknetConv2D_BN_Leaky(num_filters, (3, 3), strides=(2, 2))(x) for i in range(num_blocks): y = compose( DarknetConv2D_BN_Leaky(num_filters // 2, (1, 1)), DarknetConv2D_BN_Leaky(num_filters, (3, 3)))(x) x = Add()([x, y]) return x
def bottleneck(x, num_channels): shortcut = x x = compose( Conv2D_BN_Leaky(num_channels // 4, kernel_size=(1, 1), strides=(1, 1)), Conv2D_BN_Leaky(num_channels // 4, kernel_size=(3, 3), strides=(1, 1)), Conv2D_BN_Leaky(num_channels, kernel_size=(1, 1), strides=(1, 1)), )(x) x = Add()([x, shortcut]) x = LeakyReLU()(x) return x
def make_last_layer(feature_maps, num_filters, output_channels): """ x = compose( DarknetConv2D_BN_Leaky(num_filters, (1, 1)), DarknetConv2D_BN_Leaky(num_filters * 2, (3, 3)), DarknetConv2D_BN_Leaky(num_filters, (1, 1)), DarknetConv2D_BN_Leaky(num_filters * 2, (3, 3)), DarknetConv2D_BN_Leaky(num_filters, (1, 1)))(x) y = compose( DarknetConv2D_BN_Leaky(num_filters * 2, (3, 3)), DarknetConv2D(out_filters, (1, 1), name=output_layer_name))(x) :param feature_map: :return: """ _y = [] out_c = sum(output_channels) for idx, output in enumerate(feature_maps): x = compose(DarknetConv2D_BN_Leaky(num_filters, (1, 1)), DarknetConv2D_BN_Leaky(num_filters * 2, (3, 3)), DarknetConv2D_BN_Leaky(num_filters, (1, 1)), DarknetConv2D_BN_Leaky(num_filters * 2, (3, 3)), DarknetConv2D_BN_Leaky(num_filters, (1, 1)))(output) y = compose(DarknetConv2D_BN_Leaky(num_filters * 2, (3, 3)), DarknetConv2D(out_c, (1, 1), name="output%d" % (idx + 1)))(x) # _fp = compose( # Conv2D(num_filters * 4, kernel_size=1, strides=1, padding='same'), # Conv2D(num_filters, kernel_size=3, strides=1, padding='same'), # # Conv2D(num_filters, kernel_size=1, strides=1, padding='same'), # # Conv2D(num_filters * 2, kernel_size=3, strides=1, padding='same'), # DarknetConv2D_BN_Leaky(out_c, (1, 1)), # Conv2D(out_c, kernel_size=1, strides=1, padding='same', name="output%d" % (idx + 1)), # )(output) _y.append(y) return _y
def upsample(input_channels, times): return compose( UpSampling2D(pow(2, times)), ResnetConv2D(input_channels // pow(2, times), (3, 3), strides=(1, 1)))