天天看點

在Windows環境下OpenVINO™(2022.2 edition)的安裝與配置【For Python and Intel NCS2】

Notice:此次安裝是完整版本安裝包括優化器等,部署調用是基于Python環境,以及涉及到Intel NCS2神經網絡計算棒二代的部署

一、基本準備

1.Python3基本解釋器的準備,推薦Python3.8以上,如已有請忽略

2.硬體上至少得有一個USB3.0接口(有部署在 intel NCS2上需求的);以及一個CPU(Intel、AMD的都行)

二、環境搭建

Python環境配置

通過pip安裝可參考官方:

https://www.intel.cn/content/www/cn/zh/developer/tools/openvino-toolkit/download.html

在Windows環境下OpenVINO™(2022.2 edition)的安裝與配置【For Python and Intel NCS2】

https://www.intel.cn/content/www/cn/zh/developer/tools/openvino-toolkit/download.html

簡單而言就是:

打開cmd,cd /d 切換到一個自定義路徑,輸入指令:

步驟 1: 建立和激活虛拟環境(強烈建議使用虛拟環境,不然把Python系統環境搞得亂七八糟各種沖突的很麻煩)

python -m venv openvino_env 
python -m venv openvino_env openvino_env\Scripts\activate
           

步驟 2: 将 pip 更新至最新版本

python -m pip install --upgrade pip
           

步驟 3: 下載下傳并安裝依賴庫

pip install openvino-dev[ONNX]==2022.2.0
           

完成以上步驟之後,通過pip list檢視一下是否安裝完全,但這個時候常常無法運作,因為系統驅動以及環境變量還未配置

系統驅動及環境變量配置

去Intel官方網站下載下傳對應版本的安裝包

https://www.intel.cn/content/www/cn/zh/developer/tools/openvino-toolkit/download.html

在Windows環境下OpenVINO™(2022.2 edition)的安裝與配置【For Python and Intel NCS2】

https://www.intel.cn/content/www/cn/zh/developer/tools/openvino-toolkit/download.html

選擇如下:

在Windows環境下OpenVINO™(2022.2 edition)的安裝與配置【For Python and Intel NCS2】

 下載下傳完成後會得到一個壓縮包(個人覺得這是安裝最友善的一個版本),解壓到一個自定義路徑,如 C:\Program Files (x86)\Intel\OpenVINO

得到類似于下圖的目錄:

在Windows環境下OpenVINO™(2022.2 edition)的安裝與配置【For Python and Intel NCS2】

解壓完成後添加如下環境變量:

set "INTEL_OPENVINO_DIR=C:\Program Files (x86)\Intel\OpenVINO\"

set "OPENVINO_LIB_PATHS=
%INTEL_OPENVINO_DIR%\runtime\bin\intel64\Release;
%INTEL_OPENVINO_DIR%\runtime\bin\intel64\Debug;
%INTEL_OPENVINO_DIR%\runtime\3rdparty\tbb\bin;
%INTEL_OPENVINO_DIR%\runtime\3rdparty\hddl\bin;"

set "PATH=
%INTEL_OPENVINO_DIR%\runtime\bin\intel64\Release;
%INTEL_OPENVINO_DIR%\runtime\bin\intel64\Debug;
%INTEL_OPENVINO_DIR%\runtime\3rdparty\tbb\bin;
%INTEL_OPENVINO_DIR%\runtime\3rdparty\hddl\bin;
%INTEL_OPENVINO_DIR%\tools\compile_tool;"
           

配置完成後類似于:

在Windows環境下OpenVINO™(2022.2 edition)的安裝與配置【For Python and Intel NCS2】

配置完成後最好還是重新開機一下PC,然後打開cmd輸入cd C:\Program Files (x86)\Intel\OpenVINO,然後輸入setupvars.bat後執行,如下:

在Windows環境下OpenVINO™(2022.2 edition)的安裝與配置【For Python and Intel NCS2】

