在深度學習模型訓練流程中,資料前處理和分批訓練至關重要。資料前處理包含分詞、建立訓練資料集等步驟,將原始資料轉換成模型可理解的格式。分批訓練則將資料集分割成小批次,有效提升模型訓練效率和效能。實務上,常使用 PyTorch 等框架建立資料載入器,並透過計算批次損失來評估模型效能。選擇合適的批次大小能平衡訓練速度和記憶體需求,對於大語言模型的訓練尤為重要。

資料前處理與分批訓練

在深度學習模型的訓練過程中,資料的前處理和分批訓練是一個非常重要的步驟。這個步驟不僅能夠提高模型的訓練效率,還能夠幫助模型更好地學習資料中的模式。

資料分詞(Tokenized)

資料分詞是指將原始資料分解成更小的單位,例如單詞或字元,以便於模型進行處理。這個步驟可以幫助模型更好地理解資料中的語言結構和語義關係。

訓練資料集(Training datasets)

訓練資料集是指用於訓練模型的資料集合。這個資料集應該包含足夠多的樣本,以便於模型學習到資料中的模式和關係。

分批訓練(Training datasets in batches)

分批訓練是指將訓練資料集分成多個小批次,每個批次包含一定數量的樣本。這個方法可以幫助模型更好地學習資料中的模式,同時也可以提高訓練效率。

批次1(Batch 1)

第一批次包含了以下樣本:

  • 818
  • 262
  • 13360
  • 286
  • 5874
  • 33543
  • 11
  • 810
  • 2695
  • 13580
  • 82
  • 17700
  • 11
  • 612
  • 7160
  • 257

批次2(Batch 2)

第二批次包含了以下樣本:

  • 46944
  • 25451
  • 1900
  • 355
  • 8474
  • 13829
  • 4696
  • 13
  • 3423
  • 11
  • 31095
  • 262
  • 10296
  • 20009
  • 286

最後一批(Last batch)

最後一批包含了以下樣本:

  • 1486
  • 4847
  • 11
  • 2456
  • 502
  • 4066
  • 1231
  • 2081
  • 4007
  • 11
  • 1865
  • 351
  • 257
  • 45960
  • 286

圖表翻譯:分批訓練流程

  flowchart TD
    A[開始] --> B[資料分詞]
    B --> C[分批訓練]
    C --> D[批次1]
    C --> E[批次2]
    C --> F[最後一批]
    D --> G[模型訓練]
    E --> G
    F --> G
    G --> H[模型評估]

圖表解釋:

上述圖表展示了分批訓練的流程。首先,資料需要進行分詞處理。接下來,資料會被分成多個批次,每個批次包含一定數量的樣本。每個批次會被用於模型訓練,最後,模型會被評估以確保其效能。

評估生成式文字模型

在進行模型評估之前,我們需要先準備好訓練和驗證資料。這涉及將輸入文字分割成訓練和驗證集,然後對這些文字進行標記化(tokenization),最後將標記化的文字分割成使用者指定長度的塊(chunks)。

資料準備

首先,我們需要將輸入文字分割成訓練和驗證集。這可以透過設定一個比例來決定哪部分的資料用於訓練,哪部分用於驗證。接著,我們對這些文字進行標記化,這一步驟是將文字轉換成模型可以理解的格式。最後,我們將標記化的文字分割成塊,這些塊的長度由使用者指定。

建立資料載入器

使用create_dataloader_v1函式從第二章中,我們可以建立訓練和驗證資料載入器。這個函式需要以下引數:資料集、批次大小(batch size)、最大長度(max length)、步長(stride)、是否丟棄最後一個批次(drop_last)以及是否打亂資料順序(shuffle)。

from chapter02 import create_dataloader_v1

torch.manual_seed(123)

train_loader = create_dataloader_v1(
    train_data,
    batch_size=2,
    max_length=GPT_CONFIG_124M["context_length"],
    stride=GPT_CONFIG_124M["context_length"],
    drop_last=True,
    shuffle=True,
    num_workers=0
)

