前一篇文章整理了多模态融合Multimodal Fusion,最近看到一篇很好的跨模态检索的文章,这篇博客就来整理几篇博主认为idea还不错的跨模态检索。另,如果有其他idea很好的跨模态论文,希望你在文章后面留言!
Cross-modal Retrieval
其实图像/视频检索都可以按上面这张图做细分等等,早期一般会使用一些手工特征进行检索,但慢慢已经被深度学习方法统治,开始偏向度量学习,如上图里面的CNN,AE,GAN,attNet,RL等等,实际上涉及到很多具体任务又有很多的trick。一般一个跨模态检索过程可以既包括模态表征,模态转换,模态对齐和联合学习(唯独没有模态融合,基本上不需要融合)。废话不多说,直接开始整理一下重要的,和有意思的文章吧。
Adversarial Cross-Modal Retrieval
这篇似乎是MM2017最佳学生论文(而且是本科生)。出发点是为了把不同模型映射到一个跨模态的子空间,所以引入GAN的对抗思想,主体是让图片和文本相互对抗以达到混淆的目的,那么此时的跨模态空间就是很好的空间了,这篇文章的对抗思路也被之后的很多工作所沿用。
- 首先做文本和图像各自的特征映射
- 映射完之后的特征对抗,有监督地最大化不同模态之间语义关联和特征分布一致性,以达到混淆的目的。
- 对抗模式上主要有三种:
Modality-invariant,特征映射器。Label prediction的目的在于使映射出的不同语义(Semantic)的子空间特征可以彼此区分。
Cross-Modal similarity,特征映射器,三元组正例负例空间映射,最大化同模态不同语义item的差距同时,还需要使得跨模态相同语义的差距尽可能小。
Semantically-discriminative,模态分类器。标签lable的分类(是文本还是视频),如果分类器分辨不请,说明特征空间学习得很好了。
这篇比较经典的论文,直接看一下作者的实现代码:
class AdvCrossModalSimple(BaseModel):
def __init__(self, model_params):
BaseModel.__init__(self, model_params)
self.data_iter = DataIter(self.model_params.batch_size)
#Triple版本会有正例和负例
self.tar_img = tf.placeholder(tf.float32, [None, self.model_params.visual_feat_dim])
self.tar_txt = tf.placeholder(tf.float32, [None, self.model_params.word_vec_dim])
self.pos_img = tf.placeholder(tf.float32, [None, self.model_params.visual_feat_dim])
self.neg_img = tf.placeholder(tf.float32, [None, self.model_params.visual_feat_dim])
self.pos_txt = tf.placeholder(tf.float32, [None, self.model_params.word_vec_dim])
self.neg_txt = tf.placeholder(tf.float32, [None, self.model_params.word_vec_dim])
self.y = tf.placeholder(tf.int32, [self.model_params.batch_size,10])
self.y_single = tf.placeholder(tf.int32, [self.model_params.batch_size,1])
self.l = tf.placeholder(tf.float32, [])
self.emb_v = self.visual_feature_embed(self.tar_img) #语义嵌入维度
self.emb_w = self.label_embed(self.tar_txt)
self.emb_v_pos = self.visual_feature_embed(self.pos_img,reuse=True)
self.emb_v_neg = self.visual_feature_embed(self.neg_img,reuse=True)
self.emb_w_pos = self.label_embed(self.pos_txt,reuse=True)
self.emb_w_neg = self.label_embed(self.neg_txt,reuse=True)
# 按照论文一共会计算2种loss,emb和adv loss,其中emb由两部分组成。以下一一注释。
# triplet loss形式的emb loss
margin = self.model_params.margin
alpha = self.model_params.alpha
v_loss_pos = tf.reduce_sum(tf.nn.l2_loss(self.emb_v-self.emb_w_pos))
v_loss_neg = tf.reduce_sum(tf.nn.l2_loss(self.emb_v-self.emb_w_neg))
w_loss_pos = tf.reduce_sum(tf.nn.l2_loss(self.emb_w-self.emb_v_pos))
w_loss_neg = tf.reduce_sum(tf.nn.l2_loss(self.emb_w-self.emb_v_neg))
self.triplet_loss = tf.maximum(0.,margin+alpha*v_loss_pos-v_loss_neg) + tf.maximum(0.,margin+alpha*w_loss_pos-w_loss_neg)
# lable loss是多分类交叉熵损失
logits_v = self.label_classifier(self.emb_v)
logits_w = self.label_classifier(self.emb_w, reuse=True)
self.label_loss = tf.nn.softmax_cross_entropy_with_logits(labels=self.y, logits=logits_v) + \
tf.nn.softmax_cross_entropy_with_logits(labels=self.y, logits=logits_w)
self.label_loss = tf.reduce_mean(self.label_loss)
self.emb_loss = 100*self.label_loss + self.triplet_loss # emb loss由以上2种得到
# 模态分类对应论文的adv loss,使模型无法分清文本or图像
self.emb_v_class = self.domain_classifier(self.emb_v, self.l)#先预测lable
self.emb_w_class = self.domain_classifier(self.emb_w, self.l, reuse=True)
all_emb_v = tf.concat([tf.ones([self.model_params.batch_size, 1]),
tf.zeros([self.model_params.batch_size, 1])], 1)#拼接lable方便一起计算
all_emb_w = tf.concat([tf.zeros([self.model_params.batch_size, 1]),
tf.ones([self.model_params.batch_size, 1])], 1)
self.domain_class_loss = tf.nn.softmax_cross_entropy_with_logits(logits=self.emb_v_class, labels=all_emb_w) + \
tf.nn.softmax_cross_entropy_with_logits(logits=self.emb_w_class, labels=all_emb_v)
self.domain_class_loss = tf.reduce_mean(self.domain_class_loss)#得到adv loss
self.t_vars = tf.trainable_variables()#因为adv和emb的计算方向不一样,所以需要分别优化
self.vf_vars = [v for v in self.t_vars if 'vf_' in v.name] #vf和le是训练emb的,对应投影器
self.le_vars = [v for v in self.t_vars if 'le_' in v.name]
self.dc_vars = [v for v in self.t_vars if 'dc_' in v.name] #dc和lc是训练adv的,对应分类器
self.lc_vars = [v for v in self.t_vars if 'lc_' in v.name]
def visual_feature_embed(self, X, is_training=True, reuse=False):#即论文中的视觉特征投影器
with slim.arg_scope([slim.fully_connected], activation_fn=None, reuse=reuse):
net = tf.nn.tanh(slim.fully_connected(X, 512, scope='vf_fc_0'))
net = tf.nn.tanh(slim.fully_connected(net, 100, scope='vf_fc_1'))
net = tf.nn.tanh(slim.fully_connected(net, self.model_params.semantic_emb_dim, scope='vf_fc_2'))
return net
def label_embed(self, L, is_training=True, reuse=False):#即论文中的文本特征投影器
with slim.arg_scope([slim.fully_connected], activation_fn=None, reuse=reuse):
net = tf.nn.tanh(slim.fully_connected(L, self.model_params.semantic_emb_dim, scope='le_fc_0'))
net = tf.nn.tanh(slim.fully_connected(net, 100, scope='le_fc_1'))
net = tf.nn.tanh(slim.fully_connected(net, self.model_params.semantic_emb_dim, scope='le_fc_2'))
return net
def label_classifier(self, X, reuse=False):#标签预测
with slim.arg_scope([slim.fully_connected], activation_fn=None, reuse=reuse):
net = slim.fully_connected(X, 10, scope='lc_fc_0')
return net
def domain_classifier(self, E, l, is_training=True, reuse=False):#二分类是文本/图像
with slim.arg_scope([slim.fully_connected], activation_fn=None, reuse=reuse):
E = flip_gradient(E, l)
net = slim.fully_connected(E, self.model_params.semantic_emb_dim/2, scope='dc_fc_0')
net = slim.fully_connected(net, self.model_params.semantic_emb_dim/4, scope='dc_fc_1')
net = slim.fully_connected(net, 2, scope='dc_fc_2')
return net
完整代码的中文注释在:https://github.com/nakaizura/Source-Code-Notebook/tree/master/ACMR
其实这篇文章借鉴领域自适应挺多的,但是确实跨模态的东西与领域自适应是很像的,都是解决不同域分布的特征表示问题,有兴趣可以看下Domain Adaptation(领域自适应,MMD,DANN)。
Look, Imagine and Match: Improving Textual-Visual Cross-Modal Retrieval with Generative Models
CVPR2018,这篇是我个人很喜欢的一篇文章。也是利用Generative Models的思想,但是其本质是rank loss+双向的autoencoder(这可以学习到更好的公共特征)。具体如上图模型结构,这个图虽然一开始看不知道画的什么…但是很厉害,把RL和GAN结合在了同一个框架中。
重点:
-
1 multi-modal feature embedding。每个模态的特征抽取都会得到两个特征。图像是CNN不同层的特征(如图像左上的蓝色部分CNN由 v h , v l v_h,v_l vh,vl组成,这两个特征从 ImageNet不同层抽取),文本是双向rnn(如右上角的小绿部分由 R N N E N C h , R N N E N C l RNN^h_{ENC},RNN^l_{ENC} RNNENCh,RNNENCl组成,是双向的RNN两个特征)。即图像和文本都抽取高级和低级的特征high-level abstract features and detailed grounded features,然后给图像和文本的特征算一个约束loss(正上方的 L R + L_R+ LR+)。
-
2 image-to-text。模型图的上半部分是Encoder,下半部分就是Decoder。首先从图片到句子的解码,使用RL,即从左上到右下的蓝色线, R N N D e c RNN_{Dec} RNNDec是用RL的方式从图像得到句子。与真实的句子计算loss L X E + R L L_{XE+RL} LXE+RL。其中这个XE是word-level cost。根据RNN的decoder来predict word,使概率尽可能大。而RL是sentence-level cost。将decoder出来的句子与原句子通过metric(BLEU or CIDEr)计算score,根据score给reward。
-
3 text-to-image。再从句子到图像的重建使用GAN,即从右上到左下的绿色线,使用GAN重构图像。与真实的图像计算loss D D D。使用KL divergence衡量距离。
code:https://github.com/ujiuxiang/NLP_Practice.PyTorch/tree/master/cross_modal_retrieval
Self-Supervised Adversarial Hashing Networks for Cross-Modal Retrieval
CVPR2018,用于跨模态检索的自监督对抗哈希网络。这篇文章的亮点就是自监督+哈希。
- 哈希:适用于低存储消耗和快速响应查询,哈希算法可以通过给相似的跨模态内容赋予相似的哈希码的方式,将高维的多模态数据映射到一个公共的哈希码空间。
具体来说,模型如上图,有三个部分,一个自监督语义生成网络(LabNet)和两个分别用于图像和文本的对抗网络(ImgNet 和 TexNet)。然后使用两个对抗网络来联合学习高维特征和它们在不同模态下的对应哈希编码(有监督地最大化不同模态之间语义关联和特征分布一致性)。其中,这个自监督语义生成网络(LabNet)是用来来发现多标签标注中的语义信息,然后监督两个模态的语义空间。
paper:https://arxiv.org/abs/1804.01223
Modal-adversarial Semantic Learning Network for Extendable Cross-modal Retrieval
ICMR2018。从图可以看到,先文本和图像各自得到特征后,分类标签得到对抗损失+自监督语义学习(跨模态重建)。
- 首先网络的input是成对的Image-Text。
- 隐藏层的Code Layer用于关联两个网络的分支,挖掘不同模态间的关系(模态对之间的差异应该更小),此时计算相似度(Similarity loss): f c o r r ( v i , t i ) = ∥ f v ( v i ; Θ r ) − f t ( t i ; Θ r ) ∥ 2 2 f_{corr}(v_i,t_i)=\left \| f_v(v_i;\Theta_r)-f_t(t_i;\Theta_r) \right \|_2^2 fcorr(vi,ti)=∥fv(vi;Θr)−ft(ti;Θr)∥22
- 然后可以看到下面的黑色Class Embedding,它会对输入对的类别信息进行编码,再与Code Layer的特征进行concat。目的是使用Class Embedding作为高维的语义特征,对生成的低维的特征进行约束,使低维特征能够保留高维的语义特征。
- 两种解码器,图片特征to文本,文本特征to图片。值得注意的是,如模型图最右边,每个解码器都有两个输入,即: L I ( v i , t i ; Θ r ) = ∥ v i − v ^ i I ∥ 2 2 + ∥ t i − t ^ i I ∥ 2 2 , L T ( v i , t i ; Θ r ) = ∥ v i − v ^ i T ∥ 2 2 + ∥ t i − t ^ i T ∥ 2 2 L_I(v_i,t_i;\Theta_r)=\left \| v_i-\hat{v}_i^I \right \|_2^2+\left \| t_i-\hat{t}_i^I \right \|_2^2,\\L_T(v_i,t_i;\Theta_r)=\left \| v_i-\hat{v}_i^T \right \|_2^2+\left \| t_i-\hat{t}_i^T \right \|_2^2 LI(vi,ti;Θr)=∥∥vi−v^iI∥∥22+∥∥ti−t^iI∥∥22,LT(vi,ti;Θr)=∥∥vi−v^iT∥∥22+∥∥ti−t^iT∥∥22两个解码器都会同时重建两种特征(code layer已经将两种模态的语义拉近了,所以可以同时重建两种特征)
- 最后还是一个模态对抗的部分,去区别特征是哪一种模态的,从而进一步减少模态间的差异。
Embedding Network
TPAMI2018,这篇文章的思路没有很新奇,只是是很典型的两种方法:嵌入之后求距离(Embedding Network)和模态之间匹配的概率(Similarity Network)。
- Embedding Network。嵌入之后的X,Y,直接算三元组对
- Similarity Network。在共享子空间之后,将两个向量做点乘算相似度,再FC算交叉熵损失函数
code:https://github.com/lwwang/Two_branch_network
Deep Supervised Cross-modal Retrieval
CVPR2019。这篇论文的目的是找到一个关于模态的共同表示空间,以便可以直接比较来自不同模态。即减少标签空间和公共表示空间的识别损失,并利用权值共享策略消除多媒体数据在公共表示空间中的交叉模态差异,学习模态不变特征。
- 首先仍然是两个网络,一个ImageNet(fc7)用于图像模态u,另一个TextCNN用于文本模态v。
- 然后,一些FC做特征抽象,同时强制这两个子网络共享其最后一层的权值,以映射到一个公共表示空间。 J 3 = 1 n ∣ ∣ U − V ∣ ∣ J_3=\frac{1}{n}||U-V|| J3=n1∣∣U−V∣∣
- 最后,利用参数为P的线性分类器预测每个样本的类别。 J 1 = 1 n ∣ ∣ P T U − Y ∣ ∣ + 1 n ∣ ∣ P T V − Y ∣ ∣ J_1=\frac{1}{n}||P^TU-Y||+\frac{1}{n}||P^TV-Y|| J1=n1∣∣PTU−Y∣∣+n1∣∣PTV−Y∣∣
- 此外,还有一个 J 2 J_2 J2,会计算在公共表示空间中所有样本的识别损失,即图像和文本的相似性,图像和图像、文本和文本的相似性。
- 最后的损失函数是三者之和: J = J 1 + λ J 2 + η J 3 J=J_1+\lambda J_2+ \eta J_3 J=J1+λJ2+ηJ3
Video-Based Cross-Modal Recipe Retrieval
MM2019,使用Attention做跨模态检索的文章也有不少,调了这一篇放到博客上,主要是因为这份工作有两个Attention,一个Parallel Attention和Co-Attention。
- 视频C3D抽特征,文本Bi-GRU抽特征。
- Parallel Attention的部分是视频片段和文本片段利用标题和配料(这篇文章是菜谱检索)算注意力,找出更重要的视频帧和文本词。
- Co-Attention的部分是视频和文本算Cross-Attention,找出相互对应的相关性部分。
- 最后融合特征,rank loss。
code:https://acmmm2019.wixsite.com/pcan
A Proposal-based Approach for Activity Image-to-Video Retrieval
AAAI2020,基于图像查询的视频检索,主要的不同是将基于图的多示例学习模块(Graph Multi-Instance Learning)整合到跨模态检索框架中,用以解决检索过程中视频信息包中存在的信息冗余问题。
- 首先还是模态提取器,一个VGG一个R-C3D(因为是视频,用视频理解的方法),然后特征投影得到特征。
- 基于图的多示例模块(GMIL)。R-C3D模型使视频中尽可能包含所有可能的活动信息,但是视频的表达不可避免地存在与活动信息无关的冗余信息,所以将此问题转换为多示例学习问题,即每一个视频都被视为一个示例包( activity proposals,应该是一个视频中存在多个可能的动作,每个有关动作的视频边界对会生成,这一些的候选变成一个video bag同时被处理),而每个视频包中的活动信息被视为一个示例,然后1 基于自我注意机制,通过挑选出显著性示例来更好表达整体的信息。2 图卷积结构结合到多示例框架中,可以进一步优化每个包中的图结构信息。这里会计算所有视频片段之间的相似度…按相似度构图,然后GCN。
- 损失函数由三个部分组成。分别是基于几何投影(Geometry-aware)的三元组损失函数。语义分类损失函数。对抗损失函数。这和MM17的loss设计类似。
paper:https://arxiv.org/pdf/1911.10531.pdf
code:https://github.com/bcmi/Cross-modal-retrieval
[CVPR2020] Fine-grained Video-Text Retrieval with Hierarchical Graph Reasoning
沿着上一篇文章,继续细化所有细节。作者认为现有嵌入到同一空间的技术无法体现细节,如scenes, objects, actions或者其他组件,所以文章细化了这些组件。主要是将文本分解为包含三个层次的事件、动作、实体的层次语义图,并通过基于注意的图推理生成层次文本嵌入,最后与视频的这三个层次做match。
- code:https://github.com/cshizhe/hgr_v2t
[NIPS2020] COOT: Cooperative Hierarchical Transformer for Video-Text Representation Learning
博主又来补文了,来自NIPS做video-text检索的任务,基于Transformer的重结构。其他大部分基于BERT结构的文章博主在另一篇文章归纳了 传送门,这篇不是基于BERT范式只是Transformer所以放到这里。整体架构如上图,仍然是两路分支,其中每路都会做:
- 每个时刻的word/frame都进入T-Transformer学时序性,细节如最右的Temporal Transformer
- 然后出来了再用Attention聚合这些clip/sentence的local feature
- 另有一个小分支通过学Global的也用Transformer(其中KV是local来的,图中上下灰色阴影部分)
- 最后再用context Transformer来进一步聚合,align不同模态
虽然模型复杂比较重,但也确实是从各个层级学习了表示,frames/words, clip/sentences,videos/paragraphs等等,提供了很多丰富的实验。
- code:https://github.com/gingsi/coot-videotext
[CVPR2021] HiT: Hierarchical Transformer with Momentum Contrast for Video-Text Retrieval
继续补文,最近较火的对比学习终于也开始在各个领域泛用了,这篇文章就是结合Transformer-based和MoCo到视频检索的文章,motivation来自两点:
- 1)不同层具有不同特征语义。即Feature-level和Semantic-level两个,底层特征倾向于用基本的语法表示来编码更多的本地内容,而高级特征能捕获更复杂的语义,通常能产生更高级的语义表示,所以做Hierarchical Transformer 是很合理的。
- 2)端到端训练机制限制了小批量样本之间的负样本作用。大规模负例是能够提供优质性能的咯,所以用MoCo优化是不错的思路。
所以模型架构如上图,Video和Text Encoder都是Transformer,而low-level和high-level则是一前一后。然后拿到这些特征了做两个层面的对比学习,其中会对Video和Text都用memory back的形式来更新(这里和MoCo区别只在于会有不同模态的交互),最后在Feature和Semantic两个层面上计算matching loss来更新就好。
Progressive Semantic Matching for Video-Text Retrieval
继续补补文,今天是ACM MM21的文章。关键点是渐进语义匹配从粗到细的渐进学习过程来缩小语义差距而不是直接学对齐空间,两者的对比如上图a和b。
- (a)传统的策略直接缩小了一个公共空间中的语义差异。
- (b)所提出的PSM(Progressive Semantic Matching)方法逐步减少了语义差距的水平。其中每个级别的目标都是将相关对拉得更近,并将无关对推得更远。
具体地说,作者构造了一些辅助公共空间,并在每个辅助空间中添加一个边际损失以强制每个层次对多层次模型中的下一个编码器的鉴别特征进行编码,从而使融合公共空间更加有效。而在测试阶段,只利用融合公共空间进行推理即可。详细的模型图如下图:
从上到下来看,输入是视频和句子。然后设计了三个层次的辅助空间和一个融合空间来匹配视频和文本。其中可以看到三个层次分别用了CNN模块、biGRU和Conv 1D对视频进行编码,而且分别使用注意力、均值和最大池化方法将其聚合为𝑓𝑣1、𝑓𝑣2和𝑓𝑣3。然后使用全连接的层将输出映射到三个嵌入:𝑎𝑢𝑥𝑣1、𝑎𝑢𝑥𝑣2和𝑎𝑢𝑥𝑣3。融合三者的最下面的嵌入𝑓𝑣也是用全连接层进行映射。同样文本也被编码到四个空间中,并与视频进行联合训练。然后每层的计算都用triplet来区分正负例。
总结:
因为跨模态信息往往具有低特征异构,高语义相关,所以感觉上通用的方法差不多是
- 语义嵌入
- 特征约束
- 哈希变换
- 模态相互重构
- 注意力对齐
- 模态对抗
- trick:加标签信息,加残差,构图,多通道多视图信息补充
未来?
- 模态预训练,利用BERT,这个博主也已经整理过了,传送门。
- 更好的模态表示,如何更好的表达模态的共性和特性?
- 除了语义,模态是否也存在共现性?局部结构等。
- 继续加辅助信息,如KG。