返回文章列表

Transformer模型架構與訓練流程

本文探討 Transformer 模型的架構、訓練流程及程式碼實作。從自然語言處理的發展歷程談起,逐步引出 Transformer 的核心概念,並以 Python 程式碼展示模型的建構、訓練、翻譯流程,以及如何從原型設計環境遷移至生產環境。

機器學習 自然語言處理

Transformer 架構的出現革新了自然語言處理領域,其自注意力機制有效解決了序列資料長距離依賴的問題。本文從早期自然語言處理技術的限制談起,介紹了神經網路模型和注意力機制的演進,最終引出 Transformer 架構及其優勢。文章提供了 Python 程式碼示例,詳細說明瞭 Transformer 模型的實作、訓練和翻譯過程,並包含程式碼的解說,方便讀者理解。此外,文章也探討瞭如何將根據 Jupyter Notebook 的原型設計環境轉移至生產環境,並以 StyleSprint 公司的產品描述生成案例說明瞭 Docker 容器化佈署的優勢和實踐方法。

從自然語言處理的基礎追溯到Transformer的影響

Transformer的出現極大地推動了自然語言處理(NLP)領域的發展,為當今最先進的生成式語言模型奠定了基礎。本章節闡述了NLP的發展歷程,這些進步為這一關鍵創新鋪平了道路。最初的統計技術,如計數向量和TF-IDF,能夠提取基本的詞語模式,但它們在捕捉語義細微差別方面存在侷限性。

引入神經語言模型

隨著神經語言模型的引入,透過詞嵌入技術實作了更深入的語義表示。然而,迴圈神經網路(RNN)在處理較長序列時遇到了瓶頸。這促使了卷積神經網路(CNN)的出現,CNN透過平行計算提高了運算效率,但犧牲了對全域性上下文的感知能力。

注意力機制的誕生

注意力機制的出現成為了一個重要的里程碑。2017年,Vaswani等人進一步發展了這些進展,提出了Transformer架構。Transformer的自注意力機制能夠以平行化的方式對廣泛序列進行上下文建模。層疊的編碼器-解碼器結構精細地最佳化了表示方法,以辨別諸如翻譯等任務所需的關係。

Transformer的架構與優勢

Transformer憑藉其可平行化和可擴充套件的自注意力設計,設定了新的效能基準。其核心原則是當今高效能生成式語言模型(如GPT)的架構基礎。

Transformer模型的實作

class Transformer(nn.Module):
    def __init__(self, d_model, nhead, d_ff, num_encoder_layers, num_decoder_layers, src_vocab_size, tgt_vocab_size):
        super(Transformer, self).__init__()
        self.encoder = Encoder(d_model, nhead, d_ff, num_encoder_layers, src_vocab_size)
        self.decoder = Decoder(d_model, nhead, d_ff, num_decoder_layers, tgt_vocab_size)

    def forward(self, src, tgt):
        memory = self.encoder(src)
        output = self.decoder(tgt, memory)
        return output

內容解密:

  • Transformer類別繼承自nn.Module,定義了Transformer模型的架構。
  • __init__方法初始化了編碼器和解碼器,分別由EncoderDecoder類別例項化。
  • forward方法定義了前向傳播過程,首先透過編碼器處理源輸入,然後由解碼器根據編碼器的輸出和目標輸入生成輸出。

訓練函式

def train(model, loss_fn, optimizer, NUM_EPOCHS=10):
    for epoch in range(NUM_EPOCHS):
        model.train()
        total_loss = 0
        for batch in batch_iterator:
            src, tgt = batch
            optimizer.zero_grad()
            output = model(src, tgt)
            loss = loss_fn(output.view(-1, TGT_VOCAB_SIZE), tgt.view(-1))
            loss.backward()
            optimizer.step()
            total_loss += loss.item()
        print(f"Epoch {epoch}, Loss {total_loss / len(batch_iterator)}")

內容解密:

  • train函式負責模型的訓練過程,遍歷多個epoch和批次,計算損失並更新模型引數。
  • 在每個批次中,首先清空梯度,然後進行前向傳播、計算損失、反向傳播和引數更新。
  • 訓練過程中記錄總損失,並在每個epoch結束時列印平均損失。

翻譯函式

