在英特爾至強 CPU 上使用 🤗 Optimum Intel 實現超快 SetFit 推理

HuggingFace發表於2024-05-06

在缺少標註資料場景,SetFit 是解決的建模問題的一個有前途的解決方案,其由 Hugging Face 與 Intel 實驗室 以及 UKP Lab 合作共同開發。作為一個高效的框架,SetFit 可用於對 Sentence Transformers 模型進行少樣本微調。

SetFit 僅需很少的標註資料就能達到較高的準確率,例如,在使用 3-示例提示時,SetFit 優於 GPT-3.5;在使用 5-示例提示時,其在 Banking 77 金融意圖資料集上的表現也優於使用 3-示例提示的 GPT-4。

與基於 LLM 的方法相比,SetFit 有兩個獨特的優勢:

🗣 無需提示或詞-標籤對映器:基於 LLM 的少樣本上下文學習依賴於人工製作的提示,其對措辭比較敏感,且依賴使用者的專業知識,因此效果比較脆弱。SetFit 直接從少量標註文字樣本中生成豐富的嵌入,從而完全省去了提示。

🏎 訓練速度快:SetFit 不依賴 GPT-3.5 或 Llama2 等 LLM 來實現高準確率。因此,訓練和推理速度通常要快一個數量級(或更多)。

有關 SetFit 的更多詳情,請參閱:論文部落格程式碼及相關資料

Setfit 已被 AI 開發者社群廣泛採用,每月下載量約為 10 萬次,Hub 上的 SetFit 模型已有 1600 個之多,且平均日增量約為 4 個左右。

加速!

本文,我們將解釋如何用 🤗 Optimum Intel 最佳化你的 SetFit 模型,從而在英特爾 CPU 上實現 7.8x 的推理加速。我們還將展示如何輕鬆對模型進行訓後量化,從而實現巨大的吞吐增益。有了這些技術,使用者可在英特爾至強 CPU 上部署生產級的 SetFit 解決方案。

Optimum Intel 是一個開源庫,可在英特爾硬體上對由 Hugging Face 庫構建的端到端流水線進行加速。 Optimum Intel 實現了多種模型加速技術,如低位元量化、模型權重剪枝、蒸餾以及執行時加速。

Optimum Intel 的執行時及各種最佳化都充分利用了英特爾® AVX-512、向量神經網路指令 (VNNI) 以及最新的英特爾® 先進矩陣擴充套件(英特爾® AMX)以對模型進行極致加速。具體來說,英特爾在每個 CPU 核中都內建了 bfloat16 (bf16) 和 int8 GEMM 加速器,以加速深度學習訓練和推理工作負載。尤其值得一提的是,PyTorch 2.0 和 Intel Extension for PyTorch (IPEX) 中加入了 AMX 最佳化以進一步加速推理及訓練。

使用 Optimum Intel 可以輕鬆對各種預訓練模型進行加速,你可在此處找到很多例子。本文也附有一個 notebook 版,可供大家逐步演練。

第 1 步:使用 🤗 Optimum Intel 量化 SetFit 模型

在對 SetFit 模型進行最佳化時,我們會使用英特爾神經壓縮器 (INC) 對模型進行量化,其已整合入 Optimum Intel。

量化是一種非常流行的深度學習模型最佳化技術,可用於提高推理速度。它透過將一組高精度數值轉換為較低位寬的資料型別(如 INT8)。從而最大限度地降低神經網路的權重和/或啟用所需的位數。另外,由於位寬較低,其計算速度也可能會更快。

本文,我們將使用訓後靜態量化(PTQ)。PTQ 僅需少量未標註校準資料,無需任何訓練即可在保持模型的準確性的同時減低推理時的記憶體佔用並降低延遲。首先請確保你已安裝所有必要的庫,同時確保 Optimum Intel 版本至少為 1.14.0(因為 PTQ 功能是從該版本開始引入的):

pip install --upgrade-strategy eager optimum[ipex]

準備校準資料集

校準資料集應能在資料分佈上較好代表未見資料。一般來說,準備 100 個樣本就足夠了。在本例中,我們使用的是 rotten_tomatoes 資料集,其是一個電影評論資料集,與我們的目標資料集 sst2 類似。

首先,我們從該資料集中隨機載入 100 個樣本。然後,為了準備量化資料集,我們需要對每個樣本進行標註。我們不需要 textlabel 列,因此將其刪除。

calibration_set = load_dataset("rotten_tomatoes", split="train").shuffle(seed=42).select(range(100)) 

def tokenize(examples):
    return tokenizer(examples["text"], padding="max_length", max_length=512, truncation=True)
 
tokenizer = setfit_model.model_body.tokenizer
calibration_set = calibration_set.map(tokenize, remove_columns=["text", "label"])

量化

量化前,先要配置所需的量化方案,本例中為靜態訓後量化,再使用 optimum.intel 在校準資料集上執行量化:

from optimum.intel import INCQuantizer
from neural_compressor.config import PostTrainingQuantConfig

setfit_body = setfit_model.model_body[0].auto_model
quantizer = INCQuantizer.from_pretrained(setfit_body)
optimum_model_path = "/tmp/bge-small-en-v1.5_setfit-sst2-english_opt"
quantization_config = PostTrainingQuantConfig(approach="static", backend="ipex", domain="nlp")

