生成式AI(Generative AI)代表了人工智慧領域中一個革命性的分支,其核心能力在於創造全新的內容,而非僅分析或分類別現有資料。在開始探討前,我認為有必要先釐清生成式AI與其他AI模型的根本差異。

生成式AI與判別式AI的區別

生成式AI與判別式AI(Discriminative AI)在設計目標和運作方式上有本質區別:

  • 生成式模型專注於學習資料的內在分佈和結構,能夠生成與訓練資料相似的新樣本。例如,一個生成式模型可以學習寫作風格並創作新文章。

  • 判別式模型則專注於學習資料類別之間的決策邊界,主要用於分類別和預測任務。例如,垃圾郵件過濾器就是典型的判別式模型。

這兩種正規化的差異可以用一個簡單的例子來説明:假設我們有一組貓和狗的圖片。判別式模型會學習如何區分貓和狗的特徵,而生成式模型則會學習如何創造新的貓或狗圖片。

在實際應用中,選擇適合的模型正規化取決於具體任務需求:

if 任務需要創造新內容:
    選擇生成式模型
elif 任務需要分類別或預測:
    選擇判別式模型
else:
    考慮混合方法

這段簡單的偽程式碼説明瞭模型選擇的基本邏輯。在實際應用中,我們需要根據任務性質選擇合適的模型型別。有時候,我們也會看到兩種模型協同工作的情況,例如GAN(生成對抗網路)中,生成器和判別器就分別代表了這兩種正規化。

生成式AI的主要方法概覽

生成式AI領域中存在多種方法,每種都有其獨特的優勢和適用場景:

  1. 自迴歸模型(Autoregressive Models):如GPT系列,透過預測序列中的下一個元素來生成內容。

  2. 變分自編碼器(Variational Autoencoders, VAEs):學習資料的壓縮表示,並從這些表示中生成新樣本。

  3. 生成對抗網路(Generative Adversarial Networks, GANs):由生成器和判別器兩個網路組成,透過對抗訓練生成高品質內容。

  4. 擴散模型(Diffusion Models):如Stable Diffusion,透過逐步去噪過程生成高品質影像。

  5. 流模型(Flow Models):使用可逆變換學習複雜分佈。

在選擇合適的生成方法時,我發現需要考慮多個因素,包括資料型別、計算資源限制、所需生成內容的品質和多樣性等。例如,對於影像生成,擴散模型近期表現出色;而對於文字生成,Transformer架構的自迴歸模型則佔據主導地位。

生成式AI的演進歷程

生成式AI的發展歷程可以追溯到早期的統計語言模型,但真正的突破發生在近十年間。以下是這一演進的關鍵里程碑:

傳統NLP方法時代

早期的自然語言處理(NLP)主要依賴於規則型系統和統計方法:

  • 規則型系統:根據語言學家定義的規則進行文書處理
  • n-gram模型:使用短序列統計預測下一個詞
  • 隱馬爾可夫模型(HMM):用於序列標記和生成簡單文字

這些方法雖然在特定任務上有效,但缺乏對語言深層語義的理解,與難以擴充套件到複雜任務。

Transformer架構的革命

2017年,Google研究團隊發表的《Attention is All You Need》論文引入了Transformer架構,徹底改變了NLP領域:

class TransformerBlock(nn.Module):
    def __init__(self, embed_dim, num_heads, ff_dim, dropout=0.1):
        super(TransformerBlock, self).__init__()
        self.attention = nn.MultiheadAttention(embed_dim, num_heads)
        self.norm1 = nn.LayerNorm(embed_dim)
        self.norm2 = nn.LayerNorm(embed_dim)
        self.ff = nn.Sequential(
            nn.Linear(embed_dim, ff_dim),
            nn.ReLU(),
            nn.Dropout(dropout),
            nn.Linear(ff_dim, embed_dim)
        )
        self.dropout = nn.Dropout(dropout)
        
    def forward(self, x):
        # Self-attention with residual connection and layer normalization
        attn_output, _ = self.attention(x, x, x)
        x = self.norm1(x + self.dropout(attn_output))
        
        # Feed-forward with residual connection and layer normalization
        ff_output = self.ff(x)
        x = self.norm2(x + self.dropout(ff_output))
        return x

這段程式碼展示了Transformer架構的核心元件之一:Transformer塊。它包含多頭自注意力機制(MultiheadAttention)和前饋神經網路(Feed-Forward Network)。注意力機制使模型能夠關注輸入序列中的不同部分,而不受位置限制,這是Transformer相比RNN等傳統序列模型的重大優勢。每個元件後都有殘差連線(residual connection)和層正規化(layer normalization),這有助於訓練更深的網路。

Transformer架構的關鍵創新在於:

  1. 自注意力機制:允許模型在處理序列時考慮所有位置,而不受距離限制
  2. 平行計算能力:不同於RNN的順序處理,Transformer可以平行處理整個序列
  3. 多頭注意力:允許模型同時關注不同的表示子網路

這些創新使Transformer成為處理序列資料的強大工具,為後續大模型語言奠定了基礎。

GPT系列的發展與影響

OpenAI的GPT(Generative Pre-trained Transformer)系列模型展示了預訓練語言模型的巨大潛力:

  • GPT-1(2018):首次展示大規模預訓練加微調的效果
  • GPT-2(2019):引數量增至15億,生成能力顯著提升
  • GPT-3(2020):1750億引數,展現出令人驚訝的少樣本學習能力
  • GPT-4(2023):多模態能力,推理能力和安全性大幅提升

GPT-4的出現標誌著大模型語言(LLM)進入了一個新階段,它不僅能夠生成流暢的文字,還展現出理解上下文、遵循複雜指令和解決問題的能力。在使用過程中,我發現GPT-4的一個顯著特點是其"思考鏈"(chain-of-thought)能力,能夠像人類一樣逐步推理解決問題。

生成式AI的風險與影響

隨著生成式AI能力的提升,其帶來的風險和社會影響也日益凸顯:

  1. 內容真實性挑戰:AI生成的假新聞、深度偽造等內容難以辨別
  2. 版權與智慧財產權問題:模型訓練資料和生成內容的版權歸屬不明確
  3. 就業市場變革:可能替代部分創意和知識工作
  4. 偏見與歧視放大:模型可能繼承並放大訓練資料中的偏見
  5. 資源不平等:開發和使用先進AI模型需要大量計算資源

