使用 Optimum-Intel 和 OpenVINO GenAI 最佳化和部署模型

HuggingFace發表於2024-10-21

在端側部署 Transformer 模型需要仔細考慮效能和相容性。Python 雖然功能強大,但對於部署來說有時並不算理想,特別是在由 C++ 主導的環境中。這篇部落格將指導您如何使用 Optimum-Intel 和 OpenVINO™ GenAI 來最佳化和部署 Hugging Face Transformers 模型,確保在最小依賴性的情況下進行高效的 AI 推理。

為什麼使用 OpenVINO 來進行端側部署

OpenVINO™ 最初是作為 C++ AI 推理解決方案開發的,使其非常適合在端側裝置部署中,其中最小化依賴性至關重要。隨著引入 GenAI API,將大型語言模型 (LLMs) 整合到 C++ 或 Python 應用程式中變得更加簡單,其特性旨在簡化部署並提升效能。

第一步: 建立環境

預先準備

開始之前,請確保您的環境已正確配置了 Python 和 C++。安裝必要的 Python 包:

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

以下是本文中使用的具體包:

transformers==4.44
openvino==24.3
openvino-tokenizers==24.3
optimum-intel==1.20
lm-eval==0.4.3

有關 GenAI C++ 庫的安裝,請按照 此處 的說明進行操作。

第二步: 將模型匯出為 OpenVINO IR

Hugging Face 和 Intel 的合作促成了 Optimum-Intel 專案。該專案旨在最佳化 Transformers 模型在 Intel 硬體上的推理效能。Optimum-Intel 支援 OpenVINO 作為推理後端,其 API 為各種基於 OpenVINO 推理 API 構建的模型架構提供了封裝。這些封裝都以 OV 字首開頭,例如 OVModelForCausalLM 。除此之外,它與 🤗 Transformers 庫的 API 類似。

要將 Transformers 模型匯出為 OpenVINO 中間表示 (IR),可以使用兩種方法: 可以使用 Python 的 .from_pretrained() 方法或 Optimum 命令列介面 (CLI)。以下是使用這兩種方法的示例:

使用 Python API

from optimum.intel import OVModelForCausalLM

model_id = "meta-llama/Meta-Llama-3.1-8B"
model = OVModelForCausalLM.from_pretrained(model_id, export=True)
model.save_pretrained("./llama-3.1-8b-ov")

使用命令列 (CLI)

optimum-cli export openvino -m meta-llama/Meta-Llama-3.1-8B ./llama-3.1-8b-ov

./llama-3.1-8b-ov 資料夾將包含 .xml 和 bin IR 模型檔案以及來自源模型的所需配置檔案。🤗 tokenizer 也將轉換為 openvino-tokenizers 庫的格式,並在同一資料夾中建立相應的配置檔案。

第三步: 模型最佳化

在資源受限的端側裝置上執行大型語言模型 (LLMs) 時,模型最佳化是一個極為重要的步驟。僅量化權重是一種主流方法,可以顯著降低延遲和模型佔用空間。Optimum-Intel 透過神經網路壓縮框架 (NNCF) 提供了僅量化權重 (weight-only quantization) 的功能,該框架具有多種專為 LLMs 設計的最佳化技術: 從無資料 (data-free) 的 INT8 和 INT4 權重量化到資料感知方法,如 AWQGPTQ、量化 scale 估計、混合精度量化等。預設情況下,超過十億引數的模型的權重會被量化為 INT8 精度,這在準確性方面是安全的。這意味著上述匯出步驟會生成具有 8 位權重的模型。然而,4 位整數的僅量化權重允許實現更好的準確性和效能的權衡。

對於 meta-llama/Meta-Llama-3.1-8B 模型,我們建議結合 AWQ、量化 scale 估計以及使用反映部署用例的校準資料集進行混合精度 INT4/INT8 權重的量化。與匯出情況類似,在將 4 位元僅量化權重應用於 LLM 模型時有兩種選項:

使用 Python API

  • .from_pretrained() 方法中指定 quantization_config 引數。在這種情況下,應建立 OVWeightQuantizationConfig 物件,並將其設定為該引數,如下所示:
from optimum.intel import OVModelForCausalLM, OVWeightQuantizationConfig

MODEL_ID = "meta-llama/Meta-Llama-3.1-8B"
quantization_config = OVWeightQuantizationConfig(bits=4, awq=True, scale_estimation=True, group_size=64, dataset="c4")
model = OVModelForCausalLM.from_pretrained(MODEL_ID, export=True, quantization_config=quantization_config)
model.save_pretrained("./llama-3.1-8b-ov")

