截止2023年7月14,papers with code 上共有10篇相关论文,其中发表在cvpr上的如下,共有4篇,自2021年该主题被提出来后,陆续有了一些工作,但我的问题是在2023年上半年,meta提出了SAM,意味着在提示词模型领域已经存在了具备持续学习能力的模型,那么回来再看该主题的意义又在哪里呢?另外是不是分割任务可以包含检测任务?换句话说分割是不是更高阶级的检测任务?更新回答
来源于微信公众号的开放世界目标检测调研:
- 迈向多模态AGI之开放世界目标检测,包括 OVR-CNN, RegionCLIP, CORA.
- 一文尽览 | 开放世界目标检测的近期工作及简析!(基于Captioning/CLIP/伪标签/Prompt)2022. 12.27
- 基于DETR的开放世界目标检测——从入门到喜欢
- OW-DETR | 基于 Transformer 的开放世界目标检测器
- ECCV22|美团&上海交大开源PromptDet:无需手动标注,迈向开放词汇的目标检测
- OWOD:开放世界目标检测,更贴近现实的检测场景 | CVPR 2021 Oral
- 检测开放世界中的一切:面向通用目标检测
- 【CMU博士论文】开放世界目标检测与跟踪
- UniDetector:面向开放世界的通用检测框架
- CVPR2021 | 开放世界检测综述
- CVPR2021:Towards Open World Object Detection 开放世界的目标检测
- 一个期刊
- 一个比赛
- 黄埔算法大赛
思考:
从该问题的解决目标来看,主要分为了两个方面:让模型有自知之明,即知道自己什么知道,什么不知道;让模型具有持续学习的能力,即,在不丢失对已有标签物体识别能力的情况下,有新的监督数据来的时候,可以继续学习的能力。开放世界目标检测虽然只是在检测领域,但解决的问题却是整个AI领域面临的问题。对于以上叙述的第一点,目前的解决方案【大多是?】人工界定,比如有时你对ChatGPT提出一些请求,他会告诉你他只是一个语言模型,而不能做太多,这个太宽泛的视角了,不仅仅局限在目标检测,但有时【经常的】ChatGPT会一本正经的胡说八道正是这个问题。第二点持续学习能力,ChatGPT可能会通过提示词进行增量学习,我理解相对清楚的是SAM可持续学习,以提示词的形式。
抛开这个问题,以上的目标是实现AI的自知之明和持续学习两项能力,那么与之而来的,我想还可以有【自我意识】,人类与生俱来的具有自知之明和持续学习能力,同时还具有保持自身【物质能量】和【精神能量】的饥饿满足机制,人类不断的满足自己的饥饿,从而成长。那么现阶段的AI还缺乏这样的机制,但是随着持续学习能力的到来,这种机制越来越显得颇为重要,可以令AI感到【痛苦】的东西也是其进化的本能。人类是饥饿,表现在物质和精神上。【补充,显然这种观点在「进化论」上属于扩张式的,而与之对应的是保守式的,人类出于保护自身的物质和精神上的能量而进化。但是物质和精神是否包含了各种知觉呢?比如触觉,嗅觉,视觉,听觉,味觉等感官世界,如果可以把感官世界归结为精神世界,那么物质和精神上的饥饿本能进化论应该是「大一统的」】为AI设置物质能量可以包括模型体量这种平面化概念,还可以是训练其模型可获得的电力多少这样的立体化概念。精神能量应该就是现阶段各种AI模型的奖励函数,或者负损失函数,因为进化的本能需求是向能量较多的方向发展。【痛苦】和【幸福】是相对的,又是统一的,减少痛苦的同时就是增加幸福的过程,有了这些或减少痛苦或增加幸福的本能设置,AI的自我意识还需要什么呢?也许等这些问题被解决或者逐渐解决的过程中,这个问题才会有渐渐清晰的答案,正如此时此刻的预测。
面对开放世界的目标检测,目前主流的目标检测都是基于完全标记好的数据集进行训练,然后再利用训练好的模型进行推理,在推理阶段可能会遇到在训练阶段没有见过的新的实例,不仅是在目标检测任务上,图像分类也会在推理的时候遇到训练集中没有的实例,但是模型不会知道训练过程中没有被人类告知的实例,所以最终的结果就是给新的实例分配一个训练集中的标签。显然这种模型并不智能,可以说模型只是“在自己的世界观里自以为是的推理”,并没有真正的学会普遍的真理。事实上,类似于人类的能力,我们希望模型可以做到:知道什么是自己知道的,什么是自己不知道的(有自知之明),并且具有持续的学习能力。更具体的来说,模型可以为新加入的类别标记为"unknown",并且可以在学习新的类别的同时不忘记原来存在的类别。
开放的谈论这个问题,开放世界的模型是具有重大意义的,个人认为他让AI真正的获得了持续学习的能力,似乎这个概念相似于终身学习(continual learning, life-long learning)。终身学习意味着一个AI模型具有了类似于人类的年龄,可以随着学习时间的增长知识逐渐积累,不仅可以极大地节省计算资源,还可以减少训练模型的时间。突然感觉这“开放世界”就是“终身学习”的另一个名字……。不说了,更多的细节去看终身学习吧!!!
7.25 组会
-
完成的内容:修改论文的表述不包括公式。添加参考文献但没有添加引用,还没有去除未被引用的参考文献。B\C会调研:BMVC,ICPR,ECCV, 还没有开始接收。
-
jialan paper 已有创新点:1.伪标签,RPN(base) 2.分类头 3. 增量学习解决遗忘问题 (base) 【表述和base太像,并且伪标签的标注方法存在问题,F_store是随着训练进行而积累的特征队列,不是得分,这应该不可以分为known和unknown进行加权求和吧】
-
最新论文创新点:1. 新的评价指标,以往主要注重召回率,忽略了精确度。非物体被当作未知物体,冗余的检测框 2. 基于注意力机制的伪标签
-
优化方向:伪标签基于注意力机制,表述优化 【不太可行,因为基于注意力机制的方法一般用在single-stage,这里是two-stage的,修改量最小原则要求不采取这种方法】
- jialan paper 修改想法【筚路蓝缕】
伪标签再base论文中的作用是为后续将已知类和未知类进行聚类做准备,因为raw data中不存在Unknown的标注,因此在聚类之前需要先找到一些可能是unkonwn的物体,也就是在RPN模块中标注了一些unknown框,但是问题是,这种做法会把一些背景框作为未知物体的框引入进来,一方面导致最终位置物体检测的精确度下降,另一方面会造成检测框的冗余;同时也会引入一些已知物体的框,导致最终已知物体检测的召回率下降。所以这种伪标签的标注方法存在天然的缺陷。
根本原因是模型没有判断一个框内是否具有物体的能力,一个训练好的普通检测器如果漏检了某种物体会降低召回率,但如果在开放世界的环境下,相对于已有检测器的大量未知物体往往会导致较低的准确率,因为
在当前模型眼里,他能给出的答案只有训练集中的存在的那些标注,可是,不能否认的是,这个模型具有了判断这是一个物体的能力,只是将他识别错了类别,所以具体的责任应该由分类器来承担,而不是检测器。所以由此得到启发,负责打伪标签的检测器,可以使用训练好的模型,这样应该会降低前面叙述的天然缺点。
另外base论文的一个很明显的缺点是没有采用feature map的多尺度信息,只构建了一个类原型队列F_store,这样对目标尺度变化大的图像会降低模型性能,所以结合前面叙述的,采用多尺度的预训练RPN来标注伪标签,并且后续的聚类模块也使用多尺度的特定类的聚类中心。
0 如何从背景中找到隐藏的未知对象
以下是一些帮助从图像背景中找到隐藏或未知物体的技巧:
异常检测 – 在没有物体的正常背景图像上训练模型。在测试时,较大的重构误差很可能表示与物体相对应的异常区域。
背景减法 – 保留静态背景模型。从图像中减去背景可以突出前景物体。
图像差分 – 提取连续视频帧之间的差值。移动物体会被突出显示,而静态背景则会被抑制。
运动检测 – 使用光流或帧差来识别运动区域。这些区域可能包含隐藏的运动物体。
边缘检测 – 在图像中查找轮廓和边缘。连接的边缘可能与物体边界相对应。
语义分割 – 训练一个模型,将每个像素分为物体、背景等语义类别。这可以揭示未知物体。
对象建议生成 – 使用选择性搜索或区域建议网络来识别图像中潜在的对象区域。
超像素分割 – 将像素组合成有感知意义的原子区域。符合物体边界的超像素可以揭示隐藏的物体。
其主要思路是利用运动、边缘、异常等线索,找到与正常背景模型不同的模式。多种技术的结合往往是在复杂背景中发现未知物体的最有效方法。
- 基于以上Claude2的回答,我想到基于
图像差分
的检测方法:
开放世界目标检测关键的一点是从背景中识别出未知物体,如果是视频的话,可以通过检测动静变化来识别图中特定未知物体的存在与否,但是也只可以检测动态的物体,静止的物体依然无法识别。但从相对论的角度来看,万物都是运动的,只要让模型察觉到动静变化,那么相应的物体就会从背景中脱颖而出,这也符合人类的认知,比如,我们经常容易忽视一些东西的存在,也就是视而不见,而这些东西都有一个特点就是“不变”,即,保持原来的状态。可能这个例子不太恰当,但我们“知道”一样东西的存在,一定“经历”过他离开过所依赖的其他物体,无论是看到的实物的分离,还是思维概念上的分离。我们都看过桌子移动,所以知道桌子的存在;我们接触过原子的概念(虽然不一定看到过),所以知道原子的存在。这就是两个直接的例子,分别从实物分离和概念分离的角度。所以检测一样物体是否存在的任务,可以从动静分离的角度得到启发,数据框标注是否可以被几帧连续的图像替换?比如一个猫的识别任务,利用100帧连续的只有猫跑动的图像,给这100帧数据一个标签:猫。那么是否就可以替换掉如今昂贵的数据框人工标注,检测框完全可以通过动静变化检测由模型来标注,当模型学到了一定知识后,再迁移到静态物体检测。
1. (CVPR2021) ORE (OWOD first work)
新思路
:在隐藏空间去聚类,达到这样的目的:将没有标记的类别特征标记为“unknown”。
模型架构
:
1. 主要贡献分为3个方面:
- ①对比聚类
- 取二阶段目标检测网络某个中间层的特征向量作为隐空间变量,对于每个类别都有一个聚类中心,通过一个loss函数来希望每个图片的这个特征离自己类别的聚类中心近一点,离其他类别的聚类中心远一点。
- 通过最小化loss函数,来获得一种效果:在这个隐空间中,相同类别的ROI,其隐变量分布在较近的距离,而不同类别的较远。因此当一个ROI的隐变量离所有已知类别的聚类都很远时,说明这个ROI是unknown类,也就是未标注类别。
这个$\mathcal{p_i}$是该类别所有隐变量的均值,但是网路是训练的,所以对每个样本通过网络提取的隐变量会随着训练而变化,均值也会变化,所以$\mathcal{p_i}$也会变化。需要一个明确的更新算法:每隔$I$此迭代,用各个类别各自最近Q次迭代的样本的特征向量(隐变量)来算各个类别的均值,然后和旧的聚类中心做加权平均(平滑),作为各个类别新的聚类中心。当然一开始没有Q个样本来算聚类中心,所以一开始的Loss先按0来算,迭代$I$次之后才开始算Loss.
- ②RPN自动标记机制
上述训练需要的unknown样本,从RPN中获取。当某个ROI与所有标记的GT都不重叠时,将RPN提取的置信度最高的前N个背景枚举框作为未知目标的枚举框向后传递。
- ③基于能量的分类模型
当训练结束,推理阶段,基于一个输入特征向量F,该模型利用一个基于能量的模型去计算获取其预测类别。
$\mathcal{g}$是网络的全连接层的输出,普通的网络就是把$\mathcal{g}$给到$softmax$做分类,这里利用了$\mathcal{g}$构建$E$,$E$的意义在于:对于不同的输入$\mathcal{f}$,有不同的能量标量值与之对应,而由于在隐空间将已知类和未知类分得很开,所以这里已知类的特征向量输入产生的能量和未知类的特征向量输入产生的能量值有较大区别。因此,在推理阶段分为两步:先通过能量值判断是不是known;若是known,再看哪个类别的输出值更高。
2. 经典RPN
经典的检测方法生成检测框都非常耗时,Faster-RCNN 直接使用 RPN 生成检测框,能极大提升检测框的生成速度。RPN (Region Proposal Network) 用于生成候选区域(Region Proposal)。RPN 的输入为 backbone (VGG16, ResNet, etc) 的输出,(简称 feature maps)
RPN 包括以下部分:
- 生成 anchor boxes
- 判断每个 anchor box 为 foreground(包含物体) 或者 background(背景) ,二分类
- 边界框回归(bounding box regression) 对 anchor box 进行微调,使得 positive anchor 和真实框(Ground Truth Box)更加接近
生成 anchor boxes,也就是锚框。
import numpy as np
def generate_anchors(base_size=16, ratios=[0.5, 1, 2],
scales=2**np.arange(3, 6)):
"""
Generate anchor (reference) windows by enumerating aspect ratios X
scales wrt a reference (0, 0, 15, 15) window.
"""
base_anchor = np.array([1, 1, base_size, base_size]) - 1
ratio_anchors = _ratio_enum(base_anchor, ratios)
anchors = np.vstack([_scale_enum(ratio_anchors[i, :], scales)
for i in range(ratio_anchors.shape[0])])
return anchors
def _whctrs(anchor):
"""
Return width, height, x center, and y center for an anchor (window).
"""
w = anchor[2] - anchor[0] + 1
h = anchor[3] - anchor[1] + 1
x_ctr = anchor[0] + 0.5 * (w - 1)
y_ctr = anchor[1] + 0.5 * (h - 1)
return w, h, x_ctr, y_ctr
def _mkanchors(ws, hs, x_ctr, y_ctr):
"""
Given a vector of widths (ws) and heights (hs) around a center
(x_ctr, y_ctr), output a set of anchors (windows).
"""
ws = ws[:, np.newaxis]
hs = hs[:, np.newaxis]
anchors = np.hstack((x_ctr - 0.5 * (ws - 1),
y_ctr - 0.5 * (hs - 1),
x_ctr + 0.5 * (ws - 1),
y_ctr + 0.5 * (hs - 1)))
return anchors
def _ratio_enum(anchor, ratios):
"""
Enumerate a set of anchors for each aspect ratio wrt an anchor.
"""
w, h, x_ctr, y_ctr = _whctrs(anchor)
size = w * h
size_ratios = size / ratios
ws = np.round(np.sqrt(size_ratios))
hs = np.round(ws * ratios)
anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
return anchors
def _scale_enum(anchor, scales):
"""
Enumerate a set of anchors for each scale wrt an anchor.
"""
w, h, x_ctr, y_ctr = _whctrs(anchor)
ws = w * scales
hs = h * scales
anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
return anchors
if __name__ == '__main__':
a = generate_anchors()
print(a)
输出为:
[[ -84. -40. 99. 55.]
[-176. -88. 191. 103.]
[-360. -184. 375. 199.]
[ -56. -56. 71. 71.]
[-120. -120. 135. 135.]
[-248. -248. 263. 263.]
[ -36. -80. 51. 95.]
[ -80. -168. 95. 183.]
[-168. -344. 183. 359.]]
画框代码:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
# Array of rectangle coordinates
rect_coords = np.array([[ -84., -40., 99., 55.],
[-176., -88., 191., 103.],
[-360., -184., 375., 199.],
[ -56., -56., 71., 71.],
[-120., -120., 135., 135.],
[-248., -248., 263., 263.],
[ -36., -80., 51., 95.],
[ -80., -168., 95., 183.],
[-168., -344., 183., 359.]])
# Create a figure and axes
fig, ax = plt.subplots()
# Plot rectangles
for rect in rect_coords:
x0, y0, x1, y1 = rect
width = x1 - x0
height = y1 - y0
rectangle = patches.Rectangle((x0, y0), width, height, linewidth=1, edgecolor='r', facecolor='none')
ax.add_patch(rectangle)
# Set x and y limits
x_min = np.min(rect_coords[:, [0, 2]])
x_max = np.max(rect_coords[:, [0, 2]])
y_min = np.min(rect_coords[:, [1, 3]])
y_max = np.max(rect_coords[:, [1, 3]])
ax.set_xlim(x_min, x_max)
ax.set_ylim(y_min, y_max)
# Set aspect ratio to 'equal'
ax.set_aspect('equal')
# Show the plot
plt.show()
其中每行的4个值$(x_1,y_1,x_2,y_2)$
表示矩形左上角和右下角点坐标。9个矩形共有3种形状,长宽比包括${1:1,1:2,2:1}$
,如上图,通过anchor box 就引入了检测中常用到的多尺度方法。
- 遍历,为 feature maps 的每一个点都配9个锚框,作为初始的检测框。虽然这样得到的检测框很不准确,但后面可通过2次 bounding box regression 来修正检测框的位置。
更多关于FasterRCNN的细节见here
2. (CVPR2022) OW-DETR
3. (CVPR2023) PROB
PROB introduces a probabilistic framework for objectness estimation, where it alternates between probability distribution estimation and objectness likelihood maximization of known objects in the embedded feature space, finally it can estimate the objectness probability of different proposals.
code is available at: https://github.com/orrzohar/PROB
4. (CVPR2023) Annealing-Based Label-Transfer Learning for Open World Object Detection
ALLOW introduces a Label-Transfer Learning paradigm and a Sawtooth Annealing Scheduling strategy to decouple the known and unknown features. Also, it proposes the Equilibrium Index to comprehensively evaluate the effectiveness of the OWOD models.
code is available at: https://github.com/DIG-Beihang/ALLOW
5. (CVPR2023) CAT: LoCalization and IdentificAtion Cascade Detection Transformer for Open-World Object Detection
6. (CVPR2023) Detecting Everything in the Open World: Towards Universal Object Detection
UniDetector proposes the decoupling training manner and probability calibration to enhance the strong zero-shot generalization ability on large-vocabulary datasets like LVIS, ImageNetBoxes, and VisualGenome.
7. (CVPR2023) Unknown Sniffer for Object Detection: Don’t Turn a Blind Eye to Unknown Objects
UnSniffer introduces a negative energy suppression loss and a generalized object confidence (GOC) score to find never-seen-before objects and distinguish them from known ones. Also it uses a graph-based determination scheme to replace non-maximum suppression (NMS).
code is available at: https://github.com/Went-Liang/UnSniffer