NLP Course documentation

使用 Keras 微調一個模型

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

使用 Keras 微調一個模型

Ask a Question Open In Colab Open In Studio Lab

完成上一節中的所有數據預處理工作後,您只剩下最後的幾個步驟來訓練模型。 但是請注意,model.fit() 命令在 CPU 上運行會非常緩慢。 如果您沒有GPU,則可以在 Google Colab 上使用免費的 GPU 或 TPU(需要梯子)。

這一節的代碼示例假設您已經執行了上一節中的代碼示例。 下面一個簡短的摘要,包含了在開始學習這一節之前您需要的執行的代碼:

from datasets import load_dataset
from transformers import AutoTokenizer, DataCollatorWithPadding
import numpy as np

raw_datasets = load_dataset("glue", "mrpc")
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)


def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)


tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)

data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf")

tf_train_dataset = tokenized_datasets["train"].to_tf_dataset(
    columns=["attention_mask", "input_ids", "token_type_ids"],
    label_cols=["labels"],
    shuffle=True,
    collate_fn=data_collator,
    batch_size=8,
)

tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset(
    columns=["attention_mask", "input_ids", "token_type_ids"],
    label_cols=["labels"],
    shuffle=False,
    collate_fn=data_collator,
    batch_size=8,
)

訓練模型

從🤗 Transformers 導入的 TensorFlow 模型已經是 Keras 模型。 下面的視頻是對 Keras 的簡短介紹。

這意味著,一旦我們有了數據,就需要很少的工作就可以開始對其進行訓練。

第二章使用的方法一樣, 我們將使用二分類的 TFAutoModelForSequenceClassification類:

from transformers import TFAutoModelForSequenceClassification

model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)

您會注意到,與 第二章 不同的是,您在實例化此預訓練模型後會收到警告。 這是因為 BERT 沒有對句子對進行分類進行預訓練,所以預訓練模型的 head 已經被丟棄,而是插入了一個適合序列分類的新 head。 警告表明一些權重沒有使用(對應於丟棄的預訓練頭),而其他一些權重是隨機初始化的(新頭的權重)。 最後鼓勵您訓練模型,這正是我們現在要做的。

要在我們的數據集上微調模型,我們只需要在我們的模型上調用 compile() 方法,然後將我們的數據傳遞給 fit() 方法。 這將啟動微調過程(在 GPU 上應該需要幾分鐘)並輸出訓練loss,以及每個 epoch 結束時的驗證loss。

請注意🤗 Transformers 模型具有大多數 Keras 模型所沒有的特殊能力——它們可以自動使用內部計算的loss。 如果您沒有在 compile() 中設置損失函數,他們將默認使用內部計算的損失。 請注意,要使用內部損失,您需要將標籤作為輸入的一部分傳遞,而不是作為單獨的標籤(這是在 Keras 模型中使用標籤的正常方式)。 您將在課程的第 2 部分中看到這方面的示例,其中定義正確的損失函數可能很棘手。 然而,對於序列分類,標準的 Keras 損失函數可以正常工作,所以我們將在這裡使用它。

from tensorflow.keras.losses import SparseCategoricalCrossentropy

model.compile(
    optimizer="adam",
    loss=SparseCategoricalCrossentropy(from_logits=True),
    metrics=["accuracy"],
)
model.fit(
    tf_train_dataset,
    validation_data=tf_validation_dataset,
)

請注意這裡有一個非常常見的陷阱——你只是可以將損失的名稱作為字符串傳遞給 Keras,但默認情況下,Keras 會假設你已經對輸出應用了 softmax。 然而,許多模型在應用 softmax 之前就輸出,也稱為 logits。 我們需要告訴損失函數我們的模型是否經過了softmax,唯一的方法是直接調用它,而不是用字符串的名稱。

提升訓練的效果

如果您嘗試上面的代碼,它肯定會運行,但您會發現loss只是緩慢或零星地下降。 主要原因是學習率。 與loss一樣,當我們將優化器的名稱作為字符串傳遞給 Keras 時,Keras 會初始化該優化器具有所有參數的默認值,包括學習率。 但是,根據長期經驗,我們知道Transformer 模型更適合使用比 Adam 的默認值(1e-3)也寫成為 10 的 -3 次方,或 0.001,低得多的學習率。 5e-5 (0.00005) 比默認值大約低 20 倍,是一個更好的起點。

