Advertisement

Improved Fusion of Visual and Language Representations by Dense Symmetric Co-Attention阅读笔记

阅读量:

本文提出了一个简单的架构,在视觉和语言表示之间完全对称,其中每个问题词关注图像区域,而每个图像区域关注问题词。它可以被堆叠成一个层次结构,用于在一对图像-问题之间进行多步骤交互。
一、文章引入
自VQA (visual question answer)引入以来,在很短的一段时间内,它的研究取得了显著的进展,显示出对普通基准测试数据集性能的快速提升。这一进展主要来自于两方面的研究:更好的注意力机制的发展和从输入图像中提取的特征与问题融合的改进。
我们观察到,到目前为止,这两项研究都是独立进行的。 对于特征融合方法的研究尤其如此,即使使用特征融合方法可以实现最佳性能,也将注意力视为可选项。 但是,本文中作者认为它们是针对同一目标的两种不同方法。 特别是,作者认为更好的注意力机制会导致图像问题对的更好融合表示。
基于此,本文提出了一种新的共同注意机制来改进视觉和语言表示的融合。给定图像和问题的表示形式,它首先针对每个问题词在图像区域上生成一个注意力映射,并针对每个图像区域在问题词上生成一个注意力映射。然后,它执行参与特征的计算,连接多模态表示,并通过一个带有ReLU的单层网络和一个残差连接进行转换。这些计算被封装到一个复合网络中,称之为密集共同注意层,因为它考虑任何图像区域和任何问题词之间的每一次交互。该层在两种模式之间具有完全对称的架构,并且可以堆叠成一个层次结构,使图像-问题对之间能够进行多步交互。
从输入图像和问题的初始表示开始,层堆栈中的每个密集的共同注意层都会更新表示,然后将其输入到下一层,然后将其最终输出馈送到用于答案预测的层。在初始特征提取和答案预测层中使用了额外的注意机制。我们将包括所有这些组件的整个网络称为密集共同注意网络(DCN)。
二、框架介绍
在本节中,我们将描述DCN的体系结构, 概述见图1。 它由一叠密集的共同注意层组成,这些共同注意层反复地融合了语言和视觉特征,在其顶层有一个答案预测层,可以在多标签分类器中预测答案。 我们首先说明从输入的问题和图像中提取初始特征(第2.1节),然后描述密集的共同注意层(第2.2节)和答案预测层(第2.3节)。

在这里插入图片描述

图1:密集共同关注网络(DCN)的整体结构。
2.1. Feature Extraction(特征提取)
本文采用了先前研究中常用的预训练网络以从图像,问题和答案中编码或提取特征,例如预训练的ResNet 。
2.1.1 Question and Answer Representation
使用双向LSTM编码问题和答案。 具体来说,首先将由N个单词组成的问题转换为GloVe向量的序列{eQ1,…,eQN},然后将其输入到一层具有残差连接的双向LSTM(Bi-LSTM)中 :

在这里插入图片描述

然后我们创建一个矩阵Q = [q1,…,qN)∈Rd×N ,其中

在这里插入图片描述

。我们还将使用

在这里插入图片描述

通过整合两条路径末端的状态信息, 构建输入图像的表征. 随机初始化双向长短时记忆网络(Bi-LSTM). 采用相似策略对答案进行编码. 将包含M个单词的答案转换为向量形式{eA1,…, eAM}, 然后将其输入至同一个Bi-LSTM模型中计算最终状态向量.

在这里插入图片描述

。使用sA=

在这里插入图片描述

来表示答案。
2.1.2 Image Representation
像之前的许多研究一样,作者使用一个预先训练好的CNN(即在ImageNet上预先训练的具有152层的ResNet)来提取多个图像区域的视觉特征,但本文的提取方法略有不同。本文从四个卷积层中提取特征,然后在这些层上使用问题引导注意力来融合它们的特征。这样做是为了开发后续密集的共同注意层的最大潜力。作者推测,视觉表示层次中不同层次的特征对于正确回答各种各样的问题是必要的。
具体来说,我们在最后四个池化层之前从四个卷积层 (ReLU之后)提取输出。它们是大小不同的张量,通过应用不同池化大小的最大池,并对进行一对一卷积,将其转换为相同大小的张量(d×14×14)。同时对每个张量的深度维数应用l2归一化,将正则化张量重塑成四个d×T矩阵,其中T = 14×14。
接下来,从sQ(上面定义的整个问题的表示)创建对这四个层的关注。 使用具有724个隐藏单元的ReLU非线性双层神经网络将sQ投影为四层的得分:

