You Only Learn One Representation: Unified Network for Multiple Tasks论文阅读
paper:https://arxiv.org/pdf/2105.04206.pdf
code: https://github.com/WongKinYiu/yolor
摘要
论文中,提出了一个统一的网络将隐性知识(implicit knowledge)和显性知识(explicit knowledge)编码在一起,就像人类的大脑可以从正常的学习知识和潜意识学习,该网络可以生成一个统一的表征(representation)同时用于多个任务(刚开始还以为是可以同时作用于检测,分割,姿态估计等任务,结果实验部分只有目标检测,这个多任务好像说的是目标检测中的分类与定位。。)。可以在卷积神经网络中执行kernel space alignment,prediction refinement,multi-task learning。结果表明,将implicit knowledge引入到神经网络中,有利于所有任务的执行。作者进一步分析了从所提出的统一网络中学习到的implicit knowledge,它显示出很强的捕捉不同任务物理意义的能力。
介绍
如图1所示,人可以从多个角度分析一张图片,然而CNN通常只能实现一个目标。也就是说,从CNN提取的特征不能适用与其他类型的问题。这是因为我们只使用了网络提取的特征,而网络中丰富的隐性知识(implicit knowledge)并没有使用。然而没有系统的定义implicit learning怎样操作以及怎样获得implicit knowledge。通常,在神经网络的定义中,来自浅层网络的特征为显性知识(explicit knowledge),从深层网络得到的特征为隐性知识(implicit knowledge)。该论文中,把与观察直接对应的知识称为显性知识,对于模型中隐含的与观察无关的知识,称之为隐性知识。
作者提出一个统一的网络来融合隐性知识(implicit knowledge)和显性知识(explicit knowledge),确保模型包含一个统一的表征(representation),这个统一的表征允许子表征(sub-representation)也适用于其他任务。如图2c所示。
论文贡献如下:
- 作者提出一个统一的网络可以完成多种任务,它通过融合显性知识与隐性知识学习一个可以完成多个任务的统一表征,提出的网络可以有效的提升模型的表现,仅增加千分之一不到的计算成本;
- 作者在隐性知识学习中引入了kernel space alignment, prediction refinement, multi-task learning,并验证了其有效性;
- 作者分别讨论了建模隐性知识的方式,包括向量,神经网络,矩阵分解,并验证了这些的有效性;
- 作者证实了所提出的内隐表征学习方法能够准确地对应于特定的物理特征,并且还以视觉的方式呈现了它。还证实,如果算子符合目标的物理意义,它可以用来整合隐形知识和显性知识,并会产生乘数效应。
- 与SOTA比较,YOLOR能够实现目标检测中Scaled-YOLOv4-P7一样的精度,但是推理速度快了88%;
implicit knowledge 如何工作?
隐形表征zi是与观察不相关的,他可以是一个常量tensor Z = {z1,z2,…zk}。下面将介绍implicit knowledge是如何作为一个常量tensor在多个任务中作用的。
Manifold space reduction
作者认为,一个好的表征应该能够在它所属的流形空间中找到一个合适的投影,并有助于后续目标任务的顺利完成。如图3所示,如果在投影空间中利用超平面能成功地对目标类别进行分类,那将是最好的结果。在上面的例子中,可以利用投影向量的内积和隐式表示来达到降低流形空间维数的目的,有效地完成各种任务。
Kernel space alignment
在多任务和多头神经网络中,核空间不对齐是经常发生的问题,图4a展示了一个在多任务多头神经网络的核空间不对齐的例子。为了解决这个问题,可以对输出特征和隐形表征进行加法和乘法运算,这样就可以对核空间进行变换、旋转和缩放,以对齐神经网络的每个输出核空间,如图4.(b)所示。
该方法可以用于多个方面,比如说FPN中大目标与小目标的特征对齐,知识蒸馏中大模型与小模型的整合,处理zero-shot领域迁移和等问题;
More functions
除了可以应用于不同任务的功能外,隐性知识还可以扩展为更多的功能。如图5所示,通过引入加法,可以使神经网络预测中心坐标的偏移量。还可以引入乘法来自动搜索锚点的超参数集,这是基于锚点的对象检测器经常需要的。此外,可以分别使用点乘和concat来执行多任务特征选择和为后续计算设置前提条件。
统一网络中的implicit knowledge
implicit knowledge的形成
传统神经网络由以下公式表示,其中y为目标,fθ 表示神经网络, θ是神经网络的参数,ε是误差项;
在训练过程中,最小化ε,这表示我们期望同一目标的不同观测值是fθ 所得到的子空间中的一个点, 如图6(a)所示。换言之,我们期望得到的解空间只对当前任务ti有区别,对各种潜在任务中除ti以外的任务是不变的,T \ ti , T = {t1 , t2 , …, tn }。
为了通用目标的神经网络,我们希望获得的表征可以作用于其他所有属于T的任务。因此需要放松ε,以便能够在流形空间上同时找到每个任务的解,如图6(b)所示。然而,上述要求使得我们不可能用简单的数学方法,如一个独热向量的最大值或欧氏距离的阈值来求解ti。为了解决这个问题,我们必须对错误项进行建模,以便为不同的任务找到解决方案,如图6(c)所示。
统一网络:
为了训练所提出的统一网络,作者将显式知识和隐式知识结合起来对误差项进行建模,然后用它来指导多用途网络的训练过程。相应的训练公式如下:
其中εex和εim是建模来自观察x的显式误差和来自隐藏编码z的隐式误差。gφ这是一个特定于任务的操作,用于从显性知识和隐性知识中组合或选择信息。
有一些现有的方法来融合显性知识到fθ,所以将公式(2)表示为公式(3):
*表示一些可以融合fθ和gφ的操作,相加,相乘,concat;
如果把误差项的推导过程推广到处理多个任务,可以得到如下等式:
其中 Z = {z1 , z2 , …, zT } 是一个用于不同任务T的隐式编码集合,Φ 是用与从Z生成隐式表征的参数,Ψ 是用来从显示表征和隐式表征生成最终的输出的参数;
对于不同的任务,可以使用以下公式获得所有z∈ Z的预测:
一个共同统一的表征fθ (x),基于任务而不同的隐式表征gφ(z),最后用任务特定的判别器dΨ完成不同的任务。
建模implicit knowledge
- 向量/矩阵/tensor
向量z直接作为隐式知识的先验,直接作为隐式表示。此时,必须假设每个维度彼此独立。 - 神经网络
利用向量z作为隐式知识的先验,然后利用权矩阵W进行线性组合或非线性化,成为隐式表示。此时,必须假设每个维度相互依赖。也可以使用更复杂的神经网络来生成隐式表示。或者用马尔可夫链来模拟不同任务之间隐式表示的相关性。 - 矩阵分解
利用多个向量作为隐式知识的先验,这些隐式先验基Z和系数c构成隐式表示。还可以进一步对c进行稀疏约束,并将其转化为稀疏表示形式。此外,还可以对Z和c施加非负约束,将它们转化为非负矩阵分解(NMF)形式。
训练
当融合操作为相加,concat时,初始化implicit先验z ~ N (0, σ),如果融合方式为相乘,则初始化为z ~ N (1, σ),σ是一个近似0的很小的值,z和φ都在反向传播中更新;
推理
由于内隐知识与观察x无关,无论内隐模型g有多复杂φ 也就是说,在执行推理阶段之前,它可以被简化为一组常数张量。也就是说隐式信息不会造成额外的计算量。如果是进行相乘操作则是按照公式9,如果是相加操作则按照公式10;
实验
实验设置
通过FPN中的feature alignment, 目标检测中的prediction refinement, 和一个模型中的multi-task learning来添加implicit knowledge,使用YOLOV4-CSP作为baseline,implicit knowledge添加位置如图8所示,所有训练超参数与scaled-yolov4中一致。
FPN中的Feature alignment
目标检测中的prediction refinement
添加隐式表征到YOLO输出层,图9表示隐式表征的引入如何影响检测结果。
多任务的规范表征
当一个模型需要同时训练多个任务共享时,由于损失函数的联合优化过程是必须执行的,因此在执行过程中往往会出现多方相互拉动的情况。上述情况将导致最终的整体性能比单独训练多个模型然后将它们集成要差。为了解决这个问题,作者建议训练多任务的规范表征,通过给每个任务分支添加隐式表征开增强表征力量,结果如表3所示;
不同算子的Implicit建模
表4显示了图10中不同操作融合显式表征与隐式表征的结果;
在feature alignment实验中,相加与concat操作能够提升性能表现,相乘有所下降;特征对齐的实验结果完全符合其物理特性,因为它必须处理全局偏移和所有单个簇的缩放;
在prediction refinement实验中,由于concat会增加channel,所以只比较相加与相乘的效果,在这里相乘的效果更好;作者发现中心移位在执行预测时使用加法解码,而锚定尺度使用乘法解码。由于中心坐标是以网格为界的,影响较小,而且人工设置的锚点具有较大的优化空间,因此改进更为显著。
基于上面的分析,作者设计了两个其他实验 – {× iFA∗, × iPR∗ }。在第一个实验 – × iFA∗ 中,作者将特征空间划分为锚聚类级,并与乘法相结合,第二个实验– × iPR∗,作者只在width和height上执行相乘refinement。结果如表5,作者发现,经过相应的修改,各项指标的得分都得到了全面的提高。实验表明,在设计显性知识与隐性知识的结合时,首先要考虑结合层的物理意义,以达到倍增效应。
不同的方式建模implicit knowledge
implicit模型的分析
增加的参数不到万分之一,并且可以加快模型的收敛;
目标检测中的implicit knowledge
按照scaled-yolov4训练过程,先从头训练300epochs,然后微调150epochs,表8显示了implicit knowledge的效果,表9显示了与SOTA的比较;
结论
本文介绍了如何构造一个内隐知识与外显知识相结合的统一网络,并证明了它在单模型结构下对多任务学习仍然是非常有效的。在未来,作者将把训练扩展到多模式和多任务,如图12所示。
模型细节
YOLOv4-CSP是topology 1,scaled-yolov4论文中有架构描述;
YOLOv4-CSP-fast是基于YOLOv4-CSP进行改进,使用stem B代替了YOLOv4-CSP中的stem A;
YOLOv4-CSP-SSS属于topology 2,使用了stem C,stage B2之后与YOLOv4-CSP一致,width缩放系数和depth缩放系数设置为0.5和0.33,并且使用SiLU激活函数代替Mish;
YOLOv4-CSP-SSSS是基于YOLOv4-CSP-SSS改进的,使用stem F代替stem C,由于多了一次下采样,所以属于topology 4;
YOLOv4-P6-light 属于topology 3,使用stem D并且基准channels设置为{128, 256, 384, 512, 640},为了优化梯度传播,在B* stages中添加CSP融合,然后B2到B6的重复数量设置为 {3, 7, 7, 3, 3}。
YOLOR-P6与YOLOv4-P6-light有着相同的架构,将Mish激活函数使用SiLU代替;
YOLOR-W6是更宽的YOLOR-P6,channels设置为{128,256, 512, 768, 1024};
YOLOR-E6在YOLOR-W6的基础上扩展宽度,width缩放系数为1.25,所有下采样模块都使用CSP卷积替换;
YOLOR-D6是基于YOLOR-E6的更深版本,B2到B6模块堆叠重复数字设置为 {3, 15, 15, 7, 7};
感觉就是先基于YOLOv4-CSP进行模型改进,将模型改轻量一些,速度更快一些,然后使用论文提出的隐式表征涨点,所以达到了YOLOv4-P7的精度,速度更快;
与其他模型的比较
U5R5-S:yolov5s
U5R5-S6:yolov5s6
U5R5-M6:yolov5m6
U5R5-L6:yolov5l6
U5R5-X6:yolov5x6
YOLOR-E6比YOLOv5x6速度更快,精度更高;
YOLOV5模型虽然速度更快,但整体精度不如YOLOR;
代码
class ImplicitA(nn.Module):
def __init__(self, channel):
super(ImplicitA, self).__init__()
self.channel = channel
self.implicit = nn.Parameter(torch.zeros(1, channel, 1, 1))
nn.init.normal_(self.implicit, std=.02)
def forward(self, x):
return self.implicit.expand_as(x) + x
class ImplicitM(nn.Module):
def __init__(self, channel):
super(ImplicitM, self).__init__()
self.channel = channel
self.implicit = nn.Parameter(torch.ones(1, channel, 1, 1))
nn.init.normal_(self.implicit, mean=1., std=.02)
def forward(self, x):
return self.implicit.expand_as(x) * x
class IDetect(nn.Module):
stride = None # strides computed during build
export = False # onnx export
def __init__(self, nc=80, anchors=(), ch=()): # detection layer
super(IDetect, self).__init__()
self.nc = nc # number of classes
self.no = nc + 5 # number of outputs per anchor
self.nl = len(anchors) # number of detection layers
self.na = len(anchors[0]) // 2 # number of anchors
self.grid = [torch.zeros(1)] * self.nl # init grid
a = torch.tensor(anchors).float().view(self.nl, -1, 2)
self.register_buffer('anchors', a) # shape(nl,na,2)
self.register_buffer('anchor_grid', a.clone().view(
self.nl, 1, -1, 1, 1, 2)) # shape(nl,1,na,1,1,2)
self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1)
for x in ch) # output conv
"""
self.ia就是与隐式表征相加
self.im就是与隐式表征相乘
"""
self.ia = nn.ModuleList(ImplicitA(x) for x in ch)
self.im = nn.ModuleList(ImplicitM(self.no * self.na) for _ in ch)
def forward(self, x):
# x = x.copy() # for profiling
z = [] # inference output
self.training |= self.export
for i in range(self.nl):
"""
这里对于每层FPN的输出每个通道先加上一个隐式表征,
然后经过预测头的卷积,再每个通道乘以一个隐式表征;
"""
x[i] = self.im[i](self.m[i](self.ia[i](x[i]))) # conv
bs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85)
x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(
0, 1, 3, 4, 2).contiguous()
if not self.training: # inference
if self.grid[i].shape[2:4] != x[i].shape[2:4]:
self.grid[i] = self._make_grid(nx, ny).to(x[i].device)
y = x[i].sigmoid()
y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 +
self.grid[i]) * self.stride[i] # xy
y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * \
self.anchor_grid[i] # wh
z.append(y.view(bs, -1, self.no))
return x if self.training else (torch.cat(z, 1), x)
@staticmethod
def _make_grid(nx=20, ny=20):
yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)])
return torch.stack((xv, yv), 2).view((1, 1, ny, nx, 2)).float()