A Position-Aware Transformer for Image Captioning--------论文阅读笔记

阅读本文前最好去了解一下特征金字塔网络FPN。

摘要

近些年来,编码器-解码器模型已成为主流方法,其中CNN和LSTM用于对图像内容进行自然语言描述。在这些方法中,视觉注意力被广泛使用,通过fine-grained analysis(细粒度分析)甚至多步骤推理来实现更深入的图像理解。然而,大多数传统的视觉注意力机制都是基于高层图像特征,忽略了其他图像特征的影响,并且没有充分考虑图像特征之间的相对位置。在本文中,作者针对上述问题,提出了一种具有图像特征注意力和位置注意力机制的Positive-Aware Transformer模型。图像特征注意力首先通过使用Feature Pyramid Network(FPN),即特征金字塔网络提取多层特征,然后利用sacaled-dot-product(缩放点积)融合这些特征(注意力机制),这使得本文的模型能够更有效地检测图像中不同尺度的目标,而无需增加参数。在位置感知注意力机制中,首先获得图像特征之间的相对位置,然后将相对位置合并到原始图像特征中以更准确地生成描述。在MS COCO数据集上进行实验,与一些最先进的方法相比,本文的方法取得了有竞争力的BLUE-4,METEOR、ROUGE-L、CIDEr分数,证明了本文方法的有效性。
在这里插入图片描述
(这个数值不是很高,可以拿过来做对比)

本文中我最关注的是如何获取到图像特征之间的相对关系。

本文的贡献:

为了获得高质量的描述,提出了一种用于图像描述的Position-Aware Transformer模型。

  1. 为了使模型能够在不增加参数的情况下检测图像中不同尺度的目标,提出了图像特征注意力,它使用sacled-dot-product来融合图像特征金字塔内的多层特征;
  2. 为了生成更接近人类的描述,提出了位置感知注意力(Position-Aware Attention)来学习图像特征之间的相对位置,使得从空间关系的角度来解释特征。

提出的方法

为了生成更合理的字幕,提出了一个Position-Aware Transformer,以充分地利用相对位置信息。它包含两个组件:图像编码器和描述解码器。如下图2所示:
下图1的箭头标注了相对位置关系。在这里插入图片描述
图2:架构。
如图2所示,特征金字塔网络,图像特征注意力,位置感知注意力的组合构成了获得视觉特征的编码器。解码器是原来的Transformer解码器。给定图像,首先利用特征金字塔网络FPN获得两种图像特征,一种是包含图像全局语义的高层视觉特征,另一种是低层视觉特征,即图像的局部细节(这一招是从下面的文章中学的)。
在这里插入图片描述
将这两种特征输入到图像特征注意力和位置感知注意力中,以获得包含相对位置信息的融合特征。最后,Transformer将融合后的特征将起始标记或部分完成的句子作为输入(Transformer解码器部分的mask multi-head attention那一块的输入),其它的和Transformer的解码器工作原理没什么不同。

用于特征融合的图像特征注意力

