講透一個強大算法模型,Transformer !!

哈嘍,我是cos大壯!~

這幾天,社群裡 Transformer 相關討論一直進行著,那今兒我準備給大家分享一個以「利用Transformer進行機器翻譯」為主題進行一個分享。

今兒的內容,有點趣味兒,也有點詳細,大家記得收藏起來慢慢學起來。

首先,官話:Transformer 模型是由 Vaswani 等人在 2017 年提出的一種新型神經網絡架構,用於解決序列到序列的任務,比如機器翻譯、文本生成等。它的核心思想是通過「注意力機制」來捕捉序列中的依賴關係,而不依賴傳統的循環神經網絡(RNN)。

其次,這是重點(劃重點):給大家用一個很簡單的方式來解釋Transformer。

Transformer 是一種不依賴於順序處理序列數據的新型模型,它利用注意力機制在處理每個詞時關注整個序列中的其他詞,從而捕捉全局的依賴關係。這使得它在處理長序列時比傳統的循環神經網絡更有效、更快速。

舉一個例子,句子翻譯:

假設我們要把英文句子 ‘I am a student’ 翻譯成中文 ‘我是學生’。下面是如何一步一步進行的。

1. 輸入序列

輸入序列是英文句子 ‘I am a student’。我們將這個句子送入模型。

2. 編碼器處理

編碼器的任務是理解輸入的英文句子。我們可以把它想像成一個特別聰明的閱讀員。

  • 第一步:詞向量表示

    • 每個詞 ‘I’、’am’、’a’ 和 ‘student’ 都會被轉換成一個向量(一個包含數字的列表),這些向量代表了詞的意義。

    第二步:自注意力機制

    • 編碼器會看整個句子,計算每個詞和其他詞之間的關係。

    • 比如,它會理解 ‘I’ 和 ‘am’ 是緊密相關的,’student’ 和 ‘a’ 也是相關的。

    第三步:多層處理

    • 編碼器由多層組成,每層都會重覆上面的自注意力機制,然後更新每個詞的向量表示。

    • 經過多層處理,編碼器對每個詞的理解會越來越深刻,最後得到一組新的詞向量,這些向量包含了整個句子的上下文信息。

    3. 解碼器生成

    解碼器的任務是生成翻譯後的中文句子。可以把它想像成一個翻譯員。

    • 第一步:生成第一個詞

      • 解碼器先看編碼器的輸出(即英文句子的向量表示),然後生成第一個中文詞,比如 ‘我’。

      • 解碼器會用一個特殊的開始標記來啟動翻譯過程。

      第二步:結合已生成的詞和編碼器的輸出

      • 解碼器不僅看編碼器的輸出,還會結合已經生成的中文詞。

      • 假設我們已經生成了 ‘我’,解碼器會結合 ‘我’ 和編碼器的輸出,決定下一個詞是什麼。

      第三步:自注意力機制和交互注意力機制

      • 解碼器也有自己的自注意力機制,用來理解已生成詞之間的關係,比如 ‘我’ 和 ‘是’ 的關係。

      • 同時,解碼器還會使用交互注意力機制,結合編碼器的輸出,理解英文句子和已生成的中文詞的關係。

      第四步:逐詞生成

      • 逐步生成下一個詞,比如生成 ‘是’ 後,解碼器結合 ‘我’、’是’ 和編碼器的輸出,再生成 ‘學生’。

      • 最終,解碼器生成完整的中文句子 ‘我是學生’。

      主要構件

      到這裏,大家應該已經有了一個初步的理解了。

      上面提到了編碼器(Encoder) 和 解碼器(Decoder),是 Transformer 兩個主要部分。每個部分又包含多個相同的層。

      下面的解釋,大家應該是很容易理解了:

      1. 編碼器(Encoder)

      • 負責讀取輸入序列並生成特徵表示。

      • 每層編碼器包含兩個子層:

        • 多頭自注意力機制(Multi-Head Self-Attention):關注輸入序列中不同位置的依賴關係。

        • 前饋神經網絡(Feed-Forward Neural Network):對每個位置的特徵進行獨立處理。

        2. 解碼器(Decoder)

        • 根據編碼器的輸出和前面的解碼器輸出,生成最終序列。

        • 每層解碼器包含三個子層:

          • 多頭自注意力機制:關註解碼器中之前位置的依賴關係。

          • 編碼器-解碼器注意力機制:結合編碼器的輸出與當前解碼器的輸入。

          • 前饋神經網絡:對每個位置的特徵進行獨立處理。

          注意力機制

          注意力機制是 Transformer 的核心,它允許模型在處理當前詞語時「關注」輸入序列中與其相關的其他詞語,從而捕捉更全局的依賴關係。自注意力機制通過計算每個詞與其他詞的「相關性」(也叫注意力分數),然後對這些相關性進行加權求和,從而得到每個詞的新表示。

          原理詳解

          好的,我們將更詳細地探討Transformer模型的每一部分,包括自注意力機制、多頭注意力機制、位置編碼、編碼器和解碼器的結構以及具體的公式推導。

          1. 自注意力機制(Self-Attention Mechanism)

          計算注意力分數

          自注意力機制的核心在於計算序列中每個元素與其他元素的關係,這通過以下步驟完成:

          1. 線性變換生成查詢、鍵和值矩陣:

          對於輸入序列 (形狀為 ),通過線性變換得到查詢矩陣 、鍵矩陣  和值矩陣 

          其中  是可學習的參數矩陣,形狀均為 

          2. 計算注意力分數:

          注意力分數是通過點積計算得到的:

          這裏的  是一個縮放因子,防止點積值過大導致softmax的梯度消失。

          3. 應用softmax函數:

          對注意力分數應用softmax函數,得到注意力權重:

          4. 計算加權和:

          最後,用注意力權重對值矩陣  進行加權求和,得到最終的輸出:

          2. 多頭注意力機制(Multi-Head Attention)

          多頭注意力機制允許模型關注不同位置的信息子空間,通過並行計算多個注意力頭,並將它們的輸出結合在一起:

          1. 並行計算多個注意力頭:

          對輸入序列  進行  次自注意力計算,每次計算使用不同的線性變換參數:

          2. 連接注意力頭的輸出:

          將  個注意力頭的輸出連接起來:

          3. 線性變換多頭輸出:

          對連接後的輸出進行線性變換,得到最終的多頭注意力輸出:

          3. 位置編碼(Positional Encoding)

          由於Transformer沒有內置的序列順序信息,必須通過位置編碼來引入位置信息。位置編碼通常通過正弦和餘弦函數生成:

          其中  是序列中的位置,  是維度索引。

          4. 編碼器(Encoder)

          編碼器由多層堆疊的自注意力層和前饋神經網絡層組成。

          自注意力層

          每一層的自注意力機制如上所述,計算如下:

          前饋神經網絡層

          前饋神經網絡層包括兩個線性變換和一個激活函數(如ReLU):

          5. 解碼器(Decoder)

          解碼器結構與編碼器類似,但多了一個編碼-解碼注意力層。

          自注意力層

          與編碼器的自注意力層相同。

          編碼-解碼注意力層

          這個層的計算考慮到了編碼器的輸出:

          這裏的  和  來自編碼器的輸出,  來自解碼器的輸入。

          前饋神經網絡層

          與編碼器中的前饋神經網絡層相同。

          6. 訓練與優化

          Transformer模型通常通過以下損失函數和優化方法進行訓練:

          • 損失函數: 交叉熵損失函數(Cross-Entropy Loss)用於計算預測序列與目標序列之間的誤差。

          • 優化方法: 常用Adam優化器,並結合學習率調度策略(如學習率預熱和衰減)。

          7. 公式總結

          這裏,再給大家總結一下~

          1. 自注意力:

          2. 多頭注意力:

          3. 位置編碼:

          4. 前饋神經網絡:

          通過這些公式和結構,Transformer模型能夠高效地處理序列數據,並捕捉長距離依賴關係,極大地提升了自然語言處理任務的性能。

          完整案例

          這裏,咱們完成一個 利用Transformer進行機器翻譯 的簡易項目。

          數據集介紹

          我們將使用一個簡單的中英文平行語料庫來訓練Transformer模型。這些數據可以從公開的多語言數據集(如Tatoeba項目)中獲取。

          示例數據:

