LLM 課程文件

管道背後

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強的文件體驗

開始使用

管道背後

Ask a Question Open In Colab Open In Studio Lab

讓我們從一個完整的示例開始,看看在第 1 章中執行以下程式碼時幕後發生了什麼

from transformers import pipeline

classifier = pipeline("sentiment-analysis")
classifier(
    [
        "I've been waiting for a HuggingFace course my whole life.",
        "I hate this so much!",
    ]
)

並獲得了

[{'label': 'POSITIVE', 'score': 0.9598047137260437},
 {'label': 'NEGATIVE', 'score': 0.9994558095932007}]

正如我們在第 1 章中所看到的,這個管道將三個步驟組合在一起:預處理、透過模型傳遞輸入和後處理。

The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head.

讓我們快速回顧一下這些步驟。

使用分詞器進行預處理

像其他神經網路一樣,Transformer 模型無法直接處理原始文字,所以我們管道的第一步是將文字輸入轉換為模型能夠理解的數字。為此,我們使用分詞器,它負責:

  • 將輸入分割成單詞、子詞或符號(如標點符號),這些都被稱為標記
  • 將每個標記對映到一個整數。
  • 新增可能對模型有用的額外輸入。

所有這些預處理都必須與模型預訓練時的方式完全相同,所以我們首先需要從模型中心下載這些資訊。為此,我們使用AutoTokenizer類及其from_pretrained()方法。透過我們模型的檢查點名稱,它將自動獲取與模型分詞器相關的資料並進行快取(因此只有在您首次執行以下程式碼時才下載)。

由於sentiment-analysis管道的預設檢查點是distilbert-base-uncased-finetuned-sst-2-english(您可以在此處檢視其模型卡),我們執行以下程式碼:

from transformers import AutoTokenizer

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)

一旦我們有了分詞器,我們就可以直接將句子傳遞給它,然後會得到一個可以直接輸入模型的字典!唯一剩下的就是將輸入 ID 列表轉換為張量。

您可以使用 🤗 Transformers,而無需擔心後端使用的是哪種機器學習框架;對於某些模型,它可能是 PyTorch 或 Flax。然而,Transformer 模型只接受張量作為輸入。如果這是您第一次聽說張量,您可以將它們視為 NumPy 陣列。NumPy 陣列可以是標量(0D)、向量(1D)、矩陣(2D),或具有更多維度。它實際上是一個張量;其他機器學習框架的張量行為類似,並且通常像 NumPy 陣列一樣容易例項化。

為了指定我們希望返回的張量型別(PyTorch 或普通 NumPy),我們使用 return_tensors 引數:

raw_inputs = [
    "I've been waiting for a HuggingFace course my whole life.",
    "I hate this so much!",
]
inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt")
print(inputs)

暫時不用擔心填充和截斷;我們稍後會解釋這些。這裡要記住的主要事情是,您可以傳遞一個句子或一個句子列表,並指定您希望返回的張量型別(如果未傳遞型別,您將得到一個列表的列表作為結果)。

以下是 PyTorch 張量形式的結果:

{
    'input_ids': tensor([
        [  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172, 2607,  2026,  2878,  2166,  1012,   102],
        [  101,  1045,  5223,  2023,  2061,  2172,   999,   102,     0,     0,     0,     0,     0,     0,     0,     0]
    ]), 
    'attention_mask': tensor([
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
    ])
}

輸出本身是一個字典,包含兩個鍵:input_idsattention_maskinput_ids 包含兩行整數(每句話一行),它們是每句話中標記的唯一識別符號。我們將在本章後面解釋 attention_mask 是什麼。

透過模型

我們可以像下載分詞器一樣下載預訓練模型。🤗 Transformers 提供了一個 AutoModel 類,它也有一個 from_pretrained() 方法:

from transformers import AutoModel

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModel.from_pretrained(checkpoint)

在這段程式碼中,我們下載了之前在管道中使用的相同檢查點(它應該已經被快取了),並用它例項化了一個模型。

此架構僅包含基礎 Transformer 模組:給定一些輸入,它會輸出我們稱之為隱藏狀態,也稱為特徵。對於每個模型輸入,我們將檢索一個高維向量,它代表Transformer 模型對該輸入的上下文理解

如果這聽起來不太明白,也不用擔心。我們稍後會詳細解釋。

雖然這些隱藏狀態本身可能很有用,但它們通常是模型另一部分(稱為頭部)的輸入。在第 1 章中,不同的任務可以使用相同的架構執行,但每個任務都會有不同的關聯頭部。