在这里插入图片描述

随后对输入进行Softmax归一化处理后得到四个注意力权重α₁至α₄;将这四个加权后的矩阵相加汇总得到一个d×T维矩阵V=[v₁,…,v_T];其中每个v_t向量对应于输入图像的一个特定区域t所提取的特征信息

密集共同注意层结构如图2所示;它接收问题表示Q=[q₁,…,q_N]∈R{d×N}和图像表示V=[v₁,…,v_T]∈R{d×T}作为输入;其中Q_l和V_l分别代表第(l+1)层的状态向量;特别地当l=0时有Q₀=Q和V₀=V

密集共同注意层结构如图2所示;它接收问题表示Q=[q₁,…,q_N]∈R{d×N}和图像表示V=[v₁,…,v_T]∈R{d×T}作为输入;其中第l层的状态向量分别为Q_l=[q_{l1},…,q_{lN}]∈R{d×N}和V_l=[v_{l1},…,v_{lT}]∈R{d×T};特别地当l=0时有Q₀=Q和V₀=V

在这里插入图片描述

图形2展示了层级索引为l加一的单个密集共同注意层的内部结构。本文所提出的体系架构具有以下几个显著特征:其核心基础是共享注意力机制,并且这种机制具有密集型特点。具体而言,在模型构建过程中会分别对应于每个词和每个区域生成各自的注意力关系可视化表示(见图形3)。此外,在实际应用中可以通过引用文献[1]的方式实现模块化扩展构造过程。

在这里插入图片描述

如图3所示:基于视觉表征与问题描述生成密集型注意力掩码。

在这里插入图片描述

其中Wl是一个可学习的权重矩阵。通过对Al执行按行归一化操作,在每个图像区域中确定问题相关的关注点并生成注意力映射图

在这里插入图片描述

将数据按照列进行归一化处理,并得到问题词位置在图像中的特定区域对应的注意力分布图

在这里插入图片描述

注意,AQl和AVl的每一行都包含一个注意力映射。
Nowhere-to-attend and memory 在创建和应用每个注意图时,经常会出现没有需要模型注意的特定区域或单词的情况。为了处理这种情况,向N个问题词和T个图像区域添加K个元素。在先前的研究中,作者只使用K = 1,但是我们发现使用K > 1是有效的,它被期望作为额外的的存储器存储有用信息。具体来说,合并两个矩阵

在这里插入图片描述

在这里插入图片描述

,这是可学习的参数。在行方向上将矩阵Ql和Vl扩充为

在这里插入图片描述

在这里插入图片描述

这种扩展带来了大小为(T+K)\times(N+K)的空间Al。 AQ_lAV_l分别为(T+K)\times(N+K)型与(N+K)\times(T+K)型矩阵。
在先前的研究中, 提出了多种注意力机制, 并将其并行地作用于目标特征上, 从而生成多个关注特性, 最后通过串联将它们融合在一起。
在论文《Attention is all you need》中, 特征被线性变换到多个较低维空间中, 然后针对每个低维空间执行上述关注操作。
本文采用了类似的方法, 其主要区别在于使用多头注意力机制而非简单的串联方式来融合参与特征。
具体而言, 将\widetilde{V}_l\widetilde{Q}_l的d维特征(存放在列向量中)分别通过线性变换投影到h个较低维空间中, 每个变换后的子空间具有d_h\equiv d/h维度。

在这里插入图片描述

(i = 1,…,h)表示线性投影。 然后,第i个空间中的投影特征之间的亲和度矩阵为

在这里插入图片描述

通过按列和按行归一化从每个亲和矩阵创建注意力图

在这里插入图片描述

基于应用乘法(或乘积)注意力机制,在计算多个注意力特征的均值时,其效果等同于对注意力图求取其均值计算。

