開源 AI 食譜文件

使用 Optuna 和 Transformers 進行超引數最佳化

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強的文件體驗

開始使用

Open In Colab

使用 Optuna 和 Transformers 進行超引數最佳化

作者:Parag Ekbote

問題:

找到最佳超引數,以在 IMDB 資料集的一個子集上對輕量級 BERT 模型進行文字分類微調。

概述:

本指南演示瞭如何使用自動化搜尋技術系統地最佳化基於 Transformer 的文字分類模型的超引數。您將學習如何使用 Optuna 實現 HPO,以找到 BERT 在情感分析任務上進行微調的最佳學習率和權重衰減值。

何時使用本指南:

  • 您需要對預訓練語言模型進行分類任務的微調。

  • 您的模型效能趨於平穩,需要引數最佳化。

  • 您希望實施系統化、可重現的超引數最佳化。

注意事項

!pip install -q datasets evaluate transformers optuna wandb scikit-learn nbformat matplotlib

準備資料集和設定模型

在訓練和評估情感分析模型之前,您需要準備資料集。本節確保您的資料結構化,並且您的模型已準備好從頭開始學習或在 BERT 的情況下進行微調。

1. 載入 IMDB 資料集

首先選擇一個專注於情感分類的資料集。IMDB 是一個著名的基準資料集,其中包含被標記為正面或負面的電影評論。

2. 選擇輸入和輸出列

只關注必需項

  • text 列作為輸入(評論內容)
  • label 列作為目標(0 表示負面,1 表示正面情感)

3. 定義訓練/驗證拆分

透過選擇以下內容來選擇一致的取樣策略

  • 2000 個示例用於訓練
  • 1000 個示例用於驗證
    打亂資料時使用固定的隨機種子,以確保跨會話的可重現性。

4. 對資料集進行分詞

應用與您計劃使用的模型相容的分詞器。分詞將原始文字轉換為數字格式,以便模型能夠有效吸收。使用批處理使此步驟高效。

5. 載入評估指標

選擇“準確率”作為主要評估指標——它簡單有效,適用於此處的二分類任務。它將在以後幫助衡量您的模型在區分正面和負面情感方面的學習效果。

6. 初始化預訓練 BERT 模型

選擇一個針對序列分類任務預訓練的 BERT 模型。將輸出類別數設定為 2(正面和負面),以與您的情感標籤對齊。該模型將作為整個訓練過程中的學習器。

from datasets import load_dataset
import evaluate

from transformers import AutoModelForSequenceClassification
from transformers import AutoTokenizer
from transformers import set_seed

set_seed(42)


train_dataset = load_dataset("imdb", split="train").shuffle(seed=42).select(range(2500))
valid_dataset = load_dataset("imdb", split="test").shuffle(seed=42).select(range(1000))

model_name = "prajjwal1/bert-tiny"
tokenizer = AutoTokenizer.from_pretrained(model_name)


def tokenize(batch):
    return tokenizer(batch["text"], padding="max_length", truncation=True, max_length=512)


tokenized_train = train_dataset.map(tokenize, batched=True).select_columns(["input_ids", "attention_mask", "label"])
tokenized_valid = valid_dataset.map(tokenize, batched=True).select_columns(["input_ids", "attention_mask", "label"])

metric = evaluate.load("accuracy")


def model_init():
    return AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2)

使用 Optuna 定義儲存

為了確保您的超引數最佳化實驗可跟蹤、可重現且易於隨時間分析,使用持久化儲存後端至關重要。Optuna 透過其 `RDBStorage` 機制提供了強大的解決方案,該機制允許使用 SQLite 資料庫在多個會話中儲存試驗資料。

1. 選擇持久化儲存格式

選擇 SQLite 資料庫作為儲存介質。它輕量、可移植,非常適合本地實驗,同時仍可結構化訪問所有試驗資料。

2. 啟用 Optuna 的 RDBStorage

RDBStorage(關係型資料庫儲存)是 Optuna 將試驗結果以一致且可查詢的格式儲存的方式。這彌合了短期實驗和長期分析之間的鴻溝。

3. 保留跨會話的試驗歷史

