我正在设置新的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图像:
答案 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 没有发生。
所以我发现,在这种情况下,我必须在没有胶带的情况下传递图像,以便区分有胶带和无胶带。
我考虑了两种替代方案来尝试解决此问题:
得出的结论是,这两种替代方案都适用于我的场景。 训练损失有点混乱,但对于我非常可控的场景(系统的相机有自己的盒子和照明以减少变量),预测工作具有鲁棒性。
我不得不对第一个替代方案进行两个小的修改:
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
部分训练进度:
目前我正在使用 tensorflow 对象检测和 tensorflow==1.15,使用 fast_rcnn_resnet101_coco.config。
希望它能解决某人的问题,因为我没有在互联网上找到任何解决方案。我读到很多人说 fast_rcnn 不适用于减少 FP 的负面训练,但我的测试证明恰恰相反。