您现在的位置是:网站首页> 编程资料编程资料

Keras搭建M2Det目标检测平台示例_python_

2023-05-26 418人已围观

简介 Keras搭建M2Det目标检测平台示例_python_

什么是M2det目标检测算法

一起来看看M2det的keras实现吧,顺便训练一下自己的数据。

常见的特征提取方法如图所示有SSD形,FPN形,STDN形:

SSD型:使用了主干网络的最后两层,再加上4个使用stride=2卷积的下采样层构成;

FPN型:也称为U型网络,经过上采样操作,然后对应融合相同的scale;

STDN型:基于DenseNet的最后一个dense block,通过池化和scale-transfer操作来构建;

这三者有一定的缺点:

一是均基于分类网络作为主干提取,对目标检测任务而言特征表示可能不够;

二是每个feature map仅由主干网络的single level给出,不够全面

M2det论文新提出MLFPN型,整体思想是Multi-level&Multi-scale。是一种更加有效的适合于检测的特征金字塔结构。

源码下载

M2det实现思路

一、预测部分

1、主干网络介绍

M2det采用可以采用VGG和ResNet101作为主干特征提取网络,上图的backbone network指的就是VGG和Resnet101,本文以VGG为例介绍。

M2DET采用的主干网络是VGG网络,关于VGG的介绍大家可以看我的另外一篇博客

https://www.jb51.net/article/246917.htm

在m2det中,我们去掉了全部的全连接层,只保留了卷积层和最大池化层,即Conv1到Conv5。

1、一张原始图片被resize到(320,320,3)。

2、conv1两次[3,3]卷积网络,输出的特征层为64,输出为(320,320,64),再2X2最大池化,输出net为(160,160,64)。

3、conv2两次[3,3]卷积网络,输出的特征层为128,输出net为(160,160,128),再2X2最大池化,输出net为(80,80,128)。

4、conv3三次[3,3]卷积网络,输出的特征层为256,输出net为(80,80,256),再2X2最大池化,输出net为(40,40,256)。

5、conv4三次[3,3]卷积网络,输出的特征层为512,输出net为(40,40,512),再2X2最大池化,此时不进行池化,输出net为(40,40,512)。conv4-3的结果会进入FFM1进行特征的融合。

6、conv5三次[3,3]卷积网络,输出的特征层为1024,输出net为(40,40,1024),再2X2最大池化,输出net为(20,20,1024)。池化后的结果会进入FFM1进行特征的融合。

from keras import Model from keras.layers import Conv2D, MaxPooling2D def VGG16(inputs): net = {} #------------------------# # 输入默认为320,320,3 #------------------------# net['input'] = inputs #------------------------------------------------# # 第一个卷积部分 320,320,3 -> 160,160,64 #------------------------------------------------# net['conv1_1'] = Conv2D(64, kernel_size=(3,3), activation='relu', padding='same', name='conv1_1')(net['input']) net['conv1_2'] = Conv2D(64, kernel_size=(3,3), activation='relu', padding='same', name='conv1_2')(net['conv1_1']) net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same', name='pool1')(net['conv1_2']) #------------------------------------------------# # 第二个卷积部分 160,160,64 -> 80,80,128 #------------------------------------------------# net['conv2_1'] = Conv2D(128, kernel_size=(3,3), activation='relu', padding='same', name='conv2_1')(net['pool1']) net['conv2_2'] = Conv2D(128, kernel_size=(3,3), activation='relu', padding='same', name='conv2_2')(net['conv2_1']) net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same', name='pool2')(net['conv2_2']) y0 = net['pool2'] #------------------------------------------------# # 第三个卷积部分 80,80,128 -> 40,40,256 #------------------------------------------------# net['conv3_1'] = Conv2D(256, kernel_size=(3,3), activation='relu', padding='same', name='conv3_1')(net['pool2']) net['conv3_2'] = Conv2D(256, kernel_size=(3,3), activation='relu', padding='same', name='conv3_2')(net['conv3_1']) net['conv3_3'] = Conv2D(256, kernel_size=(3,3), activation='relu', padding='same', name='conv3_3')(net['conv3_2']) net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same', name='pool3')(net['conv3_3']) y1 = net['pool3'] #------------------------------------------------# # 第四个卷积部分 40,40,256 -> 40,40,512 #------------------------------------------------# net['conv4_1'] = Conv2D(512, kernel_size=(3,3), activation='relu', padding='same', name='conv4_1')(net['pool3']) net['conv4_2'] = Conv2D(512, kernel_size=(3,3), activation='relu', padding='same', name='conv4_2')(net['conv4_1']) net['conv4_3'] = Conv2D(512, kernel_size=(3,3), activation='relu', padding='same', name='conv4_3')(net['conv4_2']) # net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same', # name='block4_pool')(net['conv4_3']) y2 = net['conv4_3'] #------------------------------------------------# # 第五个卷积部分 40,40,512 -> 20,20,1024 #------------------------------------------------# net['conv5_1'] = Conv2D(1024, kernel_size=(3,3), activation='relu', padding='same', name='conv5_1')(net['conv4_3']) net['conv5_2'] = Conv2D(1024, kernel_size=(3,3), activation='relu', padding='same', name='conv5_2')(net['conv5_1']) net['conv5_3'] = Conv2D(1024, kernel_size=(3,3), activation='relu', padding='same', name='conv5_3')(net['conv5_2']) net['pool5'] = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='pool5')(net['conv5_3']) y3 = net['pool5'] model = Model(inputs, [y0,y1,y2,y3], name='vgg16') return model 