這一步主要是連接配接一下系統驅動與Python環境,主要是針對NCS2這樣的外置硬體,不然在運作時可能會出現NC_OUT_OF_MEMORY或者NC_ERROR這樣的錯誤(出現這樣的錯誤可能是因為驅動連接配接不上而逾時誤以為是記憶體過大而加載逾時,而另一種可能是使用的USB2.0接口導緻連接配接時間過長而逾時)

綜上,OpenVINO環境配置完畢

三、環境測試

安裝完成後激活虛拟環境,之後可用如下腳本進行測試:

from openvino.inference_engine import IECore
from openvino.runtime import Core
import numpy as np


if __name__ == '__main__':
    # device
    ie_core = IECore()
    print('devices: ', ie_core.available_devices)
    # run
    core = Core()
    net_small = core.compile_model(model='test.onnx', device_name="MYRIAD")  # CPU GPU MYRIAD ...
    output = net_small([np.array([1], dtype=np.float32)])[next(iter(net_small.outputs))]
    print('small model work state: ', output)
    print('over')
           

若運作正常則會輸出目前可用裝置以及測試模型輸出結果

測試模型可用如下腳本産生:

import torch
import torch.nn as nn
import torch.nn.functional as func


class ANN_Net(nn.Module):
    def __init__(self, IO_num):
        super(ANN_Net, self).__init__()
        self.layer_o = nn.Linear(IO_num, 1)

    def forward(self, x_in):
        # In
        x_out = func.relu(self.layer_o(x_in))
        return x_out


if __name__ == '__main__':
    x = torch.tensor([1]).to(torch.float32)
    net = ANN_Net(1)
    net.eval()
    # onnx導出
    torch.onnx.export(net, x, 'test.onnx',
                      verbose=True, keep_initializers_as_inputs=True, opset_version=11,
                      input_names=["input"], output_names=["output"])
    print("finished exporting onnx ")
    print(net(x))
           

四、關于使用OpenVINO優化模型

假如你已經有了一個訓練好的模型“test.onnx”,激活虛拟環境然後輸入指令

mo --input_model=test.onnx --model_name=test_fp16 --data_type=FP16 --enable_concat_optimization --progress
           

關于優化參數的解釋

--input_model INPUT_MODEL, -w INPUT_MODEL, -m INPUT_MODEL
    Tensorflow*: a file with a pre-trained model (binary or text .pb file after freezing). Caffe*: a model proto file with model weights
	Tensorflow *:具有預訓練模型的檔案(當機後的二進制或文本.pb檔案)。 Caffe *:具有模型權重的模型原型檔案

--model_name MODEL_NAME, -n MODEL_NAME
	Model_name parameter passed to the final create_ir transform. This parameter is used to name a network in a generated IR and output .xml/.bin files.
	将Model_name參數傳遞給最終的create_ir轉換。 此參數用于在生成的IR中命名網絡并輸出.xml / .bin檔案。

--output_dir OUTPUT_DIR, -o OUTPUT_DIR
   Directory that stores the generated IR. By default, it  is the directory from where the Model Optimizer is launched.
   存儲生成的IR的目錄。 預設情況下,它是啟動模型優化器的目錄。