val_loader = create_dataloader_v1(
    val_data,
    batch_size=2,
    max_length=GPT_CONFIG_124M["context_length"],
    stride=GPT_CONFIG_124M["context_length"],
    drop_last=False,
    shuffle=False,
    num_workers=0
)

驗證資料載入器

為了確保資料載入器被正確建立,我們可以迭代遍歷這些載入器來檢查它們的內容。

print("Train loader:")

這樣做可以幫助我們確認資料是否被正確分割和打亂,以及批次大小是否符合預期。

批次大小選擇

在實際應用中,選擇合適的批次大小對於模型的訓練效率和效果有著重要影響。較大的批次大小可以提高訓練速度,但也可能增加記憶體需求和計算複雜度。因此,需要根據具體的情況選擇合適的批次大小。在本例中,由於資料量較小,我們選擇了一個相對較小的批次大小,以減少計算資源的需求。

在未來的實踐中,訓練大語言模型(LLMs)時,批次大小通常會設定為1024或更大,以充分利用計算資源並提高訓練效率。然而,這也需要考慮到計算資源的限制和模型的複雜度。

圖表翻譯:

  flowchart TD
    A[資料準備] --> B[標記化]
    B --> C[分割成塊]
    C --> D[建立資料載入器]
    D --> E[驗證資料載入器]

圖表描述了從資料準備到建立資料載入器的過程,包括標記化、分割成塊和驗證資料載入器等步驟。這個過程對於確保模型的輸入資料正確和有效至關重要。

資料載入與驗證

在進行深度學習模型的訓練之前,瞭解資料的結構和形狀至關重要。下面,我們將展示如何檢視訓練資料和驗證資料的形狀。

# 這裡假設train_loader和val_loader已經被定義並載入了資料
for x, y in train_loader:
    print(f"訓練資料形狀:{x.shape}, {y.shape}")

對於驗證資料,同樣地,我們可以使用以下程式碼來檢視其形狀:

print("\n驗證資料載入器:")
for x, y in val_loader:
    print(f"驗證資料形狀:{x.shape}, {y.shape}")

預期的輸出結果應該反映出每個批次(batch)中的資料形狀。在這個例子中,假設每個批次包含2個樣本,每個樣本的特徵維度為256,因此輸出應該類別似於:

訓練資料形狀:torch.Size([2, 256]), torch.Size([2, 256])
訓練資料形狀:torch.Size([2, 256]), torch.Size([2, 256])
...
驗證資料載入器:
驗證資料形狀:torch.Size([2, 256]), torch.Size([2, 256])
驗證資料形狀:torch.Size([2, 256]), torch.Size([2, 256])
...

這些輸出結果告訴我們,每個批次中的資料形狀是否正確,這對於後續的模型設計和訓練過程非常重要。

內容解密:

  • train_loaderval_loader 是用於載入訓練資料和驗證資料的資料載入器。
  • for x, y in train_loader: 這個迴圈遍歷每個批次的訓練資料,其中 x 代表輸入特徵,y 代表對應的標籤。
  • print(x.shape, y.shape) 用於列印每個批次中輸入資料和標籤的形狀。
  • 同樣地,對於驗證資料,使用 val_loader 來載入和檢視其形狀。

圖表翻譯:

  flowchart TD
    A[開始] --> B[載入訓練資料]
    B --> C[檢視訓練資料形狀]
    C --> D[載入驗證資料]
    D --> E[檢視驗證資料形狀]
    E --> F[結束]

這個流程圖描述了載入和檢視訓練及驗證資料的過程,從開始到結束,依序進行資料載入和形狀檢視。

計算批次損失

計算批次損失是訓練模型的關鍵步驟。以下是計算批次損失的實作:

calc_loss_batch 函式

def calc_loss_batch(input_batch, target_batch, model, device):
    """
    計算單個批次的損失。

    Args:
        input_batch (Tensor): 輸入批次。
        target_batch (Tensor): 目標批次。
        model (nn.Module): 模型。
        device (torch.device): 計算裝置。

    Returns:
        Tensor: 單個批次的損失。
    """
    input_batch = input_batch.to(device)
    target_batch = target_batch.to(device)
    logits = model(input_batch)
    loss = torch.nn.functional.cross_entropy(logits.flatten(0, 1), target_batch.flatten())
    return loss