透過設定持久化儲存,您可以確保每次超引數試驗都被記錄下來。您可以暫停並恢復研究,稍後新增更多試驗,或者在訓練結束後很久仍能分析結果。

4. 促進可重現分析

透過集中儲存試驗資料,您可以重新訪問早期結果、重新生成視覺化或比較不同的最佳化執行。這使得您的工作流程透明、協作且科學嚴謹。

5. 支援視覺化和監控工具

持久化儲存試驗資料使您能夠接入視覺化工具——如 Optuna 內建的繪圖工具或外部儀表板——以檢查效能趨勢並迭代地最佳化您的搜尋空間。

import optuna
from optuna.storages import RDBStorage

# Define persistent storage
storage = RDBStorage("sqlite:///optuna_trials.db")

study = optuna.create_study(
    study_name="transformers_optuna_study", direction="maximize", storage=storage, load_if_exists=True
)

初始化訓練器並設定可觀察性

現在您的超引數搜尋空間已經到位,下一步是將所有內容連線起來進行最佳化和跟蹤。此設定不僅確保了以準確性為驅動的調優,還透過 Weights & Biases (W&B) 完全視覺化訓練過程。

1. 定義度量函式

首先指定如何衡量模型效能。該度量函式在每個驗證步驟後評估預測,以計算準確率、F1 分數或損失。它成為指導每個試驗學習進度的反饋迴圈。

2. 構建目標函式

這是超引數最佳化的核心。它封裝了您的訓練迴圈,並根據所選指標(如驗證準確率)返回一個標量分數。Optuna 將使用它來比較試驗並決定哪些設定能產生最佳結果。

3. 設定 Weights & Biases 以實現可觀察性

配置您的環境,將實驗指標和超引數配置記錄到 W&B。該平臺提供儀表板、繪圖和實驗比較,以跟蹤進度並發現問題。

4. 登入以獲取日誌訪問許可權

使用您的個人 API 金鑰登入 W&B。此步驟將您的訓練會話連線到您的線上帳戶,以便正確跟蹤和儲存所有指標和試驗詳細資訊。

5. 定義訓練器引數

為您的訓練管理器(例如 Hugging Face `Trainer`)準備一個配置。包括以下設定:

  • 評估策略(例如每個 epoch 後)

  • 檢查點頻率和儲存條件

  • 日誌間隔

  • 超引數搜尋方法和目標

    這確保了訓練的魯棒性、可重複性以及易於恢復或分析。

import wandb
from transformers import Trainer, TrainingArguments


def compute_metrics(eval_pred):
    predictions = eval_pred.predictions.argmax(axis=-1)
    labels = eval_pred.label_ids
    return metric.compute(predictions=predictions, references=labels)


def compute_objective(metrics):
    return metrics["eval_accuracy"]


wandb.init(project="hf-optuna", name="transformers_optuna_study")

training_args = TrainingArguments(
    output_dir="./results",
    eval_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
    logging_strategy="epoch",
    num_train_epochs=3,
    report_to="wandb",  # Logs to W&B
    logging_dir="./logs",
    run_name="transformers_optuna_study",
)


trainer = Trainer(
    model_init=model_init,
    args=training_args,
    train_dataset=tokenized_train,
    eval_dataset=tokenized_valid,
    processing_class=tokenizer,
    compute_metrics=compute_metrics,
)

定義搜尋空間並啟動試驗

在開始模型訓練之前,仔細定義模型組成部分和探索策略至關重要。此步驟為使用 Optuna 進行超引數最佳化奠定了基礎,您將系統地探索學習率、權重衰減和批大小等訓練引數的組合。

1. 設計搜尋空間

首先概述您要最佳化的超引數。為每個引數選擇合理的下限和上限:

  • 學習率——控制最佳化過程中的步長。
  • 權重衰減——增加正則化以減少過擬合。
  • 批大小——影響記憶體使用和收斂穩定性。

2. 設定最佳化方向

決定您的目標是最小化(例如損失)還是最大化(例如準確率、F1 分數)評估指標。這將引導搜尋引擎朝著正確的方向前進。

3. 選擇 Optuna 作為後端