應對這些挑戰需要技術和政策層面的共同努力,包括開發更好的AI內容檢測工具、建立明確的法律框架,以及確保AI發展的包容性和公平性。

生成式AI的應用場景

生成式AI已經在多個領域展現出變革性潛力:

  • 內容創作:文章撰寫、故事創作、詩歌生成
  • 程式開發:程式碼生成、程式除錯、API檔案撰寫
  • 設計與創意:影像生成、產品設計、UI/UX原型
  • 教育:個人化學習內容、人工智慧導師系統
  • 醫療:藥物發現、醫學影像生成與分析
  • 客戶服務:人工智慧客服、個人化推薦

這些應用只是冰山一角,隨著技術的進步,我們將看到更多創新應用場景的出現。

生成式AI型別與模式:GANs、擴散模型與Transformer概覽

在生成式AI領域,不同型別的模型架構各有所長。本文將探討三種主要的生成式AI模型:生成對抗網路(GANs)、擴散模型(Diffusion Models)和Transformer模型,分析它們的工作原理、特點和應用場景。

生成式AI模型的區別特徵

GANs、擴散模型和Transformer雖然都屬於生成式AI,但它們在設計理念、訓練方式和適用場景上有顯著差異:

模型型別核心機制訓練方式主要優勢典型應用
GANs生成器與判別器對抗對抗訓練生成高品質、逼真的樣本影像生成、風格轉換
擴散模型逐步去噪過程去噪訓練樣本多樣性、訓練穩定性高解析度影像生成、文字到影像
Transformer自注意力機制自監督預訓練長距離依賴建模、可擴充套件性文字生成、語言理解、多模態任務

深入解析生成對抗網路(GANs)

生成對抗網路由Ian Goodfellow在2014年提出,其核心思想是透過兩個網路的對抗訓練來生成高品質樣本。

GANs的基本架構

GAN由兩個主要元件組成:

  1. 生成器(Generator):嘗試生成逼真的假樣本
  2. 判別器(Discriminator):嘗試區分真實樣本和生成器產生的假樣本

這兩個網路透過一個零和博弈進行訓練:生成器試圖欺騙判別器,而判別器則努力不被欺騙。

import torch
import torch.nn as nn

# 簡化的GAN架構範例
class Generator(nn.Module):
    def __init__(self, latent_dim, output_dim):
        super(Generator, self).__init__()
        self.model = nn.Sequential(
            nn.Linear(latent_dim, 128),
            nn.LeakyReLU(0.2),
            nn.Linear(128, 256),
            nn.LeakyReLU(0.2),
            nn.Linear(256, output_dim),
            nn.Tanh()  # 輸出範圍限制在[-1, 1]
        )
    
    def forward(self, z):
        return self.model(z)

class Discriminator(nn.Module):
    def __init__(self, input_dim):
        super(Discriminator, self).__init__()
        self.model = nn.Sequential(
            nn.Linear(input_dim, 256),
            nn.LeakyReLU(0.2),
            nn.Linear(256, 128),
            nn.LeakyReLU(0.2),
            nn.Linear(128, 1),
            nn.Sigmoid()  # 輸出範圍[0, 1],表示真實樣本的機率
        )
    
    def forward(self, x):
        return self.model(x)

這段程式碼展示了GAN的基本架構。生成器接收一個隨機噪聲向量(latent_dim維度),透過多層神經網路將其轉換為目標維度的輸出(如影像)。判別器則接收一個輸入樣本(可能是真實樣本或生成器產生的樣本),輸出一個0到1之間的值,表示該樣本是真實樣本的機率。

在訓練過程中,兩個網路的損失函式如下:

# GAN訓練迴圈範例
def train_gan(generator, discriminator, real_data, epochs, batch_size, latent_dim):
    criterion = nn.BCELoss()  # 二元交叉熵損失
    optimizer_g = torch.optim.Adam(generator.parameters(), lr=0.0002)
    optimizer_d = torch.optim.Adam(discriminator.parameters(), lr=0.0002)
    
    for epoch in range(epochs):
        for batch in range(len(real_data) // batch_size):
            # 訓練判別器
            optimizer_d.zero_grad()
            
            # 真實樣本的損失
            real_samples = real_data[batch * batch_size: (batch + 1) * batch_size]
            real_labels = torch.ones(batch_size, 1)
            real_output = discriminator(real_samples)
            d_loss_real = criterion(real_output, real_labels)
            
            # 生成樣本的損失
            z = torch.randn(batch_size, latent_dim)
            fake_samples = generator(z)
            fake_labels = torch.zeros(batch_size, 1)
            fake_output = discriminator(fake_samples.detach())  # 分離計算圖
            d_loss_fake = criterion(fake_output, fake_labels)
            
            # 總判別器損失
            d_loss = d_loss_real + d_loss_fake
            d_loss.backward()
            optimizer_d.step()
            
            # 訓練生成器
            optimizer_g.zero_grad()
            z = torch.randn(batch_size, latent_dim)
            fake_samples = generator(z)
            fake_output = discriminator(fake_samples)
            
            # 生成器希望判別器將生成樣本判斷為真
            g_loss = criterion(fake_output, torch.ones(batch_size, 1))
            g_loss.backward()
            optimizer_g.step()
            
        print(f"Epoch {epoch}: D Loss: {d_loss.item()}, G Loss: {g_loss.item()}")

這段程式碼展示了GAN的訓練過程。每個訓練迭代包含兩個步驟:

  1. 訓練判別器:使用真實樣本和生成器產生的假樣本,最佳化判別器以正確區分兩者
  2. 訓練生成器:生成新樣本,並最佳化生成器使判別器將這些樣本誤判為真實樣本

這種對抗訓練過程是GAN的核心,透過不斷的博弈,生成器學會產生越來越逼真的樣本。

GANs的變種與進展

自2014年提出以來,GAN已發展出多種變體,解決了原始GAN的一些限制:

  • DCGAN:將卷積神經網路引入GAN架構,提高影像生成品質
  • WGAN:引入Wasserstein距離,改善訓練穩定性
  • CycleGAN:實作無配對資料的域轉換
  • StyleGAN:透過風格控制實作高品質、可控的影像生成

擴散模型深度剖析

擴散模型(Diffusion Models)是近年來在生成領域取得突破性進展的模型型別,特別是在影像生成方面。

擴散模型的工作原理

擴散模型的核心思想是透過一個逐步加噪和去噪的過程來生成資料:

  1. 前向過程(加噪):逐步將高斯噪聲增加到真實資料中,直到完全變為噪聲
  2. 反向過程(去噪):學習如何逐步從噪聲中還原始資料

這種方法的數學基礎是馬爾可夫鏈和變分推斷。

import torch
import torch.nn as nn

# 簡化的擴散模型範例
class DiffusionModel(nn.Module):
    def __init__(self, input_dim, hidden_dim):
        super(DiffusionModel, self).__init__()
        self.net = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.SiLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.SiLU(),
            nn.Linear(hidden_dim, input_dim)
        )
        
    def forward(self, x, t):
        # t是時間步,通常會被嵌入到網路中
        # 這裡簡化處理
        t_emb = torch.ones_like(x) * t / 1000.0
        x_input = torch.cat([x, t_emb], dim=-1)
        return self.net(x_input)

