在之前的文章中,我們瞭解了如何轉換 Pytorch 模型並使用 OpenVINO 執行,以及OpenVINO 工具包中有哪些深度學習模型最佳化工具。今天,讓我們看看如何使用 TensorFlow 訓練的模型並部署到 OpenVINO 推理引擎中執行。
概述
- 設定環境
- 準備 TensorFlow 模型
- 將模型轉換為中間表示格式
- 在 OpenVINO 中執行模型推理
- 結論
設定環境
首先,我們需要準備一個 Python 環境:Python 3.5 或更高版本(根據系統要求)和 virtualenv 是我們需要的。
python3 -m venv ~/venv/tf_openvino source ~/venv/tf_openvino/bin/activate
然後讓我們安裝所需的軟體包。
pip3 install --upgrade pip setuptools pip3 install -r requirements.txt
這裡 requirements.txt 包含以下軟體包。
numpy tqdm tensorflow-cpu==1.15 argparse scipy imageio moviepy
我們需要做的第二件事是使用官方安裝說明(在我的例子中是 Linux)安裝最新的 OpenVINO 發行版。此外,請記住設定所需的環境變數。
source /opt/intel/openvino_2021/bin/setupvars.sh
將其操作新增到 shell 初始化指令碼或虛擬環境啟用指令碼中可能很有用,以便預設情況下觸發它。
準備 TensorFlow 模型
您是否曾經希望一位著名的藝術家用獨特的美學視野和風格為您的心愛的貓咪畫一幅畫?深度神經網路時代的工具發展使得最初在藝術風格的神經演算法中提出的神經風格遷移演算法成為可能。它的想法是利用神經網路提取影像內容並將其與所使用的表示(風格)分離。然後,我們可以使用提取的風格將其與任意影像結合,並獲得令人印象深刻的人工影像結果,這些影像由原始影像的內容和所需的藝術風格組成。

