超細節的BERT/Transformer知識點

 2020-04-30 23:59:46.0

隨着NLP的不斷發展,對BERT/Transformer相關知識的研(mian)究(shi)應(ti)用(wen),也越來越細節,下面嘗試用QA的形式深入不淺出BERT/Transformer的細節知識點。

1、不考慮多頭的原因,self-attention中詞向量不乘QKV參數矩陣,會有什麼問題?
2、爲什麼BERT選擇mask掉15%這個比例的詞,可以是其他的比例嗎?
3、使用BERT預訓練模型爲什麼最多隻能輸入512個詞,最多隻能兩個句子合成?
4、爲什麼BERT在第一句前會加一個[CLS]標誌?
5、Self-Attention 的時間複雜度是怎麼計算的?
6、Transformer在哪裏做了權重共享,爲什麼可以做權重共享?
7、BERT非線性的來源在哪裏?
8、BERT的三個Embedding直接相加會對語義有影響嗎?
9、Transformer的點積模型做縮放的原因是什麼?
10、在BERT應用中,如何解決長文本問題?

1、不考慮多頭的原因,self-attention中詞向量不乘QKV參數矩陣,會有什麼問題?

Self-Attention的核心是用文本中的其它詞來增強目標詞的語義表示,從而更好的利用上下文的信息。

self-attention中,sequence中的每個詞都會和sequence中的每個詞做點積去計算相似度,也包括這個詞本身。

如果不乘QKV參數矩陣,那這個詞對應的q,k,v就是完全一樣的。

在相同量級的情況下,qi與ki點積的值會是最大的(可以從「兩數和相同的情況下,兩數相等對應的積最大」類比過來)。

那在softmax後的加權平均中,該詞本身所佔的比重將會是最大的,使得其他詞的比重很少,無法有效利用上下文信息來增強當前詞的語義表示。

而乘以QKV參數矩陣,會使得每個詞的q,k,v都不一樣,能很大程度上減輕上述的影響。

當然,QKV參數矩陣也使得多頭,類似於CNN中的多核,使捕捉更豐富的特徵/信息成爲可能。


2、爲什麼BERT選擇mask掉15%這個比例的詞,可以是其他的比例嗎?

BERT採用的Masked LM,會選取語料中所有詞的15%進行隨機mask,論文中表示是受到完形填空任務的啓發,但其實與CBOW也有異曲同工之妙

從CBOW的角度,這裏 p=15\% 有一個比較好的解釋是:在一個大小爲 1/p=100/15\approx7 的窗口中隨機選一個詞,類似CBOW中滑動窗口的中心詞,區別是這裏的滑動窗口是非重疊的。

上述非官方解釋,是來自我的一位朋友。那從CBOW的滑動窗口角度,10%~20%都是還ok的比例。


3、使用BERT預訓練模型爲什麼最多隻能輸入512個詞,最多隻能兩個句子合成一句?

這是Google BERT預訓練模型初始設置的原因,前者對應Position Embeddings,後者對應Segment Embeddings

在BERT中,Token,Position,Segment Embeddings 都是通過學習來得到的,pytorch代碼中它們是這樣的

self.word_embeddings = Embedding(config.vocab_size, config.hidden_size)self.position_embeddings = Embedding(config.max_position_embeddings, config.hidden_size)self.token_type_embeddings = Embedding(config.type_vocab_size, config.hidden_size)

而在BERT config中

"max_position_embeddings": 512"type_vocab_size": 2

因此,在直接使用Google 的BERT預訓練模型時,輸入最多512個詞(還要除掉[CLS]和[SEP]),最多隻能兩個句子合成一句。

當然,如果有足夠的硬件資源自己重新訓練BERT,可以更改 BERT config,設置更大max_position_embeddings 和 type_vocab_size值去滿足自己的需求。


4、爲什麼BERT在第一句前會加一個[CLS]標誌?

BERT在第一句前會加一個[CLS]標誌,最後一層該位對應向量可以作爲整句話的語義表示,從而用於下游的分類任務等。

爲什麼選它呢,因爲與文本中已有的其它詞相比,這個無明顯語義信息的符號會更「公平」地融合文本中各個詞的語義信息,從而更好的表示整句話的語義。