quantizer.quantize(
    quantization_config=quantization_config,
    calibration_dataset=calibration_set,
    save_directory=optimum_model_path,
    batch_size=1,
)
tokenizer.save_pretrained(optimum_model_path)

就這樣!現在,我們有了一個量化版的 SetFit 模型。下面,我們對其進行測試。

第 2 步:推理基準測試

我們在 notebook 中寫了一個 PerformanceBenchmark 類,用於計算模型延遲和吞吐量,並用於測量模型準確度。我們現在用它來對以下三種配置進行基準測試:

  • 使用 PyTorch🤗 Transformers 庫對 fp32 模型進行推理。
  • 使用 Intel Extension for PyTorch (IPEX) 對模型進行 bf16 推理,同時使用 TorchScript 對模型進行圖最佳化。
  • 使用 Optimum Intelint8 量化模型進行推理。

載入測試資料集 sst2,並使用 PyTorch 和 🤗 Transformers 庫執行基準測試:

from datasets import load_dataset
from setfit import SetFitModel
test_dataset = load_dataset("SetFit/sst2")["validation"]

model_path = "dkorat/bge-small-en-v1.5_setfit-sst2-english"
setfit_model = SetFitModel.from_pretrained(model_path)
pb = PerformanceBenchmark(
    model=setfit_model,
    dataset=test_dataset,
    optim_type="bge-small (transformers)",
)
perf_metrics = pb.run_benchmark()

第二個基準測試,我們將使用 bf16 精度和 TorchScript 兩種最佳化手段,並使用 IPEX 最佳化庫。要使用 IPEX,我們只需匯入 IPEX 庫並對模型應用 ipex.optimize(),在本例中,目標模型是 SetFit 的模型體:

dtype = torch.bfloat16
body = ipex.optimize(setfit_model.model_body, dtype=dtype)

使用 TorchScript 進行圖最佳化時,我們根據模型的最大輸入長度生成隨機序列,並從分詞器的詞彙表中取樣詞彙:

tokenizer = setfit_model.model_body.tokenizer
d = generate_random_sequences(batch_size=1, length=tokenizer.model_max_length, vocab_size=tokenizer.vocab_size)

body = torch.jit.trace(body, (d,), check_trace=False, strict=False)
setfit_model.model_body = torch.jit.freeze(body)

最後,我們對量化的 Optimum 模型執行基準測試。我們首先定義一個 SetFit 模型的包裝類,該包裝類在推理時會自動插入量化模型體(而不是原始模型體)。然後,我們用這個包裝類跑基準測試。

from optimum.intel import IPEXModel

class OptimumSetFitModel:
    def __init__(self, setfit_model, model_body):
        model_body.tokenizer = setfit_model.model_body.tokenizer
        self.model_body = model_body
        self.model_head = setfit_model.model_head


optimum_model = IPEXModel.from_pretrained(optimum_model_path)
optimum_setfit_model = OptimumSetFitModel(setfit_model, model_body=optimum_model)

pb = PerformanceBenchmark(
    model=optimum_setfit_model,
    dataset=test_dataset,
    optim_type=f"bge-small (optimum-int8)",
    model_path=optimum_model_path,
    autocast_dtype=torch.bfloat16,
)
perf_metrics.update(pb.run_benchmark())

結果

精度與延遲關係圖(batch size=1)

精度與延遲關係圖(batch size=1)

bge-small (transformers) bge-small (ipex-bfloat16) bge-small (optimum-int8)
模型大小 127.32 MB 63.74 MB 44.65 MB
測試集準確率 88.4% 88.4% 88.1%
延遲 (bs=1) 15.69 +/- 0.57 ms 5.67 +/- 0.66 ms 4.55 +/- 0.25 ms

batch size 為 1 時,我們的最佳化模型將延遲降低了 3.45 倍。請注意,此時準確率幾乎沒有下降!另外值得一提的是,模型大小縮小了 2.85x

我們將焦點轉向不同 batch size 下的吞吐量。這裡,我們獲得了更大的加速。如果比較最高吞吐量(不限 batch size),最佳化後的模型比原始 transformers fp32 模型高 7.8 倍!

總結

本文,我們展示瞭如何使用 🤗 Optimum Intel 中的量化功能來最佳化 SetFit 模型。在輕鬆快速地對模型完成訓後量化後,我們觀察到在準確度損失很小的情況下,推理吞吐量增加了 7.8 倍。使用者可以使用這種最佳化方法在英特爾至強 CPU 上輕鬆部署任何現有 SetFit 模型。

參考文獻

  • Lewis Tunstall, Nils Reimers, Unso Eun Seo Jo, Luke Bates, Daniel Korat, Moshe Wasserblat, Oren Pereg, 2022. "Efficient Few-Shot Learning Without Prompts". https://arxiv.org/abs/2209.11055

英文原文: https://hf.co/blog/setfit-optimum-intel

原文作者:Daniel Korat,Tom Aarsen,Oren Pereg,Moshe Wasserblat,Ella Charlaix,Abirami Prabhakaran

譯者: Matrix Yao (姚偉峰),英特爾深度學習工程師,工作方向為 transformer-family 模型在各模態資料上的應用及大規模模型的訓練推理。

相關文章