影像風格遷移示例
在上面的示例中,您可以看到如何將弗朗西斯·皮卡比亞的《Udnie》繪畫的藝術風格轉移到參考貓咪影像(由Dương Nhân拍攝)。顯然,要執行此類技巧,我們需要一個經過訓練的 TensorFlow 模型。我們可以從頭開始準備和訓練一個模型,但讓我們使用一個預訓練的模型。我建議使用來自此倉庫的快速風格遷移模型。它非常適合我們的目的。
引用的儲存庫提供了多個模型檢查點,每個檢查點都針對不同的藝術風格影像進行訓練,可以在這裡下載。通常,TensorFlow 檢查點包含模型權重和訓練期間使用的計算圖元資料。為了將模型部署到生產環境中並將其用於推理,我們需要獲取凍結圖。讓我們克隆倉庫並使用一個簡單的 Python 指令碼來執行此操作。
def main(checkpoint_path, input_shape, out_graph_name):
# Init graph and session to be used
g = tf.Graph()
soft_config = tf.compat.v1.ConfigProto(allow_soft_placement=True)
with g.as_default(), g.device('/cpu'), tf.compat.v1.Session(config=soft_config) as sess:
# Placeholder variable for graph input
img_placeholder = tf.compat.v1.placeholder(tf.float32, shape=input_shape, name='img_placeholder')
# The model from the repo
transform.net(img_placeholder)
# Restore model from checkpoint
saver = tf.compat.v1.train.Saver()
saver.restore(sess, checkpoint_path)
# Freeze graph from the session.
# "add_37" is the actual last operation of graph
frozen = tf.compat.v1.graph_util.convert_variables_to_constants(sess, sess.graph_def, ["add_37"])
# Write frozen graph to a file
graph_io.write_graph(frozen, './', out_graph_name, as_text=False)
print(f'Frozen graph {out_graph_name} is saved!')
指令碼的完整程式碼可以在這裡下載。
只需將指令碼放在模型倉庫的根資料夾中,並使用以下引數執行它。
python get_frozen_graph.py --checkpoint models/wave.ckpt
在上面的程式碼片段中,我們執行了所需的 TensorFlow 圖預初始化,並使用tf.Saver()從檢查點恢復模型資料。然後,我們將轉換後的凍結圖寫入檔案。
請注意,凍結圖轉換需要輸出圖操作的名稱,在本例中為“add_37”。對於任意模型,您可以透過簡單地列印網路節點或在 Netron 等工具中探索模型來找到輸出操作。
將模型轉換為中間表示格式
好的,現在我們有了凍結圖,接下來是什麼?對於PyTorch 模型,要在 OpenVINO 推理引擎中執行推理,我們必須將模型轉換為中間表示 (IR) 格式。幸運的是,OpenVINO 模型最佳化器內建了對 TensorFlow 模型轉換的支援。您可以在此OpenVINO 頁面上檢視當前支援的 TensorFlow 操作集。
在開始之前,我們應該配置模型最佳化器(如果我們在 OpenVINO 安裝期間跳過了此步驟)。您可以在此處找到配置說明。
由於我們準備好的凍結圖已經包含了所有關於模型所需的資訊,例如所需的輸入形狀和輸出節點名稱,因此我們可以使用預設引數執行模型最佳化器。
mo_tf.py --input_model inference_graph.pb
如果轉換成功,我們將獲得包含結果 IR 模型描述的 `inference_graph.xml` 和包含模型權重資料的 `inference_graph.bin`。如果轉換不成功,最好從檢查目標框架(在本例中為 TensorFlow)的支援層開始。可能需要稍微更改模型架構或為 OpenVINO 實現自定義層。
在 OpenVINO 中執行模型推理
讓我們準備一個簡單的 Python 指令碼,其中包含 OpenVINO 推理引擎初始化、IR 模型載入和提供的影像推理。此指令碼的完整版本也在這裡提供。
首先,我們匯入所需的軟體包並定義一個用於引數解析的函式。
import os
import cv2
import argparse
import time
import numpy as np
from openvino.inference_engine import IECore
from tqdm import tqdm
IMG_EXT = ('.png', '.jpg', '.jpeg', '.JPG', '.JPEG')
def parse_args():
"""Parses arguments."""
parser = argparse.ArgumentParser(description='OpenVINO inference script')
parser.add_argument('-i', '--input', type=str, default='',
help='Directory to load input images, path to a video or '
'skip to get stream from the camera (default).')
parser.add_argument('-m', '--model', type=str, default='./models/inference_graph.xml',
help='Path to IR model')
return parser.parse_args()
下一個函式用於 OpenVINO 推理初始化和中間表示模型載入。我們獲取 .xml 和 .bin 模型檔案的路徑,讀取它們並將模型載入到推理引擎中。之後,我們可以將其用於推理。
def load_to_IE(model):
# Getting the *.bin file location
model_bin = model[:-3] + "bin"
# Loading the Inference Engine API
ie = IECore()
# Loading IR files
net = ie.read_network(model=model, weights=model_bin)
input_shape = net.inputs["img_placeholder"].shape
# Loading the network to the inference engine
exec_net = ie.load_network(network=net, device_name="CPU")
print("IR successfully loaded into Inference Engine.")
return exec_net, input_shape
OpenVINO 允許我們使用兩種推理請求:同步 - 每個後續請求僅在之前的請求完成後執行,以及非同步 - 幾個請求由幾個執行器同時執行。在此示例中,我們使用同步推理請求介面。
def sync_inference(exec_net, image):
input_blob = next(iter(exec_net.inputs))
return exec_net.infer({input_blob: image})
在主函式中,我們首先準備將用於風格遷移的影像列表,然後初始化推理引擎。
def main(args):
if os.path.isdir(args.input):
# Create a list of test images
image_filenames = [os.path.join(args.input, f) for f in os.listdir(args.input) if
os.path.isfile(os.path.join(args.input, f)) and f.endswith(IMG_EXT)]
image_filenames.sort()
else:
image_filenames = [args.input]
exec_net, net_input_shape = load_to_IE(args.model)
# We need dynamically generated key for fetching output tensor
output_key = list(exec_net.outputs.keys())[0]
對於每個輸入影像,我們將它調整為網路的輸入大小,並使用 cv2.dnn.blobFromImage 將其轉換為所需的張量格式。然後,最有趣的部分 - 推理請求,然後是簡單的後處理。
for image_num in tqdm(range(len(image_filenames))):
image = cv2.imread(image_filenames[image_num])
image = cv2.resize(image, (net_input_shape[3], net_input_shape[2]))
X = cv2.dnn.blobFromImage(image, swapRB=True)
out = sync_inference(exec_net, image=X)
result_image = np.squeeze(np.clip(out[output_key], 0, 255).astype(np.uint8), axis=0).transpose((1, 2, 0))
最後,我們顯示結果影像。
cv2.imshow("Out", cv2.cvtColor(result_image, cv2.COLOR_RGB2BGR))
cv2.waitKey(0)
cv2.destroyWindow("Out")
if __name__ == "__main__":
main(parse_args())
讓我們執行指令碼,指定要應用風格遷移的影像的輸入目錄和轉換後的 IR 模型。
python openvino_inference.py -i ./images/ -m ./models/inference_graph.xml
帶有轉移風格的結果影像將在彈出視窗中顯示。
效能比較
作為最後一步,讓我們比較原始 TensorFlow 和轉換為 OpenVINO 推理管道的推理時間。為此,我在推理呼叫周圍添加了一個時間戳測量:在 TensorFlow 的情況下為會話執行呼叫,在 OpenVINO 的情況下為同步推理請求。在 100 張相同大小(720x1024x3)的影像上平均,每張影像的效能結果非常相似(以秒為單位,CPU:Intel Core i7-8700,12 個執行緒,4.60 GHz)
OpenVINO_CPU Inference time: Mean: 0.797 Min: 0.705 Max: 1.076 TensorFlow_Cpu Inference time: Mean: 0.816 Min: 0.792 Max: 0.892
但我們可以看到 OpenVINO 版本的速度略快。
結論
在這篇簡短的文章中,我們瞭解瞭如何輕鬆地轉換 TensorFlow 模型並在 OpenVINO 推理引擎環境中執行它。此外,我們還了解了神經風格遷移演算法的應用,並嘗試將其應用於任意影像。我希望這是一次有趣且有益的旅程。






