在自然語言處理的技術領域中,文字預處理是深度學習模型訓練的基本。為了讓模型有效地理解和處理文字資料,我們需要將原始文字轉換成數值化的表示形式。本文將深入探討兩種關鍵的文字預處理技術:Tokenize 和 Pad to longest sequence(填充至最長序列),並結合實際案例和程式碼範例,說明如何在 PyTorch 中實作這些技術。Tokenize 技術將文字分割成單個詞彙或子詞單元,每個單元再對映到唯一的 ID,形成模型可處理的數值序列。然而,由於文字長度不一,直接輸入模型會造成維度不匹配的問題。因此,Pad to longest sequence 技術透過新增填充符,將所有序列的長度統一至最長序列的長度,確保模型輸入的一致性。

實際應用

在實際應用中,這兩種技術可以結合使用,以實作高效的文字預處理。例如,對於以下輸入文字:

  • 1212, 318, 1194
  • 2420, 3275
  • 1212, 318, 262, 2368
  • 2420, 3275, 11, 543, 318
  • 845, 890

首先進行Tokenize,然後根據最長序列進行填充,最終得到的結果如下:

  • 1212, 318, 1194, [PAD], [PAD]
  • 2420, 3275, [PAD], [PAD], [PAD]
  • 1212, 318, 262, 2368
  • 2420, 3275, 11, 543, 318
  • 845, 890, [PAD], [PAD], [PAD]

其中,[PAD]代表填充符。

技術選型分析

在選擇文字預處理技術時,需要考慮多個因素,包括模型的複雜度、訓練時間和最終的效能指標。Tokenize和Pad to longest sequence是兩種常見且有效的技術,但是在某些情況下,也可能需要考慮其他技術,例如截斷、子詞分割等。

隨著NLP技術的不斷發展,文字預處理技術也在不斷演進。未來,可能會出現更加高效和智慧的預處理技術,例如自動學習最優填充策略、動態調整序列長度等。同時,隨著深度學習模型的不斷演進,可能會出現更加複雜和高效的文字預處理技術。

內容解密:

上述內容主要介紹了Tokenize和Pad to longest sequence兩種文字預處理技術,並給出了實際應用的例子。同時,也對這兩種技術進行了分析和比較,並討論了未來的發展方向。

  flowchart TD
    A[文字輸入] --> B[Tokenize]
    B --> C[Pad to longest sequence]
    C --> D[模型訓練]
    D --> E[模型評估]

圖表翻譯:

此圖示了文字預處理和模型訓練的流程。首先,輸入文字經過Tokenize處理,然後根據最長序列進行填充。接著,填充後的序列被用於模型訓練,最後進行模型評估,以確保模型的效能達到預期。

自然語言處理中的資料準備

在自然語言處理任務中,資料準備是一個至關重要的步驟。這涉及將原始文字資料轉換為模型可以理解的格式。在本文中,我們將探討如何準備輸入文字資料,以便用於深度學習模型的訓練。

文字轉換為Token ID序列

第一步是將每個輸入文字訊息轉換為token ID序列。這個過程涉及將文字分割為單個詞彙或子詞(token),然後將每個token對映到一個唯一的ID。這樣可以將文字資料轉換為數值格式,以便模型可以處理。

例如,假設我們有一個輸入文字訊息「這是一個示例文字」。我們可以將其轉換為token ID序列,如下所示:

  • 「這」對應的token ID為1212
  • 「是一個」對應的token ID為318
  • 「示例」對應的token ID為262
  • 「文字」對應的token ID為717

因此,輸入文字訊息可以被表示為一個token ID序列:[1212, 318, 262, 717]。

順序填充

由於不同的輸入文字訊息可能具有不同的長度,我們需要確保所有序列具有相同的長度,以便模型可以處理。為了實作這一點,我們可以使用填充token來填充較短的序列。

在上面的例子中,如果我們的模型需要輸入序列的長度為10,那麼我們可以在原始序列[1212, 318, 262, 717]後面新增填充token(ID為50256),直到達到所需的長度。填充後的序列可能如下所示:

[1212, 318, 262, 717, 50256, 50256, 50256, 50256, 50256, 50256]

這樣,所有輸入序列都具有相同的長度,模型就可以處理這些序列了。

資料載入器的建立