--input_shape INPUT_SHAPE
        Input shape(s) that should be fed to an input node(s) of the model. Shape is defined as a comma-separated  list of integer numbers enclosed in parentheses or  square brackets, for example [1,3,227,227] or (1,227,227,3), where the order of dimensions depends  on the framework input layout of the model. For  example, [N,C,H,W] is used for Caffe* models and  [N,H,W,C] for TensorFlow* models. Model Optimizer performs necessary transformations to convert the shape to the layout required by Inference Engine (N,C,H,W). The shape should not contain undefined  dimensions (? or -1) and should fit the dimensions defined in the input operation of the graph. If there  are multiple inputs in the model, --input_shape should contain definition of shape for each input separated  by a comma, for example: [1,3,227,227],[2,4] for a  model with two inputs with 4D and 2D shapes. Alternatively, specify shapes with the --input option.
    應輸入模型的輸入節點的輸入形狀。 形狀定義為用逗号分隔的用括号或方括号括起來的整數清單,例如[1,3,227,227]或(1,227,227,3),其中尺寸順序取決于模型的架構輸入布局。 例如,[N,C,H,W]用于Caffe *模型,[N,H,W,C]用于TensorFlow *模型。 模型優化器執行必要的轉換,以将形狀轉換為推理引擎所需的布局(N,C,H,W)。 形狀不應包含未定義的尺寸(?或-1),并且應适合在圖形的輸入操作中定義的尺寸。 如果模型中有多個輸入,則--input_shape應包含每個輸入的形狀定義,并用逗号分隔,例如:[1,3,227,227],[2,4]對于具有兩個4D和2D形狀的輸入的模型 。 或者,使用--input選項指定形狀。
    
--scale SCALE, -s SCALE
	All input values coming from original network inputs  will be divided by this value. When a list of inputs  is overridden by the --input parameter, this scale is  not applied for any input that does not match with the original input of the model.
	來自原始網絡輸入的所有輸入值都将被該值除。 當輸入清單被--input參數覆寫時,該比例不适用于與模型原始輸入不比對的任何輸入。

--reverse_input_channels
 	Switch the input channels order from RGB to BGR (or vice versa). Applied to original inputs of the model  if and only if a number of channels equals 3. Applied  after application of --mean_values and --scale_values  options, so numbers in --mean_values and  --scale_values go in the order of channels used in the  original model.
 	将輸入通道順序從RGB切換到BGR(反之亦然)。 當且僅當通道數等于3時,才應用于模型的原始輸入。在應用--mean_values和--scale_values選項後應用,是以--mean_values和--scale_values中的數字按通道中使用的通道順序排列 原始模型。

--log_level 		  {CRITICAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET}


--input INPUT         
	Quoted list of comma-separated input nodes names with shapes, data types, and values for freezing. The shape  and value are specified as space-separated lists. The  data type of input node is specified in braces and can have one of the values: f64 (float64), f32 (float32),   f16 (float16), i64 (int64), i32 (int32), u8 (uint8), boolean. For example, use the following format to set   input port 0 of the node `node_name1` with the shape [3 4] as an input node and freeze output port 1 of the node `node_name2` with the value [20 15] of the int32 type and shape [2]: "0:node_name1[3 4],node_name2:1[2]{i32}->[20 15]".
	用逗号分隔的輸入節點名稱(帶形狀,資料類型和當機值)的帶引号的清單。 形狀和值指定為以空格分隔的清單。 輸入節點的資料類型以大括号指定,并且可以具有以下值之一:f64(float64),f32(float32),f16(float16),i64(int64),i32(int32),u8(uint8),布爾值。 例如,使用以下格式将形狀為[3 4]的節點'node_name1'的輸入端口0設定為輸入節點,并當機節點int32的值[20 15]的節點`node_name2`的輸出端口1。 類型和形狀[2]:“ 0:node_name1 [3 4],node_name2:1 [2] {i32}-> [20 15]”。

--output OUTPUT       
	The name of the output operation of the model. For TensorFlow*, do not add :0 to this name.
	模型的輸出操作的名稱。 對于TensorFlow *,請勿在該名稱上添加:0。

--mean_values MEAN_VALUES, -ms MEAN_VALUES
	Mean values to be used for the input image per channel. Values to be provided in the (R,G,B) or  [R,G,B] format. Can be defined for desired input of the model, for example: "--mean_values  data[255,255,255],info[255,255,255]". The exact  meaning and order of channels depend on how the original model was trained.
     每個通道用于輸入圖像的平均值。 以(R,G,B)或[R,G,B]格式提供的值。 可以為模型的所需輸入定義,例如:“-mean_values data [255,255,255],info [255,255,255]”。 通道的确切含義和順序取決于原始模型的訓練方式。