# 擴散過程
def diffusion_forward(x_0, num_steps=1000, beta_min=1e-4, beta_max=0.02):
    """前向擴散過程:逐步向資料增加噪聲"""
    betas = torch.linspace(beta_min, beta_max, num_steps)
    alphas = 1 - betas
    alphas_cumprod = torch.cumprod(alphas, dim=0)
    
    # 選擇一個隨機時間步
    t = torch.randint(0, num_steps, (1,))
    alpha_cumprod_t = alphas_cumprod[t]
    
    # 增加噪聲
    noise = torch.randn_like(x_0)
    x_t = torch.sqrt(alpha_cumprod_t) * x_0 + torch.sqrt(1 - alpha_cumprod_t) * noise
    
    return x_t, noise, t

這段程式碼展示了擴散模型的基本結構和前向擴散過程。DiffusionModel類別定義了一個簡單的神經網路,用於預測去噪過程中的噪聲。diffusion_forward函式實作了前向擴散過程,即逐步向原始資料增加噪聲。

在實際訓練中,模型學習預測增加的噪聲,而不是直接預測去噪後的資料:

# 擴散模型訓練範例
def train_diffusion(model, dataloader, optimizer, num_steps=1000):
    criterion = nn.MSELoss()
    
    for x_0 in dataloader:
        optimizer.zero_grad()
        
        # 前向擴散
        x_t, noise, t = diffusion_forward(x_0, num_steps)
        
        # 模型預測噪聲
        predicted_noise = model(x_t, t)
        
        # 計算損失(預測噪聲與實際增加的噪聲之間的MSE)
        loss = criterion(predicted_noise, noise)
        
        loss.backward()
        optimizer.step()

這段程式碼展示了擴散模型的訓練過程。關鍵步驟包括:

  1. 對原始資料x_0進行前向擴散,得到帶噪聲的資料x_t
  2. 使用模型預測增加的噪聲
  3. 計算預測噪聲與實際增加噪聲之間的均方誤差作為損失函式
  4. 最佳化模型引數

訓練完成後,生成新樣本的過程是從純噪聲開始,逐步應用學習到的去噪過程。

擴散模型的優勢與應用

擴散模型相比GANs有幾個顯著優勢:

  1. 訓練穩定性:不存在GAN中生成器和判別器的平衡問題
  2. 樣本多樣性:能夠生成更多樣化的樣本
  3. 可控性:提供更精細的生成過程控制

代表性的擴散模型包括:

  • DDPM(Denoising Diffusion Probabilistic Models):奠定了現代擴散模型的基礎
  • Stable Diffusion:結合潛在擴散和文字條件,實作高品質文字到影像生成
  • DALL-E 2:OpenAI的文字到影像生成模型,部分根據擴散技術

Transformer模型與生成式應用

Transformer架構自2017年提出後,已成為自然語言處理和生成式AI的核心技術。

Transformer架構的關鍵元件

Transformer的核心創新在於自注意力機制,它使模型能夠處理序列中的長距離依賴關係:

import torch
import torch.nn as nn
import math

class SelfAttention(nn.Module):
    def __init__(self, embed_dim, num_heads):
        super(SelfAttention, self).__init__()
        self.embed_dim = embed_dim
        self.num_heads = num_heads
        self.head_dim = embed_dim // num_heads
        
        self.query = nn.Linear(embed_dim, embed_dim)
        self.key = nn.Linear(embed_dim, embed_dim)
        self.value = nn.Linear(embed_dim, embed_dim)
        self.out = nn.Linear(embed_dim, embed_dim)
        
    def forward(self, x):
        batch_size, seq_len, _ = x.size()
        
        # 線性投影
        q = self.query(x).reshape(batch_size, seq_len, self.num_heads, self.head_dim).permute(0, 2, 1, 3)
        k = self.key(x).reshape(batch_size, seq_len, self.num_heads, self.head_dim).permute(0, 2, 1, 3)
        v = self.value(x).reshape(batch_size, seq_len, self.num_heads, self.head_dim).permute(0, 2, 1, 3)
        
        # 注意力計算
        scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.head_dim)
        attention = torch.softmax(scores, dim=-1)
        
        # 加權值向量
        out = torch.matmul(attention, v).permute(0, 2, 1, 3).reshape(batch_size, seq_len, self.embed_dim)
        return self.out(out)

這段程式碼實作了Transformer的核心元件:多頭自注意力機制。它首先將輸入向量投影到查詢(Q)、鍵(K)和值(V)空間,然後計算注意力分數,最後根據這些分數對值向量進行加權求和。多頭機制允許模型同時關注不同的表示子網路。

完整的Transformer還包括前饋神經網路、層正規化和殘差連線等元件:

class TransformerEncoderLayer(nn.Module):
    def __init__(self, embed_dim, num_heads, ff_dim, dropout=0.1):
        super(TransformerEncoderLayer, self).__init__()
        self.attention = SelfAttention(embed_dim, num_heads)
        self.norm1 = nn.LayerNorm(embed_dim)
        self.norm2 = nn.LayerNorm(embed_dim)
        self.ff = nn.Sequential(
            nn.Linear(embed_dim, ff_dim),
            nn.ReLU(),
            nn.Dropout(dropout),
            nn.Linear(ff_dim, embed_dim)
        )
        self.dropout = nn.Dropout(dropout)
        
    def forward(self, x):
        # 自注意力 + 殘差連線 + 層正規化
        attn_out = self.attention(x)
        x = self.norm1(x + self.dropout(attn_out))
        
        # 前饋網路 + 殘差連線 + 層正規化
        ff_out = self.ff(x)
        x = self.norm2(x + self.dropout(ff_out))
        return x

這段程式碼實作了Transformer編碼器層的完整結構。每個編碼器層包含一個多頭自注意力子層和一個前饋神經網路子層,每個子層都有殘差連線和層正規化。這種設計使得Transformer能夠有效處理深層網路的訓練問題,並保持梯度流動。

生成式Transformer模型

在生成式AI領域,Transformer主要以自迴歸(Autoregressive)方式應用,即逐步生成序列中的下一個元素:

class GPTModel(nn.Module):
    def __init__(self, vocab_size, embed_dim, num_heads, num_layers, max_seq_len):
        super(GPTModel, self).__init__()
        self.token_embedding = nn.Embedding(vocab_size, embed_dim)
        self.position_embedding = nn.Embedding(max_seq_len, embed_dim)
        
        self.layers = nn.ModuleList([
            TransformerEncoderLayer(embed_dim, num_heads, embed_dim * 4)
            for _ in range(num_layers)
        ])
        
        self.ln_f = nn.LayerNorm(embed_dim)
        self.head = nn.Linear(embed_dim, vocab_size)
        
    def forward(self, x):
        batch_size, seq_len = x.size()
        
        # 取得token和位置嵌入
        token_emb = self.token_embedding(x)
        pos = torch.arange(0, seq_len, device=x.device).unsqueeze(0).repeat(batch_size, 1)
        pos_emb = self.position_embedding(pos)
        
        # 組合嵌入
        x = token_emb + pos_emb
        
        # 透過Transformer層
        for layer in self.layers:
            x = layer(x)
            
        x = self.ln_f(x)
        logits = self.head(x)
        
        return logits

這段程式碼實作了一個簡化版的GPT模型。它首先將輸入token轉換為嵌入向量,並增加位置嵌入以保留序列順序訊息。然後,輸入透過多個Transformer編碼器層進行處理,最後透過一個線性層對映到詞彙表大小的輸出,用於預測下一個token的機率分佈。

在生成過程中,模型通常使用自迴歸方式,即每次生成一個新token,然後將其增加到輸入序列中,再預測下一個token:

def generate_text(model, start_tokens, max_length, vocab_size):
    model.eval()
    current_tokens = start_tokens.clone()
    
    with torch.no_grad():
        for _ in range(max_length):
            # 取得模型預測
            logits = model(current_tokens)
            
            # 只關注最後一個位置的預測
            next_token_logits = logits[:, -1, :]
            
            # 可以使用不同的取樣策略,這裡使用簡單的greedy
            next_token = torch.argmax(next_token_logits, dim=-1, keepdim=True)
            
            # 將新token增加到序列中
            current_tokens = torch.cat([current_tokens, next_token], dim=1)
            
    return current_tokens

這段程式碼展示了使用Transformer模型生成文字的過程。它從一個起始序列開始,然後反覆使用模型預測下一個token,並將其增加到序列中,直到達到指定的最大長度。在實際應用中,通常會使用更複雜的取樣策略,如溫度取樣、top-k取樣或nucleus取樣,以增加生成文字的多樣性和創造性。

生成式AI模型在影像生成中的應用

為了具體展示不同生成式AI模型的應用,讓我們看它們在影像生成任務中的表現。

使用Jupyter Notebook和Google Colab

在實際開發中,Jupyter Notebook和Google Colab是探索生成式AI的常用工具。以下是在Google Colab中使用Stable Diffusion模型生成影像的範例:

# 安裝必要的函式庫
!pip install diffusers transformers accelerate

import torch
from diffusers import StableDiffusionPipeline
from PIL import Image
import matplotlib.pyplot as plt

# 載入預訓練的Stable Diffusion模型
model_id = "CompVis/stable-diffusion-v1-4"
pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
pipe = pipe.to("cuda")

# 生成影像
prompt = "一隻黑貓坐在滿月下的古老城堡屋頂上,背景是星空"
image = pipe(prompt).images[0]

# 顯示影像
plt.figure(figsize=(10, 10))
plt.imshow(image)
plt.axis('off')
plt.title(prompt)
plt.show()

# 儲存影像
image.save("black_cat_castle.png")

這段程式碼展示瞭如何使用Hugging Face的Diffusers函式庫載入預訓練的Stable Diffusion模型,並用它根據文字提示生成影像。Stable Diffusion是一種潛在擴散模型,它在壓縮的潛在空間中執行擴散過程,而不是在畫素空間中,這使得它能夠高效地生成高解析度影像。

使用CLIP模型評估生成影像

CLIP(Contrastive Language-Image Pretraining)模型可以用來評估生成影像與文字提示的比對度:

from transformers import CLIPProcessor, CLIPModel

# 載入CLIP模型
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")

# 準備文字和影像
texts = ["一隻黑貓", "一座城堡", "星空", "滿月"]
inputs = processor(text=texts, images=image, return_tensors="pt", padding=True)

# 計算相似度分數
with torch.no_grad():
    outputs = model(**inputs)
    logits_per_image = outputs.logits_per_image
    probs = logits_per_image.softmax(dim=1)

# 顯示結果
for i, text in enumerate(texts):
    print(f"'{text}' 的比對度: {probs[0][i].item():.4f}")

這段程式碼使用OpenAI的CLIP模型來評估生成影像與不同文字描述的比對度。CLIP是一個多模態模型,經過訓練可以理解影像和文字之間的關係。透過計算影像與各個文字描述之間的相似度分數,我們可以評估生成影像是否成功捕捉了提示中的關鍵元素。這種評估方法在開發和最佳化生成模型時非常有用。