calc_loss_loader 函式

def calc_loss_loader(data_loader, model, device, num_batches=None):
    """
    計算資料載入器中所有批次的損失。

    Args:
        data_loader (DataLoader): 資料載入器。
        model (nn.Module): 模型。
        device (torch.device): 計算裝置。
        num_batches (int, optional): 計算損失的批次數量。 Defaults to None.

    Returns:
        Tensor: 所有批次的平均損失。
    """
    total_loss = 0.
    if len(data_loader) == 0:
        return float("nan")
    elif num_batches is None:
        num_batches = len(data_loader)
    else:
        num_batches = min(num_batches, len(data_loader))
    for i, (input_batch, target_batch) in enumerate(data_loader):
        if i < num_batches:
            loss = calc_loss_batch(input_batch, target_batch, model, device)
            total_loss += loss.item()
    return total_loss / num_batches

這兩個函式分別計算單個批次的損失和資料載入器中所有批次的平均損失。calc_loss_batch 函式計算單個批次的損失,calc_loss_loader 函式則計算資料載入器中所有批次的平均損失。

使用方式

# 建立資料載入器
train_loader = DataLoader(train_dataset, batch_size=2, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=2, shuffle=False)

# 建立模型和裝置
model = MyModel()
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 計算訓練集和驗證集的損失
train_loss = calc_loss_loader(train_loader, model, device)
val_loss = calc_loss_loader(val_loader, model, device)

print(f"訓練集損失:{train_loss:.4f}")
print(f"驗證集損失:{val_loss:.4f}")

這樣就可以計算訓練集和驗證集的損失了。

計算批次損失的函式

在深度學習中,計算批次損失是訓練模型的重要步驟。以下是計算批次損失的函式實作:

def calc_loss_loader(data_loader, model, device, num_batches=None):
    """
    計算批次損失的函式。

    Args:
        data_loader (DataLoader): 資料載入器。
        model (Module): 神經網路模型。
        device (Device): 計算裝置(CPU或GPU)。
        num_batches (int, optional): 計算損失的批次數量。 Defaults to None.

    Returns:
        float: 平均損失。
    """
    total_loss = 0
    if num_batches is None:
        num_batches = len(data_loader)

    for batch_idx, (input_batch, target_batch) in enumerate(data_loader):
        if batch_idx >= num_batches:
            break

        # 將資料轉移到指定裝置
        input_batch, target_batch = input_batch.to(device), target_batch.to(device)

        # 清除模型的梯度
        model.zero_grad()

        # 順向傳播
        output = model(input_batch)
        loss = model.loss_fn(output, target_batch)

        # 累積損失
        total_loss += loss.item()

    # 計算平均損失
    avg_loss = total_loss / num_batches

    return avg_loss

功能解釋

此函式接受四個引數:data_loadermodeldevicenum_batches。其中,data_loader是負責載入資料的物件,model是神經網路模型,device是計算裝置(CPU或GPU),而num_batches是計算損失的批次數量,如果未指定則會計算所有批次的損失。

函式內部會迭代所有批次(或指定數量的批次),並對每個批次進行以下操作:

  1. 將輸入資料和目標資料轉移到指定裝置(CPU或GPU)。
  2. 清除模型的梯度。
  3. 進行順向傳播,計算輸出和損失。
  4. 累積損失。

最後,函式會計算平均損失並傳回。

範例使用

以下是使用此函式計算訓練和驗證損失的範例:

# 定義模型、裝置和資料載入器
model = MyModel()
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)

# 計算訓練損失
train_loss = calc_loss_loader(train_loader, model, device)

# 計算驗證損失
val_loss = calc_loss_loader(val_loader, model, device)

print(f"訓練損失:{train_loss:.4f}")
print(f"驗證損失:{val_loss:.4f}")

這個範例示範瞭如何使用calc_loss_loader函式計算訓練和驗證損失,並列印預出結果。

5.1 評估生成式文字模型

