# 以下面句子為例
>>> example = ['BigBird', 'is', 'now', 'available', 'in', 'HuggingFace', 'for', 'extractive', 'question', 'answering']
# 現在query_token的例子為available
>>> query_token = 'available'
# 初始化一個空的key_token列表,下面我們逐漸添加
>>> key_tokens = []
# 舉例窗口為3,即只考慮available詞的前一個詞和後一個詞
# 即左邊的詞」now「;右邊的詞」in「
>>> sliding_tokens = ["now", "available", "in"]
# 更新一下key_tokens集合
>>> key_tokens.append(sliding_tokens)
長程依賴(Long-range dependencies):有的任務,需要捕獲距離較遠的詞之間的關係,例如問答模型需要比較原文中每個詞與整個問題,從而發現原文中哪些詞序列更適合做正確答案。如果大多數原文詞與其他原文詞做注意力計算,而不是與問題做注意力計算,這對模型來說將會更困難的篩出重要的原文詞。
BigBird有兩種長程注意力方式,可以讓計算變的更有效:
# 例如第一個詞和最後一個詞是全局的
>>> global_tokens = ["BigBird", "answering"]
# 將全局詞加入至key_tokens集合中
>>> key_tokens.append(global_tokens)
# 現在用詞」is「做隨機詞
>>> random_tokens = ["is"]
>>> key_tokens.append(random_tokens)
>>> key_tokens
{'now', 'is', 'in', 'answering', 'available', 'BigBird'}
# 現在,詞」available「可以只與這些詞做注意力計算,而不是所有詞
上圖給出了global、sliding、random三種連接,每個節點代表了詞,每條線代表了注意力,如果兩個詞之間沒有連接,意味著兩個詞中間沒有注意力計算。
BigBird block sparse attention結合了sliding、global、random的十條連接。正常注意力機制是有6個節點的所有15條連接。正常注意力與所有詞都為全局注意力是等價的。
Normal attention:模型可以在一層之內,把每個詞的信息都與其他任意詞直接交互。以上圖為例,如果模型需要兩個詞」going「與」now「互相聯繫,就需要在一層內,建立他們的直接連接。
Block sparse attention:由於節點不是全部互相連接的,那麼模型的節點(或詞)需要互相分享信息時,信息不得不通過最短路徑的其他節點。例如,當「going」需要連接至「now」,如果只考慮窗口為左右各一個詞的sliding attention,那麼「going」與「now」之間的信息,必須通過going -> am -> i -> now,才能被「now」接收。因此,我們需要多層「Block sparse」才能有效捕獲序列中所有的組合信息,而全連接的注意力機制只在一層內就可以捕獲序列的所有組合信息。在極端情況下,如兩個詞距離最遠,需要的層數,與輸入的詞數要一樣多。當加入global connection的連接時,信息可以通過going -> i -> now的方式傳遞。如果加入random connections,信息可以通過going -> am -> now的方式傳遞。所以在有global connections、random connections的參與下,信息可以在token之間傳遞更有效。如果當我們有很多global tokens時,就已經有很多足夠短的連接了,那麼就不再需要random connections。通過設置num_random_tokens = 0,就得到這樣變體的BigBird模型,也稱為ETC。BigBird block sparese attention通過以上討論可知,Block sparse attention是一個有效的運行方式。每個詞都是與其他global tokens、 sliding tokens、 random tokens進行計算,而不是與其他所有詞進行計算。作者已經在代碼中分別實現了多種注意力矩陣,因此實現了訓練和預測時間更短的小技巧。圖中可以看到2個向左平移和向右平移的額外句子。這是計算sliding attention時需要執行的。實現block_sparse注意力的代碼(https://github.com/vasudevgupta7/transformers/blob/5f2d6a0c93ca2017961199aa04a344b9b779d454/src/transformers/models/big_bird/modeling_big_bird.py#L513)看起來長,在這裡會逐步解釋。Global Attention對於global attention,注意力的每次query都是與輸入的所有其他詞進行計算。例如第一個詞[Vasudev]和最後一個詞[them]。如下代碼所示# pseudo code
Q -> Query martix (seq_length, head_dim)
K -> Key matrix (seq_length, head_dim)
# 1st & last token attends all other tokens
Q[0] x [K[0], K[1], K[2], ., K[n-1]]
Q[n-1] x [K[0], K[1], K[2], ., K[n-1]]
# 1st & last token getting attended by all other tokens
K[0] x [Q[0], Q[1], Q[2], ., Q[n-1]]
K[n-1] x [Q[0], Q[1], Q[2], ., Q[n-1]]
計算注意力時序列中的key序列複製兩次,一個向左平移一個位置、一個向右平移一個位置,然後用query序列與三個key序列直接向量相乘,就實現了所有sliding tokens的計算。計算複雜度僅為O(3xn) = O(n)。在上圖中,橙色格子為sliding attention。在表格上方的三個句子代表三個key序列,即原key序列,向左平移的key序列、向右平移的key序列
# what we want to do
Q[i] x [K[i-1], K[i], K[i+1]] for i = 1:-1
# efficient implementation in code (assume dot product multiplication )
[Q[0], Q[1], Q[2], ., Q[n-1]] x [K[1], K[2], K[3], ., K[n-1], K[0]]
[Q[0], Q[1], Q[2], ., Q[n-1]] x [K[n-1], K[0], K[1], ., K[n-2]]
[Q[0], Q[1], Q[2], ., Q[n-1]] x [K[0], K[1], K[2], ., K[n-1]]
# Each sequence is getting multiplied by only 3 sequences to keep `window_size = 3`.
# Some computations might be missing; this is just a rough idea.
Random attention可以在計算注意力時,讓query詞與其他隨機的幾個key詞進行計算。在實際運行中,模型會隨機收到幾組注意力得分。
# r1, r2, r are some random indices; Note: r1, r2, r3 are different for each row
Q[1] x [Q[r1], Q[r2], ., Q[r]]
.
.
.
Q[n-2] x [Q[r1], Q[r2], ., Q[r]]
# leaving 0th & (n-1)th token since they are already global
在一般的Bert注意力中,序列為$X=x_1, x_2,...,x_n$,由稠密向量$Q,K,V$計算的注意力為$Z=Softmax(QK^T)$。在BigBird注意力計算中,同樣的算法就僅在個別的query向量和key向量之間計算。
下面我們來展開bigbird的block sparse attention的執行方式。首先我們假設b,r,s,g分別代表block_size, num_random_blocks, num_sliding_blocks, num_global_blocks。當b=4,r=1,g=2,s=3,d=5時:注意力得分$q_1,q_2,q_3,q_{n-2},q_{n-1},q_n$分別由以下方式計算
注意力得分q_1由a_1表示,第一個詞與序列其他所有詞計算得來
這裡 q_1 代表第一個塊, g_i 代表第i個塊,因此只是正常的注意力計算可得 q_1&g
在計算第二塊時,需要前三塊、最後一塊、第五塊,計算公式為
圖中的 g,r,s 代表global,random,sliding。
當計算注意力得分 q_{3:n-2} 時,需要用global, sliding, random三種key,與 q_{3:n-2} 進行注意力計算。這裡的sliding key的計算由上面介紹的平移方法得到。
當計算倒數第二個詞( q_{n-1} )的得分時,需要第一個塊、最後三塊和第三塊。計算公式為
當計算最後一個詞時,公式為
,這裡的注意力計算為最後一個詞與其他所有詞的計算。
結合以上所有矩陣計算為:
BigBird time complexity = O(w x n + r x n + g x n)
BERT time complexity = O(n^2)
Assumptions:
w = 3 x 64
r = 3 x 64
g = 2 x 64
When seqlen = 512
=> time complexity in BERT = 512^2
When seqlen = 1024
=> time complexity in BERT = (2 x 512)^2
=> time complexity in
=> time complexity in BigBird = (8 x 64) x (2 x 512)
=> time complexity in BigBird = 2 x 512^2
When seqlen = 4096
=> time complexity in BERT = (8 x 512)^2
=> time complexity in BERT = 64 x 512^2
=> compute in BigBird = (8 x 64) x (8 x 512)
=> compute in BigBird = 8 x (512 x 512)
=> time complexity in BigBird = 8 x 512^2
BigBird模型可以由兩種策略訓練:ITC & ETC。ITC(internal transformer construction)即為上面討論的計算方式。ETC(external transformer construction)為指定部分詞為全注意力計算方式。
ITC需要更少計算量,因為只有很少的詞是全局計算的,同時模型通過random attention保持全局信息。而ETC是設置了更多的全局計算詞,面向一些需要一些額外的全局信息任務,例如在閱讀理解任務中,問題需要與所有的答案進行注意力計算。
注意:在原論文中,ETC實驗中,不含random token夾帶私貨現已開源中文bigbird預訓練模型,從tiny至base共5個級別預訓練模型。可以從huggingface hub(https://huggingface.co/models?language=zh&sort=downloads&search=bigbird)直接下載使用,如果對您有用,歡迎star我的Github(https://github.com/LowinLi/chinese-bigbird)。