Optuna 將處理搜尋過程——智慧地選擇、評估和迭代超引數組合。

4. 指定試驗次數

定義您希望 Optuna 嘗試的單獨執行(“試驗”)次數。更多試驗可以更好地探索空間,但需要更多時間。

5. 定義目標函式

此函式計算每次試驗中要最佳化的指標。它封裝了模型如何訓練以及在測試每種配置後如何評估效能。

6. 為永續性命名研究

為您的研究指定一個名稱,以便稍後可以恢復或引用它。這在跨多個會話或機器執行實驗時特別有用。

7. 設定持久化儲存

選擇我們之前設定的儲存後端,以便您可以在以後繼續研究,分析結果,甚至在系統重啟後也能視覺化指標。

>>> def optuna_hp_space(trial):
...     return {
...         "learning_rate": trial.suggest_float("learning_rate", 1e-6, 1e-4, log=True),
...         "per_device_train_batch_size": trial.suggest_categorical("per_device_train_batch_size", [16, 32, 64, 128]),
...         "weight_decay": trial.suggest_float("weight_decay", 0.0, 0.3),
...     }


>>> best_run = trainer.hyperparameter_search(
...     direction="maximize",
...     backend="optuna",
...     hp_space=optuna_hp_space,
...     n_trials=5,
...     compute_objective=compute_objective,
...     study_name="transformers_optuna_study",
...     storage="sqlite:///optuna_trials.db",
...     load_if_exists=True,
... )

>>> print(best_run)
BestRun(run_id='0', objective=0.764, hyperparameters={'learning_rate': 7.23655165533393e-05, 'per_device_train_batch_size': 16, 'weight_decay': 0.013798094328723032}, run_summary=None)

視覺化結果

一旦您的 Optuna 研究完成其試驗,就該揭開層層謎團並解釋所發生的一切了。視覺化可以清晰地展示超引數如何影響結果,並揭示可能隱藏在原始資料中的模式。

1. 跟蹤最佳化進度

使用最佳化歷史記錄檢視目標分數在試驗中如何演變。這有助於您瞭解效能是穩步提高、趨於平穩還是波動。它是您瞭解搜尋過程的速度和軌跡的視窗。

2. 透過中間值檢查訓練行為

如果您的模型在訓練期間報告評估指標(例如每個 epoch),中間值圖可讓您即時監控每個試驗的效能。這對於早期停止決策和評估學習穩定性特別有價值。

3. 透過重要性排名揭示關鍵超引數

引數重要性圖表揭示了哪些超引數真正重要——調整學習率是否起作用,還是批大小是關鍵?瞭解這一點可以幫助您簡化或最佳化未來的搜尋空間。

>>> import optuna
>>> from optuna.visualization.matplotlib import (
...     plot_optimization_history,
...     plot_intermediate_values,
...     plot_param_importances,
... )
>>> import matplotlib.pyplot as plt

>>> # Load the study from RDB storage
>>> storage = optuna.storages.RDBStorage("sqlite:///optuna_trials.db")

>>> study = optuna.load_study(study_name="transformers_optuna_study", storage=storage)

>>> # Plot optimization history
>>> ax1 = plot_optimization_history(study)
>>> plt.show()
>>> ax1.figure.savefig("optimization_history.png")

>>> # Plot intermediate values (if using pruning and intermediate reports)
>>> ax2 = plot_intermediate_values(study)
>>> plt.show()
>>> ax2.figure.savefig("intermediate_values.png")

>>> # Plot parameter importances
>>> ax3 = plot_param_importances(study)
>>> plt.show()
>>> ax3.figure.savefig("param_importances.png")

執行最終訓練

一旦您使用 Optuna 完成超引數最佳化,就該利用您的最佳發現並執行最後一輪訓練了。

1. 獲取您的“配方”

訪問在調優過程中確定的最佳超引數集。

2. 配置訓練引數

將這些超引數值插入到您的訓練設定中。這可能包括調整學習率、批大小、時期數、 dropout 率以及其他影響訓練行為的模型特定引數。

3. 融入模型設定

將最佳化後的值應用於初始化和配置您的模型。這確保了您的最終訓練執行由透過試錯發現的最有效設定指導。