在PyTorch中,我們可以使用Dataset類別來建立自定義資料集,並使用DataLoader類別來載入資料。下面是一個簡單的例子:

import torch
from torch.utils.data import Dataset

class SpamDataset(Dataset):
    def __init__(self, csv_file, tokenizer, max_length=None, pad_token_id=50256):
        # 初始化資料集
        self.csv_file = csv_file
        self.tokenizer = tokenizer
        self.max_length = max_length
        self.pad_token_id = pad_token_id

    def __len__(self):
        # 傳回資料集的大小
        return len(self.csv_file)

    def __getitem__(self, idx):
        # 傳回一個資料點
        text = self.csv_file.iloc[idx, 0]
        labels = self.csv_file.iloc[idx, 1]

        encoding = self.tokenizer.encode_plus(
            text,
            max_length=self.max_length,
            padding='max_length',
            truncation=True,
            return_attention_mask=True,
            return_tensors='pt'
        )

        return {
            'input_ids': encoding['input_ids'].flatten(),
            'attention_mask': encoding['attention_mask'].flatten(),
            'labels': torch.tensor(labels)
        }

在這個例子中,我們定義了一個SpamDataset類別,它繼承自PyTorch的Dataset類別。這個類別負責載入資料,並將其轉換為模型可以理解的格式。

透過這些步驟,我們可以準備好輸入文字資料,以便用於深度學習模型的訓練。

資料前處理與資料載入

在進行自然語言處理(NLP)任務時,資料的前處理和載入是非常重要的步驟。以下是使用Python和PyTorch實作的資料前處理和資料載入的範例。

載入函式庫

首先,我們需要載入必要的函式庫,包括pandas用於資料操作和torch用於深度學習。

import pandas as pd
import torch

資料載入

假設我們有一個CSV檔案,包含兩個欄位:TextLabel。我們可以使用pd.read_csv函式載入這個檔案。

self.data = pd.read_csv(csv_file)

文字編碼

接下來,我們需要將文字資料編碼成可以被模型理解的格式。這裡,我們使用了一個簡單的編碼方法,將每個文字轉換成一個整數列表。

self.encoded_texts = [tokenizer.encode(text) for text in self.data["Text"]]

最大長度計算

為了確保所有的文字都有相同的長度,我們需要計算最長的文字長度。如果沒有指定最大長度,則計算所有編碼文字中的最大長度。

if max_length is None:
    self.max_length = self._longest_encoded_length()
else:
    self.max_length = max_length

文字填充

如果某個文字的長度小於最大長度,則需要填充這個文字,以確保所有文字都有相同的長度。

self.encoded_texts = [
    encoded_text + [pad_token_id] * (self.max_length - len(encoded_text))
    for encoded_text in self.encoded_texts
]

資料集類別

為了方便地使用PyTorch的資料載入器, 我們定義了一個資料集類別,包含了__getitem____len__方法。

def __getitem__(self, index):
    encoded = self.encoded_texts[index]
    label = self.data.iloc[index]["Label"]
    return (
        torch.tensor(encoded, dtype=torch.long),
        torch.tensor(label, dtype=torch.long)
    )

def __len__(self):
    return len(self.data)

這個類別允許我們使用索引存取每個樣本,並傳回編碼的文字和對應的標籤。

內容解密:

上述程式碼中,我們首先載入了CSV檔案,然後對文字進行了編碼。接著,我們計算了最長的文字長度,並根據這個長度對所有文字進行了填充。最後,我們定義了一個資料集類別,包含了__getitem____len__方法,以方便地使用PyTorch的資料載入器。

圖表翻譯:

以下是對應的Mermaid圖表,用於視覺化展示程式碼的邏輯:

  flowchart TD
    A[載入CSV檔案] --> B[編碼文字]
    B --> C[計算最大長度]
    C --> D[填充文字]
    D --> E[定義資料集類別]
    E --> F[傳回編碼文字和標籤]

這個圖表展示了程式碼中每一步的邏輯關係,從載入CSV檔案開始,到傳回編碼文字和標籤為止。

自定義資料集類別的實作

在進行文字分類別任務時,資料集的準備是一個非常重要的步驟。為了方便地對資料進行預處理和批次化,玄貓定義了一個名為 SpamDataset 的類別。這個類別負責載入從 CSV 檔案中讀取的資料,使用 GPT-2 的分詞器對文字進行分詞,並根據指定的最大長度對序列進行截斷或填充,以確保每個輸入張量的大小相同。