--scale_values SCALE_VALUES
	Scale values to be used for the input image per  channel. Values are provided in the (R,G,B) or [R,G,B]  format. Can be defined for desired input of the model, for example: "--scale_values data[255,255,255],info[255,255,255]". The exact  meaning and order of channels depend on how the original model was trained.
	每個通道用于輸入圖像的比例值。 值以(R,G,B)或[R,G,B]格式提供。 可以為模型的所需輸入定義,例如:“-scale_values data [255,255,255],info [255,255,255]”。 通道的确切含義和順序取決于原始模型的訓練方式。
      
--data_type {FP16,FP32,half,float}
	Data type for all intermediate tensors and weights. If  original model is in FP32 and --data_type=FP16 is specified, all model weights and biases are quantized  to FP16.
	所有中間張量和權重的資料類型。 如果原始模型位于FP32中,并且指定了--data_type = FP16,則所有模型權重和偏差都将量化為FP16。
       
--disable_fusing      
	Turn off fusing of linear operations to Convolution
	關閉将線性運算與卷積的融合

--disable_resnet_optimization
    Turn off resnet optimization
    關閉Resnet優化

--finegrain_fusing FINEGRAIN_FUSING
    Regex for layers/operations that won't be fused. Example: --finegrain_fusing Convolution1,.*Scale.*
    正規表達式用于不會融合的層/操作。 示例:--finegrain_fusing卷積1,。* Scale。*
    
--disable_gfusing 
  Turn off fusing of grouped convolutions
  關閉分組卷積的融合
  
--enable_concat_optimization
    Turn on Concat optimization.
    打開Concat優化。
    
--move_to_preprocess  
  Move mean values to IR preprocess section
  将平均值移至IR預處理部分
  
--extensions EXTENSIONS
     Directory or a comma separated list of directories with extensions. To disable all extensions including
those that are placed at the default location, pass an empty string.
	目錄或以逗号分隔的帶有擴充名的目錄清單。 要禁用所有擴充名,包括放置在預設位置的擴充名,請傳遞一個空字元串。
	
--batch BATCH, -b BATCH
     Input batch size
     輸入批量
     
--version  
	Version of Model Optimizer
	模型優化器的版本
	
--silent     
	Prevent any output messages except those that correspond to log level equals ERROR, that can be set with the following option: --log_level. By default,log level is already ERROR.
	防止使用與以下日志選項對應的輸出消息(與日志級别對應的消息等于ERROR除外)進行設定:--log_level。 預設情況下,日志級别已為ERROR。
	
--freeze_placeholder_with_value 		 fREEZE_PLACEHOLDER_WITH_VALUE Replaces input layer with constant node with provided value, for example: "node_name->True". It will be DEPRECATED in future releases. Use --input option to specify a value for freezing.
	FREEZE_PLACEHOLDER_WITH_VALUE用具有提供值的恒定節點替換輸入層,例如:“ node_name-> True”。 在将來的版本中将不再使用。 使用--input選項指定當機值。
	
--generate_deprecated_IR_V7
    Force to generate deprecated IR V7 with layers from old IR specification.
    強制生成具有舊IR規範中的圖層的已棄用的IR V7。
    
--static_shape  
	Enables IR generation for fixed input shape (folding `ShapeOf` operations and shape-calculating sub-graphs to `Constant`). Changing model input shape using the Inference Engine API in runtime may fail for such an IR.
	為固定的輸入形狀啟用IR生成(将“ ShapeOf”操作和形狀計算子圖折疊為“ Constant”)。 對于此類IR,在運作時使用Inference Engine API更改模型輸入形狀可能會失敗
	
--keep_shape_ops   
  The option is ignored. Expected behavior is enabled by default.
  該選項被忽略。 預設情況下啟用預期行為。

