减少误报的最佳策略:谷歌在卫星图像上的新物体检测API

时间:2017-08-14 01:54:45

标签: machine-learning tensorflow computer-vision deep-learning object-detection

我正在设置新的Tensorflow Object Detection API以查找大面积卫星图像中的小物体。它工作得很好 - 它找到了我想要的所有10个对象,但我也得到50-100个误报[看起来有点像目标对象的东西,但不是]。

我正在使用sample config中的'pets' tutorial来微调他们提供的faster_rcnn_resnet101_coco模型。我开始很小,只有100个我的对象的训练样例(只有1个类)。我的验证集中有50个示例。每个示例都是200x200像素的图像,中心带有标记对象(~40x40)。我一直训练直到我的精确度和损失曲线高原。

我对使用深度学习进行对象检测相对较新。提高精度的最佳策略是什么?例如硬负采矿?增加我的训练数据集大小?我还没有尝试他们提供的最准确的模型faster_rcnn_inception_resnet_v2_atrous_coco,因为我想保持一定的速度,但如果需要的话也会这样做。

硬阴性采矿似乎是合乎逻辑的一步。如果您同意,我如何实现它w.r.t为我的训练数据集设置tfrecord文件?假设我为50-100个误报中的每一个制作200x200图像:

  • 我是否为每个创建'annotation'xml文件,没有'object'元素?
  • ...或者我将这些硬阴性标记为第二类吗?
  • 如果我在训练集中有100个阴性到100个阳性 - 这是一个健康的比例吗?我可以包括多少负片?

2 个答案:

答案 0 :(得分:12)

我最近在我的工作中重新审视了这个主题,并且认为我会根据我目前的学习情况更新,以便将来访问。

主题出现在Tensorflow's Models repo issue tracker上。 SSD允许您设置多少负面:正面示例的比例(max_negatives_per_positive: 3),但您也可以为没有姿势的图像设置最小数量(min_negatives_per_image: 3)。这两个都在model-ssd-loss配置部分中定义。

也就是说,我在Faster-RCNN的模型配置中看不到相同的选项。问题中提到models/research/object_detection/core/balanced_positive_negative_sampler.py包含用于Faster-RCNN的代码。

该问题中讨论的另一个选项是专门为类似项创建第二个类。在培训期间,该模型将尝试学习有助于实现目的的阶级差异。

最后,我在滤波器放大器网络(FAN)上遇到了这个article,它可能为您的航空影像工作提供信息。

=============================================== ====================

以下文章描述了与您描述的目的相同的硬负面挖掘: Training Region-based Object Detectors with Online Hard Example Mining

在3.1节中,他们描述了使用前景和背景类:

  

背景知识。如果区域最大,则区域标记为背景(bg)   具有基本事实的IoU在区间[bg lo,0.5]中。一个较低的   FRCN和SPPnet都使用bg lo = 0.1的阈值,并且是   在[14]中假设粗略接近硬负采矿;该   假设与地面事实有一些重叠的区域是   更容易成为令人困惑或困难的人。我们在5.4节中展示   虽然这种启发式有助于收敛和检测准确性,   它不是最理想的,因为它忽略了一些不常见但很重要的   困难的背景区域。我们的方法删除了bg lo阈值。

事实上,本文被引用,其思想用于Tensorflow的对象检测loss.py代码,用于硬挖掘:

class HardExampleMiner(object):
"""Hard example mining for regions in a list of images.
Implements hard example mining to select a subset of regions to be
back-propagated. For each image, selects the regions with highest losses,
subject to the condition that a newly selected region cannot have
an IOU > iou_threshold with any of the previously selected regions.
This can be achieved by re-using a greedy non-maximum suppression algorithm.
A constraint on the number of negatives mined per positive region can also be
enforced.
Reference papers: "Training Region-based Object Detectors with Online
Hard Example Mining" (CVPR 2016) by Srivastava et al., and
"SSD: Single Shot MultiBox Detector" (ECCV 2016) by Liu et al.
"""

根据您的模型配置文件,在这段代码中,loss_builder.py返回HardMinerObject:

def build_hard_example_miner(config,
                            classification_weight,
                            localization_weight):
"""Builds hard example miner based on the config.
Args:
    config: A losses_pb2.HardExampleMiner object.
    classification_weight: Classification loss weight.
    localization_weight: Localization loss weight.
Returns:
    Hard example miner.
"""
loss_type = None
if config.loss_type == losses_pb2.HardExampleMiner.BOTH:
    loss_type = 'both'
if config.loss_type == losses_pb2.HardExampleMiner.CLASSIFICATION:
    loss_type = 'cls'
if config.loss_type == losses_pb2.HardExampleMiner.LOCALIZATION:
    loss_type = 'loc'

max_negatives_per_positive = None
num_hard_examples = None
if config.max_negatives_per_positive > 0:
    max_negatives_per_positive = config.max_negatives_per_positive
if config.num_hard_examples > 0:
    num_hard_examples = config.num_hard_examples