def translate(model, src_text, src_tokenizer, tgt_tokenizer, max_target_length=50):
    model.eval()
    src_tokens = src_tokenizer.encode(src_text).ids
    src_tensor = torch.LongTensor(src_tokens).unsqueeze(0)
    tgt_sos_idx = tgt_tokenizer.token_to_id("<sos>")
    tgt_eos_idx = tgt_tokenizer.token_to_id("<eos>")
    tgt_tensor = torch.LongTensor([tgt_sos_idx]).unsqueeze(0)
    for i in range(max_target_length):
        with torch.no_grad():
            output = model(src_tensor, tgt_tensor)
            predicted_token_idx = output.argmax(dim=2)[0, -1].item()
            if predicted_token_idx == tgt_eos_idx:
                break
            tgt_tensor = torch.cat((tgt_tensor, torch.LongTensor([[predicted_token_idx]])), dim=1)
    translated_token_ids = tgt_tensor[0, 1:].tolist()
    translated_text = tgt_tokenizer.decode(translated_token_ids)
    return translated_text

內容解密:

  • translate函式利用訓練好的模型將源文字翻譯成目標語言。
  • 該函式逐步生成翻譯結果,每一步根據模型的輸出選擇最可能的詞元,直到生成結束符號或達到最大目標長度。
  • 最終,將生成的詞元ID列表解碼成目標語言文字。

主要執行流程

if __name__ == "__main__":
    # 超引數定義
    NUM_ENCODER_LAYERS = 2
    NUM_DECODER_LAYERS = 2
    DROPOUT_RATE = 0.1
    EMBEDDING_DIM = 512
    NHEAD = 8
    FFN_HID_DIM = 2048
    BATCH_SIZE = 31
    LEARNING_RATE = 0.001
    
    # 分詞器和模型的例項化
    en_tokenizer = train_tokenizer(EN_TEXT)
    fr_tokenizer = train_tokenizer(FR_TEXT)
    SRC_VOCAB_SIZE = len(en_tokenizer.get_vocab())
    TGT_VOCAB_SIZE = len(fr_tokenizer.get_vocab())
    
    # 資料張量化與資料集建立
    src_tensor = tensorize_data(EN_TEXT, en_tokenizer)
    tgt_tensor = tensorize_data(FR_TEXT, fr_tokenizer)
    dataset = TextDataset(src_tensor, tgt_tensor)
    
    # 模型初始化與訓練
    model = Transformer(EMBEDDING_DIM, NHEAD, FFN_HID_DIM, NUM_ENCODER_LAYERS, NUM_DECODER_LAYERS, SRC_VOCAB_SIZE, TGT_VOCAB_SIZE)
    loss_fn = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE)
    batch_iterator = DataLoader(dataset, batch_size=BATCH_SIZE, shuffle=True, drop_last=True)
    train(model, loss_fn, optimizer, NUM_EPOCHS=10)
    
    # 翻譯示例
    src_text = "hello, how are you?"
    translated_text = translate(model, src_text, en_tokenizer, fr_tokenizer)
    print(translated_text)

內容解密:

  • 在主執行區塊中,首先定義了超引數,然後例項化了分詞器和模型。
  • 將資料轉換為張量並建立資料集,接著進行模型的訓練。
  • 最後,使用訓練好的模型進行了一個簡單的翻譯示例。

從原型到生產環境:應用預訓練生成模型

在前面的章節中,我們探討了生成式人工智慧的基本原理,介紹了各種生成模型,如生成對抗網路(GANs)、擴散模型和Transformer,並深入瞭解了自然語言處理(NLP)的變革性影響。現在,我們將進入生成式人工智慧的實際應用階段,並透過一個具體的例子來進行探討。這種方法將提供一個具體的背景,使技術層面更加貼切,學習體驗更加引人入勝。

StyleSprint:自動化產品描述生成

我們將介紹“StyleSprint”,一家希望提升其線上形象的服裝店。其中一種方法是為其各種產品編寫獨特且吸引人的產品描述。然而,手動為龐大的庫存建立吸引人的描述是一項挑戰。這正是應用生成式人工智慧的最佳時機。透過利用預訓練的生成模型,StyleSprint 可以自動生成引人入勝的產品描述,從而節省大量時間並豐富客戶的線上購物體驗。