--disable_weights_compression
      Disable compression and store weights with original precision.
      禁用壓縮并以原始精度存儲重量
      
--progress      
  Enable model conversion progress display.
  啟用模型轉換進度顯示
  
--stream_output  
   Switch model conversion progress display to a multiline mode.
   将模型轉換進度顯示切換到多行模式

--transformations_config 
	TRANSFORMATIONS_CONFIG Use the configuration file with transformations description.
	TRANSFORMATIONS_CONFIG将配置檔案與轉換說明一起使用
           

 最終将得到優化後的IR模型,包含三個檔案

這裡在NCS2上的部署代碼以NanoDet為例:

import cv2
import numpy as np

from post_process import (img_resize, use_NMS)


class OpenVINO_Forward:
    def __init__(self, net_path):
        if type(net_path) == str:
            from openvino.runtime import Core
            ie = Core()
            use_device = "CPU"  # CPU MYRIAD
            self.net = ie.compile_model(model=net_path, device_name=use_device)
            self.input_net = None
        else:
            from openvino.inference_engine import IECore
            ie = IECore()
            use_device = "MYRIAD"  # CPU MYRIAD
            IR_net = ie.read_network(model=net_path[0], weights=net_path[1])
            self.net = ie.load_network(network=IR_net, device_name=use_device)
            self.input_net = next(iter(self.net.input_info))
        self.output_net = next(iter(self.net.outputs))

    def forward(self, img, normalize=None, score_min=0.5):
        img = np.ascontiguousarray(img)
        if normalize is not None:
            img = (img - normalize[0]) / normalize[1]
        if self.input_net is None:
            img = np.transpose(np.expand_dims(img, axis=0), (0, 3, 1, 2)).astype(np.float32)
            output = self.net([img])[self.output_net]
        else:
            img = np.transpose(np.expand_dims(img, axis=0), (0, 3, 1, 2)).astype(np.float16)
            output = self.net.infer(inputs={self.input_net: img})[self.output_net]
        output = output[np.max(output[:, 4:], axis=1) >= score_min]
        return output


class Options:
    def __init__(self):
        # ---base--- #
        self.input_size = (320, 320)  # w, h
        self.classes_name = ['R3', 'B3', 'R0', 'B0', 'R4', 'B4', 'land']
        self.score_min = 0.3
        self.IoU_max = 0.35
        data_mean = np.array([103.53, 116.28, 123.675])
        data_std = np.array([57.375, 57.12, 58.395])
        # ---auto--- #
        self.normalize = [data_mean, data_std]


if __name__ == '__main__':
    options = Options()
    # 使用IR模型
    openvino_model = OpenVINO_Forward(('nets/nanodet_fp16.xml', 'nets/nanodet_fp16.bin'))
    # 使用ONNX模型
    # openvino_model = OpenVINO_Forward('nets/nanodet.onnx')

    frame = cv2.imread('test.jpg', 1)
    frame = img_resize(frame, options.input_size, keep_ratio=True)
    # 推理+解碼
    predicts = openvino_model.forward(frame, options.normalize, score_min=options.score_min)
    # 非極大值抑制
    res_bbox = use_NMS(predicts, IoU_max=options.IoU_max)
    # 顯示
    for each_bbox in res_bbox:
    # 畫框
        cv2.rectangle(frame, tuple(each_bbox[:2].astype(np.int16)), tuple(each_bbox[2: 4].astype(np.int16)),
                          (255, 0, 0))
        # 獲得最大機率類别索引
        class_index = int(np.argmax(each_bbox[4:]))
        # 獲得最大機率類别機率值
        class_possible = str(np.round(each_bbox[4:][class_index], 4))
        cv2.putText(frame, options.classes_name[class_index] + ' ' + class_possible,
                    tuple(each_bbox[:2].astype(np.int16)),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.3, (22, 7, 207))
    cv2.imshow('frame', frame)
    cv2.waitKey()
           

Thanks for reading