NLP.TM[26] | bert之我見-attention篇

2021-12-22 CS的陋室

本人有關自然語言處理和文本挖掘方面的學習和筆記,歡迎大家關注。

往期回顧:

我想現在NLP領域中,不知道bert的已經少之又少了,而bert的講解文章也已經有了很多,這裡我談一下我最近學習得到的理解。事先說明,對bert和transformer完全不懂的人看這個完全不知道咋回事的,想要看下面這些請先對這兩個玩意有初步的理解。(風格依舊,不會重複別人寫過的東西)

今天給大家談的是bert中的attention,通篇可能不會有太多篇幅對著bert講,而是把attention講懂,然後再去看bert中的attention幹了什麼,這樣大家能對bert中的attention,甚至整個注意力機制有更加深刻的理解。

從機器翻譯開始

bert的核心之一在於使用了transformer中的encoder,而transformer的架構則來源於機器翻譯中的seq2seq,因此,要完全理解bert,還是要從機器翻譯開始理解。

首先我們看seq2seq。用圖來說比較容易,簡單地,由於我們只要知道基本結構,所以用RNN來解釋更為合適。

從上面的圖其實可以看到,整個seq2seq其實就是一個encoder-decoder的模式,這個就和transformer很像了,這個就是目前機器翻譯目前的一套主流架構。Encoder負責將原始信息進行編碼匯總,整理成模型能夠理解信息,後續如果有了attention之後還能提取關鍵型信息;Decoder則是將信息整合,輸出翻譯結果。

attention機制

我認為attention機制談的最清楚的應該是張俊林在2017年寫的《深度學習中的注意力模型》,據說被刊登在《程式設計師》上了,很厲害的亞子。

首先,大家這麼理解,何為注意力,在模型上,大家可以理解為,詞彙比較關鍵的對應位置,權重會比較高,相反不重要的位置權重就比較低。深入地,這個重要性的衡量,在機器翻譯裡,是依賴於翻譯結果中對應的位置的,例如現在翻譯到了一個名詞的位置,那重要性更高的應該就是原句中名詞的部分,因此對於預測句子中的每個的位置,其實都應該有這個位置針對原句所有詞彙的重要性衡量。

按照RNN的邏輯,預測應該是這樣預測的,每個預測點與前面的位置有關,而且在這裡看來是平權的,即C是固定的沒有重點的:

而如果是注意力機制,那就會是這樣的,C是變化的:

至於這個C1,C2,C3是怎麼來的,看這個:

Y1有自己的C1,Y2有自己的C2,於是就造就了注意力機制。

那麼下一個問題就是,怎麼去構造這個根據位置變化的權重向量C了。來看看這個圖:

我對於特定詞彙位置附近的詞進行attention計算,這裡使用的是RNN的輸出,用這個輸出計算了Attention scores之後進行歸一化形成分布。然後我們來看看公式的描述吧。

我們直接先從Decoder的隱含層公式看一下吧。

第i個位置的隱含層的輸出和前一個位置的隱含層輸出、前一個位置的預測結果以及encoder結果結合,然後我們從這個ci往前推。encoder的結果是基於attenton結果導出的權重向量以及encoder的隱含層向量求得的,可以理解為一個加權求和,所以是這樣的:

h是encoder的隱含層向量,這個就與你選用的模型有關了,所以問題就落到了這個alpha上了。然後我們知道這個alpha實質上是一個標準化向量,所以裡面肯定是包裹了一層標準化函數的,所以是這樣的:

一層一層解剖下來,就到了這個e的頭上了,值得注意的是,這裡面需要區分開e對應的兩個下角標,前者是decoder對應的位置,後者是encoder對應的位置。所以問題就到了這個e上了。

首先根據attention定義,對decoder特定位置衡量encoder各個位置的重要性,到了這裡其實就是decoder和encoder之間的相關性了,當然的越相關這裡就越重要對吧,所以說白了就是衡量相關性,硬要嚴謹一些,其實就是去構造兩者的一個得分函數。

