RCNN:Rich feature hierarchies for accurate object detection and semantic segmentation

利用CNN进行目标检测的首个神经网络,首先利用选择性搜索提取图片的2000个左右的 Region Proposal,然后通过AlexNet提取得到固定长度的特征,接着使用支持向量机(SVM)分析这些特征,以实现获选区域的分类,使用边界框回归分析这些特征,获取获选框更精细位置

什么是 RCNN?

  • RCNN-20230408141544
  • 利用CNN进行目标检测的首个神经网络
  • 利用选择性搜索(SelectiveSearch,SS) 提取图片的2000个左右的 Region Proposal,然后通过AlexNet提取得到固定长度的特征,接着使用支持向量机(SVM)分析这些特征,以实现获选区域的分类,使用边界框回归(Bounding box Regression)分析这些特征,获取获选框更精细位置

RCNN的目标识别任务步骤?

  • (1)图片输入
  • (2)获取获选框: 利用选择性搜索(SelectiveSearch,SS)算法在图像中提取2000个左右的Region Proposal
  • (3)微调CNN分类模型: 将每个Region Proposal缩放成227x227的大小并输入到CNN,做N+1的多分类分类
  • (4)训练SVM分类模型: 将CNN模型的fc7层的输出作为特征,训练SVM的目标及背景的二分类器
  • (5)边界框回归: 对被SVM分类为目标的获选框,用边界框回归(Bounding box Regression)校正原来的建议窗口,生成预测窗口坐标

RCNN微调时,输入、输出是什么?损失如何计算?

  • 输入: 使用AlexNet进行微调,输入是目标检测的候选框区域的图片,缩放到(227,227),根据IOU>0.5判定正样本,自定义数据采集器,使得每次训练128个图像,其中32个正样本,96个负样本
  • 输出:输出是N+1分类,判断该候选框内的目标类别
  • 损失函数:使用交叉熵损失(CrossEntropyLoss)

什么是选择性搜索 (Selective Search, SS) ?

  • 使用一种过分割手段,将图像分割成小区域 (1k~2k 个)
  • 查看现有小区域,按照合并规则合并可能性最高的相邻两个区域。重复直到整张图像合并成一个区域位置
  • 优先合并以下四种区域: 颜色(颜色直方图)相近的, 纹理(梯度直方图)相近的,合并后总面积小的

RCNN是如何训练候选框的分类模型的?

  • 1)预训练模型:在imageNet上预训练AlexNet模型;
  • 2)微调预训练模型:修改AlexNet模型最后一层,类别改为(N+1),在N个获选框上微调模型。根据IOU>0.5判定正样本,并使得每个batchsize放入96负样本、32正样本训练
  • 3)训练SVM模型:完成微调后,输出每个获选框的fc7层4096维的特征,然后在SVM上训练该特征,获得获选框的分类模型。训练SVM给标签时,判断某个候选框是某个类别的正样本的要求是IOU>0.3,为每个类别按正负样本训练SVM分类器

RCNN 为什么不使用微调后的 Alexnet 作为获选框的分类模型,而是重新构建 SVM?

  • Drawing 2023-02-06 11.43.00.excalidraw
  • 两个模型训练时,对正样本的定义不同,微调 AlexNet 时,IOU>0.5 即可;训练 SVM 时,IOU=1,这意味着 AlexNet 的正负样本比例比 SVM 大
  • AlexNet 更加容易过拟合:为了防止 AlexNet 向负样本过拟合,取 IOU=0.5 对正负样本进行划分,但是这样也导致和现实不符合,因为 SS 采样得到的样本负样本的数量占绝大比例(虽然 batchsize 正负样本按96:32输入,也存在该问题),进而导致 AlexNet 分类效果比 SVM 差
  • SVM 仅依靠少数的支持向量就完成分类,不容易发生过拟合,按实际更小的正样本(IOU=1)比例即可完成分类,如果取 IOU>0.5 为正样本,mAp 反而变小