自然語言處理的基礎與Transformer的影響

自然語言處理(NLP)領域在過去十年經歷了翻天覆地的變化,從早期的統計方法到現代的神經網路架構,特別是Transformer的出現,徹底改變了這一領域。本文將探討NLP的發展歷程,並深入分析Transformer架構如何成為現代語言模型的根本。

NLP的早期方法

在深度學習革命之前,NLP主要依賴於統計方法和手工特徵工程:

分散式表示的興起

早期的一個重要突破是分散式表示(Distributed Representations)的概念,它根據"相似的詞出現在相似的上下文中"的假設:

# Word2Vec模型的簡化實作
import torch
import torch.nn as nn
import torch.optim as optim

class SkipGramModel(nn.Module):
    def __init__(self, vocab_size, embedding_dim):
        super(SkipGramModel, self).__init__()
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)
        self.output_layer = nn.Linear(embedding_dim, vocab_size)
        
    def forward(self, inputs):
        embeds = self.embeddings(inputs)
        output = self.output_layer(embeds)
        return output

這段程式碼實作了Word2Vec的Skip-gram模型,這是一種早期但影響深遠的詞嵌入方法。該模型學習將詞對映到密集向量空間,使得語義相似的詞在該空間中彼此接近。Skip-gram模型透過預測給定中心詞的上下文詞來學習這些表示。

這種分散式表示方法相比早期的one-hot編碼有幾個優勢:

  1. 它捕捉了詞之間的語義關係
  2. 它產生了密集而非稀疏的表示
  3. 它允許進行詞向量算術運算(如"king" - “man” + “woman” ≈ “queen”)

遷移學習的出現

另一個重要發展是遷移學習(Transfer Learning)的應用,即在一個任務上預訓練模型,然後將其應用到其他相關任務:

# 遷移學習範例:使用預訓練的詞嵌入
import torch.nn as nn

class SentimentClassifier(nn.Module):
    def __init__(self, pretrained_embeddings, hidden_dim, output_dim):
        super(SentimentClassifier, self).__init__()
        # 凍結預訓練的嵌入
        self.embedding = nn.Embedding.from_pretrained(
            pretrained_embeddings, 
            freeze=True
        )
        self.lstm = nn.LSTM(pretrained_embeddings.shape[1], hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, output_dim)
        
    def forward(self, text):
        embedded = self.embedding(text)
        output, (hidden, _) = self.lstm(embedded)
        return self.fc(hidden.squeeze(0))

這段程式碼展示瞭如何使用預訓練的詞嵌入來構建情感分類別器。透過使用在大規模語料函式庫上預訓練的詞嵌入,模型可以利用這些嵌入捕捉的語義知識,即使在較小的標記資料集上也能取得良好的效能。這是早期遷移學習在NLP中的應用範例。

神經網路在NLP中的應用

在Transformer出現之前,迴圈神經網路(RNN)特別是LSTM和GRU是NLP任務的主要架構:

# 根據LSTM的語言模型
class LSTMLanguageModel(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, num_layers, dropout_rate):
        super(LSTMLanguageModel, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers, 
                           batch_first=True, dropout=dropout_rate)
        self.dropout = nn.Dropout(dropout_rate)
        self.fc = nn.Linear(hidden_dim, vocab_size)
        
    def forward(self, text):
        # text: [batch_size, seq_len]
        embedded = self.embedding(text)  # [batch_size, seq_len, embedding_dim]
        output, (hidden, cell) = self.lstm(embedded)
        # output: [batch_size, seq_len, hidden_dim]
        
        output = self.dropout(output)
        prediction = self.fc(output)  # [batch_size, seq_len, vocab_size]
        return prediction

這段程式碼實作了一個根據LSTM的語言模型。LSTM(Long Short-Term Memory)是一種特殊的RNN,能夠更好地處理長距離依賴問題。在這個模型中,輸入文字首先透過嵌入層轉換為密集向量,然後透過LSTM層處理序列訊息,最後透過全連線層預測下一個詞的機率分佈。

雖然LSTM在當時取得了很好的效果,但它仍然存在一些限制:

  1. 序列處理是順序的,難以平行化
  2. 即使用門控機制,長距離依賴問題仍然存在
  3. 梯度消失/爆炸問題在長序列中依然明顯

Transformer架構的出現與影響

2017年,Google研究團隊發表了《Attention is All You Need》論文,引入了Transformer架構,這是NLP領域的一個重大突破。

Transformer架構的核心元件

Transformer的核心創新在於完全根據注意力機制,摒棄了迴圈結構:

import torch
import torch.nn as nn
import math

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super(MultiHeadAttention, self).__init__()
        assert d_model % num_heads == 0
        
        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads
        
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)
        
    def scaled_dot_product_attention(self, Q, K, V, mask=None):
        # Q, K, V: [batch_size, num_heads, seq_len, d_k]
        scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
        # scores: [batch_size, num_heads, seq_len, seq_len]
        
        if mask is not None:
            scores = scores.masked_fill(mask == 0, -1e9)
            
        attention = torch.softmax(scores, dim=-1)
        output = torch.matmul(attention, V)
        # output: [batch_size, num_heads, seq_len, d_k]
        return output
        
    def forward(self, query, key, value, mask=None):
        batch_size = query.shape[0]
        
        # 線性投影和重塑
        Q = self.W_q(query).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        K = self.W_k(key).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        V = self.W_v(value).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        
        # 注意力計算
        output = self.scaled_dot_product_attention(Q, K, V, mask)
        
        # 重塑和最終線性投影
        output = output.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
        return self.W_o(output)

這段程式碼實作了Transformer的多頭注意力機制。多頭注意力允許模型同時關注不同位置的不同表示子網路,增強了模型的表達能力。關鍵步驟包括:

  1. 將輸入投影到查詢(Q)、鍵(K)和值(V)空間
  2. 將每個投影分割成多個頭
  3. 對每個頭執行縮放點積注意力
  4. 合併所有頭的輸出並進行最終投影