在这里插入图片描述

特征表示的注意机制如图3所示,在计算过程中通过计算注意力加权积的方式获得问题与图像相关的特征表示ˆQl和ˆVl。其中AQl和AVl分别存储了注意力图在其各自的后K行位置上编码了与"nowhere-to-attend"相关的记忆信息。因此当这些权重矩阵作用于˜Ql和˜Vl时会按照预设的方式对其进行过滤处理

在这里插入图片描述

在计算得到注意力特征表示ˆQl和ˆVl后,在图2右侧部分展示了它们的应用场景。其中,在矩阵中每一列都记录了由第n个问题词引导的整体图像注意力表示。随后将第n列向量ˆvln与对应的第n个问题词向量qln进行级联连接(即端到端连接),生成二维向量[qTln, ˆvTln]^T。该连接后的二维向量经过一层全连接层后还原至d维空间,并通过ReLU激活函数完成后续操作

在这里插入图片描述

其中 W_{Q,l} \in \mathbb{R}^{d \times 2d}b_{Q,l} \in \mathbb{R}^d 是可学习的权重参数与偏差参数。对于每个问题词 n \in \{1,\dots,N\} ,使用同一个网络架构(其权重参数与偏差参数保持一致)进行独立处理后得到结果向量 Q_{l+1} = [q_{l+1, 1},\dots,q_{l+1, N}]^\top \in \mathbb{R}^{d \times N}。类似地,在第 t 个图像区域中,其表示向量 v_t^l 被与其所引导的问题词组的整体表示 \hat{q}_{t l} 进行融合处理,并随后将其融合结果投影至 d 维潜在空间中。

在这里插入图片描述

其中权重参数WVl属于 Rd×2d 空间空间而偏置参数bVl属于 Rd 空间空间。采用同一类型的网络架构依次应用于每一个图像区域(t取值为1到T)最终生成扩展后的表示向量 Vl+1 = [v(l+1)_1,…,v(l+1)_T] ∈ Rd×T空间空间。
对于每一层l而言这两个全连接子网络拥有独立的参数集合包括WQl 和 WVl等空间空间。
基于最后一个密集型共同注意力机制处理后的输出向量QL与VL我们可以执行以下操作:首先对这些向量分别进行自注意力计算以获取问题与图像的整体表征;接着对QL向量进行操作:i)通过在隐藏层中应用具有ReLU激活函数的两层MLP来计算各个问题词对应的得分;ii)随后应用softmax函数获得注意力权重;iii)最后通过加权求和的方式得到综合表征。

在这里插入图片描述

在信息提取过程中,我们采用了一种基于多层感知机(MLP)的聚合表示方法。具体而言,在不同权重设置下运行相同的模型结构,并得到注意力权重参数组αV₁至αV_T。随后利用对应的特征向量v_L₁至v_L_T生成综合表现向量sVL。通过结合sQL与sVL这两个指标,则可以用来预测问题的答案。本文在此基础上探讨三种实现策略:第一种策略是直接对两个指标进行算术求和运算;第二种则采用内积形式评估它们之间的关联性;第三种则引入其他非线性变换进一步优化结果。

在这里插入图片描述

基于σ是对数函数且W为可学习的权重矩阵这一逻辑下,在现有研究中广泛使用的机器学习模型(MLP)被用来计算一组预定义答案的分数;这些方法通过MLP模型计算一组预定义答案的分数;它们在整合sQL与sVL的方式上有差异;例如,在具体实现时通常采用求和方式。

在这里插入图片描述

或串联

在这里插入图片描述

三、实验结果

在这里插入图片描述

基于开放式的任务验证基准库VQA 2.0对DCNs的各个模块进行了消融实验分析,并通过符号*标识最终模型所采用的各模块

在这里插入图片描述

在类似条件下,在本文中提出的方法与现有方法在VQA 1.0上的实验结果展示(即单个模型;无需额外的数据集即可完成训练)。