除了降低學習率,我們還有第二個技巧:我們可以慢慢降低學習率。在訓練過程中。 在文獻中,您有時會看到這被稱為 decayingannealing學習率。 在 Keras 中,最好的方法是使用 learning rate scheduler。 一個好用的是PolynomialDecay——儘管有這個名字,但在默認設置下,它只是簡單地從初始值線性衰減學習率值在訓練過程中的最終值,這正是我們想要的。但是, 為了正確使用調度程序,我們需要告訴它訓練的次數。 我們將在下面為其計算“num_train_steps”。

from tensorflow.keras.optimizers.schedules import PolynomialDecay

batch_size = 8
num_epochs = 3
# 訓練步數是數據集中的樣本數除以batch size再乘以 epoch。
# 注意這裡的tf_train_dataset是一個轉化為batch後的 tf.data.Dataset,
# 不是原來的 Hugging Face Dataset,所以它的 len() 已經是 num_samples // batch_size。
num_train_steps = len(tf_train_dataset) * num_epochs
lr_scheduler = PolynomialDecay(
    initial_learning_rate=5e-5, end_learning_rate=0.0, decay_steps=num_train_steps
)
from tensorflow.keras.optimizers import Adam

opt = Adam(learning_rate=lr_scheduler)

🤗 Transformers 庫還有一個 create_optimizer() 函數,它將創建一個具有學習率衰減的 AdamW 優化器。 這是一個便捷的方式,您將在本課程的後續部分中詳細瞭解。

現在我們有了全新的優化器,我們可以嘗試使用它進行訓練。 首先,讓我們重新加載模型,以重置我們剛剛進行的訓練運行對權重的更改,然後我們可以使用新的優化器對其進行編譯:

import tensorflow as tf

model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
model.compile(optimizer=opt, loss=loss, metrics=["accuracy"])

現在,我們再次進行fit:

model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3)

💡 如果您想在訓練期間自動將模型上傳到 Hub,您可以在 model.fit() 方法中傳遞 PushToHubCallback。 我們將在 第四章 中進行介紹

模型預測

訓練和觀察的loss下降都非常好,但是如果我們想從訓練後的模型中獲得輸出,或者計算一些指標,或者在生產中使用模型呢? 為此,我們可以使用predict() 方法。 這將返回模型的輸出頭的logits數值,每個類一個。

preds = model.predict(tf_validation_dataset)["logits"]

我們可以將這些 logit 轉換為模型的類別預測,方法是使用 argmax 找到最高的 logit,它對應於最有可能的類別:

class_preds = np.argmax(preds, axis=1)
print(preds.shape, class_preds.shape)
(408, 2) (408,)

現在,讓我們使用這些 preds 來計算一些指標! 我們可以像加載數據集一樣輕鬆地加載與 MRPC 數據集相關的指標,這次使用的是 evaluate.load() 函數。 返回的對象有一個 compute() 方法,我們可以使用它來進行度量計算:

import evaluate

metric = evaluate.load("glue", "mrpc")
metric.compute(predictions=class_preds, references=raw_datasets["validation"]["label"])
{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542}

您獲得的確切結果可能會有所不同,因為模型頭的隨機初始化可能會改變它獲得的指標。 在這裡,我們可以看到我們的模型在驗證集上的準確率為 85.78%,F1 得分為 89.97。 這些是用於評估 GLUE 基準的 MRPC 數據集結果的兩個指標。 BERT 論文 中的表格報告了基本模型的 F1 分數為 88.9。 那是 uncased 模型,而我們目前使用的是 cased 模型,這解釋了為什麼我們會獲得更好的結果。

使用 Keras API 進行微調的介紹到此結束。 第 7 章將給出對大多數常見 NLP 任務執行此操作的示例。如果您想在 Keras API 上磨練自己的技能,請嘗試使第二節所使用的的數據處理在 GLUE SST-2 數據集上微調模型。