中文:  你好嗎?
英文:  How are you?

算法流程

1. 數據預處理

  • 分詞、標記化、構建詞彙表。

  • 轉換成模型輸入格式。

2. 模型構建

  • 使用Transformer架構,包括編碼器和解碼器。

3. 訓練模型

  • 定義損失函數和優化器。

  • 訓練模型,監控損失。

4. 模型評估

  • 使用驗證集評估模型性能。

  • 繪製訓練損失和驗證損失曲線。

5. 翻譯句子

  • 使用訓練好的模型翻譯新句子。

完整代碼

使用TensorFlow和Keras來實現Transformer進行機器翻譯。

import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np

# 數據預處理
# 示例數據
data = [
    ('你好', 'Hello'),
    ('你好嗎?', 'How are you?'),
    ('謝謝', 'Thank you'),
    ('再見', 'Goodbye'),
]

def preprocess_sentence(sentence):
    sentence = sentence.lower().strip()
    sentence = ' '.join(sentence)
    return sentence

input_texts = []
target_texts = []

for src, tgt in data:
    input_texts.append(preprocess_sentence(src))
    target_texts.append('<start> ' + preprocess_sentence(tgt) + ' <end>')

# 構建詞彙表
input_vocab = sorted(set(''.join(input_texts)))
target_vocab = sorted(set(' '.join(target_texts).split(' ')))

input_vocab_size = len(input_vocab) + 1
target_vocab_size = len(target_vocab) + 1

