分层共同注意力
声明:本文主要是简单整理自己对这篇论文的认识和理解,如有错误的地方,还望批评指正。
本文介绍关于Hierarchical Co-Attention这篇论文,与前面堆叠式注意力网络不同的是,这篇论文的注意力同时关注了问题和图像。
Abstract—摘要
以往的视觉问答的注意力模型,只关注与问题有关的图像区域。本文提出一个新的VQA共同注意模型。该模型不仅对视觉注意进行建模,还对问题注意进行建模。该模型共同引起了关于图像和问题注意的推理,此模型通过新颖的一维卷积神经网络以分层的方式对问题(以及因此通过注意力机制生成的图像)进行了推理。
1、Introduction—引言
视觉问答已成为学术界和行业中一个突出的多学科研究问题,最近,已经针对VQA探索了基于视觉注意的模型,其中注意机制通常会生成一个空间图,该空间图能够突出显示与回答问题有关的图像区域。但,他们的模型都集中在识别“在哪里看”或视觉注意力上。本文中,我们认为识别“听哪些单词”或问题注意力同样重要。因此本文提出一种新颖的VQA多模式注意力模型,具有如下两个功能:
-
Co-Attention : 本文提出一种新的机制,它能共同引起视觉注意和问题注意的推理。与以往只关注注意力的模型不同,本文的模型在问题和图像之间具有自然的对称性。因为图像表示可用于引导问题的注意力,而问题表示可用于引导图像的注意力。
-
Question Hierarchy:本文构建一个层次结构,该结构在三个级别上共同参与图像和问题。如下
(1) 单词级别:通过嵌入矩阵将单词嵌入到向量空间中。
(2) 短语级别:一维卷积神经网络用于捕获包含在unigrams、bigrams和trigrams中的信息。具体来说,我们将单词表示与支持不同的时间过滤器进行卷积,然后将各种n-gram相应合并到单个短语级别表示中来进行组合。
(3) 问题级别:我们使用循环神经网络对整个问题进行编码,对于此层次结构中问题表示的每个级别,我们构建联合了问题和图像的共同注意力图,然后将它们进行递归组合以最终预测答案的分布。
本文主要贡献:
- 为VQA提出了一种新颖的共同注意机制,该机制共同执行问题引导的视觉注意和图像引导的问题注意。通过两种决策(并行和交替共同注意)探讨这种机制。
- 提出一个层次结构表示问题,在三个不同级别上构造了图像-问题共同注意图:单词级别,短语级别,问题级别。然后将这些共同参与的功能从单词级别到问题解部递归组合来进行最终答案预测。
- 在短语级别上我们提出一种新的卷积池策略,以自适应地选择短语表示形式,将其表示传递给问题级别表示形式。
- 我们在两个大型数据集VQA和COCO-QA上评估了我们提出的模型。
本文模型如下图:
图中给定一个问题,分别提取其词级,短语级和问题级嵌入,在每个级别上,都会同时关注图像和问题,最终答案预测是基于所有共同参与的图像和问题特征。
2、Related Work—相关工作
3、Method—算法
首先介绍符合。为了便于理解,本文将分部分描述整个模型,首先3.2描述分层问题表示形式,然后在3.3节中描述了提出的共同注意力机制,最后3.4节展示了如何问题和图像特征组合来输出答案。
3.1 Notation—符号
- Q = { q 1 , q 2 , . . . , q T } Q=\{q_1,q_2,...,q_T\} Q={q1,q2,...,qT} :包含T个单词的问题。
- q t q_t qt:代表第t个单词的特征向量。
- q t w q^w_t qtw: 代表位置t处的单词嵌入
- q t p q^p_t qtp: 代表位置t处的短语嵌入
- q t s q^s_t qts: 代表位置t处的问题嵌入
- V = { v 1 , v 2 , . . . , v N } V=\{v_1,v_2,...,v_N\} V={v1,v2,...,vN}:表示图像特征。
- v n v_n vn:是空间位置n处的特征向量。
- v ^ r \hat{v}^r v^r和 q ^ r \hat{q}^r q^r:图像和问题在层次中每个级别的共同注意特征表示
- r ∈ { w , p , s } r\in\{w,p,s\} r∈{w,p,s}。
- W W W:表示不同模块/层的权重。
3.2 Question Hierarchy
给定问题单词的one-hot编码
Q
=
{
q
1
,
q
2
,
.
.
.
,
q
T
}
Q=\{q_1,q_2,...,q_T\}
Q={q1,q2,...,qT},我们首先将单词嵌入向量空间(端到端学习)获得
Q
w
=
{
q
1
w
,
q
2
w
,
.
.
.
,
q
T
w
}
Q^w=\{q^w_1,q^w_2,...,q^w_T\}
Qw={q1w,q2w,...,qTw},为了计算短语特征,本文在单词嵌入向量采用一维卷积。具体地,在每个单词位置,本文使用三个窗口大小的过滤器(unigram,bigram,trigram)计算单词向量的内积。对于第t个单词,窗口大小为s的卷积输出为:
q
^
s
,
t
p
=
t
a
n
h
(
W
c
s
q
t
:
t
+
s
−
1
w
)
,
s
∈
{
1
,
2
,
3
}
\hat{q}^p_{s,t} = tanh(W^s_cq^w_{t:t+s-1}),s\in\{1,2,3\}
q^s,tp=tanh(Wcsqt:t+s−1w),s∈{1,2,3}
其中
W
c
s
W^s_c
Wcs是权重参数,单词级别的特征
Q
w
Q_w
Qw在馈入bigram和trigram卷积之前进行适当的0填充,以保持卷积后序列的长度,然后在每个单词位置的不同n-gram上应用最大池化,以获得短语级特征。
q
t
p
=
m
a
x
(
q
^
1
p
,
q
^
2
p
,
q
^
3
p
)
,
t
∈
{
1
,
2
,
.
.
.
,
T
}
q^p_t = max(\hat{q}^p_1,\hat{q}^p_2,\hat{q}^p_3),t\in\{1,2,...,T\}
qtp=max(q^1p,q^2p,q^3p),t∈{1,2,...,T}
本文合并的方法在每个时间步长上自适应选择不同的语法特征,同时保留原始序列的长度和顺序,在最大池化后,再使用LSTM编码序列
q
t
p
q^p_t
qtp,相应的问题级别特征
q
t
s
q^s_t
qts是时间t的LSTM隐藏向量。如图1
图(a)表示分层问题编码,(b)编码来预测答案
3.3 Co-Attention—共同注意
本文提出两种共同注意机制,它们在生成图像和问题注意图的顺序上有所不同,我们将第一个机制称为并行共同注意,它同时生成图像和问题注意。第二种称之为交替共同注意,在生成图像和提出注意之间顺序地交替。(如图2)这些共同注意机制在问题层次结构的所有三个级别上执行。
3.3.1 Parallel Co-Attention—并行共同注意
并行共同注意同时关注图像和问题,我门通过计算所有成对的图像位置和问题位置处的图像和问题特征之间的相似度,来连接图像和问题。给定一个图像特征图
V
∈
R
d
∗
N
V\in{R^{d*N}}
V∈Rd∗N和问题表示
Q
∈
R
d
∗
T
Q\in{R^{d*T}}
Q∈Rd∗T,通过下式计算相似度矩阵。
C
=
t
a
n
h
(
Q
T
W
b
V
)
C = tanh(Q^TW_bV)
C=tanh(QTWbV)
其中
W
b
∈
R
d
∗
d
W_b\in{R^{d*d}}
Wb∈Rd∗d包含权重,在计算完此相似度矩阵之后,一种计算图像(或问题)注意力的可能方法就是简单地最大化其他模态位置上的相似度,即
a
v
[
n
]
=
m
a
x
i
(
C
i
,
n
)
a^v[n]=max_i(C_{i,n})
av[n]=maxi(Ci,n)和
a
q
[
t
]
=
m
a
x
j
(
C
t
,
j
)
a^q[t]=max_j(C_{t,j})
aq[t]=maxj(Ct,j)。与其选择最大激活量,发现如果将这种相似度矩阵视为特征并通过以下方法学习预测图像和问题注意图,则性能会得到改善。
H
v
=
t
a
n
h
(
W
v
V
+
(
W
q
Q
)
C
)
,
H
q
=
t
a
n
h
(
W
q
Q
+
(
W
v
V
)
C
T
)
H^v = tanh(W_vV+(W_qQ)C), H^q = tanh(W_qQ +(W_vV)C_T)
Hv=tanh(WvV+(WqQ)C),Hq=tanh(WqQ+(WvV)CT)
a
v
=
s
o
f
t
m
a
x
(
W
h
v
T
H
v
)
,
a
q
=
s
o
f
t
m
a
x
(
w
h
q
T
H
q
)
a_v = softmax(W^T_{hv}H^v),a_q = softmax(w^T_{hq}H^q)
av=softmax(WhvTHv),aq=softmax(whqTHq)
其中
W
v
W_v
Wv,
W
q
W_q
Wq
∈
R
k
∗
d
,
W
h
v
,
W
h
q
∈
R
k
\in{R^{k*d}},W_{hv},W_{hq}\in{R^k}
∈Rk∗d,Whv,Whq∈Rk是权重参数。
a
v
∈
R
N
a^v\in{R^N}
av∈RN和
a
q
∈
R
T
a^q\in{R_T}
aq∈RT分别是每个图像区域
v
n
v_n
vn和单词
q
t
q_t
qt的注意力概率,相似度矩阵矩阵C将问题注意空间转换为图像注意空间,根据上述注意力权重,将图像和问题注意力向量计算为图像特征和问题特征的加权和,即:
v
^
=
∑
n
=
1
a
n
v
v
n
\hat{v} = \sum_{n=1}a^v_nv_n
v^=n=1∑anvvn
q
^
=
∑
t
=
1
a
t
q
q
t
\hat{q} = \sum_{t=1}a^q_tq_t
q^=t=1∑atqqt
并行注意机制在层次结构的每个级别上完成,产生
v
^
r
,
q
^
r
,
r
∈
{
w
,
p
,
s
}
\hat{v}_r,\hat{q}_r,r\in\{w,p,s\}
v^r,q^r,r∈{w,p,s}
3.3.2 Alternating Co-Attention—交替注意
在此注意机制种,我们依次在生成图像和问题注意之间进行交替,步骤如图1(b),步骤如下:
- 将问题概括为单个向量q
- 根据问题总结q关注图像
- 根据图像特征注意关注问题
具体如下:定义一个注意操作
x
^
=
A
(
X
;
g
)
\hat{x} = A(X;g)
x^=A(X;g),该操作将图像(或问题)特征X和从问题(或图像)派生的注意指导g作为输入,并输出关注的图像(或问题)向量,该操作表示如下:
H
=
t
a
n
h
(
W
x
X
+
(
W
g
g
)
I
T
)
H = tanh(W_xX + (W_gg)I^T)
H=tanh(WxX+(Wgg)IT)
a
x
=
s
o
f
t
m
a
x
(
w
h
x
T
H
)
a^x = softmax(w^T_{hx}H)
ax=softmax(whxTH)
x
^
=
∑
a
i
x
x
i
\hat{x}=\sum{a^x_ix_i}
x^=∑aixxi
其中
I
I
I是一个所有元素都为1的向量,
W
x
,
W
g
∈
R
k
∗
d
W_x,W_g\in{R_{k*d}}
Wx,Wg∈Rk∗d和
w
h
x
∈
R
k
∗
d
w_{hx}\in{R_{k*d}}
whx∈Rk∗d是参数,
a
x
a^x
ax是特征X的注意权重。
交替第一步:
X
=
Q
,
g
=
0
X=Q,g=0
X=Q,g=0
第二步:
X
=
V
X=V
X=V,V是图像特征,而引导g是第一步中的中间注意问题特征
s
^
\hat{s}
s^;
最后:使用照看图像特征
v
^
\hat{v}
v^作为再次参加该问题的指导,即
X
=
Q
和
g
=
v
^
X=Q和g=\hat{v}
X=Q和g=v^,与并行共同注意类似,交替共同注意也在层次结构的每个级别上进行。
3.4 Encoding for Predicting Answers—编码预测答案
我们将VQA视为分类任务,我们根据所有三个级别的隐藏图像和问题特征预测答案,使用多层感知器递归编码注意力特征,如图3(b)
h
w
=
t
a
n
h
(
W
w
(
q
^
w
+
v
^
w
)
)
h_w = tanh(W_w(\hat{q}^w + \hat{v}^w))
hw=tanh(Ww(q^w+v^w))
h
p
=
t
a
n
h
(
W
p
[
q
^
p
+
v
^
p
]
,
h
w
)
h_p = tanh(W_p[\hat{q}^p + \hat{v}^p],h^w)
hp=tanh(Wp[q^p+v^p],hw)
h
s
=
t
a
n
h
(
W
s
(
q
^
s
+
v
^
s
]
,
h
p
)
h_s = tanh(W_s(\hat{q}^s + \hat{v}^s],h^p)
hs=tanh(Ws(q^s+v^s],hp)
p
=
s
o
f
t
m
a
x
(
W
h
h
s
)
p = softmax(W_hh^s)
p=softmax(Whhs)
其中
W
w
,
W
p
,
W
s
W_w,W_p,W_s
Ww,Wp,Ws是权重参数,[]代表对两个向量的串联操作,p是最终答案的概率。
4、实验
5、总结
本文采用一种新的注意力模型,该注意力不仅关注图像而且还关注问题。本文利用两种策略-并行共同注意和交替共同注意来实现该模型的共同注意,同时对于问题构建一个层次结构,该结构在三种级别上共同参与图像和问题。
附录:代码解读
import torch
import torch.nn as nn
import torch.nn.functional as fn
import torch.nn.utils.rnn as rnn
class CoattentionNet(nn.Module):
"""
Predicts an answer to a question about an image using the Hierarchical Question-Image Co-Attention
for Visual Question Answering (Lu et al, 2017) paper.
"""
def __init__(self, num_embeddings, num_classes, embed_dim=512, k=30):
super().__init__()
self.embed = nn.Embedding(num_embeddings, embed_dim)
self.unigram_conv = nn.Conv1d(embed_dim, embed_dim, 1, stride=1, padding=0)
self.bigram_conv = nn.Conv1d(embed_dim, embed_dim, 2, stride=1, padding=1, dilation=2)
self.trigram_conv = nn.Conv1d(embed_dim, embed_dim, 3, stride=1, padding=2, dilation=2)
self.max_pool = nn.MaxPool2d((3, 1))
self.lstm = nn.LSTM(input_size=embed_dim, hidden_size=embed_dim, num_layers=3, dropout=0.4)
self.tanh = nn.Tanh()
self.W_b = nn.Parameter(torch.randn(embed_dim, embed_dim))
self.W_v = nn.Parameter(torch.randn(k, embed_dim))
self.W_q = nn.Parameter(torch.randn(k, embed_dim))
self.w_hv = nn.Parameter(torch.randn(k, 1))
self.w_hq = nn.Parameter(torch.randn(k, 1))
#self.W_w = nn.Parameter(torch.randn(embed_dim, embed_dim))
#self.W_p = nn.Parameter(torch.randn(embed_dim*2, embed_dim))
#self.W_s = nn.Parameter(torch.randn(embed_dim*2, embed_dim))
self.W_w = nn.Linear(embed_dim, embed_dim)
self.W_p = nn.Linear(embed_dim*2, embed_dim)
self.W_s = nn.Linear(embed_dim*2, embed_dim)
self.fc = nn.Linear(embed_dim, num_classes)
def forward(self, image, question): # Image: B x 512 x 196
question, lens = rnn.pad_packed_sequence(question)
question = question.permute(1, 0) # Ques : B x L
words = self.embed(question).permute(0, 2, 1) # Words: B x L x 512
unigrams = torch.unsqueeze(self.tanh(self.unigram_conv(words)), 2) # B x 512 x L
bigrams = torch.unsqueeze(self.tanh(self.bigram_conv(words)), 2) # B x 512 x L
trigrams = torch.unsqueeze(self.tanh(self.trigram_conv(words)), 2) # B x 512 x L
words = words.permute(0, 2, 1)
phrase = torch.squeeze(self.max_pool(torch.cat((unigrams, bigrams, trigrams), 2)))
phrase = phrase.permute(0, 2, 1) # B x L x 512
hidden = None
phrase_packed = nn.utils.rnn.pack_padded_sequence(torch.transpose(phrase, 0, 1), lens)
sentence_packed, hidden = self.lstm(phrase_packed, hidden)
sentence, _ = rnn.pad_packed_sequence(sentence_packed)
sentence = torch.transpose(sentence, 0, 1) # B x L x 512
v_word, q_word = self.parallel_co_attention(image, words)
v_phrase, q_phrase = self.parallel_co_attention(image, phrase)
v_sent, q_sent = self.parallel_co_attention(image, sentence)
#h_w = self.tanh(torch.matmul((q_word + v_word), self.W_w))
#h_p = self.tanh(torch.matmul(torch.cat(((q_phrase + v_phrase), h_w), dim=1), self.W_p))
#h_s = self.tanh(torch.matmul(torch.cat(((q_sent + v_sent), h_p), dim=1), self.W_s))
h_w = self.tanh(self.W_w(q_word + v_word))
h_p = self.tanh(self.W_p(torch.cat(((q_phrase + v_phrase), h_w), dim=1)))
h_s = self.tanh(self.W_s(torch.cat(((q_sent + v_sent), h_p), dim=1)))
logits = self.fc(h_s)
return logits
#并行共同注意
def parallel_co_attention(self, V, Q): # V : B x 512 x 196, Q : B x L x 512
C = torch.matmul(Q, torch.matmul(self.W_b, V)) # B x L x 196
H_v = self.tanh(torch.matmul(self.W_v, V) + torch.matmul(torch.matmul(self.W_q, Q.permute(0, 2, 1)), C)) # B x k x 196
H_q = self.tanh(torch.matmul(self.W_q, Q.permute(0, 2, 1)) + torch.matmul(torch.matmul(self.W_v, V), C.permute(0, 2, 1))) # B x k x L
#a_v = torch.squeeze(fn.softmax(torch.matmul(torch.t(self.w_hv), H_v), dim=2)) # B x 196
#a_q = torch.squeeze(fn.softmax(torch.matmul(torch.t(self.w_hq), H_q), dim=2)) # B x L
a_v = fn.softmax(torch.matmul(torch.t(self.w_hv), H_v), dim=2) # B x 1 x 196
a_q = fn.softmax(torch.matmul(torch.t(self.w_hq), H_q), dim=2) # B x 1 x L
v = torch.squeeze(torch.matmul(a_v, V.permute(0, 2, 1))) # B x 512
q = torch.squeeze(torch.matmul(a_q, Q)) # B x 512
return v, q