這麼看說白了還是相似度吧。這個相似度描述其實就回到了很原始的幾大相似度衡量模型了,此處就不多談啦:

回過頭來,總結一下Attention的思想,就成了這樣:

衡量輸入和輸出兩者的相似度作為權重,做隱含層的加權平均,就這麼簡單。來看個直觀點的圖吧,這麼看大家是不是就知道怎麼回事了:

這裡就引出了attention的三個重要角色,query、key、value,query是原句,key是翻譯句,value是隱含層向量。後續討論attention模型,就只需要搞清楚這三個是啥,這個模型你就理解了一大半了(額,其實我倒是感覺很多文章裡反而沒在各種應用,包括self attention,裡面把這三個角色分別是什麼說清楚)。

Transformer

Transformer就是BERT發明的一大功臣,這裡面,實際上就是使用了self-attetion,即自注意力機制。

何為自注意力機制,就是自己對自己,這個非常好理解,但是,自己對自己裡面的計算又是什麼樣的,大家有仔細想過嗎?是每個位點自己對自己,還是自己這句對應自己這句?很明顯,是後面的,用機器翻譯的方式理解,attention說白了就是把輸入句和輸出句都當做是自己,那麼這裡計算的重要性權重,就是每個單詞在整個句子中的重要性了(我的天這不就是term weighting嗎?)

然後現在回頭來看,k、q、v就很明確了。

k、q、v對應的其實都是一套,而不是一個,都是一個向量空間裡面的,只不過計算的時候取的不是一個位點而已。

這裡也可以看到,大家理解了k、q、v之後,attention模型的應用你就非常明白了。

這裡也告訴大家一個看k、q、v很快的技巧,那就是——看!源!碼!

