Visual Relationship Detection with Deep Structural Ranking(阅读笔记)

2 minute read

Published:

该文章仅对相关论文做出个人解读,并非博客作者原创工作,如果你觉得对你的工作有所帮助,请引用原文信息。如果要转载博客内容,请告知笔者。


论文信息:

@article{liang2018Visual,
title={Visual Relationship Detection with Deep Structural Ranking},
author={Liang, Kongming and Guo, Yuhong and Chang, Hong and Chen, Xilin},
booktitle={AAAI Conference on Artificial Intelligence},
year={2018}
}

GitHub Link: https://github.com/GriffinLiang/vrd-dsr


如有任何相关问题欢迎评论或者邮件讨论wenyuanxue@bjtu.edu.cn


Introduction

视觉关系检测任务的目标是准确定位图像中的一对物体,并对他们之间的关系(predicate,“谓语”)做出判断,如图(1)所示。作为一个中间阶段的学习任务,视觉关系检测的结果可以应用在图像描述(image captioning)和视觉问答(visual question answering)等更高层的视觉理解任务。

视觉检测任务主要有以下两类挑战

  1. 如果我们将两个物体间的视觉关系表示为:主语-谓语-宾语(subject-predicate-object),假设有N种不同的物体和K个谓语(即K个关系),那么“主谓宾”这样的组合数大概有$O(N^2K)$。有一类方法就是直接将“主谓宾”这样的关系对作为学习目标(Sadeghi and Farhadi 2011),但是在真实的世界中,物体都不是等概率出现的,有些组合在数据集中可能根本没有对应的样本。因此这类方法在较大的数据集上就会表现不佳。还有一个办法是对物体和谓语分别做检测(Lu et al. 2016),那么不论主语和宾语分别是什么,只要谓语相同,他们的关系都属于一类(e.g. truck-on-street, car-on-street)。但是,在每一类谓语关系中,各类物体的分布也是不均匀的。
  2. 另一个问题是数据集的关系标注不完整。首先,在一张图像中一般存在多个物体,然而只有部分子集进行了标注。其次,给了一对物体,他们没有被标注任何关系类别,即使是他们之间确实有视觉关系。还有一种情况是一对物体通常只被标注了一种视觉关系,然而他们通常不止只有一种关系(the co-occurrence of the predicates are very common)。一种最直接的解决办法是将未标注的视觉关系看做负样本,并且将视觉关系检测任务看做是多标签分类问题来解决。因为每对物体只都只被标注了一种关系,因此之前的很多工作也将该任务视作多类别分类,但这显然忽略了视觉关系的共存现象。

Deep Structural Ranking

本文的算法流程如上图所示,根据原文,我们分为Network ArchitectureStructural Ranking Loss两部分来介绍。首先我们先作一些必要的形式化和说明:

  • $P$表示所有被标注的物体对的集合,每对物体$(s,o) \in P$中,$s$表示主语,$o$表示宾语。$P_{(s,o)}$表示物体对$(s,o)$的所有视觉关系集合(谓语集合),那么$R={(s,p,o) \mid (s,o) \in P \bigwedge p \in P_{(s,o)}}$就表示一张图像中的所有视觉关系组合。
  • 在训练阶段,物体的位置信息(bounding box)和类别信息(label)都是已知的。在测试阶段,我们首先需要尽心物体检测来获取其位置信息以及其类别。

Network Architecture

本文的网络结果融合了视觉表征、位置特征以及语义特征,下面逐一说明。

Visual Appearance Cue

这一部分主要是指通过卷积神经网络来提取视觉特征,作者共享的代码中,采用了VGG16作为骨干网络,并使用RPN来提取与主语s和宾语o对应的bounding box的区域特征,以及主谓语联合区域的特征表示。

#file: vrd-dsr/lib/nets/Vrd_Model.py line:103-116
103    x_u = self.roi_pool(x, rel_boxes)
104    x = x_u.view(x_u.size()[0], -1)
105    x = self.fc6(x)
106    x = F.dropout(x, training=self.training)
107    x = self.fc7(x)
108    x = F.dropout(x, training=self.training)
109    x = self.fc8(x)#并集区域特征表示
110
111    if(args.use_so):
112        x_s = torch.index_select(x_so, 0, ix1)#主语特征表示
113        x_o = torch.index_select(x_so, 0, ix2)#宾语特征表示
114        x_so = torch.cat((x_s, x_o), 1)
115        x_so = self.fc_so(x_so)
116        x = torch.cat((x, x_so), 1)#三个特征串联在一起

