BERT 結構與原理(1)--Embedding

1.BERT

??BERT主要是多個Transformer的Encoder作為主題,主要包含Embedding層振惰,Encoder層。

1.1 Embedding

??BERT中的Embedding主要有3種:

  • Token Embedding(詞編碼),
  • Position Embedding (位置編碼),
  • Segment Embedding

1.1.1 Token Embedding

??Token Embedding 是對詞向量進行編碼焕刮。原始的輸入是[batch,seq_len]轿塔。經過 Token Embedding 后數(shù)據的維度為[batch,seq_len,d_model]。
??在BERT中Token Embedding的內部計算流程是初始化一個二維數(shù)組裕便,大小為[vocab_size,d_model]绒净,然后將輸入的數(shù)據進行one-hot編碼见咒,維度為[batch,seq_len,vocab_size]偿衰,進行tensor的乘法。驗證如下:

  • 以torch原始的Embedding進行token編碼
import torch
import torch.nn.functional as F

## 驗證Token embedding
input = torch.tensor([[1,4,2,3,4],[4,2,3,1,5]],dtype = torch.long)
init_weight = torch.rand(6,3) # 這里是6為詞典的大小改览,3為d_model
print(init_weight)
# init_weight的值為:
# tensor([[0.2741, 0.7190, 0.5863],
#         [0.9283, 0.3595, 0.8193],
#         [0.6051, 0.4441, 0.6545],
#         [0.8852, 0.9930, 0.6367],
#         [0.0421, 0.1417, 0.6370],
#         [0.3956, 0.5442, 0.4503]])
out = F.embedding(input,init_weight)
print(out)
# out的值為:
# tensor([[[0.9283, 0.3595, 0.8193],
#          [0.0421, 0.1417, 0.6370],
#          [0.6051, 0.4441, 0.6545],
#          [0.8852, 0.9930, 0.6367],
#          [0.0421, 0.1417, 0.6370]],
# 
#         [[0.0421, 0.1417, 0.6370],
#          [0.6051, 0.4441, 0.6545],
#          [0.8852, 0.9930, 0.6367],
#          [0.9283, 0.3595, 0.8193],
#          [0.3956, 0.5442, 0.4503]]])
  • 將索引進行onehot編碼后做矩陣乘法進行驗證下翎,這里固定init_weight和上面一樣
import numpy as np
input2 = np.array([
    [[0,1,0,0,0,0],[0,0,0,0,1,0],[0,0,1,0,0,0],[0,0,0,1,0,0],[0,0,0,0,1,0]],
    [[0,0,0,0,1,0],[0,0,1,0,0,0],[0,0,0,1,0,0],[0,1,0,0,0,0],[0,0,0,0,0,1]]
])
init_weight = np.array([[0.2741, 0.7190, 0.5863],
        [0.9283, 0.3595, 0.8193],
        [0.6051, 0.4441, 0.6545],
        [0.8852, 0.9930, 0.6367],
        [0.0421, 0.1417, 0.6370],
        [0.3956, 0.5442, 0.4503]])
for i in range(len(input2)):
    out = np.dot(input2[i],init_weight)
    print(out)

# [[0.9283 0.3595 0.8193]
#  [0.0421 0.1417 0.637 ]
#  [0.6051 0.4441 0.6545]
#  [0.8852 0.993  0.6367]
#  [0.0421 0.1417 0.637 ]]


# [[0.0421 0.1417 0.637 ]
#  [0.6051 0.4441 0.6545]
#  [0.8852 0.993  0.6367]
#  [0.9283 0.3595 0.8193]
#  [0.3956 0.5442 0.4503]]

可以看見兩者的結果是一樣的,所以猜測embedding內部就是先將句子中每個詞的索引表示轉化為one-hot表示宝当,然后對編碼后的數(shù)據進行矩陣的變換视事,其中參數(shù)開始是輸出化的,后面訓練的時候可以用來學習庆揩。編碼后的輸出為[batch,seq_len,d_model]

1.1.2 Position Embedding

??BERT中的Position Embedding和Transformer不一樣俐东,transormer中式直接利用公式,計算出對用維度的值订晌。在BERT中是要學習的虏辫。比如說d_model的大小為512,那么每個句子就會生成一個[0,1,2,...511]的一維數(shù)組锈拨,然后重復batch次砌庄,因此實際的輸入為[batch,d_model],將其送到one_hot中進行編碼奕枢,具體的編碼過程和Token Embedding一樣娄昆,然后最后的輸出為[batch,seq_len,d_model]。和Token Embedding輸出的維度一樣缝彬。

1.1.3 Segment Embedding