使用命令列 (CLI)

optimum-cli export openvino -m meta-llama/Meta-Llama-3.1-8B --weight-format int4 --awq --scale-estimation --group-size 64 --dataset wikitext2 ./llama-3.1-8b-ov

第四步: 使用 OpenVINO GenAI API 進行部署

在轉換和最佳化之後,使用 OpenVINO GenAI 部署模型非常簡單。OpenVINO GenAI 中的 LLMPipeline 類提供了 Python 和 C++ API,支援各種文字生成方法,並具有最小的依賴關係。

Python API 的例子

import argparse
import openvino_genai

device = "CPU" # GPU can be used as well
pipe = openvino_genai.LLMPipeline(args.model_dir, device)
config = openvino_genai.GenerationConfig()
config.max_new_tokens = 100
print(pipe.generate(args.prompt, config))

為了執行這個示例,您需要在 Python 環境中安裝最小的依賴項,因為 OpenVINO GenAI 旨在提供輕量級部署。您可以將 OpenVINO GenAI 包安裝到相同的 Python 環境中,或者建立一個單獨的環境來比較應用程式的佔用空間:

pip install openvino-genai==24.3

C++ API 的例子

讓我們看看如何使用 OpenVINO GenAI C++ API 執行相同的流程。GenAI API 的設計非常直觀,並提供了與 🤗 Transformers API 無縫遷移的功能。

注意: 在下面的示例中,您可以為 “device” 變數指定環境中的任何其他可用裝置。例如,如果您正在使用帶有整合顯示卡的 Intel CPU,則嘗試使用 “GPU” 是一個不錯的選擇。要檢查可用裝置,您可以使用 ov::Core::get_available_devices 方法 (參考 query-device-properties)。

#include "openvino/genai/llm_pipeline.hpp"
#include <iostream>

int main(int argc, char* argv[]) {
   std::string model_path = "./llama-3.1-8b-ov";
   std::string device = "CPU" // GPU can be used as well
   ov::genai::LLMPipeline pipe(model_path, device);
   std::cout << pipe.generate("What is LLM model?", ov::genai::max_new_tokens(256));
}

自定義生成配置

LLMPipeline 還允許透過 ov::genai::GenerationConfig 來指定自定義生成選項:

ov::genai::GenerationConfig config;
config.max_new_tokens = 256;
std::string result = pipe.generate(prompt, config);

使用 LLMPipeline,使用者不僅可以輕鬆利用各種解碼演算法,如 Beam Search,還可以像下面的示例中那樣構建具有 Streamer 的互動式聊天場景。此外,使用者可以利用 LLMPipeline 的增強內部最佳化,例如利用先前聊天曆史的 KV 快取減少提示處理時間,使用 chat 方法: start_chat()finish_chat() (參考 using-genai-in-chat-scenario)。

ov::genai::GenerationConfig config;
config.max_new_tokens = 100;
config.do_sample = true;
config.top_p = 0.9;
config.top_k = 30;

auto streamer = [](std::string subword) {
    std::cout << subword << std::flush;
    return false;
};

// Since the streamer is set, the results will
// be printed each time a new token is generated.
pipe.generate(prompt, config, streamer);

最後你可以看到如何在聊天場景下使用 LLMPipeline:

pipe.start_chat()
for (size_t i = 0; i < questions.size(); i++) {
   std::cout << "question:\n";
   std::getline(std::cin, prompt);

   std::cout << pipe.generate(prompt) << std::endl;
}
pipe.finish_chat();

結論

Optimum-Intel 和 OpenVINO™ GenAI 的結合為在端側部署 Hugging Face 模型提供了強大而靈活的解決方案。透過遵循這些步驟,您可以在 Python 可能不是理想選擇的環境中實現最佳化的高效能 AI 推理,以確保您的應用在 Intel 硬體上平穩執行。

其他資源

  1. 您可以在這個 教程 中找到更多詳細資訊。
  2. 要構建上述的 C++ 示例,請參考這個 文件
  3. OpenVINO 文件
  4. Jupyter 筆記本
  5. Optimum 文件

OpenVINO GenAI C++ 聊天演示


原文連結: https://hf.co/blog/deploy-with-openvino

原文作者: Alexander, Yury Gorbachev, Ekaterina Aidova, Ilya Lavrenov, Raymond Lo, Helena, Ella Charlaix

譯者: Zipxuan

相關文章