tranformer的源碼中(https://github.com/Kyubyong/transformer/blob/master/model.py),對encodeer的attentiion是這樣的,非常一目了然。

enc = multihead_attention(queries=enc,

keys=enc,

values=enc,

key_masks=src_masks,

num_heads=self.hp.num_heads,

dropout_rate=self.hp.dropout_rate,

training=training,

causality=False)

而decoder的是這樣的。

dec = multihead_attention(queries=dec,

keys=dec,

values=dec,

key_masks=tgt_masks,

num_heads=self.hp.num_heads,

dropout_rate=self.hp.dropout_rate,

training=training,

causality=True,

scope="self_attention")

# Vanilla attention

dec = multihead_attention(queries=dec,

keys=memory,

values=memory,

key_masks=src_masks,

num_heads=self.hp.num_heads,

dropout_rate=self.hp.dropout_rate,

training=training,

causality=False,

scope="vanilla_attention")

可以看到這裡整了兩次,而這兩者的輸入是不同的,每層的decoder裡面實際上有兩個attention,第一個很明顯就是self-attention了,第二個的key和values是memory,至於這個memory是什麼,我們往前看。

# memory: encoder outputs. (N, T1, d_model)

這句話就在decoder的函數定義下的一行注釋裡,看到這個完全足夠了。由此你其實就非常明白transformer的attention機制是怎麼用的了,看看這圖是不是匹配的,而裡面怎麼整的是不是也更清楚了。

bert中的attention

終於談到bert了,這裡就可以開始談bert中的attention了,這裡用源碼來講更清楚,實際上,我們關注的就是這個代碼塊:

self.all_encoder_layers = transformer_model(

input_tensor=self.embedding_output,

attention_mask=attention_mask,

hidden_size=config.hidden_size,

num_hidden_layers=config.num_hidden_layers,

num_attention_heads=config.num_attention_heads,

intermediate_size=config.intermediate_size,

intermediate_act_fn=get_activation(config.hidden_act),

hidden_dropout_prob=config.hidden_dropout_prob,

attention_probs_dropout_prob=config.attention_probs_dropout_prob,

initializer_range=config.initializer_range,

do_return_all_layers=True)

它實際上就是引入了一個transformer_model。那麼transformer裡面有啥呢,繼續看:

attention_head = attention_layer(

from_tensor=layer_input,

to_tensor=layer_input,

attention_mask=attention_mask,

num_attention_heads=num_attention_heads,

size_per_head=attention_head_size,

attention_probs_dropout_prob=attention_probs_dropout_prob,

initializer_range=initializer_range,

do_return_2d_tensor=True,

batch_size=batch_size,

from_seq_length=seq_length,

to_seq_length=seq_length)

不多放,大部分代碼都是才處理各種輸入和輸出的參數,實質上我們就關注attention,它的應用就在這裡(這裡是構造multi-head attention中的其中一個)。於是我們就要看這個attention_layer是什麼了。可以看到,他這裡並沒有直接給出q、k、v是什麼,所以我們還要繼續往裡面去深挖。

# `query_layer` = [B*F, N*H]

query_layer = tf.layers.dense(

from_tensor_2d,

num_attention_heads * size_per_head,

activation=query_act,

name="query",

kernel_initializer=create_initializer(initializer_range))

# `key_layer` = [B*T, N*H]

key_layer = tf.layers.dense(

to_tensor_2d,

num_attention_heads * size_per_head,

activation=key_act,

name="key",

kernel_initializer=create_initializer(initializer_range))

# `value_layer` = [B*T, N*H]

value_layer = tf.layers.dense(

to_tensor_2d,

num_attention_heads * size_per_head,

activation=value_act,

name="value",

kernel_initializer=create_initializer(initializer_range))

找到了函數裡的這個,可以看到的是query用的是fromtensor2d,key和value用的是totensor2d,那我們回過頭來看這兩個是啥,其實就能看到他們都是layer_input,說白了就哈市self attention,而且沒有別的attention結構了,這也就印證了bert中的用的就是transformer中的encoder。

attention源碼

然後我們來看看attention的源碼吧其實不是很長:

def scaled_dot_product_attention(Q, K, V, key_masks,

causality=False, dropout_rate=0.,

training=True,

scope="scaled_dot_product_attention"):

'''See 3.2.1.

Q: Packed queries. 3d tensor. [N, T_q, d_k].

K: Packed keys. 3d tensor. [N, T_k, d_k].

V: Packed values. 3d tensor. [N, T_k, d_v].

key_masks: A 2d tensor with shape of [N, key_seqlen]

causality: If True, applies masking for future blinding

dropout_rate: A floating point number of [0, 1].

training: boolean for controlling droput

scope: Optional scope for `variable_scope`.

'''

with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):

d_k = Q.get_shape().as_list()[-1]

# dot product

outputs = tf.matmul(Q, tf.transpose(K, [0, 2, 1])) # (N, T_q, T_k)

# scale

outputs /= d_k ** 0.5

# key masking

outputs = mask(outputs, key_masks=key_masks, type="key")

# causality or future blinding masking

if causality:

outputs = mask(outputs, type="future")

# softmax

outputs = tf.nn.softmax(outputs)

attention = tf.transpose(outputs, [0, 2, 1])

tf.summary.image("attention", tf.expand_dims(attention[:1], -1))

# # query masking

# outputs = mask(outputs, Q, K, type="query")

# dropout

outputs = tf.layers.dropout(outputs, rate=dropout_rate, training=training)

# weighted sum (context vectors)

outputs = tf.matmul(outputs, V) # (N, T_q, d_v)

return outputs

點乘等各種操作,注釋其實寫的很好了,大家根據代碼翻譯為公式。

參考文獻

CS224N,Lecture Notes: Part VI, Neural Machine Translation, Seq2seq and Attention.

張俊林,深度學習中的attention機制:https://zhuanlan.zhihu.com/p/37601161

Attention機制詳解(二)——Self-Attention與Transformer:https://zhuanlan.zhihu.com/p/47282410