資料集類別的方法

_longest_encoded_length 方法用於計算編碼後文字的最大長度。這個方法遍歷所有編碼後的文字,記錄下最長的那一個,並傳回這個最大長度。

def _longest_encoded_length(self):
    max_length = 0
    for encoded_text in self.encoded_texts:
        encoded_length = len(encoded_text)
        if encoded_length > max_length:
            max_length = encoded_length
    return max_length

初始化資料集

初始化 SpamDataset 物件時,可以指定 CSV 檔案的路徑、最大長度和分詞器。例如:

train_dataset = SpamDataset(
    csv_file="train.csv",
    max_length=None,
    tokenizer=tokenizer
)

在這個例子中,max_length 引數被設定為 None,表示資料集會自動計算出序列的最大長度。這個最大長度值會被儲存在資料集的 max_length 屬性中。如果你想知道最長序列的token數量,可以使用以下程式碼:

print(train_dataset.max_length)

這樣就可以列印預出最長序列的token數量。

資料預處理

資料集類別還提供了對序列進行預處理的功能,包括截斷和填充。這些操作確保了每個輸入張量的大小相同,這對於建立訓練資料載入器是必要的。

預處理步驟

  1. 分詞: 使用 GPT-2 的分詞器對文字進行分詞。
  2. 截斷: 如果序列長度超過指定的最大長度,則截斷序列。
  3. 填充: 如果序列長度小於最大長度,則填充序列,使其與最大長度相同。

這些步驟確保了資料的一致性和完整性,有利於後續的模型訓練和評估。

資料集長度與模型限制

在訓練資料集中,序列的最大長度是 120 個token,這是文字訊息的常見長度。然而,模型可以處理長達 1,024 個token的序列,這是由其上下文長度限制決定的。如果您的資料集包含更長的文字,您可以在建立訓練資料集時傳遞 max_length=1024 以確保資料不超過模型支援的輸入(上下文)長度。

資料集填充與截斷

接下來,我們需要將驗證和測試集填充到與最長訓練序列相同的長度。重要的是,任何超過最長訓練範例長度的驗證和測試集樣本都會使用 encoded_text[:self.max_length] 進行截斷,這是在我們之前定義的 SpamDataset 程式碼中實作的。這種截斷是可選的,您可以為驗證和測試集設定 max_length=None,假設這些集中的序列不超過 1,024 個token。

val_dataset = SpamDataset(
    csv_file="validation.csv",
    max_length=train_dataset.max_length,
    tokenizer=tokenizer
)

test_dataset = SpamDataset(
    csv_file="test.csv",
    max_length=train_dataset.max_length,
    tokenizer=tokenizer
)

建立資料載入器

使用資料集作為輸入,我們可以例項化資料載入器,類別似於當時我們處理文字資料時的情況。然而,在這種情況下,目標代表類別標籤而不是文字中的下一個token。例如,如果我們選擇批次大小為 8,每個批次將由八個訓練範例組成,每個範例的長度為 120,及其對應的類別標籤,如圖 6.7 所示。

內容解密:

上述程式碼定義瞭如何根據訓練資料集的最大長度對驗證和測試資料集進行填充和截斷。這一步驟確保了所有資料集在處理時具有相同的長度,有助於模型的訓練和評估。

練習 6.1:增加上下文長度

填充輸入到模型支援的最大token數,並觀察它如何影響預測效能。

圖表翻譯:

以下是資料集處理流程的Mermaid圖表:

  flowchart TD
    A[資料集載入] --> B[資料集填充]
    B --> C[資料集截斷]
    C --> D[資料載入器建立]
    D --> E[模型訓練]

這個圖表展示了從資料集載入到模型訓練的整個流程,包括填充和截斷步驟,以確保所有資料集具有相同的長度。

自然語言處理中的文字分類別

在自然語言處理(NLP)中,文字分類別是一項基本任務,涉及將給定的文字分類別為預先定義的類別之一。例如,垃圾郵件過濾是一種常見的文字分類別應用,其中電子郵件被分類別為“spam”(垃圾郵件)或“ham”(非垃圾郵件)。

資料準備

