作為主要面向 RAG 任務(wù)方向的框架,Semantic Kernel 可以簡(jiǎn)化大模型應(yīng)用開(kāi)發(fā)過(guò)程,而在 RAG 任務(wù)中最常用的深度學(xué)習(xí)模型就是 Embedding 和 Text completion,分別實(shí)現(xiàn)文本的語(yǔ)義向量化和文本生成,因此本文主要會(huì)分享如何在 Semantic Kernel 中調(diào)用 OpenVINO runtime 部署 Embedding 和 Text completion 模型。
Semantic Kernel簡(jiǎn)介
Semantic Kernel 是微軟推出的大模型應(yīng)用框架,支持 C#, Python 和 Java 等開(kāi)發(fā)環(huán)境,通過(guò) Semantic Kernel 集成的API接口,開(kāi)發(fā)者可以直接調(diào)用 OpenAI 或是 Hugging Face 中的大語(yǔ)言模型,進(jìn)一步構(gòu)建上層應(yīng)用任務(wù),例如 Chat Copilot 或是 Code completion ,等。顧名思義,Semantic Kernel 的核心就在于由 Kernel 所連接的 pipeline/chain,它通過(guò)上下文,實(shí)現(xiàn)在各個(gè)函數(shù)組件間共享數(shù)據(jù),下面這張展示的就是用戶的輸入 Prompt 如何在這些組件中進(jìn)行流轉(zhuǎn),最終返回響應(yīng)結(jié)果。