在實際應用預訓練的大語言模型(LLM)時,首先要做的是建立一個有利於使用生成模型進行原型設計的Python環境。這個設定對於將專案從原型階段轉移到生產就緒狀態至關重要,為StyleSprint實作自動化內容生成的目標奠定了基礎。

環境設定與轉換

在第2章和第3章中,我們使用Google Colab進行原型設計,因為它易於使用且具有可存取的GPU資源。它是一個測試想法的好平台。然而,當我們將重點轉向在現實環境中佈署我們的生成模型時,瞭解從原型設計環境(如Google Colab)轉換到更強健、生產就緒的設定是至關重要的。這種轉換將確保我們的解決方案具有可擴充套件性、可靠性和最佳化,以處理現實世界的流量。

在本章中,我們將逐步介紹設定生產就緒的Python環境的步驟,強調從原型到生產平穩轉換的關鍵考慮因素。

原型設計環境與生產環境的比較

Jupyter筆記本的優缺點

Jupyter筆記本提供了一個互動式的計算環境,能夠將程式碼執行、文字、數學、繪圖和豐富媒體結合到單個檔案中。它們非常適合原型設計和互動式開發,因此成為資料科學家、研究人員和工程師的首選。以下是它們提供的功能:

  • 核心(Kernel):Jupyter筆記本的核心是一個計算引擎,負責執行筆記本中的程式碼。對於Python來說,這通常是一個IPython核心。當筆記本開啟時,該核心保持活動狀態並維護筆記本計算的狀態。
  • 互動式執行:程式碼單元允許您編寫和執行程式碼,檢查結果並根據需要調整程式碼。
  • 依賴管理:您可以使用pip或conda命令直接在筆記本中安裝和管理函式庫和依賴項。
  • 視覺化:您可以嵌入繪圖、圖形和其他視覺化內容,以互動方式探索資料和結果。
  • 檔案:將Markdown單元與程式碼單元結合使用,可以建立檔案齊全、自成體系的筆記本,解釋程式碼及其輸出。

Jupyter筆記本的一個缺點是,它們通常依賴於個人電腦的計算資源。大多數個人筆記型電腦和桌上型電腦並未針對計算密集型過程進行最佳化或配備。因此,具有足夠的計算資源對於管理實驗大語言模型的計算複雜性至關重要。幸運的是,我們可以透過根據雲的平台擴充套件Jupyter筆記本的功能,這些平台提供計算加速器,如圖形處理單元(GPUs)和張量處理單元(TPUs)。例如,Google Colab即時增強了Jupyter筆記本,使其適合計算密集型實驗。以下是根據雲的筆記本環境(如Google Colab)的一些關鍵特性:

  • GPU/TPU存取:提供免費或負擔得起的GPU和TPU資源存取,用於加速計算,這在處理要求苛刻的機器學習模型時至關重要。
  • 協作:允許輕鬆分享和實時協作,類別似於Google Docs。
  • 整合:允許輕鬆儲存和存取筆記本和資料。

生產就緒環境的設定

為了將我們的生成式應用從原型設計環境轉移到生產就緒設定,我們需要定義一個可靠且可重複的策略,用於評估、監控和佈署模型到生產環境。這將確保我們的解決方案能夠處理現實世界的流量,並具有可擴充套件性和可靠性。

內容解密:

在本章中,我們將瞭解如何設定生產就緒的Python環境,並強調從原型到生產平穩轉換的關鍵考慮因素。這包括瞭解Jupyter筆記本的優缺點、根據雲的筆記本環境的特性,以及如何定義一個可靠且可重複的策略,用於評估、監控和佈署模型到生產環境。

# 示例程式碼:設定Python環境
import os

def setup_environment():
    # 安裝必要的函式庫
    os.system('pip install numpy pandas')
    # 組態環境變數
    os.environ['MY_VAR'] = 'my_value'

# 呼叫函式
setup_environment()

內容解密:

上述程式碼展示瞭如何設定Python環境。首先,我們匯入了os模組,它提供了與作業系統互動的功能。然後,我們定義了一個名為setup_environment的函式,用於安裝必要的函式庫和組態環境變數。在這個例子中,我們使用pip安裝了numpypandas函式庫,並設定了一個名為MY_VAR的環境變數。最後,我們呼叫了這個函式來執行設定。

