深度學習模型訓練是一個迭代的過程,涉及多個步驟,從資料準備到模型評估,每個環節都至關重要。首先,我們需要將資料批次化,以便有效地訓練模型。接著,進行前向傳播,將資料輸入模型以獲得預測結果。然後,計算預測結果與真實標籤之間的差異,即損失函式。為了避免梯度累積,我們需要在每次迭代前重置梯度。然後,透過反向傳播計算損失函式對模型引數的梯度,並使用最佳化器(例如 SGD、Adam 等)更新模型引數。此外,預訓練模型的使用能有效提升模型效能,我們可以載入預先訓練的權重,並根據下游任務進行微調。在訓練過程中,我們需要監控訓練損失和驗證損失,以判斷模型是否過擬合。最後,我們可以透過溫度縮放等技術控制生成文字的隨機性,增加文字的多樣性。

深度神經網路訓練流程

在深度學習中,訓練模型的過程是一個迭代的流程。以下是使用 PyTorch 訓練深度神經網路的典型步驟:

  1. 資料批次化:將訓練資料分成小批次,以便於模型訓練。
  2. 前向傳播:將批次資料輸入模型,計算輸出結果。
  3. 梯度重置:重置上一個批次的梯度,以避免梯度累積。
  4. 損失計算:計算當前批次的損失函式,通常使用交叉熵或均方差等。
  5. 反向傳播:計算損失函式對模型引數的梯度,通常使用反向傳播演算法。
  6. 模型更新:使用最佳化器更新模型引數,通常使用 SGD、Adam 等最佳化演算法。
  7. 損失列印:列印訓練集和驗證集的損失值,以監視訓練進度。
  8. 樣本生成:生成樣本文字,以視覺化檢查模型的輸出。

這些步驟是深度神經網路訓練的基本流程。透過這些步驟,可以實作模型的訓練和最佳化。

內容解密:

上述步驟可以使用 PyTorch 實作。以下是簡單的範例:

import torch
import torch.nn as nn
import torch.optim as optim

