作為主要面向 RAG 任務方向的框架,Semantic Kernel 可以簡化大模型應用開發過程,而在 RAG 任務中最常用的深度學習模型就是 Embedding 和 Text completion,分別實現文本的語義向量化和文本生成,因此本文主要會分享如何在 Semantic Kernel 中調用 OpenVINO runtime 部署 Embedding 和 Text completion 模型。
Semantic Kernel簡介
Semantic Kernel 是微軟推出的大模型應用框架,支持 C#, Python 和 Java 等開發環境,通過 Semantic Kernel 集成的API接口,開發者可以直接調用 OpenAI 或是 Hugging Face 中的大語言模型,進一步構建上層應用任務,例如 Chat Copilot 或是 Code completion ,等。顧名思義,Semantic Kernel 的核心就在于由 Kernel 所連接的 pipeline/chain,它通過上下文,實現在各個函數組件間共享數據,下面這張展示的就是用戶的輸入 Prompt 如何在這些組件中進行流轉,最終返回響應結果。
圖:Semantic Kernel組件示意圖
OpenVINO 簡介
OpenVINO 作為英特爾官方推出的深度學習模型部署工具,可以極大地提升本地模型任務的推理性能。同時 OpenVINO 支持了多種推理后端,使模型可以在多種不同的硬件架構上進行部署和切換,進一步提升任務的靈活性與系統資源利用率,例如我們可以利用 NPU 來部署一些輕負載的 AI 模型以降低功耗,利用 GPU 來部署大模型以優化反饋延遲。總之,在大模型本地化趨勢越來越熱的今天,OpenVINO 勢必成為在 PC 端部署大模型任務的好幫手。
OpenVINO 與 Semantic Kernel
集成實現
Semantic Kernel 的 Connector 是一種用于連接外部數據源和服務的設計模式,包括獲取數據和保存輸出結果,而 Semantic Kernel 已經原生集成了許多開箱即用的大模型服務 Plugin,其中就包括了基于 Hugging Face Transformers 構建的的 Embedding 和 Text completion Service,因此我們可以參考這兩個 Service 的代碼,來實現一組 OpenVINO 的 Service,完成和 Connectors 組件的集成,分別命名為 OpenVINOTextEmbedding 以及 OpenVINOTextCompletion。
1
Text completion service
首先是 Text completion 任務,由于 OpenVINO 可以通過 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 的基礎上直接將 Transformers 的模型加載對象切換為 Optimum-intel 的對象,以實現基于 OpenVINO runtime 的模型推理。這里可通過 OVModelForCausalLM 類來部署 "text-generation" 類型的大模型,通過 OVModelForSeq2SeqLM 類調用 "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 庫來實現的,并調用 encode 函數來進行 Embedding 文本向量化。
generator=sentence_transformers.SentenceTransformer(model_name_or_path=ai_model_id, device=resolved_device), embeddings = self.generator.encode(texts)
而 OpenVINO 目前暫未直接對接 sentence_transformers 的模型部署接口,因此這里我們需要手動將 sentence_transformers 的 PyTorch 模型對象轉化為 OpenVINO IR 格式后,再重新構建它的 encode 函數 pipeline。
可以看到 Hugging Face 的 embedding 模型除了支持 Sentence-Transformers 對象部署方式外,還可以基于 Transformers 庫的方式,通過 AutoModel.from_pretrained 獲取 nn.module 格式的模型對象,而 OpenVINO 的 PyTorch 前端則已經支持對該格式對象的直接轉換,所以我們首先需要手寫一個轉換腳本,來實現 Embedding 模型從 PyTorch 對象到 OpenVINO IR 格式的轉化過程。
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 函數時,鑒于在 RAG 系統中的各個句子的向量化任務往往沒有依賴關系,因此我們可以通過 OpenVINO 的 AsyncInferQueue 接口,將這部分任務并行化,以提升整個 Embedding 任務的吞吐量。
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 庫中導出的 Embedding 模型是不包含 mean_pooling 和歸一化操作的,因此我們需要在獲取模型推理結果后,再實現這部分后處理任務。并將其作為 callback function 與 AsyncInferQueue 進行綁定。
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)
測試驗證
當完成這兩個關鍵對象的創建后,我們可以來驗證一下重新構建的 OpenVINO 任務效果。
第一步:我們需要將 Embedding 和 Text completion 這兩個模型分轉換并導出到本地。這里以 all-MiniLM-L6-v2 和 gpt2 為例。
Embedding 模型可以通過剛剛定義的轉換腳本導出模型:
python3 export_embedding.py -m sentence-transformers/all-MiniLM-L6-v2
Text completion 模型可以通過 Optimum-intel 中自帶命令行工具導出:
optimum-cli export openvino --model gpt2 llm_model
第二步:通過修改 Semantic Kernel 官方提供的 Hugging Face Plugins 示例
來測試 OpenVINO Plugin 的效果,該示例基于 Embedding 和 Text completion 模型構建了一個最小化的 RAG 任務 pipeline。此處只需要把原始的 Hugging Face service 對象替換為我們剛剛構建的 OpenVINOTextEmbedding 和 OpenVINOTextCompletion 對象,其中 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"), )
在這個示例中 Kernel 是通過 kernel.memory.save_information 函數來實現知識的注入,過程中會調用 Embedding service 來完成對于文本的語義向量化操作。我們可以通過執行以下命令來執行完整的 notebook 測試腳本。
$ jupyter lab sample.ipynb
示例中為了簡化模型下載和轉化步驟,采用了相較主流 LLM 更輕量化的gpt2來實現文本內容生成,因此在輸出內容上會相對單一,如果需要實現更復雜的內容生成能力,可以將其替換為一些參數規模更大的文本生成模型,最終輸出結果如下:
gpt2 completed prompt with: 'I know these animal facts: ["Dolphins are mammals."] ["Flies are insects."] ["Penguins are birds."] and "Horses are mammals."
對比官方原始 Hugging Face Plugins 示例的輸出結果,與注入的知識庫信息,兩者對于 animal facts 的判斷使一致的,這也證明我們的重新構建的 OpenVINO Plugin 在模型輸出的準確性上是沒有問題的。
總結
在醫療、工業等領域,行業知識庫的構建已經成為了一個普遍需求,通過 Semantic-Kernel 與 OpenVINO 的加持,我們可以讓用戶對于知識庫的查詢以及反饋變得更加精準高效,降低 RAG 任務的開發門檻,帶來更加友好的交互體驗。
審核編輯:劉清
-
JAVA
+關注
關注
19文章
2970瀏覽量
104838 -
OpenAI
+關注
關注
9文章
1097瀏覽量
6566 -
大模型
+關注
關注
2文章
2477瀏覽量
2834 -
LLM
+關注
關注
0文章
292瀏覽量
351
原文標題:OpenVINO? 協同 Semantic Kernel:優化大模型應用性能新路徑 | 開發者實戰
文章出處:【微信號:英特爾物聯網,微信公眾號:英特爾物聯網】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論