hard_example_miner = losses.HardExampleMiner(
    num_hard_examples=num_hard_examples,
    iou_threshold=config.iou_threshold,
    loss_type=loss_type,
    cls_loss_weight=classification_weight,
    loc_loss_weight=localization_weight,
    max_negatives_per_positive=max_negatives_per_positive,
    min_negatives_per_image=config.min_negatives_per_image)
return hard_example_miner

由model_builder.py返回并由train.py调用。基本上,在我看来,简单地生成真正的正面标签(使用像LabelImg或RectLabel这样的工具)应该足以使列车算法在相同的图像中找到硬阴性。相关问题提供了很好的walkthrough

如果您想要输入没有真阳性的数据(即图像中没有任何内容),只需将负图像添加到tfrecord,不带边界框。

答案 1 :(得分:0)

我想我正在经历相同或接近的场景,值得与您分享。

我设法通过将没有注释的图像传递给训练器来解决它。

在我的场景中,我正在构建一个项目来实时检测客户产品中的装配故障。 我通过对具有明显负面模式的组件(例如有螺丝打开/关闭的螺丝(只有孔))使用检测+分类并仅检测没有的东西,成功地获得了非常强大的结果(对于生产环境)底片(例如可以放在任何地方的胶带)。

在系统上,用户必须录制 2 个视频,一个包含正面场景,另一个包含负面场景(或 n 个视频,包含 n 个正面和负面模式,以便算法可以概括)。

经过一段时间的测试后,我发现如果我注册仅检测磁带,则检测器会给出非常有把握的 (0.999) 磁带误报检测。它正在学习插入磁带而不是磁带本身的模式。当我有另一个组件(比如它的负片格式上的螺丝)时,我在没有明确意识到它的情况下传递了负片图案,所以 FP 没有发生。

所以我发现,在这种情况下,我必须在没有胶带的情况下传递图像,以便区分有胶带和无胶带。

我考虑了两种替代方案来尝试解决此问题:

  1. 训练传递大量没有任何注释的图像(占我所有负样本的 10%)以及我有真实注释的所有图像。
  2. 在我没有注释的图像上,我创建了一个带有虚拟标签的虚拟注释,以便我可以强制检测器使用该图像进行训练(从而学习无磁带模式)。稍后,当获得虚拟预测时,只需忽略它们即可。

得出的结论是,这两种替代方案都适用于我的场景。 训练损失有点混乱,但对于我非常可控的场景(系统的相机有自己的盒子和照明以减少变量),预测工作具有鲁棒性。

我不得不对第一个替代方案进行两个小的修改:

  1. 所有没有任何注释的图像我都通过了一个虚拟注释(class=None,xmin/ymin/xmax/ymax=-1)
  2. 生成 tfrecord 文件时,我使用此信息(在本例中为 xmin == -1)为示例添加一个空列表:
def create_tf_example(group, path, label_map):
    with tf.gfile.GFile(os.path.join(path, '{}'.format(group.filename)), 'rb') as fid:
        encoded_jpg = fid.read()
    encoded_jpg_io = io.BytesIO(encoded_jpg)
    image = Image.open(encoded_jpg_io)
    width, height = image.size

    filename = group.filename.encode('utf8')
    image_format = b'jpg'

    xmins = []
    xmaxs = []
    ymins = []
    ymaxs = []
    classes_text = []
    classes = []

    for index, row in group.object.iterrows():
        if not pd.isnull(row.xmin):
            if not row.xmin == -1:
                xmins.append(row['xmin'] / width)
                xmaxs.append(row['xmax'] / width)
                ymins.append(row['ymin'] / height)
                ymaxs.append(row['ymax'] / height)
                classes_text.append(row['class'].encode('utf8'))
                classes.append(label_map[row['class']])

    tf_example = tf.train.Example(features=tf.train.Features(feature={
        'image/height': dataset_util.int64_feature(height),
        'image/width': dataset_util.int64_feature(width),
        'image/filename': dataset_util.bytes_feature(filename),
        'image/source_id': dataset_util.bytes_feature(filename),
        'image/encoded': dataset_util.bytes_feature(encoded_jpg),
        'image/format': dataset_util.bytes_feature(image_format),
        'image/object/bbox/xmin': dataset_util.float_list_feature(xmins),
        'image/object/bbox/xmax': dataset_util.float_list_feature(xmaxs),
        'image/object/bbox/ymin': dataset_util.float_list_feature(ymins),
        'image/object/bbox/ymax': dataset_util.float_list_feature(ymaxs),
        'image/object/class/text': dataset_util.bytes_list_feature(classes_text),
        'image/object/class/label': dataset_util.int64_list_feature(classes),
    }))
    return tf_example

部分训练进度:

enter image description here

目前我正在使用 tensorflow 对象检测和 tensorflow==1.15,使用 fast_rcnn_resnet101_coco.config。

希望它能解决某人的问题,因为我没有在互联网上找到任何解决方案。我读到很多人说 fast_rcnn 不适用于减少 FP 的负面训练,但我的测试证明恰恰相反。