# 定義模型
class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.fc1 = nn.Linear(784, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

# 初始化模型、損失函式和最佳化器
model = Model()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 訓練模型
for epoch in range(10):
    for x, y in train_loader:
        # 前向傳播
        output = model(x)
        loss = criterion(output, y)

        # 反向傳播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        # 列印損失
        print(f'Epoch {epoch+1}, Loss: {loss.item()}')

這個範例示範瞭如何定義模型、初始化損失函式和最佳化器,以及如何訓練模型。

深度神經網路訓練流程

深度神經網路的訓練過程涉及多個步驟,包括資料前處理、模型定義、損失函式計算、最佳化器更新等。在 PyTorch 中,訓練流程通常如下所述。

訓練迴圈

訓練迴圈是指模型對訓練資料集進行多次迭代,以期達到最佳的模型引數。一個 epoch 指的是模型對整個訓練資料集進行一次完整的迭代。批次(batch)的數量由使用者決定,通常根據可用的計算資源和資料集的大小來設定。

在每個訓練迴圈中,模型會對每個批次的資料計算損失函式,然後根據損失函式的梯度更新模型引數。這個過程會在多個 epoch 中重複進行,直到模型收斂或達到預設的停止條件。

訓練流程實作

以下是使用 PyTorch 實作的簡單訓練流程:

def train_model_simple(model, train_loader, val_loader, optimizer, device, num_epochs, eval_freq, eval_iter, start_context, tokenizer):
    train_losses, val_losses, track_tokens_seen = [], [], []
    tokens_seen, global_step = 0, -1

    for epoch in range(num_epochs):
        model.train()
        for input_batch, target_batch in train_loader:
            optimizer.zero_grad()
            loss = calc_loss_batch(input_batch, target_batch, model, device)
            loss.backward()
            #... 更新模型引數...

在這個實作中,train_model_simple 函式接受多個引數,包括模型、訓練資料載入器、驗證資料載入器、最佳化器、裝置、epoch 數量等。函式內部的迴圈結構反映了訓練流程的步驟,包括對每個批次的資料計算損失函式、更新模型引數等。

損失函式計算

損失函式計算是訓練流程中的關鍵步驟。損失函式用於衡量模型預測結果與真實標籤之間的差異。常見的損失函式包括均方差損失、交叉熵損失等。在 PyTorch 中,可以使用 calc_loss_batch 函式計算每個批次的損失函式:

def calc_loss_batch(input_batch, target_batch, model, device):
    #... 計算損失函式...
    return loss

最佳化器更新

最佳化器更新是根據損失函式的梯度更新模型引數的過程。常見的最佳化器包括 SGD、Adam 等。在 PyTorch 中,可以使用 optimizer 物件更新模型引數:

optimizer.zero_grad()
loss.backward()
optimizer.step()

監控步驟

監控步驟包括列印損失值、生成文字樣本等,用於評估模型的效能。在 PyTorch 中,可以使用 print 函式列印損失值:

print(f'Epoch {epoch+1}, Loss: {loss.item()}')

內容解密:模型訓練過程

在模型訓練過程中,首先需要更新模型的引數,使用 optimizer.step() 來實作。然後,需要跟蹤已經看到的token數量,使用 tokens_seen 變數來記錄。

接下來,需要計算模型的訓練損失和驗證損失,使用 evaluate_model 函式來實作。這個函式會計算模型在訓練集和驗證集上的損失,並傳回這兩個損失值。

然後,需要將訓練損失和驗證損失儲存起來,使用 train_lossesval_losses 列表來記錄。同時,也需要跟蹤已經看到的token數量,使用 track_tokens_seen 列表來記錄。

在每次模型更新後,需要列印預出當前的訓練損失和驗證損失,使用 print 函式來實作。同時,也需要生成並列印預出一個樣本,使用 generate_and_print_sample 函式來實作。

最後,需要傳回訓練損失、驗證損失和已經看到的token數量的列表,使用 return 陳述式來實作。

圖表翻譯:

  flowchart TD
    A[模型訓練] --> B[更新模型引數]
    B --> C[計算訓練損失和驗證損失]
    C --> D[儲存訓練損失和驗證損失]
    D --> E[跟蹤已經看到的token數量]
    E --> F[列印預出當前的訓練損失和驗證損失]
    F --> G[生成並列印預出一個樣本]
    G --> H[傳回訓練損失、驗證損失和已經看到的token數量的列表]

這個流程圖描述了模型訓練過程中各個步驟的執行順序。首先,更新模型引數,然後計算訓練損失和驗證損失,接下來儲存這些損失值,然後跟蹤已經看到的token數量,然後列印預出當前的訓練損失和驗證損失,最後生成並列印預出一個樣本,並傳回相關的列表。

深度學習模型的預訓練過程

在深度學習中,預訓練是一個至關重要的步驟,尤其是在處理大量未標記的資料時。這個過程涉及使用大規模的未標記資料集來訓練模型,以學習到有用的特徵表示。接下來,我們將探討預訓練的具體實作步驟。

預訓練的主要目標

預訓練的主要目標是使模型學習到能夠有效地表示資料的特徵。這些特徵可以用於下游任務,如影像分類別、語言翻譯等。透過預訓練,模型可以學習到更好的初始權重,這些權重可以用作下游任務的起點。

預訓練過程

預訓練過程通常涉及以下步驟:

  1. 資料準備:收集和準備大規模的未標記資料集。
  2. 模型定義:定義一個適合預訓練任務的模型結構。
  3. 損失函式選擇:選擇一個適合預訓練任務的損失函式。
  4. 最佳化器選擇:選擇一個適合預訓練任務的最佳化器。
  5. 訓練迴圈:開始訓練迴圈,計算損失梯度,更新模型權重。

訓練迴圈詳細步驟

  • 計算損失梯度:計算當前批次的損失梯度。
  • 更新模型權重:使用損失梯度更新模型權重。
  • 可選的評估步驟:在每個epoch結束後,進行評估以檢查模型的效能。

評估模型效能

評估模型效能是一個重要的步驟,透過評估,可以檢查模型在訓練和驗證集上的效能。這通常涉及計算模型在這些資料集上的損失。

def evaluate_model(model, train_loader, val_loader, device, eval_iter):
    model.eval()
    with torch.no_grad():
        train_loss = calc_loss_loader(train_loader, model, device, num_batches=eval_iter)
        val_loss = calc_loss_loader(val_loader, model, device, num_batches=eval_iter)
    # 進一步處理和傳回train_loss和val_loss

預訓練的挑戰

預訓練也面臨著一些挑戰,例如:

  • 過度適應:模型可能過度適應訓練資料,從而導致在新資料上的效能不佳。
  • 欠適應:模型可能沒有足夠地學習到有用的特徵,從而導致效能不佳。
圖表翻譯:
  flowchart TD
    A[開始] --> B[資料準備]
    B --> C[模型定義]
    C --> D[損失函式選擇]
    D --> E[最佳化器選擇]
    E --> F[訓練迴圈]
    F --> G[評估模型效能]
    G --> H[傳回結果]

上述流程圖展示了預訓練過程中的主要步驟,從資料準備到評估模型效能。每一步驟都對於預訓練的成功至關重要。

訓練迴圈中的評估和生成

在訓練迴圈中,評估模型的效能和生成文字樣本是兩個重要的步驟。評估模型的效能可以幫助我們瞭解模型的訓練進度,而生成文字樣本可以提供一個直觀的方式來觀察模型的生成能力。

評估模型

評估模型的效能可以透過 evaluate_model 函式來完成。這個函式計算模型在驗證集上的損失和準確率,並傳回這些指標。透過這個函式,我們可以得到一個數值上的評估結果,以便於觀察模型的訓練進度。

def evaluate_model(model, device, val_loader, num_batches):
    model.eval()
    total_loss = 0
    with torch.no_grad():
        for batch in val_loader:
            input_ids, attention_mask, labels = batch
            input_ids, attention_mask, labels = input_ids.to(device), attention_mask.to(device), labels.to(device)
            outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
            loss = outputs.loss
            total_loss += loss.item()
    return total_loss / num_batches

生成文字樣本

生成文字樣本可以透過 generate_and_print_sample 函式來完成。這個函式接收一個文字片段作為輸入,將其轉換為令牌 ID,並使用 generate_text_simple 函式生成一個文字樣本。

def generate_and_print_sample(model, tokenizer, device, start_context):
    model.eval()
    context_size = model.pos_emb.weight.shape[0]
    encoded = text_to_token_ids(start_context, tokenizer).to(device)
    with torch.no_grad():
        token_ids = generate_text_simple(
            model=model, idx=encoded,
            max_new_tokens=50, context_size=context_size
        )
        decoded_text = token_ids_to_text(token_ids, tokenizer)
        print(decoded_text.replace("\n", " "))
    model.train()

選擇最佳化器

在訓練迴圈中,我們選擇使用 AdamW 最佳化器。AdamW 是 Adam 最佳化器的一種變體,它改進了權重衰減的方法,以減少模型複雜度和過擬合的風險。這使得 AdamW 能夠實作更有效的正則化和更好的泛化能力。

optimizer = AdamW(model.parameters(), lr=1e-5)

Dropout 和梯度追蹤

在評估模型時,我們會停用 Dropout 和梯度追蹤,以確保結果的穩定性和可複製性。這是因為在評估階段,我們不需要更新模型引數,因此可以停用梯度追蹤以減少計算負擔。

model.eval()
with torch.no_grad():
    # 評估模型
    pass

透過這些步驟,我們可以在訓練迴圈中評估模型的效能和生成文字樣本,並使用 AdamW 最佳化器和停用 Dropout 和梯度追蹤來確保結果的穩定性和可複製性。

訓練大語言模型(LLM)

讓我們透過實際操作來瞭解大語言模型的訓練過程。首先,我們需要設定模型的隨機種子,以確保結果的一致性。

torch.manual_seed(123)

接下來,我們建立一個 GPT 模型例項,指定其組態為 124M。

model = GPTModel(GPT_CONFIG_124M)

然後,我們將模型移到指定的裝置(如 GPU 或 CPU)。

model.to(device)

為了最佳化模型的引數,我們使用 AdamW 最佳化器,設定學習率為 0.0004 和權重衰減為 0.1。

optimizer = torch.optim.AdamW(
    model.parameters(),
    lr=0.0004, weight_decay=0.1
)

現在,我們設定訓練的 epochs 數量為 10。

num_epochs = 10

接著,我們呼叫 train_model_simple 函式開始訓練過程,傳入模型、訓練資料載入器、驗證資料載入器、最佳化器、裝置、epochs 數量、評估頻率和評估迭代次數等引數。

train_losses, val_losses, tokens_seen = train_model_simple(
    model, train_loader, val_loader, optimizer, device,
    num_epochs=num_epochs, eval_freq=5, eval_iter=5,
    start_context="Every effort moves you", tokenizer=tokenizer
)

訓練過程約需 5 分鐘完成,過程中會輸出訓練和驗證損失的變化情況。從輸出的結果可以看到,隨著訓練的進行,訓練損失從 9.781 下降到 0.391,驗證損失從 9.933 下降到 6.452。

內容解密:

上述程式碼展示瞭如何訓練一個大語言模型。首先,我們設定隨機種子以確保結果的一致性。然後,我們建立一個 GPT 模型例項並將其移到指定的裝置。接著,我們設定最佳化器和學習率,然後開始訓練過程。訓練過程中會輸出訓練和驗證損失的變化情況,從而可以觀察到模型的效能改善情況。

圖表翻譯:

下面是使用 Matplotlib 繪製的訓練和驗證損失變化圖表。

  flowchart TD
    A[開始] --> B[設定隨機種子]
    B --> C[建立 GPT 模型]
    C --> D[設定最佳化器和學習率]
    D --> E[開始訓練過程]
    E --> F[輸出訓練和驗證損失]
    F --> G[繪製損失變化圖表]

這個圖表展示了訓練過程中訓練和驗證損失的變化情況,可以直觀地觀察到模型的效能改善情況。

圖表示意:

此圖表使用 Matplotlib 繪製,展示了訓練和驗證損失隨著 epochs 的變化。從圖表中可以看到,訓練損失迅速下降,而驗證損失也呈現下降趨勢,但最終仍然高於訓練損失。這表明模型在訓練資料上取得了良好的效果,但在驗證資料上仍然存在一定的過擬合現象。

訓練和驗證損失分析

在深度學習模型的訓練過程中,監控訓練和驗證損失的變化是非常重要的。這可以幫助我們瞭解模型的學習情況和是否出現過擬合(overfitting)的問題。

import matplotlib.pyplot as plt
import torch
from matplotlib.ticker import MaxNLocator

# 假設 epochs_seen、train_losses、val_losses 和 tokens_seen 已經定義
fig, ax1 = plt.subplots(figsize=(5, 3))
ax1.plot(epochs_seen, train_losses, label="訓練損失")
ax1.plot(epochs_seen, val_losses, linestyle="-.", label="驗證損失")
ax1.set_xlabel("Epochs")
ax1.set_ylabel("損失")
ax1.legend(loc="upper right")
ax1.xaxis.set_major_locator(MaxNLocator(integer=True))

ax2 = ax1.twiny()
ax2.plot(tokens_seen, train_losses, alpha=0)
ax2.set_xlabel("已見字元數")

fig.tight_layout()
plt.show()

# 定義 epochs_tensor
epochs_tensor = torch.linspace(0, num_epochs, len(train_losses))

# 定義 plot_losses 函式
def plot_losses(epochs, tokens_seen, train_losses, val_losses):
    # 在這裡實作 plot_losses 函式的邏輯
    pass

plot_losses(epochs_tensor, tokens_seen, train_losses, val_losses)

內容解密:

上述程式碼用於繪製訓練和驗證損失隨著epoch數量的變化。首先,建立一個子圖ax1,然後在這個子圖上繪製訓練損失和驗證損失的曲線。接著,設定x軸和y軸的標籤,並新增圖例。然後,建立另一個子圖ax2,這個子圖與ax1分享同一個y軸,但具有不同的x軸,代表已見字元數。最後,呼叫plot_losses函式繪製損失曲線。

圖表翻譯:

圖5.12顯示了訓練和驗證損失的變化。在開始的幾個epoch中,兩種損失都迅速下降,這表明模型正在學習。然而,隨著epoch數量的增加,訓練損失繼續下降,而驗證損失停滯不前甚至上升,這是模型過擬合的跡象。這意味著模型過度擬合了訓練資料,不能很好地泛化到新的、未見過的資料。這種現象通常需要透過調整模型結構、增加正則化項或使用早停機制等方法來解決。

控制隨機性的解碼策略

在前面的章節中,我們探討瞭如何訓練一個大語言模型(LLM)。然而,當我們使用這個模型生成文字時,會發現它往往會記住訓練資料中的內容,而不是生成新的、原創的文字。這是因為我們的訓練資料集太小,模型在多個epoch中反覆學習相同的資料。

為瞭解決這個問題,我們可以使用一些解碼策略來控制隨機性,從而提高LLM生成文字的原創性。首先,我們來看看generate_text_simple函式,這個函式是我們之前用來生成文字的。

def generate_text_simple(model, input_ids, max_length):
    #...

接下來,我們將介紹兩種技術:溫度縮放(temperature scaling)和top-k取樣(top-k sampling),用於改進generate_text_simple函式。

首先,我們需要將模型切換到評估模式,以關閉隨機元件,如dropout:

model.to("cpu")
model.eval()

然後,我們可以將GPTModel例項(model)插入generate_text_simple函式中,使用LLM生成一個token tại một時間:

output = model.generate(input_ids, max_length=max_length)

內容解密:

上述程式碼中,我們使用model.generate方法來生成文字。這個方法會根據輸入的input_idsmax_length引數生成一個token序列。

圖表翻譯:

此圖示為LLM文字生成流程圖:

  flowchart TD
    A[輸入] --> B[模型]
    B --> C[生成]
    C --> D[輸出]

在這個流程圖中,輸入是指用於初始化LLM的token序列,模型是指GPTModel例項,生成是指LLM生成token的過程,輸出是指生成的token序列。

接下來,我們將探討溫度縮放和top-k取樣兩種技術,來改進LLM文字生成的原創性。

訓練模型並載入預先訓練的權重

在本章中,我們將探討如何訓練大語言模型(LLM)以生成類別似人類的文字。此外,我們還會實作額外的 LLM 文字生成策略,以減少訓練資料的記憶化。

首先,我們需要載入預先訓練的權重從 OpenAI 到我們的 LLM 模型中。這些預先訓練的權重可以幫助我們的模型更快地收斂並生成更好的文字。

儲存和載入模型權重

為了方便未來的訓練和使用,我們需要實作函式來儲存和載入 LLM 權重。這樣,我們就可以在任何時候繼續訓練模型或使用已經訓練好的模型。

import torch

def save_model_weights(model, filename):
    torch.save(model.state_dict(), filename)

def load_model_weights(model, filename):
    model.load_state_dict(torch.load(filename))

實作額外的 LLM 文字生成策略

為了減少訓練資料的記憶化,我們可以實作額外的 LLM 文字生成策略。例如,我們可以使用不同的解碼策略,例如 top-k 解碼或核樣本解碼。

def generate_text(model, input_ids, max_new_tokens, context_size):
    # 實作 top-k 解碼
    output = model.generate(input_ids, max_new_tokens=max_new_tokens, context_size=context_size, top_k=50)
    return output

# 測試生成文字
tokenizer = tiktoken.get_encoding("gpt2")
input_ids = text_to_token_ids("Every effort moves you", tokenizer)
output = generate_text(model, input_ids, max_new_tokens=25, context_size=GPT_CONFIG_124M["context_length"])
print("Output text:\n", token_ids_to_text(output, tokenizer))

載入預先訓練的權重

最後,我們需要載入預先訓練的權重從 OpenAI 到我們的 LLM 模型中。

# 載入預先訓練的權重
load_model_weights(model, "pretrained_weights.pth")

圖表翻譯:

以下是使用 Mermaid 圖表來展示我們的 LLM 文字生成流程:

  flowchart TD
    A[輸入文字] --> B[編碼器]
    B --> C[解碼器]
    C --> D[生成文字]
    D --> E[輸出文字]

在這個圖表中,我們可以看到輸入文字被編碼器處理,然後由解碼器生成文字,最後輸出生成的文字。

5.3 解碼策略:控制生成文字的隨機性

在前面的章節中,我們瞭解瞭如何使用大語言模型(LLM)生成文字。然而,預設的生成過程是根據確定性的,即每次給定相同的起始上下文,模型都會生成相同的輸出。為了增加生成文字的多樣性和隨機性,我們可以使用溫度縮放(temperature scaling)技術。

5.3.1 溫度縮放

溫度縮放是一種新增機率選擇過程到下一個token生成任務的技術。之前,在generate_text_simple函式中,我們總是使用torch.argmax選擇機率最高的token作為下一個token,也就是所謂的貪婪解碼。為了生成具有更多變化的文字,我們可以用一個從機率分佈中抽樣的函式替換argmax,這裡的機率分佈是LLM在每個token生成步驟中為每個詞彙項生成的機率分數。

示例:使用小詞彙演示機率抽樣

讓我們使用一個非常小的詞彙來演示機率抽樣過程:

vocab = {
    "closer": 0,
    "every": 1,
    "effort": 2,
    "forward": 3,
    "inches": 4,
    "moves": 5,
    "pizza": 6,
    "toward": 7,
    "you": 8,
}

inverse_vocab = {v: k for k, v in vocab.items()}

假設LLM給定起始上下文"every effort moves you",並生成以下的下一個token的logits:

next_token_logits = torch.tensor([
    4.51, 0.89, -1.90, 6.75, 1.63, -1.62, -1.89, 6.28, 1.79
])

如第4章所討論的,內部generate_text_simple,我們透過softmax函式將logits轉換為機率,並透過argmax函式獲得對應於生成token的ID,然後透過逆詞彙將其映射回文字:

probas = torch.softmax(next_token_logits, dim=0)
next_token_id = torch.argmax(probas).item()
print(inverse_vocab[next_token_id])

由於最大logit值和相應的最大softmax機率分數在第四個位置(索引位置3,因為Python使用0索引),因此生成的單詞是"forward"。

實作機率抽樣過程

為了實作機率抽樣過程,我們可以用PyTorch中的multinomial函式替換argmax

torch.manual_seed(123)
next_token_id = torch.multinomial(probas, num_samples=1).item()
print(inverse_vocab[next_token_id])

輸出的結果仍然是"forward"。這是因為multinomial函式根據其機率分數對下一個token進行抽樣,而"forward"仍然是最可能的token。

重複抽樣

讓我們實作一個函式,重複這個抽樣過程1000次:

def print_sampled_tokens(probas):
    torch.manual_seed(123)
    sample = [torch.multinomial(probas, num_samples=1).item() for _ in range(1_000)]
    sampled_ids = torch.bincount(torch.tensor(sample))
    #...

這個函式會顯示出每個token被抽樣到的次數,從而給出對模型生成文字隨機性的直觀感受。

語言模型的溫度調整

在前面的章節中,我們探討瞭如何使用多元分佈進行語言模型的取樣。現在,我們來看看如何透過溫度調整(temperature scaling)來控制語言模型的輸出分佈。

多元分佈取樣

首先,讓我們觀察一下取樣的輸出結果:

73 x closer 0 x every 0 x effort 582 x forward 2 x inches 0 x moves 0 x pizza 343 x toward

從這個結果中,我們可以看到「forward」這個詞被取樣的次數最多(582次),但其他詞彙如「closer」、「inches」和「toward」也會被取樣到。這意味著,如果我們在生成函式中使用多元分佈函式來取代argmax函式,語言模型就會有機會生成不同的文字,例如「every effort moves you toward」、「every effort moves you inches」和「every effort moves you closer」,而不僅僅是「every effort moves you forward」。

溫度調整

現在,讓我們來看看如何使用溫度調整來控制語言模型的輸出分佈。溫度調整是一個簡單的概念,就是將logits除以一個溫度引數。以下是實作溫度調整的Python函式:

import torch

def softmax_with_temperature(logits, temperature):
    scaled_logits = logits / temperature
    return torch.softmax(scaled_logits, dim=0)

溫度引數大於1會導致語言模型的輸出分佈更加均勻,而溫度引數小於1會導致輸出分佈更加集中(或更尖峰)。讓我們透過一些例子來演示這個概念。

圖表翻譯:

  graph LR
    A[溫度調整] -->|溫度大於1|> B[均勻分佈]
    A -->|溫度小於1|> C[集中分佈]
    B --> D[語言模型輸出]
    C --> D

內容解密:

在上面的例子中,我們可以看到溫度調整如何影響語言模型的輸出分佈。當溫度大於1時,語言模型的輸出分佈會更加均勻,這意味著所有詞彙都有相似的機會被取樣到。當溫度小於1時,語言模型的輸出分佈會更加集中,這意味著某些詞彙會被取樣到的機會更高。

探索溫度引數對語言模型預測的影響

在語言模型中,溫度引數(temperature)是一個重要的超引數,它控制著模型預測的隨機性。在本文中,我們將探討溫度引數對語言模型預測的影響,並透過實驗結果進行分析。

實驗設定

首先,我們定義了一個溫度引數列表 temperatures = [1, 0.1, 5],其中每個溫度值代表著不同的隨機性水平。接著,我們計算了每個溫度下的 softmax 機率 scaled_probas,並使用 PyTorch 的 softmax_with_temperature 函式進行計算。

import torch
import matplotlib.pyplot as plt

# 定義溫度引數列表
temperatures = [1, 0.1, 5]

# 定義詞彙表
vocab = {'forward': 0, 'backward': 1, 'left': 2, 'right': 3}

# 定義 softmax 函式
def softmax_with_temperature(logits, T):
    return torch.softmax(logits / T, dim=0)

# 計算每個溫度下的 softmax 機率
scaled_probas = [softmax_with_temperature(torch.tensor([0.6, 0.2, 0.1, 0.1]), T) for T in temperatures]

結果分析

接著,我們使用 Matplotlib 將每個溫度下的 softmax 機率繪製成條形圖。圖中,每個條形代表著一個詞彙的機率,x 軸代表著詞彙,y 軸代表著機率。

# 繪製條形圖
x = torch.arange(len(vocab))
bar_width = 0.15
fig, ax = plt.subplots(figsize=(5, 3))

for i, T in enumerate(temperatures):
    rects = ax.bar(x + i * bar_width, scaled_probas[i], bar_width, label=f'Temperature = {T}')

ax.set_ylabel('Probability')
ax.set_xticks(x)
ax.set_xticklabels(vocab.keys(), rotation=90)
ax.legend()
plt.tight_layout()
plt.show()

從圖中可以看出,當溫度引數為 1 時,模型的預測結果與原始 softmax 機率相同,即不使用任何溫度縮放。在這種情況下,詞彙 “forward” 的機率約為 60%,如圖所示。

溫度引數的影響

透過實驗結果可以看出,溫度引數對語言模型預測的影響非常大。當溫度引數增加時,模型的預測結果變得更加隨機,詞彙的機率分佈變得更加均勻。相反,當溫度引數減少時,模型的預測結果變得更加確定,詞彙的機率分佈變得更加集中。

因此,在實際應用中,需要根據具體情況選擇合適的溫度引數,以達到最佳的預測結果。

從模型訓練、預訓練到解碼策略的全面探討來看,構建高效能的大語言模型(LLM)需要多個環節的密切配合。透過PyTorch程式碼範例的演示,我們深入瞭解了模型訓練的核心流程,包含資料批次化、前向傳播、反向傳播及模型引數更新等關鍵步驟。此外,預訓練策略的應用,特別是損失函式的選擇和最佳化器的設定,對於模型最終效能的提升至關重要。然而,僅僅完成模型訓練並不足以確保生成高品質的文字。控制生成文字隨機性的解碼策略,例如溫度縮放和top-k取樣,是避免模型過擬合訓練資料、提升文字原創性的有效手段。同時,模型的評估和監控也是不可或缺的環節。透過觀察訓練和驗證損失曲線,我們可以及時發現並解決潛在的過擬合問題。玄貓認為,大語言模型的訓練是一個複雜且迭代的過程,需要持續的實驗和調優。未來,隨著模型架構的創新和訓練資料的積累,LLM的生成能力將會進一步提升,並在更多應用場景中展現其巨大的潛力。對於臺灣的開發者而言,掌握這些核心技術,並結合本地語言和文化特性進行模型的客製化訓練,將是未來在AI領域取得成功的關鍵。