返回文章列表

TensorFlow 建構 Attention 機制與 Transformer 模型

本文深入探討如何使用 TensorFlow 建構 Attention 機制和 Transformer 模型,包含 MultiHeadAttention、自定義 Attention Layer、以及 TensorFlow Model Garden 中的 Transformer 層等實作方式,並以 IMDB

深度學習 自然語言處理

深度學習模型中,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 是一種機制,允許模型關注輸入序列中的不同部分,以便更好地理解輸入資料。透過使用多個頭,模型可以捕捉到輸入序列中的不同模式和關係。

圖表翻譯:

在這個圖表中,我們展示了 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_layertf.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 層來實作注意力機制的流程圖。 在這個流程圖中,查詢輸入、鍵輸入和值輸入是注意力機制的三個輸入,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_scaleTrue以啟用注意力權重的縮放,並指定了一個丟棄率以緩解過擬合。

然後,我們對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 方法用於定義層的可訓練權重。在這裡,我們定義了兩個權重:Wb,分別使用正常分佈和零初始值進行初始化。
  • add_weight 方法用於向層增加可訓練權重,需要指定權重的形狀和初始值。
  • super(Attention, self).build(input_shape) 用於呼叫父類別的 build 方法,以完成層的初始化。

圖表翻譯:

此圖表描述了自訂注意力層的初始化過程,從初始化開始,到定義權重,然後初始化父類別,最終完成初始化。

自訂注意力層的實作

在這個範例中,我們建立了一個自訂的注意力層,繼承自 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

圖表翻譯:

在這個圖表中,我們展示了注意力層的計算流程,從輸入資料到最終的輸出。

使用 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.Inputtf.keras.layers.Embedding 來實作。
  • 然後,我們使用雙向 LSTM 層來提取序列的特徵,使用 tf.keras.layers.Bidirectionaltf.keras.layers.LSTM 來實作。
  • 接下來,我們使用 Transformer 層來實作自注意力機制,使用 tf.keras.layers.MultiHeadAttention 來實作。
  • 我們增加了層歸一化和全連線神經網路,使用 tf.keras.layers.LayerNormalizationtf.keras.layers.Dense 來實作。
  • 最後,我們定義了輸出層,使用 tf.keras.layers.Dense 來實作。
  • 我們建立了模型,使用 tf.keras.Model 來實作。
  • 我們編譯了模型,指定最佳化器和損失函式,使用 tf.keras.optimizers.Adambinary_crossentropy 來實作。
  • 我們訓練了模型,使用 model.fit 來實作。

圖表翻譯:

此圖示為 Transformer 模型的架構,包括輸入層、嵌入層、自注意力機制、層歸一化、全連線神經網路和輸出層。

深入 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])

圖表翻譯:

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title TensorFlow 建構 Attention 機制與 Transformer 模型

package "機器學習流程" {
    package "資料處理" {
        component [資料收集] as collect
        component [資料清洗] as clean
        component [特徵工程] as feature
    }

    package "模型訓練" {
        component [模型選擇] as select
        component [超參數調優] as tune
        component [交叉驗證] as cv
    }

    package "評估部署" {
        component [模型評估] as eval
        component [模型部署] as deploy
        component [監控維護] as monitor
    }
}

collect --> clean : 原始資料
clean --> feature : 乾淨資料
feature --> select : 特徵向量
select --> tune : 基礎模型
tune --> cv : 最佳參數
cv --> eval : 訓練模型
eval --> deploy : 驗證模型
deploy --> monitor : 生產模型

note right of feature
  特徵工程包含:
  - 特徵選擇
  - 特徵轉換
  - 降維處理
end note

note right of eval
  評估指標:
  - 準確率/召回率
  - F1 Score
  - AUC-ROC
end note

@enduml

這個過程將輸入資料轉換為適合 Transformer 編碼器的格式。接下來,我們可以使用 TransformerEncoderBlock 來建立 Transformer 編碼器,並將其應用於二元分類別任務。

Transformers 的位置嵌入和編碼器區塊

在 Transformers 的架構中,位置嵌入(Positional Embedding)是一個重要的元件,負責為輸入序列中的每個位置提供一個唯一的嵌入向量。這使得模型可以學習到輸入序列中不同位置的元素之間的關係。

從技術架構視角來看,本文深入探討了在 TensorFlow 中構建 Attention 機制與 Transformer 模型的各種方法,涵蓋了自定義 Attention 層、利用 TensorFlow 內建的 AttentionMultiHeadAttention 層,以及使用 TensorFlow Model Garden 中的 TransformerEncoderBlock 等多種實作策略。分析比較了不同方法的優劣,例如自定義層的靈活性與內建層的便捷性,同時也闡明瞭位置嵌入在 Transformer 模型中的重要性,以及如何結合詞嵌入(Token Embedding)和位置嵌入來提升模型效能。然而,文章並未深入探討不同注意力機制(例如 Dot-product attention 和 Luong-style attention)的效能差異及適用場景,這也是未來可以深入研究的方向。展望未來,隨著 Transformer 架構的持續發展和社群的積極貢獻,預期會有更多高效且易用的 Transformer 模組和工具出現,進一步降低開發門檻並拓展其應用範圍。對於希望將注意力機制和 Transformer 應用於實際專案的開發者,建議優先使用 TensorFlow 提供的內建層和 Model Garden 中的預訓練模型,以提升開發效率並確保模型效能。