注意力機制在自然語言處理中的應用:https://www.cnblogs.com/robert-dlut/p/5952032.html

一文讀懂bert(原理篇):https://blog.csdn.net/sunhua93/article/details/102764783

【NLP】徹底搞懂BERT:https://www.cnblogs.com/rucwxb/p/10277217.html

transformer源碼:https://github.com/Kyubyong/transformer

bert源碼:https://github.com/google-research/bert

相關焦點

  • bert之我見-attention
    我想現在NLP領域中,不知道bert的已經少之又少了,而bert的講解文章也已經有了很多,這裡我談一下我最近學習得到的理解。(風格依舊,不會重複別人寫過的東西)今天給大家談的是bert中的attention,通篇可能不會有太多篇幅對著bert講,而是把attention講懂,然後再去看bert中的attention幹了什麼,這樣大家能對bert中的attention,甚至整個注意力機制有更加深刻的理解。
  • bert之我見-positional encoding
    近期我會一連幾篇談談bert中的關鍵細節,這個position encoding是我看到的bert(實質上是transformer中提出的)中最為驚喜的但是卻被很多人忽略(可以理解為媒體鼓吹最少的)一個細節,這裡給大家談談。什麼是position encoding顧名思義,就是基於位置的一套詞嵌入方法,說得簡單點,就是對於一個句子,都有對應的一個向量。
  • Spark NLP 中使用 BERT 的命名實體識別 (NER)
    from pyspark.sql import SparkSessionfrom pyspark.ml import pipelinefrom sparknlp.annotator import * from sparknlp.common import * from sparknlp.base import *import sparknlp spark
  • NLP之文本分類:「Tf-Idf、Word2Vec和BERT」三種模型比較
    本教程比較了傳統的詞袋法(與簡單的機器學習算法一起使用)、流行的詞嵌入模型(與深度學習神經網絡一起使用)和最先進的語言模型(和基於attention的transformers模型中的遷移學習一起使用),語言模型徹底改變了NLP的格局。
  • 從 one-hot 到 BERT,帶你一步步理解 BERT
    而自google在2018年10月底公布BERT在11項nlp任務中的卓越表後,BERT(Bidirectional Encoder Representation from Transformers)就成為NLP一枝獨秀,本文將為大家層層剖析bert。NLP常見的任務主要有:中文自動分詞、句法分析、自動摘要、問答系統、文本分類、指代消解、情感分析等。
  • BERT/Transformer/遷移學習NLP資源大列表
    https://github.com/cedrickchee/awesome-bert-nlpGenerative Modeling with Sparse Transformers by OpenAI - an algorithmic improvement of the attention mechanism to extract patterns from sequences 30x longer than possible previously.
  • 2019已經過去一大半了,努力一把成為NLP專家!
    v=XXtpJxZBa2chttps://papers.nips.cc/paper/7181-attention-is-all-you-need.pdfhttps://www.youtube.com/watch?
  • 站在BERT肩膀上的NLP新秀們(PART II)
    再補一個THU的ERNIE報告PPT:ERNIE from THU (https://pan.baidu.com/s/1TjGOB2myXT-bln3OpFcbgA 提取碼:35fv)今天我們來看看另外幾個有意思的BERT新秀:XLMs from FacebookLASER from Facebook
  • NLP中的詞向量對比:word2vec/glove/fastText/elmo/GPT/bert
    四、深入解剖bert(與elmo和GPT比較)1、為什麼bert採取的是雙向Transformer Encoder,而不叫decoder?2、elmo、GPT和bert在單雙向語言模型處理上的不同之處?3、bert構建雙向語言模型不是很簡單嗎?不也可以直接像elmo拼接Transformer decoder嗎?
  • nlp領域發生了新的技術突破,用attention機制研究nlp領域
    近期,nlp領域發生了一系列的技術突破。包括:attention機制,cnn,adaptive attention network(an),兩層cnn相比較,an表現優於一層的cn。lstm,已經有了兩種不同的,看似性能和效率差異不大的attention機制:rnnattention,lstmattention。今天我們將從這兩種attention機制開始研究nlp領域突破性技術!
  • NLP.TM | 我的NLP學習之路
    17年9月入學,至12月,我完成了第一篇有關研究內容的初稿,從什麼都不知道,到有論文吧,這段時間除了偶爾看看LPL的比賽,基本就在學校理學樓221裡面(學校一間幾乎被廢棄,桌子除了我的位置基本都是塵的教室裡)自習,嚴格而言都不算實驗室,只是一個可供自習落腳的地方吧,這麼一個環境學習下來的。
  • 2019,不可錯過的NLP「高光時刻」
    RoBERTa: https://ai.facebook.com/blog/roberta-an-optimized-method-for-pretraining-self-supervised-nlp-systems/Facebook AI的研究人員最近還發布了一種基於全注意力層(all-attention layer)的方法,用於提高Transformer語言模型的效率
  • 【BERT】Sentence-Bert論文筆記
    如果使用bert模型,那麼每一次一個用戶問題過來,都需要與標準問庫計算一遍。在實時交互的系統中,是不可能上線的。而作者提出了Sentence-BERT網絡結構來解決bert模型的不足。簡單通俗地講,就是借鑑孿生網絡模型的框架,將不同的句子輸入到兩個bert模型中(但這兩個bert模型是參數共享的,也可以理解為是同一個bert模型),獲取到每個句子的句子表徵向量;而最終獲得的句子表徵向量,可以用於語義相似度計算,也可以用於無監督的聚類任務。對於同樣的10000個句子,我們想要找出最相似的句子對,只需要計算10000次,需要大約5秒就可計算完全。
  • 搞定NLP領域的「變形金剛」!教你用BERT進行多標籤文本分類
    Bert-Base模型有12個attention層,所有文本都將由標記器轉換為小寫。我們在亞馬遜雲 p3.8xlarge EC2實例上運行此模型,該實例包含4個Tesla V100 GPU,GPU內存總共64 GB。
  • 一文學會目前最火NLP三大方法:基於TransFormer、RNN\CNN、機器學習!真實實例+解決方法快速入門!
    實例說明1.nlp-getting-started 是kaggle入門機器學習競賽之一(https://www.kaggle.com/c/nlp-getting-started) 對於希望開始使用自然語言處理的數據科學家而言,這一特殊挑戰是完美的。比賽數據集不是太大,即使你沒有太多的個人計算能力,則可以完成所有的工作。
  • 基於Bert和通用句子編碼的Spark-NLP文本分類
    文本分類問題中使用了幾個基準數據集,可以在nlpprogress.com上跟蹤最新的基準。以下是關於這些數據集的基本統計數據。import sparknlpspark = sparknlp.start() # sparknlp.start(gpu=True) >> 在GPU上訓練from sparknlp.base import *from sparknlp.annotator import
  • NLP領域最優秀的8個預訓練模型(附開源地址)
    如果你是自然語言處理的初學者,我建議你參加我們的熱門課程:《NLP using Python》(《使用 Python 進行自然語言處理》):https://courses.analyticsvidhya.com/courses/natural-language-processing-nlp?
  • 圖解當前最強語言模型BERT:NLP是如何攻克遷移學習的?
    這篇論文僅使用單層神經網絡作為分類器就取得了非常優良的結果。因為其中沒有編碼器,所以這些解碼器層不會有編碼器-解碼器注意子層(attention sublayer),而原本的 Transformer 解碼器層中有這樣的注意子層。但是,OpenAI Transformer 中仍然有自注意層。
  • 搞定NLP領域的「變形金剛」!手把手教你用BERT進行多標籤文本分類
    Bert-Base模型有12個attention層,所有文本都將由標記器轉換為小寫。我們在亞馬遜雲 p3.8xlarge EC2實例上運行此模型,該實例包含4個Tesla V100 GPU,GPU內存總共64 GB。