Transformer 與 BERT:從原理到實踐
- 前言
- 一、背景介紹
- 二、核心公式推導
- 1. 注意力機制(Attention Mechanism)
- 2. 多頭注意力機制(Multi-Head Attention)
- 3. Transformer 編碼器(Transformer Encoder)
- 4. BERT 的預訓練任務
- 三、代碼實現
- 1. 注意力機制
- 2. 多頭注意力機制
- 3. Transformer 編碼器層
- 4. Transformer 編碼器
- 5. BERT 模型
- 四、總結
前言
在自然語言處理(NLP)的發展歷程中,Transformer 和 BERT 無疑是具有里程碑意義的技術。它們的出現,徹底改變了 NLP 領域的研究和應用格局。本文將深入探討 Transformer 和 BERT 的背景、核心公式推導,并提供代碼實現,幫助大家更好地理解和應用這兩項技術。
一、背景介紹
在 Transformer 出現之前,循環神經網絡(RNN)及其變體長短時記憶網絡(LSTM)、門控循環單元(GRU)等在 NLP 任務中占據主導地位。RNN 能夠處理序列數據,通過隱狀態傳遞信息,從而捕捉上下文依賴關系。然而,RNN 存在嚴重的梯度消失和梯度爆炸問題,使得訓練深層網絡變得困難。此外,RNN 的順序計算特性導致其難以并行化,處理長序列時效率低下。
為了解決這些問題,2017 年谷歌團隊在論文《Attention Is All You Need》中提出了 Transformer 架構。Transformer 完全摒棄了循環結構,采用多頭注意力機制(Multi-Head Attention)替代 RNN,實現了并行計算,大幅提高了訓練效率。同時,多頭注意力機制能夠更好地捕捉序列中的長距離依賴關系,在機器翻譯、文本生成等多個 NLP 任務中取得了優異的性能。
BERT(Bidirectional Encoder Representations from Transformers)則是基于 Transformer 的預訓練語言模型,由谷歌在 2018 年提出。與傳統的語言模型(如 Word2Vec、GPT)不同,BERT 采用雙向 Transformer 編碼器,能夠同時利用上下文信息,學習到更豐富的語義表示。通過在大規模文本數據上進行預訓練,并在特定任務上進行微調,BERT 在問答系統、文本分類、命名實體識別等眾多 NLP 任務中刷新了當時的最優成績,開啟了預訓練模型在 NLP 領域的新時代。
二、核心公式推導
1. 注意力機制(Attention Mechanism)
注意力機制的核心思想是根據輸入序列的不同部分對當前任務的重要程度,分配不同的權重,從而聚焦于關鍵信息。其計算過程如下:
給定查詢向量 (Q),鍵向量 (K) 和值向量 (V),注意力分數 (scores) 計算為:
s c o r e s = Q K T d k scores = \frac{QK^T}{\sqrt{d_k}} scores=dk??QKT?
其中, d k d_k dk? 是鍵向量 K K K 的維度, d k \sqrt{d_k} dk?? 用于縮放,防止分數過大導致 softmax 函數梯度消失。
通過 softmax 函數對注意力分數進行歸一化,得到注意力權重 (attention weights):
a t t e n t i o n _ w e i g h t s = s o f t m a x ( s c o r e s ) attention\_weights = softmax(scores) attention_weights=softmax(scores)
最后,加權求和得到注意力輸出 A t t e n t i o n ( Q , K , V ) Attention(Q, K, V) Attention(Q,K,V):
A t t e n t i o n ( Q , K , V ) = a t t e n t i o n _ w e i g h t s ? V Attention(Q, K, V) = attention\_weights \cdot V Attention(Q,K,V)=attention_weights?V
2. 多頭注意力機制(Multi-Head Attention)
多頭注意力機制通過多個獨立的注意力頭并行計算,從不同角度捕捉輸入序列的特征,然后將各個頭的輸出拼接并線性變換得到最終輸出。具體計算過程如下:
首先,將輸入 X X X分別通過三個線性變換得到 Q Q Q, K K K, V V V:
Q = X W Q K = X W K V = X W V Q = XW^Q\\ K = XW^K\\ V = XW^V Q=XWQK=XWKV=XWV
其中, W Q W^Q WQ, W K W^K WK, W V W^V WV 是可學習的權重矩陣。
然后,將 Q Q Q, K K K, V V V 分割成 h h h 個頭部(head),每個頭部的維度為 d k / h d_{k/h} dk/h?, d v / h d_{v/h} dv/h?:
Q i = Q ( i ? 1 ) d k / h : i d k / h K i = K ( i ? 1 ) d k / h : i d k / h V i = V ( i ? 1 ) d v / h : i d v / h Q_i = Q_{(i-1)d_{k/h}:id_{k/h}} \\ K_i = K_{(i-1)d_{k/h}:id_{k/h}} \\ V_i = V_{(i-1)d_{v/h}:id_{v/h}} Qi?=Q(i?1)dk/h?:idk/h??Ki?=K(i?1)dk/h?:idk/h??Vi?=V(i?1)dv/h?:idv/h??
對每個頭部分別計算注意力輸出:
h e a d i = A t t e n t i o n ( Q i , K i , V i ) head_i = Attention(Q_i, K_i, V_i) headi?=Attention(Qi?,Ki?,Vi?)
將所有頭部的輸出拼接起來:
c o n c a t ( h e a d 1 , . . . , h e a d h ) concat(head_1, ..., head_h) concat(head1?,...,headh?)
最后,通過一個線性變換得到多頭注意力機制的最終輸出:
M u l t i H e a d A t t e n t i o n ( X ) = W O ? c o n c a t ( h e a d 1 , . . . , h e a d h ) MultiHeadAttention(X) = W^O \cdot concat(head_1, ..., head_h) MultiHeadAttention(X)=WO?concat(head1?,...,headh?)
其中, W O W^O WO是可學習的權重矩陣。
3. Transformer 編碼器(Transformer Encoder)
Transformer 編碼器由多個相同的層堆疊而成,每個層包含兩個子層:多頭注意力機制子層和前饋神經網絡子層。每個子層都使用了殘差連接(Residual Connection)和層歸一化(Layer Normalization)。
輸入 (X) 首先經過多頭注意力機制子層:
X 1 = L a y e r N o r m ( X + M u l t i H e a d A t t e n t i o n ( X ) ) X_1 = LayerNorm(X + MultiHeadAttention(X)) X1?=LayerNorm(X+MultiHeadAttention(X))
然后, X 1 X_1 X1? 經過前饋神經網絡子層:
X 2 = L a y e r N o r m ( X 1 + F F N ( X 1 ) ) X_2 = LayerNorm(X_1 + FFN(X_1)) X2?=LayerNorm(X1?+FFN(X1?))
其中, F F N ( X ) FFN(X) FFN(X)是前饋神經網絡,通常由兩個線性層和一個激活函數組成:
F F N ( X ) = m a x ( 0 , X W 1 + b 1 ) W 2 + b 2 FFN(X) = max(0, XW_1 + b_1)W_2 + b_2 FFN(X)=max(0,XW1?+b1?)W2?+b2?
4. BERT 的預訓練任務
BERT 采用了兩個預訓練任務:掩碼語言模型(Masked Language Model,MLM)和下一句預測(Next Sentence Prediction,NSP)。
在掩碼語言模型任務中,隨機將輸入文本中的一些單詞替換為 [MASK] 標記,然后讓模型預測這些被掩碼的單詞。例如,對于句子 “I love natural language processing”,可能會將 “love” 替換為 [MASK],模型需要根據上下文預測出 “love”。
下一句預測任務用于學習句子之間的關系。給定一對句子,判斷第二個句子是否是第一個句子的下一句。例如,句子對 “今天天氣很好。我們去公園散步吧。” 標簽為正例,而 “今天天氣很好。我喜歡吃蘋果。” 標簽為負例。
BERT 通過最小化這兩個任務的損失函數進行預訓練,損失函數為:
L = L M L M + L N S P L = L_{MLM} + L_{NSP} L=LMLM?+LNSP?
三、代碼實現
下面我們使用 PyTorch 實現一個簡單的 Transformer 編碼器和 BERT 預訓練模型。
1. 注意力機制
import torch
import torch.nn as nndef scaled_dot_product_attention(Q, K, V):d_k = K.size(-1)scores = torch.matmul(Q, K.transpose(-2, -1)) / torch.sqrt(torch.tensor(d_k, dtype=torch.float32))attention_weights = nn.functional.softmax(scores, dim=-1)return torch.matmul(attention_weights, V)
2. 多頭注意力機制
class MultiHeadAttention(nn.Module):def __init__(self, d_model, num_heads):super(MultiHeadAttention, self).__init__()self.num_heads = num_headsself.d_model = d_modelself.depth = d_model // num_headsself.WQ = nn.Linear(d_model, d_model)self.WK = nn.Linear(d_model, d_model)self.WV = nn.Linear(d_model, d_model)self.WO = nn.Linear(d_model, d_model)def split_heads(self, x):batch_size = x.size(0)return x.view(batch_size, -1, self.num_heads, self.depth).transpose(1, 2)def forward(self, X):Q = self.split_heads(self.WQ(X))K = self.split_heads(self.WK(X))V = self.split_heads(self.WV(X))attention = scaled_dot_product_attention(Q, K, V)concatenated_attention = attention.transpose(1, 2).contiguous().view(-1, self.d_model)return self.WO(concatenated_attention)
3. Transformer 編碼器層
class TransformerEncoderLayer(nn.Module):def __init__(self, d_model, num_heads):super(TransformerEncoderLayer, self).__init__()self.attention = MultiHeadAttention(d_model, num_heads)self.ffn = nn.Sequential(nn.Linear(d_model, d_model * 4),nn.ReLU(),nn.Linear(d_model * 4, d_model))self.layernorm1 = nn.LayerNorm(d_model)self.layernorm2 = nn.LayerNorm(d_model)def forward(self, X):attn_output = self.attention(X)X = self.layernorm1(X + attn_output)ffn_output = self.ffn(X)return self.layernorm2(X + ffn_output)
4. Transformer 編碼器
class TransformerEncoder(nn.Module):def __init__(self, num_layers, d_model, num_heads):super(TransformerEncoder, self).__init__()self.layers = nn.ModuleList([TransformerEncoderLayer(d_model, num_heads) for _ in range(num_layers)])def forward(self, X):for layer in self.layers:X = layer(X)return X
5. BERT 模型
class BERT(nn.Module):def __init__(self, vocab_size, num_layers, d_model, num_heads):super(BERT, self).__init__()self.embedding = nn.Embedding(vocab_size, d_model)self.transformer = TransformerEncoder(num_layers, d_model, num_heads)self.mlm_head = nn.Linear(d_model, vocab_size)self.nsp_head = nn.Linear(d_model, 2)def forward(self, X, masked_indices=None):X = self.embedding(X)X = self.transformer(X)if masked_indices is not None:masked_X = torch.gather(X, 1, masked_indices.unsqueeze(-1).repeat(1, 1, X.size(-1)))mlm_logits = self.mlm_head(masked_X)else:mlm_logits = Nonensp_logits = self.nsp_head(X[:, 0])return mlm_logits, nsp_logits
以上代碼實現了 Transformer 編碼器和 BERT 模型的基本結構。在實際應用中,還需要進行數據預處理、模型訓練和評估等步驟。
四、總結
Transformer 和 BERT 作為 NLP 領域的重要技術,以其獨特的架構和強大的性能,推動了 NLP 技術的快速發展。通過本文對 Transformer 和 BERT 的背景介紹、公式推導和代碼實現,相信大家對它們有了更深入的理解。隨著研究的不斷深入,Transformer 和 BERT 的應用場景也在不斷拓展,未來它們將在更多領域發揮重要作用。希望本文能為大家的學習和研究提供幫助,歡迎大家在評論區交流討論。