在訓練大語言模型(LLM)時,評估其效能是一個重要的步驟。評估的目標是計算模型在生成文字上的損失(loss),這通常是透過計算模型預測的結果與真實結果之間的差異來實作的。

計算批次損失

計算批次損失的過程涉及到以下步驟:

  1. 計算每個批次的損失:對於每個批次的資料,計算模型預測的結果與真實結果之間的差異。
  2. 計算所有批次的平均損失:將每個批次的損失加總,然後除以批次的數量,得到平均損失。

以下是計算批次損失的示例程式碼:

def calc_loss_loader(loader, model, device):
    total_loss = 0
    num_batches = 0
    with torch.no_grad():
        for batch in loader:
            input_ids = batch['input_ids'].to(device)
            labels = batch['labels'].to(device)
            outputs = model(input_ids, labels=labels)
            loss = outputs.loss
            total_loss += loss.item()
            num_batches += 1
    return total_loss / num_batches

應用於訓練和驗證集

現在,我們可以將 calc_loss_loader 函式應用於訓練和驗證集,以計算模型在這些資料上的損失:

model.to(device)

with torch.no_grad():
    train_loss = calc_loss_loader(train_loader, model, device)
    val_loss = calc_loss_loader(val_loader, model, device)

print("訓練損失:", train_loss)
print("驗證損失:", val_loss)

輸出結果如下:

訓練損失: 10.98758347829183
驗證損失: 10.98110580444336

由於模型尚未進行訓練,損失值相對較高。當模型學習生成下一個 token 時,損失值會趨近於 0。

訓練模型

現在,我們可以開始訓練模型,以減少損失值,使其更好地生成文字。這個過程將在下一節中詳述。

圖表翻譯:

以下是計算批次損失的流程圖:

  flowchart TD
    A[計算每個批次的損失] --> B[計算所有批次的平均損失]
    B --> C[輸出平均損失]

這個流程圖展示了計算批次損失的步驟,從計算每個批次的損失到計算所有批次的平均損失。

人工智慧模型的最佳化與應用

在人工智慧的應用中,模型的最佳化和正確使用是非常重要的。以下幾點是關於人工智慧模型的最佳化與應用的一些重點:

1. 文字生成

文字生成是人工智慧的一個基本應用,涉及到自然語言處理(NLP)領域。透過訓練模型,可以讓它學習到語言的模式和結構,從而生成類別似的人類語言文字。

2. 文字評估

文字評估是另一項重要的應用,涉及到對生成文字的品質和相關性進行評估。這可以透過各種指標和模型來實作,例如計算生成文字與目標文字之間的相似度。

3. 訓練和驗證損失

在模型訓練過程中,監控訓練損失和驗證損失是非常重要的。訓練損失反映了模型在訓練資料上的表現,而驗證損失則反映了模型在未見資料上的泛化能力。

4. 大語言模型訓練

大語言模型(LLM)的訓練是一項複雜的任務,需要大量的計算資源和資料。透過最佳化模型架構和訓練策略,可以提高模型的效能和效率。

5. 文字生成功能

文字生成功能是人工智慧模型的一個基本功能,透過輸入提示或條件,模型可以生成相關的文字內容。這項功能在各種應用中都非常重要,例如聊天機器人、文字摘要和內容生成等。

內容解密:

上述幾點強調了人工智慧模型的最佳化與應用中的重要環節。透過對模型進行最佳化和正確使用,可以提高其效能和效率,從而在各種應用中發揮更大的作用。

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

# 定義模型
class LLM(nn.Module):
    def __init__(self):
        super(LLM, self).__init__()
        self.fc1 = nn.Linear(128, 128)  # 輸入層
        self.fc2 = nn.Linear(128, 128)  # 隱藏層
        self.fc3 = nn.Linear(128, 128)  # 輸出層

    def forward(self, x):
        x = torch.relu(self.fc1(x))  # 啟用函式
        x = torch.relu(self.fc2(x))
        x = self.fc3(x)
        return x