縮放點積注意力是Transformer的核心操作,它計算查詢與所有鍵的相似度,然後用這些相似度對值進行加權求和。

除了多頭注意力外,Transformer還包含前饋神經網路、層正規化和殘差連線等元件:

class PositionwiseFeedForward(nn.Module):
    def __init__(self, d_model, d_ff):
        super(PositionwiseFeedForward, self).__init__()
        self.fc1 = nn.Linear(d_model, d_ff)
        self.fc2 = nn.Linear(d_ff, d_model)
        self.relu = nn.ReLU()
        
    def forward(self, x):
        return self.fc2(self.relu(self.fc1(x)))

class EncoderLayer(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout):
        super(EncoderLayer, self).__init__()
        self.self_attention = MultiHeadAttention(d_model, num_heads)
        self.feed_forward = PositionwiseFeedForward(d_model, d_ff)
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(dropout)
        
    def forward(self, x, mask=None):
        # 自注意力子層
        attn_output = self.self_attention(x, x, x, mask)
        x = self.norm1(x + self.dropout(attn_output))
        
        # 前饋神經網路子層
        ff_output = self.feed_forward(x)
        x = self.norm2(x + self.dropout(ff_output))
        return x

這段程式碼實作了Transformer編碼器層的兩個主要元件:位置前饋網路和完整的編碼器層。每個編碼器層包含兩個子層:多頭自注意力和前饋神經網路,每個子層都有殘差連線和層正規化。這種設計使得Transformer能夠有效處理深層網路的訓練問題。

序列到序列學習

Transformer最初是為序列到序列(Sequence-to-Sequence)任務設計的,如機器翻譯:

class Encoder(nn.Module):
    def __init__(self, vocab_size, d_model, num_heads, d_ff, num_layers, dropout, max_seq_len):
        super(Encoder, self).__init__()
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.pos_encoding = PositionalEncoding(d_model, max_seq_len)
        self.layers = nn.ModuleList([
            EncoderLayer(d_model, num_heads, d_ff, dropout)
            for _ in range(num_layers)
        ])
        self.dropout = nn.Dropout(dropout)
        
    def forward(self, src, src_mask=None):
        # src: [batch_size, src_len]
        src_embedded = self.embedding(src)
        src_embedded = self.pos_encoding(src_embedded)
        x = self.dropout(src_embedded)
        
        for layer in self.layers:
            x = layer(x, src_mask)
            
        return x

class Decoder(nn.Module):
    def __init__(self, vocab_size, d_model, num_heads, d_ff, num_layers, dropout, max_seq_len):
        super(Decoder, self).__init__()
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.pos_encoding = PositionalEncoding(d_model, max_seq_len)
        self.layers = nn.ModuleList([
            DecoderLayer(d_model, num_heads, d_ff, dropout)
            for _ in range(num_layers)
        ])
        self.fc_out = nn.Linear(d_model, vocab_size)
        self.dropout = nn.Dropout(dropout)
        
    def forward(self, trg, enc_output, trg_mask=None, src_mask=None):
        # trg: [batch_size, trg_len]
        trg_embedded = self.embedding(trg)
        trg_embedded = self.pos_encoding(trg_embedded)
        x = self.dropout(trg_embedded)
        
        for layer in self.layers:
            x = layer(x, enc_output, trg_mask, src_mask)
            
        output = self.fc_out(x)
        return output

這段程式碼實作了Transformer的編碼器和解碼器模組。編碼器將源序列轉換為連續表示,而解碼器則使用這些表示和之前生成的輸出來預測下一個token。關鍵元件包括:

  1. 嵌入層:將離散token轉換為連續向量
  2. 位置編碼:增加位置訊息,因為Transformer沒有迴圈結構
  3. 多層編碼器/解碼器:逐層處理序列訊息
  4. 輸出層:將解碼器輸出對映到詞彙表大小

位置編碼是Transformer的另一個重要元件,它為模型提供序列中token的位置訊息:

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_seq_len=5000):
        super(PositionalEncoding, self).__init__()
        
        # 建立位置編碼矩陣
        pe = torch.zeros(max_seq_len, d_model)
        position = torch.arange(0, max_seq_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0)
        
        # 註冊為非引數緩衝區
        self.register_buffer('pe', pe)
        
    def forward(self, x):
        # x: [batch_size, seq_len, d_model]
        return x + self.pe[:, :x.size(1), :]

這段程式碼實作了Transformer的位置編碼。由於Transformer沒有迴圈結構,它需要額外的位置訊息來區分序列中不同位置的token。位置編碼使用正弦和餘弦函式的組合,具有以下特性:

  1. 每個位置有唯一的編碼
  2. 不同位置之間的相對關係可以透過線性變換學習
  3. 可以擴充套件到訓練中未見過的序列長度

自迴歸Transformer與生成式AI

在生成式AI中,Transformer主要以自迴歸(Autoregressive)方式應用,即逐步生成序列中的下一個元素:

def generate_sequence(model, start_tokens, max_length, vocab_size):
    model.eval()
    current_tokens = start_tokens.clone()
    
    with torch.no_grad():
        for _ in range(max_length):
            # 建立注意力遮罩
            trg_mask = generate_square_subsequent_mask(current_tokens.size(1)).to(current_tokens.device)
            
            # 取得模型預測
            output = model(current_tokens, trg_mask)
            
            # 只關注最後一個位置的預測
            next_token_logits = output[:, -1, :]
            
            # 取樣下一個token
            next_token = sample_next_token(next_token_logits, temperature=0.8)
            
            # 將新token增加到序列中
            current_tokens = torch.cat([current_tokens, next_token.unsqueeze(1)], dim=1)
            
    return current_tokens

def generate_square_subsequent_mask(sz):
    """生成方形後續遮罩"""
    mask = (torch.triu(torch.ones(sz, sz)) == 1).transpose(0, 1)
    mask = mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0))
    return mask

def sample_next_token(logits, temperature=1.0):
    """使用溫度取樣下一個token"""
    if temperature == 0:
        # 貪婪解碼
        return torch.argmax(logits, dim=-1)
    else:
        # 溫度取樣
        logits = logits / temperature
        probs = torch.softmax(logits, dim=-1)
        return torch.multinomial(probs, num_samples=1).squeeze(-1)