复制代码
    def trainModel(trainLoader, valLoader, model, criterion, optimizer, scheduler, checkpoint, idx2ans, opt):
    	best_accuracy = 0.
    	start_epoch = 0
    	bad_counter = 0
    	history = []
    
    	writer = None                               #可视化训练过程
    	if opt.use_tensorboard and SummaryWriter is not None:
    		writer = SummaryWriter(log_dir="logs/%s" % opt.model)
    
    	if checkpoint is not None:               #从保存的模型里读数据
    		best_accuracy = checkpoint["best_accuracy"]
    		start_epoch = checkpoint["last_epoch"]
    		bad_counter = checkpoint["bad_counter"]
    		history = checkpoint["history"]
    
    	for epoch in range(start_epoch, opt.num_epoch):                  #训练轮次
    		Initializer.manual_seed(opt.seed + epoch)
    		print("----------------------------------------------")
    		train_loss, train_accuracy = trainEpoch(epoch, trainLoader, model, criterion, optimizer, scheduler, opt, writer)
    		print(">>>> Train [{:.3f}] \t loss: {:.3f} \t accuracy: {:.3f}".format(epoch, train_loss, train_accuracy))
    
    		is_best = False
    		is_save = False
    		if valLoader is not None:
    			val_loss, val_accuracy = evalEpoch(epoch, valLoader, model, criterion, opt, writer)
    			print(">>>> Val [{:.3f}] \t loss: {:.3f} \t accuracy: {:.3f}".format(epoch, val_loss, val_accuracy))
    			history.append(val_accuracy)
    
    			if best_accuracy <= val_accuracy:
    				best_accuracy = val_accuracy
    				bad_counter = 0
    				is_best = True
    
    			if (len(history) > opt.patience) and val_accuracy <= torch.Tensor(history[:-opt.patience]).max():
    				bad_counter += 1
    				if bad_counter > opt.patience:
    					print("** Early Stop!")
    					break
    
    		if (epoch + 1) % opt.save_freq == 0:
    			is_save = True
    
    		is_parallel = True if len(opt.gpus) > 1 else False             #保存模型参数
    		model_state_dict = extract_statedict(model, excludes=["word_embedded"], is_parallel=is_parallel)
    		checkpoint = {
    			"last_epoch": epoch + 1,
    			"args": opt,
    			"state_dict": model_state_dict,
    			"best_accuracy": best_accuracy,
    			"bad_counter": bad_counter,
    			"history": history,
    			"optimizer": optimizer.state_dict(),
    			"lr_scheduler": scheduler.state_dict(),
    		}
    		save_checkpoint(opt.model, checkpoint, is_best, is_save, opt.directory)
    	try:
    		if valLoader is not None:
    			vqaEval(valLoader, model, criterion, idx2ans, opt)
    	except Exception as e:                             #捕获异常类
    		print(">>>> Exception:", e)
    
    	if writer is not None:
    		writer.close()

DCN模型

复制代码
    class DCN(nn.Module):
    
    	def __init__(self, opt, num_ans):
    		super(DCN, self).__init__()
    		#文本特征
    		self.lang_extract = LSTM(300, opt.ques_size, opt.num_layers, opt.droprnn, residual_embeddings=True)
    		
    		rnn_dim = (opt.ques_size - 300)
    		#图像特征
    		self.img_extract = ImageExtractionLayer(opt.num_layers*rnn_dim, opt.img_size, 
    			opt.num_img_attn, cnn_name=opt.cnn_name)
    		#注意力
    		self.dense_coattn = DCNLayer(opt.img_size, opt.ques_size, opt.num_dense_attn, opt.num_none, 
    			opt.num_seq, opt.dropout)
    		#预测
    		self.predict = PredictLayer(opt.img_size, opt.ques_size, opt.num_predict_attn, num_ans, opt.dropout)
    		self.apply(Initializer.xavier_normal)
    
    	def forward(self, img, ques, img_mask, ques_mask):
    		ques, ques_vec, ques_mask = self.lang_extract(ques, ques_mask)
    		img = self.img_extract(img, ques_vec)
    
    		img, ques = self.dense_coattn(img, ques, img_mask, ques_mask)
    		score = self.predict(img, ques, img_mask, ques_mask)
    
    		return score

全部评论 (0)

还没有任何评论哟~