要進行文字分類別,首先需要準備好資料。這通常涉及將文字資料轉換為數值表示,以便於模型處理。在這個例子中,每個文字訊息被表示為一系列的token ID,每個token ID對應於一個單詞或子詞。

import torch
from torch.utils.data import DataLoader

# 假設我們有以下資料
text_messages = [
    "Dear voucher holder...",
    "XMAS Prize draws!...",
    #...
]

class_labels = [0, 1, 0, 1, 0, 0, 1, 0]  # 0代表"ham",1代表"spam"

資料載入器

PyTorch提供了DataLoader類別來方便地載入資料。以下程式碼建立了訓練、驗證和測試集的資料載入器,每批次大小為8。

batch_size = 8

train_loader = DataLoader(dataset=text_messages, batch_size=batch_size, shuffle=True)
val_loader = DataLoader(dataset=text_messages, batch_size=batch_size, shuffle=False)
test_loader = DataLoader(dataset=text_messages, batch_size=batch_size, shuffle=False)

文字表示

每個文字訊息被表示為一系列的token ID,每個token ID對應於一個單詞或子詞。文字訊息被填充到120個token,以確保所有訊息具有相同的長度。

# 假設我們有以下token ID
token_ids = [
    [1, 2, 3,..., 120],
    [4, 5, 6,..., 120],
    #...
]

class_label_array = torch.tensor([0, 1, 0, 1, 0, 0, 1, 0])  # 0代表"ham",1代表"spam"

模型定義

接下來,需要定義一個模型來進行文字分類別。這個模型可以是一個簡單的神經網路,也可以是一個更複雜的模型,如BERT或RoBERTa。

import torch.nn as nn

class TextClassifier(nn.Module):
    def __init__(self):
        super(TextClassifier, self).__init__()
        self.fc1 = nn.Linear(120, 128)  # 輸入層(120)-> 隱藏層(128)
        self.fc2 = nn.Linear(128, 2)  # 隱藏層(128)-> 輸出層(2)

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

訓練模型

最後,需要訓練模型來進行文字分類別。這涉及將模型輸出與真實標籤進行比較,並根據損失函式更新模型引數。

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

for epoch in range(10):
    for batch in train_loader:
        inputs, labels = batch
        inputs, labels = inputs.to(device), labels.to(device)
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
    print(f'Epoch {epoch+1}, Loss: {loss.item()}')

圖表翻譯:

此圖示展示瞭如何使用PyTorch進行文字分類別。首先,需要準備好資料,包括文字訊息和對應的標籤。然後,需要定義一個模型來進行文字分類別,並使用資料載入器載入資料。最後,需要訓練模型來進行文字分類別。

  flowchart TD
    A[資料準備] --> B[模型定義]
    B --> C[資料載入]
    C --> D[模型訓練]
    D --> E[模型評估]

內容解密:

此段程式碼展示瞭如何使用PyTorch進行文字分類別。首先,需要準備好資料,包括文字訊息和對應的標籤。然後,需要定義一個模型來進行文字分類別,並使用資料載入器載入資料。最後,需要訓練模型來進行文字分類別。

每個步驟都非常重要,因為它們都貢獻於最終的文字分類別結果。首先,需要準備好資料,以便於模型學習。然後,需要定義一個模型來進行文字分類別,這個模型需要能夠有效地捕捉文字訊息中的模式和特徵。最後,需要訓練模型來進行文字分類別,這涉及將模型輸出與真實標籤進行比較,並根據損失函式更新模型引數。

資料載入器設定

在設定好資料集後,我們需要建立資料載入器(DataLoader),以便能夠批次地讀取資料。以下是建立資料載入器的程式碼:

num_workers = 0  # 設定工作執行緒數
batch_size = 8  # 設定批次大小

torch.manual_seed(123)  # 設定隨機種子

# 建立訓練資料載入器
train_loader = DataLoader(
    dataset=train_dataset,  # 訓練資料集
    batch_size=batch_size,  # 批次大小
    shuffle=True,  # 是否打亂資料順序
    num_workers=num_workers,  # 工作執行緒數
    drop_last=True,  # 是否丟棄最後一個批次
)

# 建立驗證資料載入器
val_loader = DataLoader(
    dataset=val_dataset,  # 驗證資料集
    batch_size=batch_size,  # 批次大小
    num_workers=num_workers,  # 工作執行緒數
    drop_last=False,  # 是否丟棄最後一個批次
)