Spatial Location Cue

接下来就是空间位置特征,由于卷积神经网络具有的一些性质,如平移不变性等,这使得其很难学到诸如上、下、左、右等一些空间位置的特征。文中介绍了两种空间位置的表示方法:首先是主语s和宾语o的相对位置特征,由一个4维的向量构成。对于主语s来说,其表示为:

\[l_x = \frac{x_s - x_o}{x_o},l_y = \frac{y_s - y_o}{y_o},l_w = \log{\frac{w_s}{w_o}},l_h = \log{\frac{h_s}{h_o}}\]

$(x,y,w,h)$就分别代表bounding box的左上角坐标以及宽和高。这一部分对应的代码是:

file: vrd-dsr/lib/data_layers/vrd_data_layer.py line:273-279
273  def _getRelativeLoc(self, aBB, bBB):
274      sx1, sy1, sx2, sy2 = aBB.astype(np.float32)
275      x1, oy1, ox2, oy2 = bBB.astype(np.float32)
276      sw, sh, ow, oh = sx2-sx1, sy2-sy1, ox2-ox1, oy2-oy1
277      xy = np.array([(sx1-ox1)/ow, (sy1-oy1)/oh, (ox1-sx1)/sw, (oy1-sy1)/sh])
278      wh = np.log(np.array([sw/ow, sh/oh, ow/sw, oh/sh]))
279      return np.hstack((xy, wh))

此外,作者还提供了另外一个选择来表示空间关系,那就是空间模板。一个物体的空间模板首先被初始化为一个与原图同样尺寸的零矩阵,然后物体所在的bounding box区域进行非零填充,最后再缩放到$32 \times 32$。主语s和谓语o的空间模板串联起来构成了第二种类型的空间位置特征。

file: vrd-dsr/lib/data_layers/vrd_data_layer.py line:261-271
261  def _getDualMask(self, ih, iw, bb):
262     rh = 32.0 / ih
263     rw = 32.0 / iw
264     x1 = max(0, int(math.floor(bb[0] * rw)))
265     x2 = min(32, int(math.ceil(bb[2] * rw)))
266     y1 = max(0, int(math.floor(bb[1] * rh)))
267     y2 = min(32, int(math.ceil(bb[3] * rh)))
268     mask = np.zeros((32, 32))
269     mask[y1 : y2, x1 : x2] = 1
270     assert(mask.sum() == (y2 - y1) * (x2 - x1))
271     return mask

Semantic Embedding Cue

然后是语义表示特征,很多情况下,一个谓语可以表示多个主宾之间的关系(e.g. car-near-street, person-near-building),但是这种视觉关系之间的联系可能很难从视觉特征中学习到,特别是在样本不均衡的情况下,所以这里又引入了语义表示特征。具体地,本文通过word-to-vector的方法分别将主语s和谓语o的物体类别表示为一个向量,然后将两个向量连接在一起,经过一层全连接,再与之前的视觉特征混合。表示该部分的具体代码如下:

#file: vrd-dsr/lib/nets/Vrd_Model.py line:127-134
127  if(args.use_obj):
128      emb = self.emb(classes)
129      emb = torch.squeeze(emb, 1)
130      emb_s = torch.index_select(emb, 0, ix1)
131      emb_o = torch.index_select(emb, 0, ix2)
132      emb_so = torch.cat((emb_s, emb_o), 1)
133      emb_so = self.fc_so_emb(emb_so)
134      x = torch.cat((x, emb_so), 1)

Structural Ranking Loss

前文中已经提到,很多物体间不止有一种关系(比如,people-above-bike, people-on-bike),所以本文中采用了多标签损失函数,代码中使用的是MultiLabelMarginLoss,公式如下:

\[loss(x,y) = \sum_{x,y}{\frac{max(0,1-(x[y[j]]-x[i]))}{x.size(0)}}\]