input_token_index = dict([(char, i + 1) for i, char in enumerate(input_vocab)])
target_token_index = dict([(word, i + 1) for i, word in enumerate(target_vocab)])

max_encoder_seq_length = max([len(txt) for txt in input_texts])
max_decoder_seq_length = max([len(txt.split(' ')) for txt in target_texts])

encoder_input_data = np.zeros((len(input_texts), max_encoder_seq_length), dtype='float32')
decoder_input_data = np.zeros((len(input_texts), max_decoder_seq_length), dtype='float32')
decoder_target_data = np.zeros((len(input_texts), max_decoder_seq_length, target_vocab_size), dtype='float32')

for i, (input_text, target_text) in enumerate(zip(input_texts, target_texts)):
    for t, char in enumerate(input_text):
        encoder_input_data[i, t] = input_token_index[char]
    for t, word in enumerate(target_text.split(' ')):
        decoder_input_data[i, t] = target_token_index[word]
        if t > 0:
            decoder_target_data[i, t - 1, target_token_index[word]] = 1.0

# 構建Transformer模型
from tensorflow.keras.layers import Input, Embedding, LSTM, Dense
from tensorflow.keras.models import Model

# 定義編碼器
encoder_inputs = Input(shape=(None,))
encoder_embedding = Embedding(input_vocab_size, 256)(encoder_inputs)
encoder_lstm = LSTM(256, return_state=True)
encoder_outputs, state_h, state_c = encoder_lstm(encoder_embedding)
encoder_states = [state_h, state_c]

# 定義解碼器
decoder_inputs = Input(shape=(None,))
decoder_embedding = Embedding(target_vocab_size, 256)(decoder_inputs)
decoder_lstm = LSTM(256, return_sequences=True, return_state=True)
decoder_outputs, _, _ = decoder_lstm(decoder_embedding, initial_state=encoder_states)
decoder_dense = Dense(target_vocab_size, activation='softmax')
decoder_outputs = decoder_dense(decoder_outputs)

# 定義模型
model = Model([encoder_inputs, decoder_inputs], decoder_outputs)

# 編譯模型
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')

# 訓練模型
history = model.fit(
    [encoder_input_data, decoder_input_data], decoder_target_data,
    batch_size=64,
    epochs=100,
    validation_split=0.2
)

# 繪製訓練損失和驗證損失曲線
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.legend()
plt.show()

# 翻譯新句子
def decode_sequence(input_seq):
    states_value = encoder_model.predict(input_seq)

    target_seq = np.zeros((1, 1))
    target_seq[0, 0] = target_token_index['<start>']

    stop_condition = False
    decoded_sentence = ''

    while not stop_condition:
        output_tokens, h, c = decoder_model.predict([target_seq] + states_value)

        sampled_token_index = np.argmax(output_tokens[0, -1, :])
        sampled_word = target_vocab[sampled_token_index - 1]

        decoded_sentence += ' ' + sampled_word

        if (sampled_word == '<end>' or
           len(decoded_sentence.split(' ')) > max_decoder_seq_length):
            stop_condition = True

        target_seq = np.zeros((1, 1))
        target_seq[0, 0] = sampled_token_index

        states_value = [h, c]

    return decoded_sentence

# 構建編碼器和解碼器模型
encoder_model = Model(encoder_inputs, encoder_states)

decoder_state_input_h = Input(shape=(256,))
decoder_state_input_c = Input(shape=(256,))
decoder_states_inputs = [decoder_state_input_h, decoder_state_input_c]
decoder_outputs, state_h, state_c = decoder_lstm(
    decoder_embedding, initial_state=decoder_states_inputs)
decoder_states = [state_h, state_c]
decoder_outputs = decoder_dense(decoder_outputs)
decoder_model = Model(
    [decoder_inputs] + decoder_states_inputs,
    [decoder_outputs] + decoder_states)

# 測試翻譯
for seq_index in range(len(input_texts)):
    input_seq = encoder_input_data[seq_index: seq_index + 1]
    decoded_sentence = decode_sequence(input_seq)
    print('-')
    print('Input sentence:', input_texts[seq_index])
    print('Decoded sentence:', decoded_sentence)

整個代碼,大家可以根據註釋讀懂。

算法優化點

1. 增加數據量:使用更大規模的平行語料庫,提高模型的泛化能力。

2. 調整模型架構:增加Transformer層數、調整每層的隱藏單元數量。使用多頭注意力機制增強模型性能。

3. 超參數調整:調整學習率、batch size等超參數,使用網格搜索或貝葉斯優化。

4. 正則化技術:使用dropout、L2正則化等方法防止過擬合。

5. 優化訓練過程:使用更高級的優化器(如Adam)。增加訓練輪數,使用學習率衰減策略。

6. 數據增強:使用數據增強技術,如回譯(back-translation)等,增強訓練數據的多樣性。

通過這些優化,可以進一步提高Transformer模型的機器翻譯性能。