bert是怎麼生成動態詞向量的?它與word2vec的區別和聯繫是什麼?


先說word2vec,無論cbow還是skip-gram,所有參數是輸入輸出兩個矩陣(伺服器故障貼不了圖)。訓練得到的詞向量即矩陣 [公式] ,實際inference就是對該矩陣的embedding_lookup,對同一個詞得到的詞向量肯定是不變的,所以是靜態的。

而bert的inference過程會複雜很多,會利用到上下文的信息經過transformer編碼(即self-attention交互),同一個詞如果上下文信息不同,那麼就會得到不同的embedding,所以是動態的。

可以結合bert代碼來看,會有直觀的認識:https://github.com/google-research/bert/blob/master/modeling.py#L156

with tf.variable_scope(scope, default_name="bert"):
with tf.variable_scope("embeddings"):
# Perform embedding lookup on the word ids.
(self.embedding_output, self.embedding_table) = embedding_lookup(
input_ids=input_ids,
vocab_size=config.vocab_size,
embedding_size=config.hidden_size,
initializer_range=config.initializer_range,
word_embedding_name="word_embeddings",
use_one_hot_embeddings=use_one_hot_embeddings)

# Add positional embeddings and token type embeddings, then layer
# normalize and perform dropout.
self.embedding_output = embedding_postprocessor(
input_tensor=self.embedding_output,
use_token_type=True,
token_type_ids=token_type_ids,
token_type_vocab_size=config.type_vocab_size,
token_type_embedding_name="token_type_embeddings",
use_position_embeddings=True,
position_embedding_name="position_embeddings",
initializer_range=config.initializer_range,
max_position_embeddings=config.max_position_embeddings,
dropout_prob=config.hidden_dropout_prob)

with tf.variable_scope("encoder"):
# This converts a 2D mask of shape [batch_size, seq_length] to a 3D
# mask of shape [batch_size, seq_length, seq_length] which is used
# for the attention scores.
attention_mask = create_attention_mask_from_input_mask(
input_ids, input_mask)

# Run the stacked transformer.
# `sequence_output` shape = [batch_size, seq_length, hidden_size].
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)

self.sequence_output = self.all_encoder_layers[-1]
# The "pooler" converts the encoded sequence tensor of shape
# [batch_size, seq_length, hidden_size] to a tensor of shape
# [batch_size, hidden_size]. This is necessary for segment-level
# (or segment-pair-level) classification tasks where we need a fixed
# dimensional representation of the segment.
with tf.variable_scope("pooler"):
# We "pool" the model by simply taking the hidden state corresponding
# to the first token. We assume that this has been pre-trained
first_token_tensor = tf.squeeze(self.sequence_output[:, 0:1, :], axis=1)
self.pooled_output = tf.layers.dense(
first_token_tensor,
config.hidden_size,
activation=tf.tanh,
kernel_initializer=create_initializer(config.initializer_range))


假定你有兩個句子 「I have a apple」,"I have a pen", 把兩個句子分別作為bert的input 那麼你覺得 兩個句子中「a」對應的embedding會是完全相等的么(注意是完全相等)?即bert是動態的,能夠很好的解決一詞多義。

word2vec就很好理解了 在你的語料訓練好一個lookup table的時候,對於上面的兩個句子中的「a」的embedding只用查詢lookup table就完事了。word2vec是靜態的,一詞多義是個大問題。

還有一點bert是一種更深層的網路,依照elmo的理論,bert的每一次可能都會提取不同的信息,而self-attention提高了抽取信息的能力。而w2v直觀上就能看出就一淺層的神經網路。

如果不熟悉bert的結構,網上一大堆闡述的。可以看樓上的那篇博客,需要注意的是 Bert的transformer block結構跟Transformer中transformer block結構稍微有點不一樣,比如兩者的激活函數是不同的。輸入端也有一點小細節,不是bert所謂的三種embedding相加,而是Transformer中會對輸入word embedding進行一個放大,然後再與positional embedding作加和。而bert中並沒有此種操作。


所謂動態就是每次都要過模型計算,所謂靜態就是用已經訓練好的權重。其實bert的embedding層也可以作為靜態的詞向量。


為何是動態與建模方式有關,從word2vec到bert中間變化太多,具體可見我的一篇博客。https://zhuanlan.zhihu.com/p/164632541


簡單來說,在word2vec中,一個詞不管在什麼樣的上下文環境下,它的向量表示都是一樣的,跟上下文環境無關,也就是所謂的靜態的。而在bert中,一個詞的向量表示也包含了周圍詞的信息,在不同上下文環境下,這個詞的表示是不一樣的,也就是所謂的動態的。


謝邀,說來話長, 先要理解Attention 機制哦, 先參考jalammar 的Blog 。

The Illustrated Transformer?

jalammar.github.io圖標

周末,再來補充細節。

########################分割線#######################

周末了,我來了。 老師這題,我會! 昨天我還和同事討論過,為什麼 Bert的詞向量 具有一詞多義,我同事的回答也是 含糊不清的。 為知識所困的可不只是你哦, 這好像是滅霸對鋼鐵俠說的話吧。扯遠了,回歸正題。