# 建立測試資料載入器
test_loader = DataLoader(
    dataset=test_dataset,  # 測試資料集
    batch_size=batch_size,  # 批次大小
    num_workers=num_workers,  # 工作執行緒數
    drop_last=False,  # 是否丟棄最後一個批次
)

驗證資料載入器

為了確保資料載入器正確工作,我們可以迭代訓練資料載入器,並印出最後一個批次的維度:

for input_batch, target_batch in train_loader:
    pass  # 不做任何事情,只是為了迭代到最後一個批次

print("Input batch dimensions:", input_batch.shape)
print("Label batch dimensions:", target_batch.shape)

輸出結果如下:

Input batch dimensions: torch.Size([8, 120])
Label batch dimensions: torch.Size([8])

從輸出結果可以看到,輸入批次的維度為 (8, 120),代表有 8 個訓練範例,每個範例有 120 個 token。標籤批次的維度為 (8,),代表有 8 個標籤。

印出批次數量

最後,我們可以印出每個資料集的批次數量:

print(f"{len(train_loader)} training batches")

這樣可以讓我們瞭解資料集的大小。

準備模型進行微調

在完成資料準備後,我們需要將模型準備好以進行微調。這個步驟對於識別垃圾郵件訊息至關重要。

初始化預訓練模型

首先,我們需要初始化一個預訓練好的模型。這裡,我們選擇使用「gpt2-small (124M)」作為我們的基礎模型,因為它在自然語言處理任務中表現出色。同時,我們定義了一個輸入提示「Every effort moves」,這將幫助模型瞭解我們的任務目標。

步驟一:資料集準備回顧

在開始模型準備之前,讓我們快速回顧一下資料集的準備步驟:

  1. 下載資料集:確保我們擁有需要的資料集。
  2. 預處理資料:對資料進行必要的轉換和清理,以便模型可以理解和處理。

模型初始化

現在,我們開始初始化預訓練模型的過程。這涉及到載入預訓練權重並組態模型以適應我們的特定任務——識別垃圾郵件訊息。

# 載入必要的函式庫
import torch
from transformers import GPT2Tokenizer, GPT2Model

# 定義模型和輸入提示
CHOOSE_MODEL = "gpt2-small (124M)"
INPUT_PROMPT = "Every effort moves"

# 初始化tokenizer和模型
tokenizer = GPT2Tokenizer.from_pretrained(CHOOSE_MODEL)
model = GPT2Model.from_pretrained(CHOOSE_MODEL)

# 輸入提示的編碼
inputs = tokenizer(INPUT_PROMPT, return_tensors="pt")

# 執行模型
outputs = model(**inputs)

內容解密:

上述程式碼片段展示瞭如何初始化一個預訓練好的GPT2模型,並使用指定的輸入提示對其進行組態。這個過程包括載入預訓練的tokenizer和模型,然後使用輸入提示對模型進行初始化。這些步驟為我們的微調任務奠定了基礎。

圖表翻譯:

  flowchart TD
    A[載入函式庫] --> B[初始化tokenizer和模型]
    B --> C[編碼輸入提示]
    C --> D[執行模型]
    D --> E[輸出結果]

圖表翻譯:

此流程圖描述了初始化預訓練模型和執行它的步驟。從載入必要的函式庫開始,到初始化tokenizer和模型,然後編碼輸入提示,最後執行模型並得到輸出結果。這個過程展示瞭如何準備和使用預訓練模型進行特定任務的微調。

從技術架構視角來看,本文介紹的Tokenize和Pad to longest sequence技術是自然語言處理中資料預處理的關鍵環節。透過將文字轉換為Token ID序列並進行填充,模型得以有效處理長度不一的文字資料。然而,填充策略的選擇(例如固定長度填充或動態填充)會直接影響模型的效能和計算資源消耗。目前技術的限制在於如何有效處理超長文字以及如何在填充過程中保留更多上下文資訊。對於追求極致效能的應用,可以考慮結合子詞分割等更進階的技術。玄貓認為,隨著Transformer模型的普及,動態填充和更智慧的截斷策略將成為未來的發展趨勢,同時硬體加速技術的進步也將進一步提升預處理效率。對於開發者而言,深入理解不同預處理技術的優劣,並根據實際應用場景選擇合適的策略至關重要。