透過這種方式,我們可以確保我們的Python環境已經準備好用於開發和佈署生成式模型。接下來的章節將探討如何利用預訓練的大語言模型來自動生成產品描述,並將其佈署到生產環境中。

從原型環境轉型至生產環境:以 StyleSprint 為例

在前面的章節中,我們已經使用 Google Colab 初步建立了一個生成式模型的原型,用於自動生成產品描述。現在,我們需要進一步思考如何將這個原型轉移到生產環境中。為了確保順利過渡,我們必須仔細評估原型環境的關鍵特性,並將其對映到相應的生產解決方案。

原型環境的關鍵特性

在 Google Colab 中,我們享受了許多便利的功能,例如:

  • 套件管理:透過 !pip install 命令輕鬆安裝所需的函式庫。
  • 相依性隔離:Colab 自動隔離不同專案之間的相依性,避免衝突。
  • 互動式程式碼執行:可以逐一執行程式碼片段,方便測試和偵錯。
  • 資源存取:Colab 提供了簡便的 GPU 和 TPU 存取方式,適合運算密集型任務。
  • 資料整合:可以輕鬆連線資料來源進行分析和建模。
  • 版本控制和協作:Colab 可以與 Git 無縫整合,方便進行版本控制和團隊協作。
  • 錯誤處理和偵錯:可以直接存取 Python 執行環境,檢視錯誤訊息和追蹤記錄。

將原型環境對映到生產環境

為了確保生產環境的穩定性和可擴充套件性,我們可以使用 Docker 這個領先的容器化工具。Docker 可以將應用程式及其相依性封裝在一起,確保在不同系統上的一致性。

特性原型環境生產環境
套件管理內建套件管理器Docker 可簡化應用程式佈署和套件管理的一致性
相依性隔離內建於 notebookDocker 可確保專案之間的隔離,避免衝突
互動式程式碼執行支援逐一執行程式碼片段不一定需要,但可使用偵錯工具進行即時偵錯
資源存取簡便的 GPU 和 TPU 存取需要根據實際需求組態適當的運算資源
資料整合簡單的資料來源連線可以將資料直接佈署到環境中,或連線到遠端資料來源
版本控制和協作可與 Git 無縫整合需要整合 Git 進行版本控制,並與遠端儲存函式庫同步
錯誤處理和偵錯直接存取 Python 執行環境需要適當的日誌記錄和錯誤處理機制

使用 Docker 進行容器化佈署

Docker 可以幫助我們建立一個乾淨、一致的生產環境,確保 StyleSprint 的生成式模型能夠穩定執行。以下是使用 Docker 的一些好處:

  • 一致性:Docker 容器確保了開發、測試和生產環境的一致性,避免了「在我的機器上可以執行」的問題。
  • 隔離性:Docker 容器提供了良好的隔離性,避免了不同專案之間的相依性衝突。
  • 可移植性:Docker 容器可以在不同的系統上執行,無需擔心環境差異。
# 使用官方 Python 映像作為基礎
FROM python:3.9-slim

# 設定工作目錄
WORKDIR /app

# 複製 requirements.txt 檔案
COPY requirements.txt .

# 安裝所需的函式庫
RUN pip install --no-cache-dir -r requirements.txt

# 複製應用程式碼
COPY . .

# 設定環境變數
ENV PYTHONUNBUFFERED=1

# 執行應用程式
CMD ["python", "app.py"]

內容解密:

  1. FROM python:3.9-slim:使用官方 Python 3.9 映像作為基礎映像,slim 版本較小,適合生產環境。
  2. WORKDIR /app:設定容器內的工作目錄為 /app
  3. COPY requirements.txt .:將主機上的 requirements.txt 檔案複製到容器內的工作目錄。
  4. RUN pip install --no-cache-dir -r requirements.txt:安裝 requirements.txt 中指定的函式庫,--no-cache-dir 引數避免快取套件。
  5. COPY . .:將主機上的當前目錄(即應用程式碼)複製到容器內的工作目錄。
  6. ENV PYTHONUNBUFFERED=1:設定環境變數 PYTHONUNBUFFERED1,使 Python 輸出不被緩衝。
  7. CMD ["python", "app.py"]:設定容器的預設命令為執行 python app.py