RCNN中,图片Resize有几种方式?

  • B先扩充后裁剪: 直接在原始图片中,把bounding box的边界进行扩展延伸成正方形,然后再进行裁剪;如果已经延伸到了原始图片的外边界,那么就用bounding box中的颜色均值填充
  • C先裁剪后扩充:先把bounding box图片裁剪出来,然后用固定的背景颜色填充成正方形图片(背景颜色也是采用bounding box的像素颜色均值)
  • **D强制裁剪:**不管图片的长宽比例,管它是否扭曲,进行缩放就是了,全部缩放到CNN输入的大小

RCNN如何做边界框回归(Bounding box Regression)?

  • 对每一类目标,使用一个线性脊回归器进行精修。 输入为深度网络pool5层的4096维特征,输出为xy方向的缩放和平移。 训练样本:判定为本类的候选框中和真值重叠面积大于0.6的候选框
  • 例子:以密集连接层输出输出边界框的左上、右下的坐标点,说明使用候选框的4096维特征可以计算得到获选框坐标
    • 搭建模型,输出为边界框的左上、右下的坐标点

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      # load the VGG16 network, ensuring the head FC layers are left off
      vgg = VGG16(weights="imagenet", include_top=False, input_tensor=Input(shape=(224, 224, 3)))
      vgg.trainable = False
      flatten = vgg.output
      flatten = Flatten()(flatten)
      bboxHead = Dense(128, activation="relu")(flatten)
      bboxHead = Dense(64, activation="relu")(bboxHead)
      bboxHead = Dense(32, activation="relu")(bboxHead)
      bboxHead = Dense(4, activation="sigmoid")(bboxHead) # 输出为边界框的左上、右下的坐标点
      model = Model(inputs=vgg.input, outputs=bboxHead)
      opt = Adam(lr=INIT_LR)
      model.compile(loss="mse", optimizer=opt)
    • 模型训练:

      BASE_PATH = "dataset"
      IMAGES_PATH = os.path.sep.join([BASE_PATH, "images"])
      ANNOTS_PATH = os.path.sep.join([BASE_PATH, "airplanes.csv"])
      
      data = []
      targets = []
      for row in rows:
          (filename, startX, startY, endX, endY) = row
          imagePath = os.path.sep.join([IMAGES_PATH, filename])
          image = cv2.imread(imagePath)
      
          # 模型监督信息为:边界框的真实左上、右下的坐标点,按图片大小归一化
          (h, w) = image.shape[:2]
          startX = float(startX) / w
          startY = float(startY) / h
          endX = float(endX) / w
          endY = float(endY) / h
      
          image = load_img(imagePath, target_size=(224, 224))
          image = img_to_array(image)
      
          data.append(image)
          targets.append((startX, startY, endX, endY)) 	BASE_PATH = "dataset"
      IMAGES_PATH = os.path.sep.join([BASE_PATH, "images"])
      ANNOTS_PATH = os.path.sep.join([BASE_PATH, "airplanes.csv"])
      
      data = []
      targets = []
      for row in rows:
          (filename, startX, startY, endX, endY) = row
          imagePath = os.path.sep.join([IMAGES_PATH, filename])
          image = cv2.imread(imagePath)
      
          # 模型监督信息为:边界框的真实左上、右下的坐标点,按图片大小归一化
          (h, w) = image.shape[:2]
          startX = float(startX) / w
          startY = float(startY) / h
          endX = float(endX) / w
          endY = float(endY) / h
      
          image = load_img(imagePath, target_size=(224, 224))
          image = img_to_array(image)
      
          data.append(image)
          targets.append((startX, startY, endX, endY)) 
      
      
    • 模型输出

RCNN有哪些缺点?

  • 1、训练分多步:R-CNN的训练先要fine tuning一个预训练的网络,然后针对每个类别都训练一个SVM分类器,最后还要用regressors对bounding-box进行回归,另外region proposal也要单独用selective search的方式获得,步骤比较繁琐
  • 2、时间和内存消耗比较大。在训练SVM和回归的时候需要用网络训练的特征作为输入,特征保存在磁盘上再读入的时间消耗还是比较大的
  • 3、测试的时候也比较慢,每张图片的每个 region proposal 都要做卷积,重复操作太多