这里的$x,y$都是二维的Tensor,对于一个样本,$x$表示的网络输出的各个类别的score,$y$表示的是该样本所属类别的向量。该loss的目标就是使$x$中正确类别($y[j]$)对应的score要大于非正确类别对应的score($y[j] \neq i$)。

在论文中,作者列举了一种该任务中可能出现的情况,那就是检测出来的关系谓语$r^{‘} \in R^{‘}$,但是这个关系谓语并没有出现在标注中$(R^{‘} = {(s^{‘},p^{‘},o^{‘}) \mid (s^{‘},o^{‘}) \in P \bigwedge p^{‘} \notin P_{s^{‘},o^{‘}}})$。如果这个检测结果本应该是正确的,比如该关系组合出现在了其他图像中,但由于不是显著性关系,所以并没有在当前数据中进行标注。作者将该种情况下的损失形式化为:

\[loss(x) = \sum_{r \in R, r^{'} \in R^{''}}{[\Delta(r, r^{'})+\Phi(x,r^{'})-\Phi(x,r)]_{+}}\]

去掉$\Delta(r, r^{‘})$不看,剩下的部分和上述的MultiLabelMarginLoss的表示应该是一致的。但是在这种因为不完备标注产生的误差是我们不希望的,这种偏差会导致$(\Phi(x,r^{‘})-\Phi(x,r))$这一项的margin变小,这也会势必会影响到整个算法的优化。因此,本文引入了$\Delta(r, r^{‘})$:

\[\Delta(r, r^{'})=\Delta(\{s,p,o\},\{s^{'},p^{'},o^{'}\}) \\ =1+P(p|c_s,c_o)-P(p^{'}|c_{s^{'}},c_{o^{'}}) \\ =1-(P(p^{'}|c_{s^{'}},c_{o^{'}})-P(p|c_s,c_o))\]

$P(p \mid c_s,c_o)$表示的是数据集上统计的有标注的类别p的先验概率,$P(p^{‘} \mid c_{s^{‘}},c_{o^{‘}})$则是标注了关系对中对应的物体,却没有标注其关系的的概率。当后一项的概率比较大时,说明检测到的视觉关系更有可能是一个被漏掉的标注,两概率的差值因此也会对上面提到的减小的margin做出一些补偿。从而使整个训练过程得到优化。

file: vrd-dsr/tools/train.py line: 82
82  args.criterion = nn.MultiLabelMarginLoss().cuda()
file: vrd-dsr/lib/model.py line: 29
29  loss = args.criterion((rel_so_prior+rel_score).view(1, -1), target)

Experiments

作者已经在论文里对实验进行了详尽的说明,这里不多做赘述,只分享一点:Recall@50Recall@100。这两个指标最早应该是在(Lu et al. 2016)1中提到的,起初看时没有认真地思考,想当然地认为:

[✖]对于一个样本(s,p,o),我们需要对这个组合进行分类,如果一共有K种谓语关系,那么网络输出的结果应该是一个K维的向量,处理成softmax概率分布,取概率最大的前z个,如果这z个里有其对应的真实类别,则我们就认为预测正确。然而这样理解是不正确的。因为,拿这个vrd这个数据集来说,一共只有70个类别,显然Recall@100就没法解释。

后来欧同学在邮件中和我讨论另一篇文章时指出了这个问题,我对比这篇论文与代码,认识到了之前理解的错误,这个问题正确的理解应该是这样的:

[✔]对于一张图像,存在N个物体,那么一共可以组成$N \cdot (N-1)$个关系对,再算上一共有K种关系,那么可能的组合一共是$K \cdot N \cdot (N-1)$,将这些组合的结果按照confidence进行排序。分别统计前50和100个预测中的True Positive与50和100做比值就得到了Recall@50和Recall@100。

如果大家有任何问题,欢迎来信交流(wenyuanxue@bjtu.edu.cn)

  1. C. Lu, R. Krishna, M. Bernstein, and L. Fei-Fei. Visual relationship detection with language priors. In Proc. Eur. Conf. Comp. Vis., pages 852–869. Springer, 2016.