图像描述的输入是图像。传统方法使用图像分类任务上预训练的CNN模型作为特征提取器,并且大多采用最终的卷积层特征图作为图像表示。然而,并非图像中的所有对象都具有存储在该表示中的相应特征,特别是那些小尺寸的对象。如下图3所示,图3中分别是原始图像,以及图像的第一层,第二层,第三层,第四层特征图:
在这里插入图片描述
上图3中的(a)是原始图像,其他是具有从低级到高级语义的图像特征。特征越低,包含的信息越多,呈现的语义越弱。较弱的语义不利于模型把握图像主题;但高层较少的信息也不利于捕获也不利于捕获图像的局部细节。因此,确定图像特征的最佳水平总是难以把握。为了识别不同尺度的图像对象,本文作者使用FPN模型构建特征金字塔。金字塔中的特征通过自上而下的路径和横向连接(lateral connections)将(低分辨率,语义强的特征)与(高分辨率,语义弱的特征)结合起来。在这项工作中,特征金字塔总共有四个特征图,前两个是高级功能,其余是低级功能。
对特征金字塔的每一层的特征进行预测有很多限制,特别是推理时间会大大增加,使得这种方法在实际应用中不切实际。因此,就内存而言,对所有特征进行端到端的深度网络训练是不可行的。为了构建有效且轻量级的模型,作者分别从高级特征和低级特征中选择一个特征:
V l o w V^{low} Vlow={ v 1 l v_1^l v1l,…, v m l v_m^l vml}, v i l v_i^l vil R d m o d e l R^{d_{model}} Rdmodel;
V h i g h V^{high} Vhigh={ v 1 h v_1^h v1h,…, v m h v_m^h vmh}, v i h v_i^h vih R d m o d e l R^{d_{model}} Rdmodel
其中 d m o d e l d_{model} dmodel是模型的隐藏维度。因为低级特征仍然太大而无法使用(eg:空间大小是高级特征的4倍),因此根据图4使用图像特征注意力来融合这两个特征。
在这里插入图片描述
也就是把高级特变成Q,低级特征变成K,然后进行注意力的运算,不过看公式不同的在于,没有见到式子V。
V l o w V^{low} Vlow V h i g h V^{high} Vhigh作为图像特征注意力的输入,然后计算这俩的相关系数矩阵(相关性,也就是注意力分数),如下式(1)。
在这里插入图片描述
然后根据C计算注意力群众W:
在这里插入图片描述
然后计算融合特征 V f u s e d V^{fused} Vfused
在这里插入图片描述

位置感知注意力(Position-Aware Attention)

从图像特征的角度看,图像被分割成大小相等的区域的统一网格。从这个意义上,作者将图像特征建模为规范的有向图,如下图5所示。每个顶点(图中的蓝色块)代表某个图像区域的特征,每条有向边(红色箭头),表示两个顶点之间的相对关系。这里所有的边都是单向的,因为从A到B,和从B到A,这个相对位置是不同的。
在这里插入图片描述
位置感知注意力需要两个输入(构造Q和V): V f u s e d V^{fused} Vfused和边缘矩阵E,其中每个元素 E i j E_{ij} Eij表示从顶点 S i S_i Si S j S_j Sj的边缘。在这种情况下,作者使用公式(4)计算 V f u s e d V^{fused} Vfused内元素的相关系数。
在这里插入图片描述
然后得到融合了相对位置信息的 V f u s e d V^{fused} Vfused新表示。
在这里插入图片描述
给定大小为m×n的feature map,有向图模型有mn个顶点,每个顶点都有直接连接任何其他顶点的边,因此位置感知注意力必须维护O( m 2 m^2 m2 n 2 n^2 n2)条边(这是把顶点到自身也算上了)。但是这在大多数情况下冗余的,这是因为物体在图像中通常稀疏(因为一张图像不可能全是物体的有效信息,总归是有背景的,那么物体的像素就占图像的像素相对比较少)。此外,以空间复杂度O( m 2 m^2 m2 n 2 n^2 n2)维护边缘会导致要训练的参数显著增加。
为了降低复杂度,利用两个顶点在水平和垂直方向上的位置来构造这两个顶点之间的相对位置。如下图所示,顶点放置在笛卡尔坐标中,每个顶点都有唯一的坐标。
在这里插入图片描述
使用以下算法计算边缘矩阵E:
在这里插入图片描述
模型的复杂度降低到O(max(m,n))