這段程式碼展示了使用Transformer模型生成序列的過程。關鍵步驟包括:

  1. 從起始token開始
  2. 使用模型預測下一個token的機率分佈
  3. 根據某種取樣策略選擇下一個token
  4. 將新token增加到序列中
  5. 重複步驟2-4直到達到最大長度或生成結束標記

注意遮罩(attention mask)確保模型在預測位置i時只能看到位置0到i-1的token,這是自迴歸生成的關鍵。溫度引數控制取樣的隨機性:較高的溫度產生更多樣化但可能不太連貫的輸出,較低的溫度產生更確定但可能重複的輸出。

實作原始Transformer

為了更深入理解Transformer架構,讓我們實作一個完整的Transformer模型用於機器翻譯任務:

# 資料載入與準備
from torchtext.datasets import Multi30k
from torchtext.data.utils import get_tokenizer
from torchtext.vocab import build_vocab_from_iterator

# 定義tokenizer
SRC_LANGUAGE = 'de'
TGT_LANGUAGE = 'en'
token_transform = {}
vocab_transform = {}

token_transform[SRC_LANGUAGE] = get_tokenizer('spacy', language='de_core_news_sm')
token_transform[TGT_LANGUAGE] = get_tokenizer('spacy', language='en_core_web_sm')

# 建立詞彙表
def yield_tokens(data_iter, language):
    for data_sample in data_iter:
        yield token_transform[language](data_sample[language])

for language in [SRC_LANGUAGE, TGT_LANGUAGE]:
    train_iter = Multi30k(split='train', language_pair=(SRC_LANGUAGE, TGT_LANGUAGE))
    vocab_transform[language] = build_vocab_from_iterator(
        yield_tokens(train_iter, language),
        min_freq=2,
        specials=['<unk>', '<pad>', '<bos>', '<eos>']
    )

這段程式碼展示瞭如何準備機器翻譯任務的資料。它使用Multi30k資料集(德語到英語的翻譯任務),並為源語言和目標語言定義tokenizer和詞彙表。特殊token包括:

  • <unk>: 未知詞
  • <pad>: 填充標記
  • <bos>: 序列開始標記
  • <eos>: 序列結束標記

接下來,我們需要將文字轉換為模型可以處理的張量:

# 資料張量化
from torch.nn.utils.rnn import pad_sequence

def sequential_transforms(*transforms):
    def func(txt_input):
        for transform in transforms:
            txt_input = transform(txt_input)
        return txt_input
    return func

def tensor_transform(token_ids):
    return torch.cat((torch.tensor([BOS_IDX]), token_ids, torch.tensor([EOS_IDX])))

# 特殊標記索引
SRC_VOCAB_SIZE = len(vocab_transform[SRC_LANGUAGE])
TGT_VOCAB_SIZE = len(vocab_transform[TGT_LANGUAGE])
UNK_IDX = 0
PAD_IDX = 1
BOS_IDX = 2
EOS_IDX = 3

# 轉換函式
text_transform = {}
for language in [SRC_LANGUAGE, TGT_LANGUAGE]:
    text_transform[language] = sequential_transforms(
        token_transform[language],
        lambda x: [vocab_transform[language][token] for token in x],
        tensor_transform
    )

# 批次處理函式
def collate_fn(batch):
    src_batch, tgt_batch = [], []
    for src_sample, tgt_sample in batch:
        src_batch.append(text_transform[SRC_LANGUAGE](src_sample.rstrip("\n")))
        tgt_batch.append(text_transform[TGT_LANGUAGE](tgt_sample.rstrip("\n")))
    
    src_batch = pad_sequence(src_batch, padding_value=PAD_IDX)
    tgt_batch = pad_sequence(tgt_batch, padding_value=PAD_IDX)
    return src_batch, tgt_batch

這段程式碼定義了將文字轉換為模型輸入張量的函式。主要步驟包括:

  1. 文字標記化(tokenization)
  2. 將標記轉換為詞彙表索引
  3. 增加序列開始和結束標記
  4. 對批次中的序列進行填充,使它們具有相同長度

現在,我們可以實作完整的Transformer模型:

# 完整的Transformer模型
class Transformer(nn.Module):
    def __init__(self, src_vocab_size, tgt_vocab_size, d_model, num_heads, num_layers, d_ff, max_seq_len, dropout):
        super(Transformer, self).__init__()
        self.encoder_embedding = nn.Embedding(src_vocab_size, d_model)
        self.decoder_embedding = nn.Embedding(tgt_vocab_size, d_model)
        self.positional_encoding = PositionalEncoding(d_model, max_seq_len)
        
        self.transformer = nn.Transformer(
            d_model=d_model,
            nhead=num_heads,
            num_encoder_layers=num_layers,
            num_decoder_layers=num_layers,
            dim_feedforward=d_ff,
            dropout=dropout
        )
        
        self.output_layer = nn.Linear(d_model, tgt_vocab_size)
        self.d_model = d_model
        
    def create_mask(self, src, tgt):
        src_seq_len = src.shape[0]
        tgt_seq_len = tgt.shape[0]
        
        # 源序列填充遮罩
        src_mask = torch.zeros((src_seq_len, src_seq_len), device=src.device).type(torch.bool)
        
        # 目標序列填充遮罩和後續遮罩
        tgt_mask = generate_square_subsequent_mask(tgt_seq_len).to(tgt.device)
        
        src_padding_mask = (src == PAD_IDX).transpose(0, 1)
        tgt_padding_mask = (tgt == PAD_IDX).transpose(0, 1)
        
        return src_mask, tgt_mask, src_padding_mask, tgt_padding_mask
        
    def forward(self, src, tgt):
        # src, tgt: [seq_len, batch_size]
        
        # 建立遮罩
        src_mask, tgt_mask, src_padding_mask, tgt_padding_mask = self.create_mask(src, tgt)
        
        # 嵌入和位置編碼
        src_embedded = self.positional_encoding(self.encoder_embedding(src) * math.sqrt(self.d_model))
        tgt_embedded = self.positional_encoding(self.decoder_embedding(tgt) * math.sqrt(self.d_model))
        
        # Transformer處理
        output = self.transformer(
            src_embedded, tgt_embedded,
            src_mask, tgt_mask,
            None, src_padding_mask, tgt_padding_mask
        )
        
        # 輸出層
        return self.output_layer(output)