高維向量?

Transformer 模組輸出的向量通常很大。它通常有三個維度:

  • 批大小:一次處理的序列數量(在我們的示例中為 2)。
  • 序列長度:序列數字表示的長度(在我們的示例中為 16)。
  • 隱藏大小:每個模型輸入的向量維度。

由於最後一個值,它被稱為“高維”。隱藏大小可以非常大(對於較小的模型,768 很常見,在較大的模型中,這可以達到 3072 或更多)。

如果我們將預處理後的輸入饋送到模型中,我們可以看到這一點:

outputs = model(**inputs)
print(outputs.last_hidden_state.shape)
torch.Size([2, 16, 768])

請注意,🤗 Transformers 模型的輸出行為類似於 namedtuple 或字典。您可以透過屬性(如我們所做)或透過鍵(outputs["last_hidden_state"])訪問元素,甚至如果您確切知道所需內容的位置,也可以透過索引(outputs[0])訪問。

模型頭部:從數字中理解意義

模型頭部將高維隱藏狀態向量作為輸入,並將其投影到不同的維度。它們通常由一個或幾個線性層組成:

A Transformer network alongside its head.

Transformer 模型的輸出直接傳送到模型頭部進行處理。

在此圖中,模型由其嵌入層和後續層表示。嵌入層將標記化輸入中的每個輸入 ID 轉換為一個表示關聯標記的向量。後續層使用注意力機制操作這些向量,以生成句子的最終表示。

🤗 Transformers 中有許多不同的架構,每種架構都旨在解決特定的任務。以下是一個不完全列表:

  • *Model(檢索隱藏狀態)
  • *ForCausalLM
  • *ForMaskedLM
  • *ForMultipleChoice
  • *ForQuestionAnswering
  • *ForSequenceClassification
  • *ForTokenClassification
  • 以及其他 🤗

對於我們的例子,我們將需要一個帶有序列分類頭的模型(以便能夠將句子分類為積極或消極)。所以,我們實際上不會使用 AutoModel 類,而是使用 AutoModelForSequenceClassification

from transformers import AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
outputs = model(**inputs)

現在,如果我們檢視輸出的形狀,維度會低得多:模型頭將我們之前看到的高維向量作為輸入,並輸出包含兩個值(每個標籤一個)的向量:

print(outputs.logits.shape)
torch.Size([2, 2])

由於我們只有兩個句子和兩個標籤,所以從模型中得到的結果形狀是 2 x 2。

後處理輸出

我們從模型輸出的值本身不一定有意義。我們來看看:

print(outputs.logits)
tensor([[-1.5607,  1.6123],
        [ 4.1692, -3.3464]], grad_fn=<AddmmBackward>)

我們的模型預測第一句話為[-1.5607, 1.6123],第二句話為[4.1692, -3.3464]。這些不是機率,而是對數,是模型最後一層輸出的原始、未歸一化的分數。要將其轉換為機率,它們需要經過一個SoftMax層(所有🤗 Transformers 模型都輸出對數,因為訓練的損失函式通常會將最後一個啟用函式(如 SoftMax)與實際的損失函式(如交叉熵)融合在一起)。

import torch

predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
print(predictions)
tensor([[4.0195e-02, 9.5980e-01],
        [9.9946e-01, 5.4418e-04]], grad_fn=<SoftmaxBackward>)

現在我們可以看到,模型預測第一個句子為 [0.0402, 0.9598],第二個句子為 [0.9995, 0.0005]。這些都是可識別的機率分數。

為了獲得每個位置對應的標籤,我們可以檢查模型配置的 id2label 屬性(更多內容將在下一節介紹):

model.config.id2label
{0: 'NEGATIVE', 1: 'POSITIVE'}

現在我們可以得出結論,模型預測結果如下:

  • 第一句話:消極:0.0402,積極:0.9598
  • 第二句話:消極:0.9995,積極:0.0005

我們已經成功地再現了管道的三個步驟:使用分詞器進行預處理、透過模型傳遞輸入和後處理!現在讓我們花點時間深入瞭解每個步驟。

✏️ 試一試! 選擇您自己的兩(或更多)段文字,並透過 sentiment-analysis 管道執行它們。然後自己重複您在這裡看到的步驟,並檢查您是否獲得了相同的結果!

< > 在 GitHub 上更新

© . This site is unofficial and not affiliated with Hugging Face, Inc.