圖:Semantic Kernel組件示意圖
OpenVINO 簡(jiǎn)介
OpenVINO 作為英特爾官方推出的深度學(xué)習(xí)模型部署工具,可以極大地提升本地模型任務(wù)的推理性能。同時(shí) OpenVINO 支持了多種推理后端,使模型可以在多種不同的硬件架構(gòu)上進(jìn)行部署和切換,進(jìn)一步提升任務(wù)的靈活性與系統(tǒng)資源利用率,例如我們可以利用 NPU 來(lái)部署一些輕負(fù)載的 AI 模型以降低功耗,利用 GPU 來(lái)部署大模型以優(yōu)化反饋延遲??傊?strong>在大模型本地化趨勢(shì)越來(lái)越熱的今天,OpenVINO 勢(shì)必成為在 PC 端部署大模型任務(wù)的好幫手。
OpenVINO 與 Semantic Kernel
集成實(shí)現(xiàn)
Semantic Kernel 的 Connector 是一種用于連接外部數(shù)據(jù)源和服務(wù)的設(shè)計(jì)模式,包括獲取數(shù)據(jù)和保存輸出結(jié)果,而 Semantic Kernel 已經(jīng)原生集成了許多開(kāi)箱即用的大模型服務(wù) Plugin,其中就包括了基于 Hugging Face Transformers 構(gòu)建的的 Embedding 和 Text completion Service,因此我們可以參考這兩個(gè) Service 的代碼,來(lái)實(shí)現(xiàn)一組 OpenVINO 的 Service,完成和 Connectors 組件的集成,分別命名為 OpenVINOTextEmbedding 以及 OpenVINOTextCompletion。
1
Text completion service
首先是 Text completion 任務(wù),由于 OpenVINO 可以通過(guò) Optimum-intel 直接部署 Hugging Face中的 "summarization", "text-generation", "text2text-generation" 等模型,相較原生 Transformers API 的使用方式,也僅僅需要做少量修改(如以下代碼所示)。
- from transformers import AutoModelForCausalLM
+ from optimum.intel.openvino import OVModelForCausalLM
- model = AutoModelForCausalLM.from_pretrained(model_id)
+ ov_model = OVModelForCausalLM.from_pretrained(model_id)
generate_ids = ov_model.generate(input_ids)
因此,我們也可以直接在 Hugging Face Text completion service 的基礎(chǔ)上直接將 Transformers 的模型加載對(duì)象切換為 Optimum-intel 的對(duì)象,以實(shí)現(xiàn)基于 OpenVINO runtime 的模型推理。這里可通過(guò) OVModelForCausalLM 類來(lái)部署 "text-generation" 類型的大模型,通過(guò) OVModelForSeq2SeqLM 類調(diào)用 "text2text-generation", "summarization" 類型模型。
if task == "text-generation":
ov_model = OVModelForCausalLM.from_pretrained(
ai_model_id, **_model_kwargs)
elif task in ("text2text-generation", "summarization"):
ov_model = OVModelForSeq2SeqLM.from_pretrained(
ai_model_id, **_model_kwargs)
2
Embedding service
不同于 Text completion service, Semantic Kernel 中集成的 Hugging Face Embedding service 是基于 sentence_transformers 庫(kù)來(lái)實(shí)現(xiàn)的,并調(diào)用 encode 函數(shù)來(lái)進(jìn)行 Embedding 文本向量化。
generator=sentence_transformers.SentenceTransformer(model_name_or_path=ai_model_id, device=resolved_device), embeddings = self.generator.encode(texts)
而 OpenVINO 目前暫未直接對(duì)接 sentence_transformers 的模型部署接口,因此這里我們需要手動(dòng)將 sentence_transformers 的 PyTorch 模型對(duì)象轉(zhuǎn)化為 OpenVINO IR 格式后,再重新構(gòu)建它的 encode 函數(shù) pipeline。
可以看到 Hugging Face 的 embedding 模型除了支持 Sentence-Transformers 對(duì)象部署方式外,還可以基于 Transformers 庫(kù)的方式,通過(guò) AutoModel.from_pretrained 獲取 nn.module 格式的模型對(duì)象,而 OpenVINO 的 PyTorch 前端則已經(jīng)支持對(duì)該格式對(duì)象的直接轉(zhuǎn)換,所以我們首先需要手寫一個(gè)轉(zhuǎn)換腳本,來(lái)實(shí)現(xiàn) Embedding 模型從 PyTorch 對(duì)象到 OpenVINO IR 格式的轉(zhuǎn)化過(guò)程。
tokenizer = AutoTokenizer.from_pretrained(args.model_id)
model = AutoModel.from_pretrained(args.model_id)
dummy_inputs = {"input_ids": torch.ones((1, 10), dtype=torch.long), "attention_mask": torch.ones(
(1, 10), dtype=torch.long), "token_type_ids": torch.zeros((1, 10), dtype=torch.long)}
ov_model = ov.convert_model(model, example_input=dummy_inputs)
ov.save_model(ov_model, model_path / "openvino_model.xml")
在定義新的 encode 函數(shù)時(shí),鑒于在 RAG 系統(tǒng)中的各個(gè)句子的向量化任務(wù)往往沒(méi)有依賴關(guān)系,因此我們可以通過(guò) OpenVINO 的 AsyncInferQueue 接口,將這部分任務(wù)并行化,以提升整個(gè) Embedding 任務(wù)的吞吐量。
infer_queue = ov.AsyncInferQueue(self.model, nireq)
for i, sentence in enumerate(sentences_sorted):
inputs = {}
features = self.tokenizer(
sentence, padding=True, truncation=True, return_tensors='np')
for key in features:
inputs[key] = features[key]
infer_queue.start_async(inputs, i)
infer_queue.wait_all()
此外,從 HuggingFace Transfomers 庫(kù)中導(dǎo)出的 Embedding 模型是不包含 mean_pooling 和歸一化操作的,因此我們需要在獲取模型推理結(jié)果后,再實(shí)現(xiàn)這部分后處理任務(wù)。并將其作為 callback function 與 AsyncInferQueue 進(jìn)行綁定。
def postprocess(request, userdata):
embeddings = request.get_output_tensor(0).data
embeddings = np.mean(embeddings, axis=1)
if self.do_norm:
embeddings = normalize(embeddings, 'l2')
all_embeddings.extend(embeddings)
infer_queue.set_callback(postprocess)
測(cè)試驗(yàn)證
當(dāng)完成這兩個(gè)關(guān)鍵對(duì)象的創(chuàng)建后,我們可以來(lái)驗(yàn)證一下重新構(gòu)建的 OpenVINO 任務(wù)效果。
第一步:我們需要將 Embedding 和 Text completion 這兩個(gè)模型分轉(zhuǎn)換并導(dǎo)出到本地。這里以 all-MiniLM-L6-v2 和 gpt2 為例。
Embedding 模型可以通過(guò)剛剛定義的轉(zhuǎn)換腳本導(dǎo)出模型:
python3 export_embedding.py -m sentence-transformers/all-MiniLM-L6-v2
Text completion 模型可以通過(guò) Optimum-intel 中自帶命令行工具導(dǎo)出:
optimum-cli export openvino --model gpt2 llm_model
第二步:通過(guò)修改 Semantic Kernel 官方提供的 Hugging Face Plugins 示例
來(lái)測(cè)試 OpenVINO Plugin 的效果,該示例基于 Embedding 和 Text completion 模型構(gòu)建了一個(gè)最小化的 RAG 任務(wù) pipeline。此處只需要把原始的 Hugging Face service 對(duì)象替換為我們剛剛構(gòu)建的 OpenVINOTextEmbedding 和 OpenVINOTextCompletion 對(duì)象,其中 ai_model_id 需要修改為模型文件夾的本地路徑。
kernel.add_text_completion_service( service_id="gpt2", service=OpenVINOTextCompletion(ai_model_id="./llm_model", task="text-generation", model_kwargs={ "device": "CPU", "ov_config": ov_config}, pipeline_kwargs={"max_new_tokens": 64}) ) kernel.add_text_embedding_generation_service( service_id="sentence-transformers/all-MiniLM-L6-v2", service=OpenVINOTextEmbedding(ai_model_id="./embedding_model"), )
在這個(gè)示例中 Kernel 是通過(guò) kernel.memory.save_information 函數(shù)來(lái)實(shí)現(xiàn)知識(shí)的注入,過(guò)程中會(huì)調(diào)用 Embedding service 來(lái)完成對(duì)于文本的語(yǔ)義向量化操作。我們可以通過(guò)執(zhí)行以下命令來(lái)執(zhí)行完整的 notebook 測(cè)試腳本。
$ jupyter lab sample.ipynb
示例中為了簡(jiǎn)化模型下載和轉(zhuǎn)化步驟,采用了相較主流 LLM 更輕量化的gpt2來(lái)實(shí)現(xiàn)文本內(nèi)容生成,因此在輸出內(nèi)容上會(huì)相對(duì)單一,如果需要實(shí)現(xiàn)更復(fù)雜的內(nèi)容生成能力,可以將其替換為一些參數(shù)規(guī)模更大的文本生成模型,最終輸出結(jié)果如下:
gpt2 completed prompt with: 'I know these animal facts: ["Dolphins are mammals."] ["Flies are insects."] ["Penguins are birds."] and "Horses are mammals."
對(duì)比官方原始 Hugging Face Plugins 示例的輸出結(jié)果,與注入的知識(shí)庫(kù)信息,兩者對(duì)于 animal facts 的判斷使一致的,這也證明我們的重新構(gòu)建的 OpenVINO Plugin 在模型輸出的準(zhǔn)確性上是沒(méi)有問(wèn)題的。
總結(jié)
在醫(yī)療、工業(yè)等領(lǐng)域,行業(yè)知識(shí)庫(kù)的構(gòu)建已經(jīng)成為了一個(gè)普遍需求,通過(guò) Semantic-Kernel 與 OpenVINO 的加持,我們可以讓用戶對(duì)于知識(shí)庫(kù)的查詢以及反饋?zhàn)兊酶泳珳?zhǔn)高效,降低 RAG 任務(wù)的開(kāi)發(fā)門檻,帶來(lái)更加友好的交互體驗(yàn)。
審核編輯:劉清
-
JAVA
+關(guān)注
關(guān)注
20文章
2997瀏覽量
116135 -
OpenAI
+關(guān)注
關(guān)注
9文章
1242瀏覽量
9915 -
大模型
+關(guān)注
關(guān)注
2文章
3604瀏覽量
5106 -
LLM
+關(guān)注
關(guān)注
1文章
345瀏覽量
1302
原文標(biāo)題:OpenVINO? 協(xié)同 Semantic Kernel:優(yōu)化大模型應(yīng)用性能新路徑 | 開(kāi)發(fā)者實(shí)戰(zhàn)
文章出處:【微信號(hào):英特爾物聯(lián)網(wǎng),微信公眾號(hào):英特爾物聯(lián)網(wǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
突破傳統(tǒng)桎梏,PPEC Workbench 開(kāi)啟電源智能化設(shè)計(jì)新路徑
無(wú)法在NPU上推理OpenVINO?優(yōu)化的 TinyLlama 模型怎么解決?
在CentOS從源代碼構(gòu)建OpenVINO?時(shí),無(wú)法找到設(shè)置腳本怎么解決?
構(gòu)建開(kāi)源OpenVINO?工具套件后,模型優(yōu)化器位于何處呢?
OpenVINO中的量化模型與OpenVINO ESR模型結(jié)果不一致是怎么回事?
如何使用OpenVINO?運(yùn)行對(duì)象檢測(cè)模型?
請(qǐng)問(wèn)使用2022.2時(shí)是否可以讀取模型OpenVINO?層?
使用模型優(yōu)化器命令將ONNX模型轉(zhuǎn)換為OpenVINO? IR格式時(shí)出現(xiàn)“ReplacementID”錯(cuò)誤怎么解決?
運(yùn)行時(shí)OpenVINO?找不到模型優(yōu)化器,為什么?
通過(guò)Docker映像OpenVINO? DL Workbench OpenVINO?安裝,無(wú)法上傳模型怎么解決?
為什么無(wú)法通過(guò)OpenVINO?深度學(xué)習(xí) (DL) 工作臺(tái)優(yōu)化 MYRIAD 導(dǎo)入的模型?
為什么無(wú)法在運(yùn)行時(shí)C++推理中讀取OpenVINO?模型?
C#集成OpenVINO?:簡(jiǎn)化AI模型部署
C#中使用OpenVINO?:輕松集成AI模型!
OpenVINO?協(xié)同Semantic Kernel:優(yōu)化大模型應(yīng)用性能新路徑
評(píng)論