這段程式碼實作了完整的Transformer模型,使用PyTorch的nn.Transformer模組。主要元件包括:

  1. 源語言和目標語言的嵌入層
  2. 位置編碼
  3. Transformer編碼器和解碼器
  4. 輸出線性層

create_mask方法建立了四種遮罩:

  • src_mask:源序列的自注意力遮罩(在翻譯任務中通常不需要)
  • tgt_mask:目標序列的自注意力遮罩,確保自迴歸屬性
  • src_padding_mask:源序列的填充遮罩,忽略填充標記
  • tgt_padding_mask:目標序列的填充遮罩,忽略填充標記

最後,我們定義訓練和翻譯函式:

# 訓練函式
def train_epoch(model, optimizer, train_dataloader, criterion):
    model.train()
    losses = 0
    
    for src, tgt in train_dataloader:
        src = src.to(device)
        tgt = tgt.to(device)
        
        # 目標輸入和輸出
        tgt_input = tgt[:-1, :]  # 移除最後一個token (EOS)
        tgt_output = tgt[1:, :]  # 移除第一個token (BOS)
        
        # 前向傳播
        logits = model(src, tgt_input)
        
        # 重塑輸出和目標
        output_dim = logits.shape[-1]
        logits = logits.contiguous().view(-1, output_dim)
        tgt_output = tgt_output.contiguous().view(-1)
        
        # 計算損失
        loss = criterion(logits, tgt_output)
        
        # 反向傳播和最佳化
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        losses += loss.item()
        
    return losses / len(train_dataloader)

# 翻譯函式
def translate(model, src_sentence, src_vocab, tgt_vocab, device, max_len=50):
    model.eval()
    
    # 處理源句子
    src_tokens = text_transform[SRC_LANGUAGE](src_sentence).unsqueeze(1).to(device)
    
    # 初始化目標序列
    tgt_tokens = torch.tensor([[BOS_IDX]]).to(device)
    
    for i in range(max_len):
        # 預測下一個token
        logits = model(src_tokens, tgt_tokens)
        next_token = logits.argmax(2)[-1, :]
        
        # 增加預測的token
        tgt_tokens = torch.cat([tgt_tokens, next_token.unsqueeze(0)], dim=0)
        
        # 如果預測到EOS,停止生成
        if next_token.item() == EOS_IDX:
            break
    
    # 將索引轉換回詞
    tgt_tokens = tgt_tokens.squeeze(1).tolist()
    tgt_words = []
    for token in tgt_tokens[1:]:  # 跳過BOS
        if token == EOS_IDX:
            break
        tgt_words.append(tgt_vocab.get_itos()[token])
    
    return " ".join(tgt_words)

這段程式碼定義了Transformer模型的訓練和翻譯函式:

訓練函式(train_epoch):

  1. 將源序列和目標序列移動到裝置(CPU或GPU)
  2. 準備目標輸入(移除EOS)和目標輸出(移除BOS)
  3. 執行前向傳播
  4. 計算損失
  5. 執行反向傳播和最佳化

翻譯函式(translate):

  1. 處理源句子
  2. 從BOS標記開始
  3. 反覆預測下一個token並增加到序列中
  4. 如果預測到EOS或達到最大長度,停止生成
  5. 將token索引轉換回詞

最後,我們可以執行主程式來訓練和評估模型:

# 主執行函式
def main():
    # 模型引數
    SRC_VOCAB_SIZE = len(vocab_transform[SRC_LANGUAGE])
    TGT_VOCAB_SIZE = len(vocab_transform[TGT_LANGUAGE])
    EMB_SIZE = 512
    NHEAD = 8
    FFN_HID_DIM = 2048
    NUM_ENCODER_LAYERS = 6
    NUM_DECODER_LAYERS = 6
    DROPOUT = 0.1
    MAX_SEQ_LEN = 100
    
    # 初始化模型
    transformer = Transformer(
        SRC_VOCAB_SIZE, TGT_VOCAB_SIZE,
        EMB_SIZE, NHEAD, NUM_ENCODER_LAYERS,
        FFN_HID_DIM, MAX_SEQ_LEN, DROPOUT
    ).to(device)
    
    # 損失函式和最佳化器
    criterion = nn.CrossEntropyLoss(ignore_index=PAD_IDX)
    optimizer = torch.optim.Adam(transformer.parameters(), lr=0.0001, betas=(0.9, 0.98), eps=1e-9)
    
    # 資料載入器
    train_iter = Multi30k(split='train', language_pair=(SRC_LANGUAGE, TGT_LANGUAGE))
    train_dataloader = DataLoader(list(train_iter), batch_size=128, collate_fn=collate_fn)
    
    # 訓練迴圈
    NUM_EPOCHS = 10
    for epoch in range(NUM_EPOCHS):
        train_loss = train_epoch(transformer, optimizer, train_dataloader, criterion)
        print(f"Epoch: {epoch+1}, Train loss: {train_loss:.3f}")
    
    # 翻譯範例
    test_iter = Multi30k(split='test', language_pair=(SRC_LANGUAGE, TGT_LANGUAGE))
    for src, tgt in list(test_iter)[:5]:
        print(f"Source: {src}")
        print(f"Target: {tgt}")
        translation = translate(transformer, src, vocab_transform[SRC_LANGUAGE], 
                               vocab_transform[TGT_LANGUAGE], device)
        print(f"Predicted: {translation}")
        print("-" * 50)

這段程式碼定義了主執行函式,包括:

  1. 設定模型引數
  2. 初始化Transformer模型
  3. 定義損失函式(交叉熵)和最佳化器(Adam)
  4. 建立訓練資料載入器
  5. 執行訓練迴圈
  6. 使用訓練好的模型翻譯測試集中的例子

這個實作展示了Transformer架構的完整工作流程,從資料準備到模型訓練再到推理。雖然這是一個簡化版本,但它包含了Transformer的所有核心元件和機制。