4. 微調您的訓練管道

使用最佳引數設定您的最佳化器、損失函式和資料載入器。從模型學習速度到它一次處理的資料量,一切都應該反映您的最佳化配置。

5. 執行完整訓練

開始使用整個訓練資料集(或至少您在 HPO 期間使用的訓練/驗證拆分)訓練您的模型。此過程應反映您在不進行探索性變異的情況下學習資料模式的最佳嘗試。

from datasets import load_dataset
from transformers import AutoTokenizer

# Load IMDb dataset
dataset = load_dataset("imdb")

# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")


# Tokenize the text
def tokenize_function(example):
    return tokenizer(example["text"], padding="max_length", truncation=True)


# Apply tokenization
tokenized_dataset = dataset.map(tokenize_function, batched=True)

# Clean up columns
tokenized_dataset = tokenized_dataset.remove_columns(["text"])
tokenized_dataset = tokenized_dataset.rename_column("label", "labels")

# Set PyTorch format
tokenized_dataset.set_format("torch", columns=["input_ids", "attention_mask", "labels"])

# Subset for quick testing (optional)
train_dataset = tokenized_dataset["train"].shuffle(seed=42).select(range(2000))
valid_dataset = tokenized_dataset["test"].shuffle(seed=42).select(range(500))
from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer

# Define the model
model = AutoModelForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=2)

# Load best hyperparameters (already defined earlier as best_hparams)
training_args = TrainingArguments(
    output_dir="./final_model",
    learning_rate=best_hparams["learning_rate"],
    per_device_train_batch_size=best_hparams["per_device_train_batch_size"],
    weight_decay=best_hparams["weight_decay"],
    eval_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
    logging_strategy="epoch",
    num_train_epochs=3,
    report_to="wandb",
    run_name="final_run_with_best_hparams",
)

# Create Trainer
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=valid_dataset,
    processing_class=tokenizer,
    compute_metrics=lambda eval_pred: {"accuracy": (eval_pred.predictions.argmax(-1) == eval_pred.label_ids).mean()},
)

# Train
trainer.train()

# Save the model
trainer.save_model("./final_model")

上傳到 Hugging Face Hub

您已成功訓練出一個強大且最佳化的模型,現在是時候將其提供給世界了。在 Hugging Face Hub 上共享您的模型不僅使其可重用且可用於推理,而且還為開源社群做出了貢獻。

1. 慶祝最佳化成果

經過嚴格的調優和最終訓練,您的模型現在能夠更高效、更穩定地執行。這些改進使其成為情感分析等實際任務的理想選擇,例如分類電影評論以微調內容推薦。

2. 在本地儲存您的工作

在共享之前,請在本地系統上儲存訓練好的模型——包括權重、配置、分詞器(如果適用)和訓練工件。此步驟可確保您的模型設定可重現並已準備好上傳。

3. 使用 Hugging Face Hub 進行身份驗證

要上傳您的模型,您需要登入 Hugging Face Hub。無論是透過終端還是 Notebook 介面,身份驗證都將您的環境連線到平臺上的個人或組織空間,從而實現推送訪問。

4. 上傳並共享

將您儲存的模型推送到 Hugging Face Hub。這使得模型可以公開訪問(或私有),並允許其他人載入、使用和微調它。您還將建立一個模型卡,解釋模型的功能、預期用例和效能基準。

📌 重要性:

  • 集中式模型儲存鼓勵版本控制、可重現性和透明度。
  • 該 Hub 透過與 `transformers` 相容的 API 簡化了下游任務的整合。
  • 共享模型有助於建立您的個人資料並支援機器學習社群內的協作。
from transformers import AutoTokenizer, AutoModelForSequenceClassification

# Load your saved model from the path
model = AutoModelForSequenceClassification.from_pretrained("./final_model")
tokenizer = AutoTokenizer.from_pretrained("./final_model")

# Push to your repository on the hub
model.push_to_hub("AINovice2005/bert-imdb-optuna-hpo")
tokenizer.push_to_hub("AINovice2005/bert-imdb-optuna-hpo")
< > 在 GitHub 上更新

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