這裏補充一下bert的輸出,有兩種:

一種是get_pooled_out(),就是上述[CLS]的表示,輸出shape是[batch size,hidden size]。

一種是get_sequence_out(),獲取的是整個句子每一個token的向量表示,輸出shape是[batch_size, seq_length, hidden_size],這裏也包括[CLS],因此在做token級別的任務時要注意它。


5、Self-Attention 的時間複雜度是怎麼計算的?

Self-Attention時間複雜度: O(n^2 \cdot d) ,這裏,n是序列的長度,d是embedding的維度。

Self-Attention包括三個步驟:相似度計算,softmax和加權平均,它們分別的時間複雜度是:

相似度計算可以看作大小爲(n,d)和(d,n)的兩個矩陣相乘: (n,d)*(d,n)=O(n^2 \cdot d) ,得到一個(n,n)的矩陣

softmax就是直接計算了,時間複雜度爲 O(n^2)

加權平均可以看作大小爲(n,n)和(n,d)的兩個矩陣相乘: (n,n)*(n,d)=O(n^2 \cdot d) ,得到一個(n,d)的矩陣

因此,Self-Attention的時間複雜度是 O(n^2 \cdot d)


6、Transformer在哪裏做了權重共享,爲什麼可以做權重共享?

Transformer在兩個地方進行了權重共享:

(1)Encoder和Decoder間的Embedding層權重共享;

(2)Decoder中Embedding層和FC層權重共享。

對於(1),《Attention is all you need》中Transformer被應用在機器翻譯任務中,源語言和目標語言是不一樣的,但它們可以共用一張大詞表,對於兩種語言中共同出現的詞(比如:數字,標點等等)可以得到更好的表示,而且對於Encoder和Decoder,嵌入時都只有對應語言的embedding會被激活,因此是可以共用一張詞表做權重共享的。

論文中,Transformer詞表用了bpe來處理,所以最小的單元是subword。英語和德語同屬日耳曼語族,有很多相同的subword,可以共享類似的語義。而像中英這樣相差較大的語系,語義共享作用可能不會很大。

但是,共用詞表會使得詞表數量增大,增加softmax的計算時間,因此實際使用中是否共享可能要根據情況權衡。

該點參考:zhihu.com/question/3334

對於(2),Embedding層可以說是通過onehot去取到對應的embedding向量,FC層可以說是相反的,通過向量(定義爲 x)去得到它可能是某個詞的softmax概率,取概率最大(貪婪情況下)的作爲預測值。

那哪一個會是概率最大的呢?在FC層的每一行量級相同的前提下,理論上和 x 相同的那一行對應的點積和softmax概率會是最大的(可類比本文問題1)。

因此,Embedding層和FC層權重共享,Embedding層中和向量 x 最接近的那一行對應的詞,會獲得更大的預測概率。實際上,Decoder中的Embedding層和FC層有點像互爲逆過程

通過這樣的權重共享可以減少參數的數量,加快收斂。

但開始我有一個困惑是:Embedding層參數維度是:(v,d),FC層參數維度是:(d,v),可以直接共享嘛,還是要轉置?其中v是詞表大小,d是embedding維度。

查看 pytorch 源碼發現真的可以直接共享:

fc = nn.Linear(d, v, bias=False)    # Decoder FC層定義weight = Parameter(torch.Tensor(out_features, in_features))   # Linear層權重定義

Linear 層的權重定義中,是按照 (out_features, in_features) 順序來的,實際計算會先將 weight 轉置在乘以輸入矩陣。所以 FC層 對應的 Linear 權重維度也是 (v,d),可以直接共享。


7、BERT非線性的來源在哪裏?

前饋層的gelu激活函數和self-attention,self-attention是非線性的,感謝評論區指出。


還有幾個問題也非常好,值得重點關注,但網上已經有很好的解答了,如下:


8、BERT的三個Embedding直接相加會對語義有影響嗎?

參考:zhihu.com/question/3748


9、Transformer的點積模型做縮放的原因是什麼?

參考:zhihu.com/question/3397


10、在BERT應用中,如何解決長文本問題?

參考:zhihu.com/question/3274

文章來源:知乎