人類通過(guò)視覺(jué)和語(yǔ)言感知世界。人工智能的一個(gè)長(zhǎng)期目標(biāo)是構(gòu)建智能體,通過(guò)視覺(jué)和語(yǔ)言輸入來(lái)理解世界,并通過(guò)自然語(yǔ)言與人類交流。比如,在《幾行代碼加速 Stable Diffusion,使用 OpenVINO 輕松文生圖》中,我們介紹了利用 OpenVINO 運(yùn)行 Stable Diffusion 模型,快速實(shí)現(xiàn)文生圖應(yīng)用。讓人人可以成為繪畫(huà)大師,利用 AI 隨心作畫(huà)。
隨著計(jì)算機(jī)視覺(jué)和自然語(yǔ)言處理領(lǐng)域的快速發(fā)展,視覺(jué)與語(yǔ)言的融合越來(lái)越受到研究人員的重視。在這個(gè)背景下,BLIP(Bootstrapping Language-Image Pre-training)作為一種創(chuàng)新的預(yù)訓(xùn)練模型,引起了廣泛關(guān)注。該模型在大規(guī)模的圖像文本數(shù)據(jù)集上預(yù)訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)模型,以提高下游視覺(jué)語(yǔ)言任務(wù)的性能,如圖像文本檢索、圖像字幕和視覺(jué)問(wèn)答。通過(guò)聯(lián)合訓(xùn)練圖像和文本數(shù)據(jù),為視覺(jué)與語(yǔ)言的融合提供了強(qiáng)大的基礎(chǔ)。
BLIP 的預(yù)訓(xùn)練過(guò)程涉及兩個(gè)關(guān)鍵組件:圖像編碼器和文本編碼器。圖像編碼器負(fù)責(zé)將輸入的圖像轉(zhuǎn)換為低維向量表示,而文本編碼器則將輸入的文本轉(zhuǎn)換為另一個(gè)低維向量表示。為了實(shí)現(xiàn)統(tǒng)一的視覺(jué)-語(yǔ)言預(yù)訓(xùn)練,BLIP 采用了一種跨模態(tài)約束策略,即在預(yù)訓(xùn)練階段,圖像編碼器和文本編碼器被設(shè)計(jì)成相互約束的。這樣的約束機(jī)制強(qiáng)制模型學(xué)習(xí)將視覺(jué)信息和語(yǔ)言信息進(jìn)行對(duì)齊,從而使得模型在后續(xù)任務(wù)中能夠更好地處理視覺(jué)與語(yǔ)言之間的聯(lián)合信息。
除了視覺(jué)-語(yǔ)言理解任務(wù),BLIP 還在視覺(jué)-語(yǔ)言生成任務(wù)中表現(xiàn)出色。在這個(gè)任務(wù)中,模型需要根據(jù)輸入的圖像和文本生成相關(guān)的描述或回答問(wèn)題。BLIP 通過(guò)聯(lián)合訓(xùn)練和引入了圖像-文本生成任務(wù),使得模型具備了更強(qiáng)大的圖像描述和問(wèn)題回答能力。這使得 BLIP 在圖像描述生成和視覺(jué)問(wèn)答等任務(wù)上取得了優(yōu)異的成績(jī)。
接下來(lái),我們一起來(lái)看看如何在研揚(yáng)科技(AAEON)的新品 UP Squared Pro 7000 Edge 運(yùn)行利用 OpenVINO 來(lái)優(yōu)化加速 BLIP 的推理有哪些重點(diǎn)步驟吧。
作為研揚(yáng) UP Squared Pro 系列的第三代產(chǎn)品,Upsquared Pro 7000 系列 (https://ic-item.jd.com/10074763043245.html)[1] 透過(guò)高性能計(jì)算能力、升級(jí)的電路板設(shè)計(jì)和擴(kuò)展的顯示接口,提供更大的開(kāi)發(fā)潛力。作為該系列中首款采用 Intel Core/Atom/N 系列處理器(原 Alder Lake-N)的產(chǎn)品,UP Squared Pro 7000 是首款配備板載 LPDDR5 內(nèi)存的產(chǎn)品,提高了 I/O 的運(yùn)行速度。此外,UP Squared Pro 7000 在圖像處理和顯示功能方面都有顯著提升,支持 MIPI CSI 照相機(jī),并搭配 Intel UHD 顯卡,可同時(shí)進(jìn)行三臺(tái) 4K 顯示器。
1.4 倍以上 CPU 性能提升
UP Squared Pro 7000 采用 Intel Core/Atom/N- 系列處理器,CPU 性能是上一代的 1.4 倍。UP Squared Pro 7000 擁有多達(dá) 8 個(gè) Gracemont 內(nèi)核,支持 OpenVINO Toolkit,以及第 12 代 Intel處理器的 UHD 顯卡,擁有強(qiáng)大的計(jì)算能力、優(yōu)化的推理引擎和圖像處理功能,提供絕佳的智能解決方案。
同步支持 3 臺(tái) 4K 顯示器
UP Squared Pro 7000 配備 HDMI 2.0b、DP 1.2 埠和透過(guò) USB Type-C 的 DP 1.4a,擁有出色的顯示接口。UP Squared Pro 7000 整合了 GPU 和多重輸出,可以同步支持三個(gè) 4K 顯示器,非常適合用于數(shù)字廣告牌等視覺(jué)導(dǎo)向型的相關(guān)應(yīng)用。
雙倍的高速系統(tǒng)內(nèi)存
作為 UP Squared Pro 系列中第一塊配備板載 LPDDR5 系統(tǒng)內(nèi)存的板卡,UP Squared Pro 7000 搭載了 16GB 的系統(tǒng)內(nèi)存,是上一代的兩倍。此外,快達(dá) 4800MHz 的內(nèi)存速度讓用戶的帶寬和數(shù)據(jù)傳輸速度加倍,同時(shí)也更加省電。
全面的 I/O 升級(jí)
除了維持 UP Squared Pro 系列 4" x 4" 的緊湊外形之外,UP Squared Pro 7000 在電路板設(shè)計(jì)上更為精實(shí)。UP Squared Pro 7000 配備了兩個(gè) 2.5GbE、三個(gè) USB 3.2 和一個(gè) FPC 端口,可外接更多像是 MIPI CSI 相機(jī)的外圍設(shè)備。將這些特色與板載 LPDDR5 及性能強(qiáng)大的 CPU 相結(jié)合,非常適合用于智慧工廠機(jī)器人方面的視覺(jué)解決方案。
注意:
以下步驟中的所有代碼來(lái)自 OpenVINO Notebooks 開(kāi)源倉(cāng)庫(kù)中的 233-blip-visual-language-processing notebook 代碼示例,您可以復(fù)制以下鏈接到瀏覽器直達(dá)源代碼。https://github.com/openvinotoolkit/openvino_notebooks/tree/main/notebooks/233-blip-visual-language-processing
第一步:安裝相應(yīng)工具包、加載模型并轉(zhuǎn)換為 OpenVINO IR 格式
本次代碼示例需要首先安裝 BLIP 相應(yīng)工具包。
!pip install "transformers >= 4.26.0"
向右滑動(dòng)查看完整代碼
然后下載及加載相應(yīng)的 PyTorch 模型。在本問(wèn)中,您將使用可從 Hugging Face 下載的 blip-vqa-base [2] 基本模型。同樣的操作也適用于 BLIP 系列中的其它模型。盡管該模型類是為執(zhí)行問(wèn)答而設(shè)計(jì)的,但其組件也可以用于圖像字幕。要開(kāi)始使用該模型,需要使用 from_pretrained 方法實(shí)例化 BlipForQuestionAnswering 類。BlipProcessor 是一個(gè)助手類,用于準(zhǔn)備文本和視覺(jué)模態(tài)的輸入數(shù)據(jù)以及生成結(jié)果的后處理。
import sys import time from PIL import Image from transformers import BlipProcessor, BlipForQuestionAnswering sys.path.append("../utils") from notebook_utils import download_file # Get model and processor processor = BlipProcessor.from_pretrained("Salesforce/blip-vqa-base") model = BlipForQuestionAnswering.from_pretrained("Salesforce/blip-vqa-base")
接下來(lái),我們看看如何將原始模型轉(zhuǎn)換為 OpenVINO IR格式的模型,并利用 OpenVINO 進(jìn)行相應(yīng)的優(yōu)化以及部署推理加速。
第二步:將模型轉(zhuǎn)換為 OpenVINO IR 格式
根據(jù)我們前面的介紹,BLIP 模型包含視覺(jué)模型、文本編碼和文本解碼三個(gè)模型,因此我們需要分別將這三個(gè)模型轉(zhuǎn)換為 OpenVINO IR 格式。視覺(jué)模型的轉(zhuǎn)換操作比較常規(guī),具體代碼可以參考我們的 notebook[3],這里重點(diǎn)介紹一下文本編碼和文本解碼模型的轉(zhuǎn)換部分。
文本編碼器轉(zhuǎn)換
視覺(jué)問(wèn)答任務(wù)使用文本編碼器來(lái)構(gòu)建問(wèn)題的嵌入表示。它采用經(jīng)過(guò)分詞后的問(wèn)題的 input_ids,并輸出從視覺(jué)模型獲得的圖像嵌入和它們的注意力掩碼。根據(jù)問(wèn)題文本的不同,標(biāo)記化輸入后的標(biāo)記數(shù)量可能不同。因此,為使用標(biāo)記的模型輸入保留動(dòng)態(tài)形狀,dynamic_axes 參數(shù)負(fù)責(zé)在 torch.onx.export 中保留輸入的動(dòng)態(tài)特定維度。代碼如下:
TEXT_ENCODER_OV = Path("blip_text_encoder.xml") TEXT_ENCODER_ONNX = TEXT_ENCODER_OV.with_suffix(".onnx") text_encoder = model.text_encoder text_encoder.eval() # if openvino model does not exist, convert it to onnx and then to IR if not TEXT_ENCODER_OV.exists(): if not TEXT_ENCODER_ONNX.exists(): # prepare example inputs for ONNX export image_embeds = vision_outputs[0] image_attention_mask = torch.ones(image_embeds.size()[:-1], dtype=torch.long) input_dict = {"input_ids": inputs["input_ids"], "attention_mask": inputs["attention_mask"], "encoder_hidden_states": image_embeds, "encoder_attention_mask": image_attention_mask} # specify variable length axes dynamic_axes = {"input_ids": {1: "seq_len"}, "attention_mask": {1: "seq_len"}} # export PyTorch model to ONNX with torch.no_grad(): torch.onnx.export(text_encoder, input_dict, TEXT_ENCODER_ONNX, input_names=list(input_dict), dynamic_axes=dynamic_axes) # convert ONNX model to IR using model conversion Python API, use compress_to_fp16=True for compressing model weights to FP16 precision ov_text_encoder = mo.convert_model(TEXT_ENCODER_ONNX, compress_to_fp16=True) # save model on disk for next usages serialize(ov_text_encoder, str(TEXT_ENCODER_OV)) print(f"Text encoder successfuly converted and saved to {TEXT_ENCODER_OV}") else: print(f"Text encoder will be loaded from {TEXT_ENCODER_OV}")
向右滑動(dòng)查看完整代碼
文本解碼器轉(zhuǎn)換
文本解碼器負(fù)責(zé)使用圖像(以及問(wèn)題,如果需要的話)的表示來(lái)生成模型輸出(問(wèn)題的答案或標(biāo)題)的分詞 token 序列。生成方法基于這樣的假設(shè),即單詞序列的概率分布可以分解為下一個(gè)單詞條件分布的乘積。換言之,模型預(yù)測(cè)由先前生成的 token 引導(dǎo)循環(huán)生成下一個(gè) token,直到達(dá)到停止生成的條件(生成達(dá)到最大長(zhǎng)度序列或獲得的字符串結(jié)束的 token)。在預(yù)測(cè)概率之上選擇下一個(gè) token的方式由所選擇的解碼方法來(lái)驅(qū)動(dòng)。與文本編碼器類似,文本解碼器可以處理不同長(zhǎng)度的輸入序列,并且需要保留動(dòng)態(tài)輸入形狀。這部分特殊的處理可由如下代碼完成:
text_decoder = model.text_decoder text_decoder.eval() TEXT_DECODER_OV = Path("blip_text_decoder.xml") TEXT_DECODER_ONNX = TEXT_DECODER_OV.with_suffix(".onnx") # prepare example inputs for ONNX export input_ids = torch.tensor([[30522]]) # begin of sequence token id attention_mask = torch.tensor([[1]]) # attention mask for input_ids encoder_hidden_states = torch.rand((1, 10, 768)) # encoder last hidden state from text_encoder encoder_attention_mask = torch.ones((1, 10), dtype=torch.long) # attention mask for encoder hidden states input_dict = {"input_ids": input_ids, "attention_mask": attention_mask, "encoder_hidden_states": encoder_hidden_states, "encoder_attention_mask": encoder_attention_mask} # specify variable length axes dynamic_axes = {"input_ids": {1: "seq_len"}, "attention_mask": {1: "seq_len"}, "encoder_hidden_states": {1: "enc_seq_len"}, "encoder_attention_mask": {1: "enc_seq_len"}} # specify output names, logits is main output of model output_names = ["logits"] # past key values outputs are output for caching model hidden state past_key_values_outs = [] text_decoder_outs = text_decoder(**input_dict) for idx, _ in enumerate(text_decoder_outs["past_key_values"]): past_key_values_outs.extend([f"out_past_key_value.{idx}.key", f"out_past_key_value.{idx}.value"])
向右滑動(dòng)查看完整代碼
接下來(lái),對(duì)于文本解碼器的轉(zhuǎn)換,還有來(lái)自前一步驟的隱藏狀態(tài)的額外輸入。與輸出類似,在模型導(dǎo)出為 ONNX 格式后,它們將被展平。需要使用新的輸入層更新 dynamic_axies 和 input_names。因此,其后面的轉(zhuǎn)換過(guò)程與前面的文本編碼器的轉(zhuǎn)換過(guò)程類似,在本文中不再贅述。
第三步:運(yùn)行 OpenVINO 推理
如前所述,在這里我們將主要展示 BLIP 進(jìn)行視覺(jué)問(wèn)答以及圖像字幕的流水線如何搭建、以及如何運(yùn)行 OpenVINO 來(lái)進(jìn)行推理的情況。
圖像字幕
視覺(jué)模型接受 BlipProcessor 預(yù)處理的圖像作為輸入,并生成圖像嵌入,這些圖像嵌入直接傳遞給文本解碼器以生成字幕標(biāo)記。生成完成后,分詞 tokenizer 的輸出序列被提供給 BlipProcessor,用于使用 tokenizer 解碼為文本。
定義 OVBLIPModel 類:
class OVBlipModel: """ Model class for inference BLIP model with OpenVINO """ def __init__(self, config, decoder_start_token_id:int, vision_model, text_encoder, text_decoder): """ Initialization class parameters """ self.vision_model = vision_model self.vision_model_out = vision_model.output(0) self.text_encoder = text_encoder self.text_encoder_out = text_encoder.output(0) self.text_decoder = text_decoder self.config = config self.decoder_start_token_id = decoder_start_token_id self.decoder_input_ids = c
向右滑動(dòng)查看完整代碼
定義圖像字幕函數(shù)如下,
def generate_caption(self, pixel_values:torch.Tensor, input_ids:torch.Tensor = None, attention_mask:torch.Tensor = None, **generate_kwargs): """ Image Captioning prediction Parameters: pixel_values (torch.Tensor): preprocessed image pixel values input_ids (torch.Tensor, *optional*, None): pregenerated caption token ids after tokenization, if provided caption generation continue provided text attention_mask (torch.Tensor): attention mask for caption tokens, used only if input_ids provided Retruns: generation output (torch.Tensor): tensor which represents sequence of generated caption token ids """ batch_size = pixel_values.shape[0] image_embeds = self.vision_model(pixel_values.detach().numpy())[self.vision_model_out] image_attention_mask = torch.ones(image_embeds.shape[:-1], dtype=torch.long) if isinstance(input_ids, list): input_ids = torch.LongTensor(input_ids) elif input_ids is None: input_ids = ( torch.LongTensor([[self.config.text_config.bos_token_id, self.config.text_config.eos_token_id]]) .repeat(batch_size, 1) ) input_ids[:, 0] = self.config.text_config.bos_token_id attention_mask = attention_mask[:, :-1] if attention_mask is not None else None outputs = self.text_decoder.generate( input_ids=input_ids[:, :-1], eos_token_id=self.config.text_config.sep_token_id, pad_token_id=self.config.text_config.pad_token_id, attention_mask=attention_mask, encoder_hidden_states=torch.from_numpy(image_embeds), encoder_attention_mask=image_attention_mask, **generate_kwargs, ) return outputs
向右滑動(dòng)查看完整代碼
視覺(jué)問(wèn)答
視覺(jué)回答的流水線看起來(lái)很相似,但有額外的問(wèn)題處理。在這種情況下,由 BlipProcessor 標(biāo)記的圖像嵌入和問(wèn)題被提供給文本編碼器,然后多模態(tài)問(wèn)題嵌入被傳遞給文本解碼器以執(zhí)行答案的生成。
在 OVBLIPModel 類內(nèi)部同理可定義視覺(jué)問(wèn)答函數(shù)如下:
def generate_answer(self, pixel_values:torch.Tensor, input_ids:torch.Tensor, attention_mask:torch.Tensor, **generate_kwargs): """ Visual Question Answering prediction Parameters: pixel_values (torch.Tensor): preprocessed image pixel values input_ids (torch.Tensor): question token ids after tokenization attention_mask (torch.Tensor): attention mask for question tokens Retruns: generation output (torch.Tensor): tensor which represents sequence of generated answer token ids """ image_embed = self.vision_model(pixel_values.detach().numpy())[self.vision_model_out] image_attention_mask = np.ones(image_embed.shape[:-1], dtype=int) if isinstance(input_ids, list): input_ids = torch.LongTensor(input_ids) question_embeds = self.text_encoder([input_ids.detach().numpy(), attention_mask.detach().numpy(), image_embed, image_attention_mask])[self.text_encoder_out] question_attention_mask = np.ones(question_embeds.shape[:-1], dtype=int) bos_ids = np.full((question_embeds.shape[0], 1), fill_value=self.decoder_start_token_id) outputs = self.text_decoder.generate( input_ids=torch.from_numpy(bos_ids), eos_token_id=self.config.text_config.sep_token_id, pad_token_id=self.config.text_config.pad_token_id, encoder_hidden_states=torch.from_numpy(question_embeds), encoder_attention_mask=torch.from_numpy(question_attention_mask), **generate_kwargs, ) return outputs
向右滑動(dòng)查看完整代碼
初始化 OpenVINO 運(yùn)行時(shí)并運(yùn)行推理
初始化 OpenVINO Core 對(duì)象,選擇推理設(shè)備,并加載、編譯模型
# create OpenVINO Core object instance core = Core() import ipywidgets as widgets device = widgets.Dropdown( options=core.available_devices + ["AUTO"], value='AUTO', description='Device:', disabled=False, ) device # load models on device ov_vision_model = core.compile_model(VISION_MODEL_OV, device.value) ov_text_encoder = core.compile_model(TEXT_ENCODER_OV, device.value) ov_text_decoder = core.compile_model(TEXT_DECODER_OV, device.value) ov_text_decoder_with_past = core.compile_model(TEXT_DECODER_WITH_PAST_OV, device.value)
向右滑動(dòng)查看完整代碼
運(yùn)行圖像字幕推理
out = ov_model.generate_caption(inputs["pixel_values"], max_length=20) caption = processor.decode(out[0], skip_special_tokens=True) fig = visualize_results(raw_image, caption)
運(yùn)行視覺(jué)問(wèn)答推理
start = time.perf_counter() out = ov_model.generate_answer(**inputs, max_length=20) end = time.perf_counter() - start answer = processor.decode(out[0], skip_special_tokens=True) fig = visualize_results(raw_image, answer, question)
向右滑動(dòng)查看完整代碼
小結(jié)
整個(gè)的步驟就是這樣!現(xiàn)在就開(kāi)始跟著我們提供的代碼和步驟,動(dòng)手試試用 Open VINO 和 BLIP 吧。
關(guān)于英特爾 OpenVINO 開(kāi)源工具套件的詳細(xì)資料,包括其中我們提供的三百多個(gè)經(jīng)驗(yàn)證并優(yōu)化的預(yù)訓(xùn)練模型的詳細(xì)資料。
除此之外,為了方便大家了解并快速掌握 OpenVINO 的使用,我們還提供了一系列開(kāi)源的 Jupyter notebook demo。運(yùn)行這些 notebook,就能快速了解在不同場(chǎng)景下如何利用 OpenVINO 實(shí)現(xiàn)一系列、包括計(jì)算機(jī)視覺(jué)、語(yǔ)音及自然語(yǔ)言處理任務(wù)。OpenVINO notebooks 的資源可以在 GitHub 這里下載安裝。
研揚(yáng)科技簡(jiǎn)介
研揚(yáng)科技成立于 1992 年,是工業(yè)物聯(lián)網(wǎng)和人工智能邊緣解決方案的領(lǐng)先設(shè)計(jì)商和制造商之一。以不斷創(chuàng)新為核心價(jià)值觀,研揚(yáng)科技為市場(chǎng)帶來(lái)可靠、高質(zhì)量的計(jì)算平臺(tái),包括工業(yè)主板和系統(tǒng)、強(qiáng)固式平板電腦、嵌入式人工智能系統(tǒng)、uCPE 網(wǎng)絡(luò)設(shè)備以及 LoRaWAN/WWAN 解決方案。研揚(yáng)科技還帶來(lái)行業(yè)領(lǐng)先的經(jīng)驗(yàn)和知識(shí),以在全球范圍內(nèi)提供 OEM/ODM 服務(wù)。此外,研揚(yáng)科技與諸多城市和政府緊密合作,開(kāi)發(fā)和部署智能城市生態(tài)系統(tǒng),提供個(gè)性化平臺(tái)和端到端解決方案。研揚(yáng)科技與頂級(jí)芯片設(shè)計(jì)商緊密合作,提供穩(wěn)定、可靠的平臺(tái),并被認(rèn)可為 Intel物聯(lián)網(wǎng)解決方案聯(lián)盟的鈦金級(jí)成員。
審核編輯:湯梓紅
-
處理器
+關(guān)注
關(guān)注
68文章
18927瀏覽量
227228 -
英特爾
+關(guān)注
關(guān)注
60文章
9748瀏覽量
170647 -
cpu
+關(guān)注
關(guān)注
68文章
10702瀏覽量
209366 -
AI
+關(guān)注
關(guān)注
87文章
28877瀏覽量
266225
原文標(biāo)題:OpenVINO? 賦能 BLIP 實(shí)現(xiàn)視覺(jué)語(yǔ)言 AI 邊緣部署|開(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)先 登錄
相關(guān)推薦
評(píng)論