首先,Bert的實質是Transformer中的Encoder 結構。 Encode結構中 最重要的就是Self-Attention機制,先談什麼是Self-Attention。 Attention名字聽起來高大上,本質就是兩個向量的相似度而已,最Naive的相似度計算,不就是兩個向量做點積(dot-product)嗎。 假設有兩句話,「我想吃一顆蘋果」和「我想買蘋果手機」,這兩句話中的「蘋果」表示著不同的意義,那麼Self-Attention 機制面對著兩句話,是怎麼Work的呢?

懶得畫圖啊,直接將草稿紙的圖貼上來哦。

先說Self-attention機制:

有兩句話:「我想吃一顆蘋果」和「我想買蘋果手機」,這兩個「蘋果」意義不一樣,實際上在過tokenizer 或者說是word embedding的時候,這裡兩個「蘋果」的向量是相同的。然後是Position embedding,實際上Posting embedding 是人為加入的區分詞語在句子中的位置信息的,純工程化的處理。

重點就是K、Q、V矩陣, 每個詞經過embedding再加上Position embedding,對應著3個向量k、q、v,需要注意的是這3個向量是training出來的哦。 所謂self-attention就是每個詞(或者character)對應的q和每個k做 點積(dot-product ),當然了還要除以個縮放因子 [公式] 。這個點積的結果,還要過一層Softmax,然後與向量v做點積得到最後的向量b,這個b就是最後的「詞向量」。並行化處理寫成矩陣的形式有:

過了Attention Layer 這兩個「蘋果」的向量已經有了很大的區別,至於transformer的細節還有後面的處理,其他的博客和官方代碼注釋已經寫得很多了。

再談Bert:

Bert實質就是transformer的Encoder部分, 理解其雙向的含義,就是指被mask的詞上下文都可以被模型get 到。Bert的Pretrain有兩大任務,一個是 Masked LM,另一個是Next Sentence的預測。

抽取「詞向量」,我們只看第一個任務。Bert可能受到了英文完形填空和CBOW思想的啟發,隨機將一個句子中15%的詞mask起來,實際上15%的詞中,80%的詞進行Mask,10%的詞保留,10%的詞隨機替換,是因為預測任務中,沒有Mask標籤,需要和預測任務匹配。

被Mask的詞,經過模型學習抽取得到,使得填入到這個裡面的詞,放入到整個句子中沒有「違和感」。 需要注意的是,BERT模型已經夠深了,所以在抽取「詞向量」的時候,最後選用簡單的線性多分類器即可,這也體現了Bert抽取出來的特徵已經足夠好了。

最後,Word2Vec 其訓練原理和演算法,就不贅述了。其詞向量就是Lookup from table的方式獲取嘛,其他答主也說的很清楚了。

有說的不對的地方還請指正,很少有人或者有條件 自己pretrain 一個Bert,哈哈。

參考資料:

1.李宏毅 《深度學習》

2.The illustrated Transformer


bert裡面用到的是transformer的encoder,每個輸入在得到其對應的輸出之前都會和其他位置上的輸入計算attention,這樣就導致「我喜歡吃蘋果」、「我喜歡用蘋果」中「蘋果」對應的輸出是不同的。


加上自己的個人理解,可能有錯,歡迎探討:

詞向量根據語料訓練結束後,每個詞的表徵都是固定下來的,後續使用通過查表就可以得到。Bert訓練之後得到的是模型的網路參數,之後需要再進行一次推理才能得到每個輸入對應的表徵。

根據上面的例子,「我喜歡吃蘋果」、「我喜歡用蘋果」,如果語料中涉及蘋果的就這兩個,人來看的話,這裡「蘋果」應該有兩種意思(就是之前說的表徵),姑且認為 [公式][公式]

那麼對於詞向量來說,經過訓練,「蘋果」對應的表徵只會有一個,介於[公式][公式]之間,但應該也不是相加平均,具體怎麼算,期待大佬解答,哈哈哈。

然後,對於Bert來講,同樣的語料來計算的話,得到網路層中的參數,上面句子輸進去,會因為「吃」和「用」的不同,使得「蘋果」對應的輸出是不同的。


因為BERT的網路參數也是詞向量的一部分,而word2vec是直接拿embedding層當詞向量。用數學表示大概就是若x是embedding層,BERT生成的詞向量是 [公式] ,而word2vec是 [公式]


Bert的動態詞向量指的是將文本經過Bert處理之後形成的表示。word2vec的詞向量是在一個預訓練好的詞表示矩陣中查某個詞的表示向量。區別就在於計算前者的時候需要過一次模型,後者直接檢索(look up)參數表就能得到,不需要過模型。

細說的話,每個模型都要為所有單詞創建一個固定的向量表示(所有單詞的表示構成一個矩陣),然後訓練時優化它。靜態的意思就在這,每個單詞的表示是固定的。Bert也有這樣的矩陣,所以我們也可以用檢索的方式獲得Bert的靜態詞向量。動態詞向量是模型依據單詞上下文計算的表示,是根據上下文變化的。


推薦閱讀:
相关文章