??BERT 能夠處理對輸入句子對的分類任務萌焰。這類任務就像判斷兩個文本是否是語義相似的。句子對中的兩個句子被簡單的拼接在一起后送入到模型中谷浅。那BERT如何去區(qū)分一個句子對中的兩個句子呢扒俯?答案就是segment embeddings.
image.png

一般是不用的,只在句子對的時候采用壳贪。其編碼后的維度也是[batch,seq_len,d_model]陵珍。

  • BERT預訓練模型中關于embedding的代碼如下:
class BertEmbeddings(nn.Module):
    """Construct the embeddings from word, position and token_type embeddings.
    """
    def __init__(self, config):
        super(BertEmbeddings, self).__init__()
        self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size, padding_idx=0)
        self.position_embeddings = nn.Embedding(config.max_position_embeddings, config.hidden_size)
        self.token_type_embeddings = nn.Embedding(config.type_vocab_size, config.hidden_size)

        # self.LayerNorm is not snake-cased to stick with TensorFlow model variable name and be able to load
        # any TensorFlow checkpoint file
        self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12) # 層歸一化就是對最后一個維度進行歸一化
        self.dropout = nn.Dropout(config.hidden_dropout_prob)

    def forward(self, input_ids, token_type_ids=None):
        seq_length = input_ids.size(1) # 句子的長度,input_ids的維度一般位【batch_size,seq_length】
        position_ids = torch.arange(seq_length, dtype=torch.long, device=input_ids.device)
        position_ids = position_ids.unsqueeze(0).expand_as(input_ids) # 將維度轉化位和input_ids一樣的維度
        if token_type_ids is None:
            token_type_ids = torch.zeros_like(input_ids)

        words_embeddings = self.word_embeddings(input_ids) # word_embedding就是直接將input_ids作為輸入送入embedding
        position_embeddings = self.position_embeddings(position_ids)
        token_type_embeddings = self.token_type_embeddings(token_type_ids)

        embeddings = words_embeddings + position_embeddings + token_type_embeddings # 將三者相加作為encoder的輸入
        embeddings = self.LayerNorm(embeddings)
        embeddings = self.dropout(embeddings)
        return embeddings

    class BertLayerNorm(nn.Module):
        def __init__(self, hidden_size, eps=1e-12):
            """Construct a layernorm module in the TF style (epsilon inside the square root).
            """
            super(BertLayerNorm, self).__init__()
            self.weight = nn.Parameter(torch.ones(hidden_size))
            self.bias = nn.Parameter(torch.zeros(hidden_size))
            self.variance_epsilon = eps

        def forward(self, x):
            u = x.mean(-1, keepdim=True) # layerNorm就是對最后一個維度進行變化的
            s = (x - u).pow(2).mean(-1, keepdim=True)
            x = (x - u) / torch.sqrt(s + self.variance_epsilon)
            return self.weight * x + self.bias
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末违施,一起剝皮案震驚了整個濱河市互纯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌磕蒲,老刑警劉巖留潦,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件只盹,死亡現(xiàn)場離奇詭異,居然都是意外死亡兔院,警方通過查閱死者的電腦和手機殖卑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坊萝,“玉大人孵稽,你說我怎么就攤上這事∈迹” “怎么了菩鲜?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長惦积。 經常有香客問我接校,道長,這世上最難降的妖魔是什么狮崩? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任蛛勉,我火速辦了婚禮,結果婚禮上睦柴,老公的妹妹穿的比我還像新娘诽凌。我一直安慰自己,他們只是感情好爱只,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布皿淋。 她就那樣靜靜地躺著,像睡著了一般恬试。 火紅的嫁衣襯著肌膚如雪窝趣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天训柴,我揣著相機與錄音哑舒,去河邊找鬼。 笑死幻馁,一個胖子當著我的面吹牛洗鸵,可吹牛的內容都是我干的。 我是一名探鬼主播仗嗦,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼膘滨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了稀拐?” 一聲冷哼從身側響起火邓,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后铲咨,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體躲胳,經...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年纤勒,在試婚紗的時候發(fā)現(xiàn)自己被綠了坯苹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡摇天,死狀恐怖粹湃,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情闸翅,我是刑警寧澤再芋,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布歪沃,位于F島的核電站腮郊,受9級特大地震影響戚绕,放射性物質發(fā)生泄漏。R本人自食惡果不足惜记某,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望构捡。 院中可真熱鬧液南,春花似錦、人聲如沸勾徽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喘帚。三九已至畅姊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吹由,已是汗流浹背若未。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留倾鲫,地道東北人粗合。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像乌昔,于是被迫代替她去往敵國和親隙疚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內容