2、FFM1特征初步融合

FFM1具体的结构如下:

FFM1会对VGG提取到的特征进行初步融合。

在利用VGG进行特征提取的时候,我们会取出shape为(40,40,512)、(20,20,1024)的特征层进行下一步的操作。

在FFM1中,其会对(20,20,1024)的特征层进行进行一个通道数为512、卷积核大小为3x3、步长为1x1的卷积,然后再进行上采样,使其Shape变为(40,40,512);

同时会对(40,40,512)的特征层进行进行一个通道数为256、卷积核大小为1x1,步长为1x1的卷积,使其Shape变为(40,40,256);

然后将两个卷积后的结果进行堆叠,变成一个(40,40,768)的初步融合特征层

实现代码为:

def FFMv1(C4, C5, feature_size_1=256, feature_size_2=512, name='FFMv1'): #------------------------------------------------# # C4特征层 40,40,512 # C5特征层 20,20,1024 #------------------------------------------------# # 40,40,512 -> 40,40,256 F4 = conv2d(C4, filters=feature_size_1, kernel_size=(3, 3), strides=(1, 1), padding='same', name='F4') # 20,20,1024 -> 20,20,512 F5 = conv2d(C5, filters=feature_size_2, kernel_size=(1, 1), strides=(1, 1), padding='same', name='F5') # 20,20,512 -> 40,40,512 F5 = keras.layers.UpSampling2D(size=(2, 2), name='F5_Up')(F5) # 40,40,256 + 40,40,512 -> 40,40,768 outputs = keras.layers.Concatenate(name=name)([F4, F5]) return outputs 

3、细化U型模块TUM

Tum的结构具体如下:

当我们给Tum输入一个(40,40,256)的有效特征层之后,Tum会对输入进来的特征层进行U型的特征提取,这里的结构比较类似特征金字塔的结构,先对特征层进行不断的特征压缩,然后再不断的上采样进行特征融合,利用Tum我们可以获得6个有效特征层,大小分别是(40,40,128)、(20,20,128)、(10,10,128)、(5,5,128)、(3,3,128)、(1,1,128)。

def TUM(stage, inputs, feature_size=256, name="TUM"): #---------------------------------# # 进行下采样的部分 #---------------------------------# # 40,40,256 f1 = inputs # 40,40,256 -> 20,20,256 f2 = conv2d(f1, filters=feature_size, kernel_size=(3, 3), strides=(2, 2), padding='same',name=name + "_" + str(stage) + '_f2') # 20,20,256 -> 10,10,256 f3 = conv2d(f2, filters=feature_size, kernel_size=(3, 3), strides=(2, 2), padding='same',name=name + "_" + str(stage) + '_f3') # 10,10,256 -> 5,5,256 f4 = conv2d(f3, filters=feature_size, kernel_size=(3, 3), strides=(2, 2), padding='same',name=name + "_" + str(stage) + '_f4') # 5,5,256 -> 3,3,256 f5 = conv2d(f4, filters=feature_size, kernel_size=(3, 3), strides=(2, 2), padding='same',name=name + "_" + str(stage) + '_f5') # 3,3,256 -> 1,1,256 f6 = conv2d(f5, filters=feature_size, kernel_size=(3, 3), strides=(2, 2), padding='valid',name=name + "_" + str(stage) + '_f6') size_buffer = [] # 40,40 size_buffer.append([int(f1.shape[1]), int(f1.shape[2])]) # 20,20 size_buffer.append([int(f2.shape[1]), int(f2.shape[2])]) # 10,10 size_buffer.append([int(f3.shape[1]), int(f3.shape[2])]) # 5,5 size_buffer.append([int(f4.shape[1]), int(f4.shape[2])]) # 3,3 size_buffer.append([int(f5.shape[1]), int(f5.shape[2])]) #---------------------------------# # 进行上采样与特征融合的部分 #---------------------------------# c6 = f6 # 1,1,256 -> 1,1,256 c5 = conv2d(c6, filters=feature_size, kernel_size=(3, 3), strides=(1, 1), padding='same',name=name + "_" + str(stage) + '_c5') # 1,1,256 -> 3,3,256 c5 = keras.layers.Lambda(lambda x: tf.image.resize_bilinear(x, size=size_buffer[4]), name=name + "_" + str(stage) + '_upsample_add5')(c5) c5 = keras.layers.Add()([c5, f5]) # 3,3,256 -> 3,3,256 c4 = conv2d(c5, filters=feature_size, kernel_size=(3, 3), strides=(1, 1), padding='same', name=name + "_" + str(stage) + '_c4') # 3,3,256 -> 5,5,256 c4 = keras.layers.Lambda(lambda x: tf.image.resize_bilinear(x, size=size_b
                
                

-六神源码网