Patch Embedding 回顧
上節(jié)回顧
Seq2Seq中的attention
在Transformer之前的RNN,其實已經(jīng)用到了注意力機制。Seq2Seq。
對于Original RNN,每個RNN的輸入,都是對應(yīng)一個輸出。對于original RNN,他的輸入和輸出必須是一樣的。
在處理不是一對一的問題時,提出了RNN Seq2Seq。也就是在前面先輸入整體,然后再依次把對應(yīng)的輸出出來。
雖然Seq2Seq解決了輸入和輸出不定是相同長度的問題,但是我們所有信息都存在模型的一定地方,我們叫上下文,或者叫hidden state。又由于輸入的都是同一個模型,每次都更新同一個位置,那么當(dāng)我們的句子很長,或者是一個段落時,可能這個上下文就不會work,因為我們decoder的所有信息都是來自上下文的。效果不夠好。把很多信息輸入,就是encoder。后面把上下文信息解析出來,就是decoder。
很多學(xué)者想了辦法去改進它。希望把前面時間段的信息,傳遞給解碼decoder的時候。如下圖所示。
我們除了在encoder的部分傳遞h,還會多存一份p,直接傳給decoder。
RNN每次都是傳遞一個h。h是隱變量,高層的語義信息。c就是attention。它等于前面所有時間點的語義信息分別乘以a,再sum。c看到了前面的所有時間點,如果是一個句子,就是看到了句子里的所有token。c看到了h1-hn。那它看到的誰更重要,是a1-an控制的。那么a應(yīng)該怎么設(shè)置呢?最好的辦法是,是讓a可學(xué)習(xí)。即通過大量的句子數(shù)據(jù)訓(xùn)練一個網(wǎng)絡(luò),讓c1明白,他應(yīng)該更關(guān)注前面句子里的哪個token,哪個token的a就是最大的。
Transformer中的attention
上述是RNN中的attention機制,下面來論述attention在Transformer中是如何工作的。
x1-x3都是image token,也就是patch embedding后的token特征。他們首先會做一個projection。這里使用了神經(jīng)網(wǎng)絡(luò),或升維,或降維。得到Vector v。v和權(quán)重a相乘再相加,得到了attention c。注意,這里的c1是給x1做的attention。
我們又在x的這里另開了一個網(wǎng)絡(luò),對x進行另一個網(wǎng)絡(luò)的projection Projk。得到另一個feature vector k1。他和v1可能維度不同,也可以相同。
x,k,v都是feature vector。a是通過兩個k的點積得到的。這里a是一個scalar數(shù)值。k1會分別和k1,k2,k3進行點擊,得到a1,a2,a3,a稱為attention weights。注意里面的Projk是同一個,并且是可學(xué)習(xí)的。Projk可學(xué)習(xí),就相當(dāng)于a是可學(xué)習(xí)的,也相當(dāng)于c是可學(xué)習(xí)的。
現(xiàn)在我們多出來一個Wq分支。q即query,也就是查詢。q和k做點積,和上面講的k與k做點積并沒有不同,也就是我們不再通過k去做點積,而是通過q。query的作用就是去查詢與key的相關(guān)性。比如q1,當(dāng)它和其它k1,k2,k3點積加權(quán)得到attention c1時,c1就是表示x1與其它x的相關(guān)性。上述方法也就是讓query和key進行了分離,key作索引功能,query作查詢功能。給誰算attention,就用誰的query點積別人的key(包括自己的)。
這里x是vetor,就是一個patch feature,projection其實也是embedding,即提取特征。所以W的列其實就是embedd_dim(本質(zhì)即卷積操作)。我們的attention是針對每一個token的。x1,x2,x3就是每一個單詞token,或者圖像的patch。Wq,Wk,Wv參數(shù)是不同的,他們都是可學(xué)習(xí)的。
p是attention weight。attention是表達,是token通過Transformer計算出來的,一個feature vector和其它vector的相關(guān)性,就是通過p表達的。
我們?yōu)槭裁匆詃k。variance方差表示數(shù)據(jù)的離散程度。如果variance值很大時,對于softmax,他會更偏向更大的那個值。如果variance更小,softmax波動就沒有那么大。為了避免softmax在更大值上,我們需要把variance拉回來一點,讓我們的attention更穩(wěn)定一點,不能只盯著一個人看,讓注意力更均衡一點,雨露均沾。這里是softmax寫錯了,要寫最外面。
也就是我們輸入多少個token,我們輸出的attention z還是多少個。以上內(nèi)容就是全部的self-attention了。
下面我們再講講multi-head self-attention。
multi-head self-attention就是你看你的,我看我的。讓不同的人去看相同的序列信息,qkv進行復(fù)制,但是他們的參數(shù)是不同的,然后最后集眾家所長。大家最后統(tǒng)一一下意見。這個統(tǒng)一也是learnable的。z輸出也是不變維度,還是n行(和token個數(shù)對應(yīng))。文章來源:http://www.zghlxwxcb.cn/news/detail-583206.html
下面說下如何進行高效的attention計算,用矩陣計算。
將Multi-Head Attention帶回Vit整體結(jié)構(gòu)中,如下圖所示。
下面是Attention class的代碼:文章來源地址http://www.zghlxwxcb.cn/news/detail-583206.html
import paddle
import paddle.nn as nn
paddle.set_device('cpu')
class Attention(nn.Layer):
def __init__(self, embed_dim, num_heads, qkv_bias, qk_scale, dropout=0., attention_dropout=0.):
super().__init__()
self.embed_dim = embed_dim
self.num_heads = num_heads
self.head_dim = int(embed_dim / num_heads)
self.all_head_dim = self.head_dim * num_heads # 避免不能整除
self.qkv = nn.Linear(embed_dim,
self.all_head_dim * 3,
bias_attr=False if qkv_bias is False else None) # bias=None,在paddle里是默認給0
self.scale = self.head_dim ** -0.5 if qk_scale is None else qk_scale
self.softmax = nn.Softmax(-1)
self.proj = nn.Linear(self.all_head_dim, embed_dim)
def transpose_multi_head(self, x):
new_shape = x.shape[:-1] + [self.num_heads, self.head_dim]
x = x.reshape(new_shape) # [B, N, num_heads, head_dim]
x = x.transpose([0, 2, 1, 3]) # [B, num_heads, N, head_dim]
return x
def forward(self, x):
# [B, N, all_head_dim] * 3
B, N, _ = x.shape
qkv = self.qkv(x).chunk(3, -1) # [B, N, all_head_dim] * 3
q, k, v = map(self.transpose_multi_head, qkv) # q,k,v: [B, num_heads, N, head_dim]
attn = paddle.matmul(q, k, transpose_y=True) # q * k^t
attn = self.scale * attn
attn = self.softmax(attn) # [B, num_heads, N]
attn_weight = attn
# dropout
# attn:[B, num_heads, N, N]
out = paddle.matmul(attn, v)
out = out.transpose([0, 2, 1, 3]) # attn:[B, N, num_heads, head_dim]
out = out.reshape([B, N, -1])
out = self.proj(out)
# dropout
return out, attn_weight
def main():
t = paddle.randn([4, 16, 96])
print('input shape = ', t.shape)
model = Attention(embed_dim=96, num_heads=8,
qkv_bias=False, qk_scale=None, dropout=0., attention_dropout=0.)
print(model)
out, attn_weights = model(t)
print(out.shape) # [4, 16, 96]
print(attn_weights.shape) # [4, 8, 16, 16] 8是num_heads,8個人去看; N(num_patch)=16, 16個img token互相看
if __name__ == "__main__":
main()
到了這里,關(guān)于圖解Vit 2:Vision Transformer——視覺問題中的注意力機制的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!