深度學習模型中,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_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 層來實作注意力機制的流程圖。

  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_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 方法,以完成層的初始化。

圖表翻譯:

  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.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 模型的架構,包括輸入層、嵌入層、自注意力機制、層歸一化、全連線神經網路和輸出層。

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