深度學習模型中,Attention 機制賦予模型聚焦輸入序列特定部分的能力,提升理解力。本文將使用 TensorFlow 建構 Attention 機制,並以 IMDB 電影評論分類別為例,示範如何應用於實際任務。首先,我們會使用 tf.keras.layers.MultiHeadAttention
建立多頭注意力層,接著探討如何自定義 Attention Layer,最後則會使用 TensorFlow Model Garden 中的 Transformer 層,包含位置嵌入和編碼器區塊,建構更進階的 Transformer 模型。過程中,我們會詳細說明各個元件的程式碼實作、功能和原理,並提供圖表輔助理解。透過這些實作範例,讀者可以更深入地理解 Attention 機制和 Transformer 模型的運作方式,並學習如何應用於各種自然語言處理任務。
建立 Attention Layer
現在,我們可以建立 Attention Layer。Attention Mechanism 是一種機制,允許模型關注輸入序列中的不同部分,以便更好地理解輸入資料。在這個例子中,我們將使用 tf.keras.layers.MultiHeadAttention
類別來建立 Attention Layer。
from tensorflow.keras.layers import MultiHeadAttention
attention_layer = MultiHeadAttention(num_heads=8, key_dim=128)
在這個例子中,我們建立了一個具有 8 個頭的 Attention Layer,每個頭的 key dimension 為 128。
內容解密:
在這個段落中,我們使用了 tf.keras.layers.MultiHeadAttention
類別來建立 Attention Layer。MultiHeadAttention 是一種機制,允許模型關注輸入序列中的不同部分,以便更好地理解輸入資料。透過使用多個頭,模型可以捕捉到輸入序列中的不同模式和關係。
圖表翻譯:
graph LR A[輸入序列] --> B[Attention Layer] B --> C[多頭注意力機制] C --> D[輸出]
在這個圖表中,我們展示了 Attention Layer 的架構。輸入序列首先被輸入到 Attention Layer,然後經過多頭注意力機制,最後產生輸出。
使用 TensorFlow 的 Attention 層
TensorFlow 提供了一個名為 tf.keras.layers.Attention
的 Attention 層,可以用於實作 dot-product 或 Luong-style 的注意力機制。這個層需要兩個輸入:查詢張量(query tensor)和值張量(value tensor)。另外,還可以提供一個鍵張量(key tensor),如果不提供,則使用值張量作為鍵和值。
由於 Attention 層需要多個輸入,因此無法使用順序 API 來建立模型。相反,我們將使用功能 API 來構建模型。以下是相關的程式碼:
text_input = tf.keras.Input(shape=(None,))
在這段程式碼中,tf.keras.Input
用於定義模型的輸入層。shape
引數指定了輸入資料的形狀,在這裡是 (None,)
,表示輸入是一個變長的序列。
接下來,我們需要定義查詢、鍵和值張量。假設我們有三個輸入:查詢輸入、鍵輸入和值輸入。
query_input = tf.keras.Input(shape=(None,), name='query')
key_input = tf.keras.Input(shape=(None,), name='key')
value_input = tf.keras.Input(shape=(None,), name='value')
然後,我們可以使用 tf.keras.layers.Attention
層來實作注意力機制。
attention_layer = tf.keras.layers.Attention()
output = attention_layer([query_input, value_input, key_input])
在這裡,attention_layer
是 tf.keras.layers.Attention
的例項,output
是注意力機制的輸出結果。
最後,我們可以定義模型的輸出層和編譯模型。
model = tf.keras.Model(inputs=[query_input, key_input, value_input], outputs=output)
model.compile(optimizer='adam', loss='mean_squared_error')
這樣就完成了使用 TensorFlow 的 Attention 層來實作注意力機制的過程。
內容解密:
上述程式碼展示瞭如何使用 tf.keras.layers.Attention
層來實作注意力機制。首先,我們定義了查詢、鍵和值輸入,然後使用 tf.keras.layers.Attention
層來計算注意力權重和輸出結果。最後,我們定義了模型的輸出層和編譯模型。
圖表翻譯:
此圖示為使用 TensorFlow 的 Attention 層來實作注意力機制的流程圖。
flowchart TD A[查詢輸入] --> B[鍵輸入] B --> C[值輸入] C --> D[Attention 層] D --> E[注意力權重] E --> F[輸出結果]
在這個流程圖中,查詢輸入、鍵輸入和值輸入是注意力機制的三個輸入,Attention 層計算注意力權重和輸出結果。
使用 Attention Mechanism 的神經網路模型構建
在深度學習中,Attention Mechanism是一種強大的工具,能夠幫助模型關注輸入序列中的重要部分。以下是使用TensorFlow構建的一個簡單的神經網路模型,該模型使用Attention Mechanism來處理變長整數序列。
模型架構
首先,我們定義了輸入層,該層接受變長整數序列作為輸入。接下來,我們使用tf.keras.layers.Embedding
層將每個整數值對映到一個稠密向量表示。這一步驟對於將原始資料轉換為神經網路可以理解的格式至關重要。
text_input = tf.keras.layers.Input(shape=(None,))
text_embeddings = tf.keras.layers.Embedding(num_words_to_keep, 32, input_length=max_words)(text_input)
增加捲積層和注意力機制
接著,我們增加了一個卷積層,以提取序列中的區域性特徵。然後,我們使用tf.keras.layers.Attention
層實作注意力機制,該機制允許模型根據輸入序列的不同部分分配不同的權重。
sequence_encoding = tf.keras.layers.Conv1D(64, kernel_size=4, padding='same')(text_embeddings)
attention_sequence = tf.keras.layers.Attention(use_scale=True, dropout=0.6)([sequence_encoding, sequence_encoding])
全域性平均池化和密集層
為了進一步提取序列中的全域性特徵,我們使用tf.keras.layers.GlobalAveragePooling1D
層對編碼序列和注意力序列進行全域性平均池化。最後,我們使用tf.keras.layers.Dense
層輸出最終結果。
query_encoding = tf.keras.layers.GlobalAveragePooling1D()(sequence_encoding)
query_value_attention = tf.keras.layers.GlobalAveragePooling1D()(attention_sequence)
concat_layer = tf.keras.layers.Concatenate()([query_encoding, query_value_attention])
outputs = tf.keras.layers.Dense(1)(concat_layer)
模型定義和編譯
我們定義了模型的輸入和輸出,並使用Adam最佳化器和二元交叉熵損失函式進行編譯。
model = tf.keras.Model(inputs=text_input, outputs=outputs)
model.compile(optimizer=tf.keras.optimizers.Adam(1e-4), loss='binary_crossentropy', metrics=['accuracy'])
模型訓練
最後,我們使用訓練集和驗證集對模型進行訓練。
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=20, batch_size=128, verbose=2)
這個例子展示瞭如何使用Attention Mechanism構建一個簡單的神經網路模型來處理變長整數序列。透過調整模型的架構和超引數,可以應用這種方法於各種自然語言處理任務中。
文字編碼和注意力機制
在深度學習中,文字編碼是一個非常重要的步驟,能夠將原始文字轉換為機器能夠理解的資料。其中,嵌入(embedding)是一種常用的文字編碼方法,能夠將每個詞彙對映為一個固定維度的向量。
在本例中,我們使用了32維的嵌入向量作為輸出,並設定最大輸入序列長度為max_words
。接著,我們建立了一個一維卷積層,具有100個過濾器和4的核大小。padding='same'
確保卷積輸出的形狀與輸入相同。然後,我們將輸入的text_embeddings
傳遞給定義的卷積層,得到sequence_encoding
,代表編碼序列。
接下來,我們將注意力機制應用於sequence_encoding
以計算查詢-值注意力。為此,我們將sequence_encoding
放入列表中兩次,作為查詢和值向量,並將列表作為輸入傳遞給注意力層。注意力機制為輸入序列的不同部分賦予不同的權重,捕捉重要訊息。我們設定use_scale
為True
以啟用注意力權重的縮放,並指定了一個丟棄率以緩解過擬合。
然後,我們對sequence_encoding
沿序列軸應用全域性平均池化,計算每個過濾器在序列長度上的平均值,得到查詢編碼。同樣,我們對attention_sequence
應用全域性平均池化,得到查詢-值注意力。接著,我們將查詢編碼和查詢-值注意力串聯起來,得到一個供後續前饋神經網路部分使用的層。
由於這是一個二元分類別問題,我們在串聯層上應用了一個單位密集層以產生模型的最終輸出。最後,我們例項化了模型,並編譯並訓練了它以進行二元分類別。
注意力機制的替代方法
除了使用一維卷積層外,我們也可以使用迴圈神經網路(RNN)型別的層進行編碼。例如,在上面的程式碼中,我們可以用LSTM層替換第5行的Conv1D層,如下所示:
sequence_encoding = tf.keras.layers.LSTM(100, return_sequences=True)(text_embeddings)
模型摘要
模型的摘要如下:
圖11.4:注意力模型的預摘要
注意:IMDB資料集中的評論文字已經預處理,每個評論文字都被編碼為一個整數列表(單詞索引)。因此,我們不需要使用任何TextVectorization層來編碼原始文字。
模型評估
模型在測試資料上的最終評估結果如下:
圖11.5:評估模型
模型在測試資料上達到了87.56%的準確率。
使用自訂注意力層
除了使用 TensorFlow 的預設注意力層外,我們也可以建立自訂的注意力層。要在 TensorFlow 中建立自訂層,需要繼承 tf.keras.layers.Layer
類別。在 __init__
方法中,我們可以定義層的特定引數,並呼叫 super().__init__()
初始化基礎層類別。接下來,我們需要實作 build()
方法來定義層的可訓練變數(權重)。我們可以使用 add_weight
方法以所需的形狀和初始值來建立和註冊權重。另外,我們需要實作 call()
方法來定義層的前向傳遞邏輯,這裡是我們指定層如何處理輸入並產生所需輸出的地方。
一旦定義了自訂層,我們就可以在神經網路模型中使用它,方法是將它整合到模型的架構中。透過自訂層,你可以擴充套件 TensorFlow 的功能,並實作標準層集合中不可用的專用層或複雜操作。以下是定義自訂注意力層的範例程式碼:
class Attention(tf.keras.layers.Layer):
def __init__(self, return_sequences=True):
self.return_sequences = return_sequences
super(Attention, self).__init__()
def build(self, input_shape):
self.W = self.add_weight(shape=(input_shape[-1], 1), initializer="normal")
self.b = self.add_weight(shape=(input_shape[1], 1), initializer="zeros")
super(Attention, self).build(input_shape)
內容解密:
__init__
方法用於初始化層的屬性,包括return_sequences
,它控制是否傳回序列輸出。然後呼叫父類別的__init__
方法。build
方法用於定義層的可訓練權重。在這裡,我們定義了兩個權重:W
和b
,分別使用正常分佈和零初始值進行初始化。add_weight
方法用於向層增加可訓練權重,需要指定權重的形狀和初始值。super(Attention, self).build(input_shape)
用於呼叫父類別的build
方法,以完成層的初始化。
圖表翻譯:
flowchart TD A[初始化] --> B[定義權重] B --> C[初始化父類別] C --> D[完成初始化]
此圖表描述了自訂注意力層的初始化過程,從初始化開始,到定義權重,然後初始化父類別,最終完成初始化。
自訂注意力層的實作
在這個範例中,我們建立了一個自訂的注意力層,繼承自 tf.keras.layers.Layer
類別。這個層可以選擇是否傳回序列資料,取決於 return_sequences
引數。
class AttentionLayer(tf.keras.layers.Layer):
def __init__(self, return_sequences=False):
super(AttentionLayer, self).__init__()
self.return_sequences = return_sequences
def build(self, input_shape):
self.W = self.add_weight(name='W', shape=(input_shape[-1], 1),
initializer='random_normal')
self.b = self.add_weight(name='b', shape=(input_shape[1], 1),
initializer='zeros')
def call(self, x):
dot_prod = tf.keras.activations.tanh(tf.matmul(x, self.W) + self.b)
attention = tf.keras.activations.softmax(dot_prod, axis=1)
out_sequences = x * attention
if self.return_sequences:
return out_sequences
return tf.math.reduce_sum(out_sequences, axis=1)
內容解密:
在這段程式碼中,我們定義了一個名為 AttentionLayer
的類別,繼承自 tf.keras.layers.Layer
。這個類別有兩個方法:__init__
和 call
。
__init__
方法用於初始化類別,定義了return_sequences
引數。build
方法用於定義層的權重,包括一個權重矩陣W
和一個偏差向量b
。call
方法是層的主邏輯,計算注意力權重並將其應用於輸入資料x
。
圖表翻譯:
flowchart TD A[輸入資料] --> B[計算點積] B --> C[應用tanh啟用函式] C --> D[計算注意力權重] D --> E[應用softmax啟用函式] E --> F[計算注意力權重與輸入資料的點積] F --> G[判斷是否傳回序列] G -->|是| H[傳回注意力權重與輸入資料的點積] G -->|否| I[傳回注意力權重與輸入資料的點積之和]
在這個圖表中,我們展示了注意力層的計算流程,從輸入資料到最終的輸出。
使用 TensorFlow 的自帶 Transformer 層實作 IMDB 電影評論分類別模型
在前面的章節中,我們探討瞭如何使用自定義的注意力機制來增強模型的表達能力。現在,我們將使用 TensorFlow 的官方模型中的 Transformer 層來實作一個根據 Transformer 的 IMDB 電影評論分類別模型。
定義模型架構
首先,我們需要定義模型的輸入層和嵌入層。假設我們的輸入文字序列的最大長度為 max_words
,我們可以使用以下程式碼定義輸入層和嵌入層:
text_input = tf.keras.Input(shape=(max_words,))
x = tf.keras.layers.Embedding(num_words_to_keep, 32, input_length=max_words)(text_input)
接下來,我們可以使用雙向 LSTM 層來提取序列的特徵:
x = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32, return_sequences=True))(x)
然後,我們可以使用 Transformer 層來實作自注意力機制:
x = tf.keras.layers.MultiHeadAttention(num_heads=8, key_dim=32)(x, x)
注意,我們在這裡使用了 MultiHeadAttention
層,這是 TensorFlow 官方模型中提供的 Transformer 層的實作。
增加層歸一化和全連線神經網路
根據 Transformer 的架構,我們需要在自注意力機制之後增加層歸一化和全連線神經網路。以下是相關程式碼:
x = tf.keras.layers.LayerNormalization()(x)
x = tf.keras.layers.Dense(64, activation='relu')(x)
定義輸出層
最後,我們可以定義輸出層:
outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x)
建立模型
現在,我們可以建立模型了:
model = tf.keras.Model(inputs=text_input, outputs=outputs)
編譯模型
編譯模型時,我們需要指定最佳化器和損失函式:
model.compile(optimizer=tf.keras.optimizers.Adam(1e-4), loss='binary_crossentropy', metrics=['accuracy'])
訓練模型
訓練模型時,我們可以使用以下程式碼:
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=20, verbose=2)
這樣就完成了使用 TensorFlow 的自帶 Transformer 層實作 IMDB 電影評論分類別模型的過程。
內容解密:
- 我們首先定義了模型的輸入層和嵌入層,使用
tf.keras.Input
和tf.keras.layers.Embedding
來實作。 - 然後,我們使用雙向 LSTM 層來提取序列的特徵,使用
tf.keras.layers.Bidirectional
和tf.keras.layers.LSTM
來實作。 - 接下來,我們使用 Transformer 層來實作自注意力機制,使用
tf.keras.layers.MultiHeadAttention
來實作。 - 我們增加了層歸一化和全連線神經網路,使用
tf.keras.layers.LayerNormalization
和tf.keras.layers.Dense
來實作。 - 最後,我們定義了輸出層,使用
tf.keras.layers.Dense
來實作。 - 我們建立了模型,使用
tf.keras.Model
來實作。 - 我們編譯了模型,指定最佳化器和損失函式,使用
tf.keras.optimizers.Adam
和binary_crossentropy
來實作。 - 我們訓練了模型,使用
model.fit
來實作。
圖表翻譯:
此圖示為 Transformer 模型的架構,包括輸入層、嵌入層、自注意力機制、層歸一化、全連線神經網路和輸出層。
graph LR A[輸入層] --> B[嵌入層] B --> C[自注意力機制] C --> D[層歸一化] D --> E[全連線神經網路] E --> F[輸出層]
深入 TensorFlow Model Garden
TensorFlow Model Garden 是一個使用 TensorFlow 建立的機器學習模型和相關資源的倉函式庫。這個 Model Garden 提供了廣泛的模型,包括最先進的模型,適用於影像分類別、物體偵測、自然語言處理等任務。Model Garden 還包括其他資源,如資料預處理指令碼、評估工具和訓練管線。這些模型是使用 TensorFlow 實作的,並附有預訓練權重和詳細檔案,以方便使用和理解。TensorFlow 官方模型是 Model Garden 的一部分,它是一組使用 TensorFlow 高階 API 的模型集合。
使用 Transformer 層
TensorFlow 提供了 Transformer 層作為 TensorFlow 官方模型 NLP 函式庫的一部分。要使用 Transformer 層,我們需要明確安裝 tf-models-official
函式庫,因為它不隨 Google Colab 提供。請參考以下程式碼:
!pip3 install tf-models-official
安裝完畢後,我們需要先匯入這個函式庫:
import tensorflow_models as tfm
我們將使用 TransformerEncoderBlock
,可在 tfm.nlp.layers
中找到,來建立一個 Transformer 編碼器สำหร我們的模型。注意,我們正在解決一個二元分類別問題,這裡不需要 Transformer 的解碼部分。
建立 Transformer 模型
早先,我們設定了 pad_sequences
函式的 maxlen
引數為 max_words
,其中 max_words
的值為 500。因此,在我們的輸入資料中,每篇評論都會有一個固定 500 個字。在我們的 Transformer 基礎模型中,我們將設定輸入層的形狀為預期的長度,即 (max_words,)
。
在圖 11.2 中,我們觀察到 Transformer 的編碼部分接受輸入資料的位置嵌入和普通 token 嵌入的串接。Token 嵌入可以由 tf.keras.layers.Embedding
層生成。這個層的輸入維度是詞彙大小或是我們早先設定的 num_words_to_keep
,即 5000。位置嵌入可以使用以下方法生成:
內容解密:
from tensorflow.keras.layers import Embedding
# 定義 token 嵌入層
token_embedding = Embedding(input_dim=5000, output_dim=128, input_length=max_words)
位置嵌入可以使用 tf.keras.layers.PositionalEmbedding
生成:
from tensorflow.keras.layers import PositionalEmbedding
# 定義位置嵌入層
positional_embedding = PositionalEmbedding(max_words, 128)
然後,我們可以將這兩個嵌入層串接起來,作為 Transformer 編碼器的輸入:
from tensorflow.keras.layers import Concatenate
# 串接 token 嵌入和位置嵌入
embedded_input = Concatenate()([token_embedding, positional_embedding])
圖表翻譯:
graph LR A[輸入資料] --> B[Token 嵌入] B --> C[位置嵌入] C --> D[串接] D --> E[Transformer 編碼器]
這個過程將輸入資料轉換為適合 Transformer 編碼器的格式。接下來,我們可以使用 TransformerEncoderBlock
來建立 Transformer 編碼器,並將其應用於二元分類別任務。
Transformers 的位置嵌入和編碼器區塊
在 Transformers 的架構中,位置嵌入(Positional Embedding)是一個重要的元件,負責為輸入序列中的每個位置提供一個唯一的嵌入向量。這使得模型可以學習到輸入序列中不同位置的元素之間的關係。
從技術架構視角來看,本文深入探討了在 TensorFlow 中構建 Attention 機制與 Transformer 模型的各種方法,涵蓋了自定義 Attention 層、利用 TensorFlow 內建的 Attention
和 MultiHeadAttention
層,以及使用 TensorFlow Model Garden 中的 TransformerEncoderBlock
等多種實作策略。分析比較了不同方法的優劣,例如自定義層的靈活性與內建層的便捷性,同時也闡明瞭位置嵌入在 Transformer 模型中的重要性,以及如何結合詞嵌入(Token Embedding)和位置嵌入來提升模型效能。然而,文章並未深入探討不同注意力機制(例如 Dot-product attention 和 Luong-style attention)的效能差異及適用場景,這也是未來可以深入研究的方向。展望未來,隨著 Transformer 架構的持續發展和社群的積極貢獻,預期會有更多高效且易用的 Transformer 模組和工具出現,進一步降低開發門檻並拓展其應用範圍。對於希望將注意力機制和 Transformer 應用於實際專案的開發者,建議優先使用 TensorFlow 提供的內建層和 Model Garden 中的預訓練模型,以提升開發效率並確保模型效能。