后续的实验结果、消融实验、结论读论文原文

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
"Structure-Aware Transformer for Graph Representation Learning"是一篇使用Transformer模型进行图表示学习的论文。这篇论文提出了一种名为SAT(Structure-Aware Transformer)的模型,它利用了图中节点之间的结构信息,以及节点自身的特征信息。SAT模型在多个图数据集上都取得了非常好的结果。 以下是SAT模型的dgl实现代码,代码中使用了Cora数据集进行示例: ``` import dgl import numpy as np import torch import torch.nn as nn import torch.nn.functional as F class GraphAttentionLayer(nn.Module): def __init__(self, in_dim, out_dim, num_heads): super(GraphAttentionLayer, self).__init__() self.num_heads = num_heads self.out_dim = out_dim self.W = nn.Linear(in_dim, out_dim*num_heads, bias=False) nn.init.xavier_uniform_(self.W.weight) self.a = nn.Parameter(torch.zeros(size=(2*out_dim, 1))) nn.init.xavier_uniform_(self.a.data) def forward(self, g, h): h = self.W(h).view(-1, self.num_heads, self.out_dim) # Compute attention scores with g.local_scope(): g.ndata['h'] = h g.apply_edges(fn.u_dot_v('h', 'h', 'e')) e = F.leaky_relu(g.edata.pop('e'), negative_slope=0.2) g.edata['a'] = torch.cat([e, e], dim=1) g.edata['a'] = torch.matmul(g.edata['a'], self.a).squeeze() g.edata['a'] = F.leaky_relu(g.edata['a'], negative_slope=0.2) g.apply_edges(fn.e_softmax('a', 'w')) # Compute output features g.ndata['h'] = h g.update_all(fn.u_mul_e('h', 'w', 'm'), fn.sum('m', 'h')) h = g.ndata['h'] return h.view(-1, self.num_heads*self.out_dim) class SATLayer(nn.Module): def __init__(self, in_dim, out_dim, num_heads): super(SATLayer, self).__init__() self.attention = GraphAttentionLayer(in_dim, out_dim, num_heads) self.dropout = nn.Dropout(0.5) self.norm = nn.LayerNorm(out_dim*num_heads) def forward(self, g, h): h = self.attention(g, h) h = self.norm(h) h = F.relu(h) h = self.dropout(h) return h class SAT(nn.Module): def __init__(self, in_dim, hidden_dim, out_dim, num_heads): super(SAT, self).__init__() self.layer1 = SATLayer(in_dim, hidden_dim, num_heads) self.layer2 = SATLayer(hidden_dim*num_heads, out_dim, 1) def forward(self, g, h): h = self.layer1(g, h) h = self.layer2(g, h) return h.mean(0) # Load Cora dataset from dgl.data import citation_graph as citegrh data = citegrh.load_cora() g = data.graph features = torch.FloatTensor(data.features) labels = torch.LongTensor(data.labels) train_mask = torch.BoolTensor(data.train_mask) val_mask = torch.BoolTensor(data.val_mask) test_mask = torch.BoolTensor(data.test_mask) # Add self loop g = dgl.remove_self_loop(g) g = dgl.add_self_loop(g) # Define model and optimizer model = SAT(features.shape[1], 64, data.num_classes, 8) optimizer = torch.optim.Adam(model.parameters(), lr=0.005, weight_decay=5e-4) # Train model for epoch in range(200): model.train() logits = model(g, features) loss = F.cross_entropy(logits[train_mask], labels[train_mask]) optimizer.zero_grad() loss.backward() optimizer.step() acc = (logits[val_mask].argmax(1) == labels[val_mask]).float().mean() if epoch % 10 == 0: print('Epoch {:03d} | Loss {:.4f} | Accuracy {:.4f}'.format(epoch, loss.item(), acc.item())) # Test model model.eval() logits = model(g, features) acc = (logits[test_mask].argmax(1) == labels[test_mask]).float().mean() print('Test accuracy {:.4f}'.format(acc.item())) ``` 在这个示例中,我们首先加载了Cora数据集,并将其转换为一个DGL图。然后,我们定义了一个包含两个SAT层的模型,以及Adam优化器。在训练过程中,我们使用交叉熵损失函数和验证集上的准确率来监控模型的性能。在测试阶段,我们计算测试集上的准确率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值