# 初始化模型和最佳化器
model = LLM()
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 訓練模型
for epoch in range(100):
    optimizer.zero_grad()
    outputs = model(inputs)
    loss = criterion(outputs, labels)
    loss.backward()
    optimizer.step()
    print('Epoch {}: Loss = {:.4f}'.format(epoch+1, loss.item()))

圖表翻譯:

此圖示為一個簡單的人工智慧模型架構,包括輸入層、隱藏層和輸出層。透過這個模型,可以實作基本的文字生成和評估功能。

  flowchart TD
    A[輸入層] --> B[隱藏層]
    B --> C[輸出層]
    C --> D[輸出]

圖表翻譯:此流程圖描述了人工智慧模型的基本架構,從輸入層開始,經過隱藏層進行處理,最終生成輸出結果。這個流程是在人工智慧應用中非常重要的一部分。

訓練大語言模型(LLM)

5.2 訓練 LLM

在本文中,我們將實作大語言模型(LLM)的預訓練過程。為了保持程式碼的簡潔和可讀性,我們將關注於一個簡單的訓練迴圈。對於有興趣的讀者,可以在附錄 D 中學習更多高階技術,包括學習率預熱、餘弦退火和梯度裁剪。

圖 5.11 展示了一個典型的 PyTorch 神經網路訓練工作流程,我們將使用這個工作流程來訓練 LLM。它概述了八個步驟,從迭代每個 epoch 開始,然後處理批次,重置梯度,計算損失和新的梯度,並更新模型引數。

訓練 LLM 的步驟

  1. 迭代每個 epoch:我們需要迭代多個 epoch,以確保模型充分學習。
  2. 迭代批次:在每個 epoch 中,我們需要迭代批次,以便模型可以學習到不同的資料。
  3. 重置梯度:在每個批次中,我們需要重置梯度,以便模型可以從頭開始學習。
  4. 計算損失:我們需要計算模型的損失,以便評估模型的效能。
  5. 計算新的梯度:我們需要計算新的梯度,以便更新模型引數。
  6. 更新模型引數:我們需要更新模型引數,以便模型可以學習到新的知識。
  7. 儲存和載入預訓練權重:我們需要儲存和載入預訓練權重,以便可以繼續訓練模型或使用已經訓練好的模型。
  8. 實作額外的文字生成策略:我們需要實作額外的文字生成策略,以減少訓練資料的記憶化。

實作預訓練

在實作預訓練過程中,我們需要關注於以下幾點:

  • 學習率預熱:我們需要使用學習率預熱來提高模型的學習效率。
  • 餘弦退火:我們需要使用餘弦退火來調整學習率,以便模型可以更好地學習。
  • 梯度裁剪:我們需要使用梯度裁剪來防止梯度爆炸,以便模型可以更穩定地學習。
圖表翻譯

上述流程圖展示了大語言模型(LLM)的預訓練過程。從開始到結束,流程圖概述了八個步驟,包括迭代每個 epoch、迭代批次、重置梯度、計算損失、計算新的梯度、更新模型引數、儲存和載入預訓練權重,以及實作額外的文字生成策略。這些步驟都是預訓練過程中非常重要的部分,可以使模型更好地學習和生成人類般的文字。

從技術架構視角來看,資料前處理和分批訓練是深度學習模型訓練的基本。本文深入剖析了資料分詞、訓練資料集的建立以及分批訓練的流程,並以圖表形式清晰地展示了資料處理的步驟。透過將資料分割成小批次進行訓練,模型能更有效地學習資料模式,提升訓練效率,尤其在處理大型資料集時效果顯著。然而,分批訓練也存在一些限制,例如批次大小的選擇會影響模型的收斂速度和泛化能力,過小的批次可能導致訓練震盪,過大的批次則可能超出記憶體容量。對於大語言模型(LLM)的訓練,更需要仔細權衡批次大小、上下文長度以及計算資源之間的關係。展望未來,隨著硬體效能的提升和演算法的最佳化,動態批次大小調整和更高效的資料載入機制將成為重要的研究方向,進一步提升LLM的訓練效率和效能。玄貓認為,深入理解資料處理流程和分批訓練策略,並根據實際情況進行調整,是成功訓練深度學習模型的關鍵。