Skip to content

Commit 1b0217a

Browse files
author
wz
committed
add convert openvino example
1 parent 98c27cd commit 1b0217a

19 files changed

+1246
-81
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ flower_data
1515
*.xml
1616
*.bin
1717
*.mapping
18+
*.csv
1819
checkpoint
1920
data
2021
VOCdevkit
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
本项目展示如何将Pytorch中的ResNet34网络转成Openvino的IR格式,并进行量化处理,具体使用流程如下:
2+
1. 按照`requirements.txt`配置环境
3+
2. 下载事先训练好的ResNet34权重(之前在花分类数据集上训练得到的)放在当前文件夹下。百度云链接: https://pan.baidu.com/s/1x4WFX1HynYcXLium3UaaFQ 密码: qvi6
4+
3. 使用`convert_pytorch2onnx.py`将Resnet34转成ONNX格式
5+
4. 在命令行中使用以下指令将ONNX转成IR格式:
6+
```
7+
mo --input_model resnet34.onnx \
8+
--input_shape "[1,3,224,224]" \
9+
--mean_values="[123.675,116.28,103.53]" \
10+
--scale_values="[58.395,57.12,57.375]" \
11+
--data_type FP32 \
12+
--output_dir ir_output
13+
```
14+
5. 下载并解压花分类数据集,将`quantization_int8.py`中的`data_path`指向解压后的`flower_photos`
15+
6. 使用`quantization_int8.py`量化模型

deploying_service/deploying_pytorch/convert_openvino/compare_fps.py renamed to deploying_service/deploying_pytorch/convert_openvino/convert_resnet34/compare_fps.py

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import cv2
21
import time
32
import numpy as np
43
import torch
4+
import matplotlib.pyplot as plt
55
from openvino.runtime import Core
6-
from model import mobilenet_v3_large
6+
from torchvision.models import resnet34
77

88

99
def normalize(image: np.ndarray) -> np.ndarray:
@@ -39,6 +39,8 @@ def onnx_inference(onnx_path: str, image: np.ndarray, num_images: int = 20):
3939
f"seconds per image, FPS: {num_images / time_onnx:.2f}"
4040
)
4141

42+
return num_images / time_onnx
43+
4244

4345
def ir_inference(ir_path: str, image: np.ndarray, num_images: int = 20):
4446
# Load the network in Inference Engine
@@ -61,12 +63,13 @@ def ir_inference(ir_path: str, image: np.ndarray, num_images: int = 20):
6163
f"seconds per image, FPS: {num_images / time_ir:.2f}"
6264
)
6365

66+
return num_images / time_ir
67+
6468

65-
def pytorch_inference(weights_path: str, image: np.ndarray, num_images: int = 20):
69+
def pytorch_inference(image: np.ndarray, num_images: int = 20):
6670
image = torch.as_tensor(image, dtype=torch.float32)
6771

68-
model = mobilenet_v3_large(num_classes=5)
69-
model.load_state_dict(torch.load(weights_path, map_location='cpu'))
72+
model = resnet34(pretrained=False, num_classes=5)
7073
model.eval()
7174

7275
with torch.no_grad():
@@ -81,29 +84,45 @@ def pytorch_inference(weights_path: str, image: np.ndarray, num_images: int = 20
8184
f"FPS: {num_images / time_torch:.2f}"
8285
)
8386

87+
return num_images / time_torch
88+
89+
90+
def plot_fps(v: dict):
91+
x = list(v.keys())
92+
y = list(v.values())
93+
94+
plt.bar(range(len(x)), y, align='center')
95+
plt.xticks(range(len(x)), x)
96+
for i, v in enumerate(y):
97+
plt.text(x=i, y=v+0.5, s=f"{v:.2f}", ha='center')
98+
plt.xlabel('model format')
99+
plt.ylabel('fps')
100+
plt.title('FPS comparison')
101+
plt.show()
102+
plt.savefig('fps_vs.jpg')
103+
84104

85105
def main():
86106
image_h = 224
87107
image_w = 224
88-
image_filename = "test.jpg"
89-
onnx_path = "mobilenet_v3.onnx"
90-
ir_path = "ir_output/mobilenet_v3.xml"
91-
pytorch_weights_path = "mbv3_flower.pth"
92-
93-
image = cv2.cvtColor(cv2.imread(image_filename), cv2.COLOR_BGR2RGB)
108+
onnx_path = "resnet34.onnx"
109+
ir_path = "ir_output/resnet34.xml"
94110

95-
resized_image = cv2.resize(image, (image_w, image_h))
96-
normalized_image = normalize(resized_image)
111+
image = np.random.randn(image_h, image_w, 3)
112+
normalized_image = normalize(image)
97113

98114
# Convert the resized images to network input shape
99115
# [h, w, c] -> [c, h, w] -> [1, c, h, w]
100-
input_image = np.expand_dims(np.transpose(resized_image, (2, 0, 1)), 0)
116+
input_image = np.expand_dims(np.transpose(image, (2, 0, 1)), 0)
101117
normalized_input_image = np.expand_dims(np.transpose(normalized_image, (2, 0, 1)), 0)
102118

103-
onnx_inference(onnx_path, normalized_input_image, num_images=50)
104-
ir_inference(ir_path, input_image, num_images=50)
105-
pytorch_inference(pytorch_weights_path, normalized_input_image, num_images=50)
119+
onnx_fps = onnx_inference(onnx_path, normalized_input_image, num_images=50)
120+
ir_fps = ir_inference(ir_path, input_image, num_images=50)
121+
pytorch_fps = pytorch_inference(normalized_input_image, num_images=50)
122+
plot_fps({"pytorch": round(pytorch_fps, 2),
123+
"onnx": round(onnx_fps, 2),
124+
"ir": round(ir_fps, 2)})
106125

107126

108127
if __name__ == '__main__':
109-
main()
128+
main()

deploying_service/deploying_pytorch/convert_openvino/compare_onnx_and_ir.py renamed to deploying_service/deploying_pytorch/convert_openvino/convert_resnet34/compare_onnx_and_ir.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import cv2
21
import numpy as np
32
from openvino.runtime import Core
43

@@ -48,18 +47,15 @@ def ir_inference(ir_path: str, image: np.ndarray):
4847
def main():
4948
image_h = 224
5049
image_w = 224
51-
image_filename = "test.jpg"
52-
onnx_path = "mobilenet_v3.onnx"
53-
ir_path = "ir_output/mobilenet_v3.xml"
50+
onnx_path = "resnet34.onnx"
51+
ir_path = "ir_output/resnet34.xml"
5452

55-
image = cv2.cvtColor(cv2.imread(image_filename), cv2.COLOR_BGR2RGB)
56-
57-
resized_image = cv2.resize(image, (image_w, image_h))
58-
normalized_image = normalize(resized_image)
53+
image = np.random.randn(image_h, image_w, 3)
54+
normalized_image = normalize(image)
5955

6056
# Convert the resized images to network input shape
6157
# [h, w, c] -> [c, h, w] -> [1, c, h, w]
62-
input_image = np.expand_dims(np.transpose(resized_image, (2, 0, 1)), 0)
58+
input_image = np.expand_dims(np.transpose(image, (2, 0, 1)), 0)
6359
normalized_input_image = np.expand_dims(np.transpose(normalized_image, (2, 0, 1)), 0)
6460

6561
onnx_res = onnx_inference(onnx_path, normalized_input_image)

deploying_service/deploying_pytorch/convert_openvino/convert_pytorch2onnx.py renamed to deploying_service/deploying_pytorch/convert_openvino/convert_resnet34/convert_pytorch2onnx.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import onnx
44
import onnxruntime
55
import numpy as np
6-
from model import mobilenet_v3_large
6+
from torchvision.models import resnet34
77

88
device = torch.device("cpu")
99

@@ -13,15 +13,15 @@ def to_numpy(tensor):
1313

1414

1515
def main():
16-
weights_path = "mbv3_flower.pth"
17-
onnx_file_name = "mobilenet_v3.onnx"
16+
weights_path = "resNet34(flower).pth"
17+
onnx_file_name = "resnet34.onnx"
1818
batch_size = 1
1919
img_h = 224
2020
img_w = 224
2121
img_channel = 3
2222

2323
# create model and load pretrain weights
24-
model = mobilenet_v3_large(num_classes=5)
24+
model = resnet34(pretrained=False, num_classes=5)
2525
model.load_state_dict(torch.load(weights_path, map_location='cpu'))
2626

2727
model.eval()

deploying_service/deploying_pytorch/convert_openvino/quantization_int8.py renamed to deploying_service/deploying_pytorch/convert_openvino/convert_resnet34/quantization_int8.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@
33
from compression.graph import load_model, save_model
44
from compression.graph.model_utils import compress_model_weights
55
from compression.pipeline.initializer import create_pipeline
6-
from utils import MyDataSet, Accuracy, read_split_data
6+
from utils import MyDataLoader, Accuracy, read_split_data
77

88

99
def main():
1010
data_path = "/data/flower_photos"
11-
ir_model_xml = "ir_output/mobilenet_v3.xml"
12-
ir_model_bin = "ir_output/mobilenet_v3.bin"
11+
ir_model_xml = "ir_output/resnet34.xml"
12+
ir_model_bin = "ir_output/resnet34.bin"
1313
save_dir = "quant_ir_output"
14-
model_name = "quantized_mobilenet_v3"
14+
model_name = "quantized_resnet34"
1515
img_w = 224
1616
img_h = 224
1717

1818
model_config = Dict({
19-
'model_name': 'mobilenet_v3',
19+
'model_name': 'resnet34',
2020
'model': ir_model_xml,
2121
'weights': ir_model_bin
2222
})
@@ -45,7 +45,7 @@ def main():
4545

4646
# Step 2: Initialize the data loader.
4747
_, _, val_images_path, val_images_label = read_split_data(data_path, val_rate=0.2)
48-
data_loader = MyDataSet(dataset_config, val_images_path, val_images_label, img_w, img_h)
48+
data_loader = MyDataLoader(dataset_config, val_images_path, val_images_label, img_w, img_h)
4949

5050
# Step 3 (Optional. Required for AccuracyAwareQuantization): Initialize the metric.
5151
metric = Accuracy(top_k=1)

deploying_service/deploying_pytorch/convert_openvino/requirements.txt renamed to deploying_service/deploying_pytorch/convert_openvino/convert_resnet34/requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ torchvision==0.12.0
33
onnx==1.9.0
44
onnxruntime==1.8.0
55
protobuf==3.19.4
6-
openvino-dev==2022.1.0
6+
openvino-dev==2022.1.0
7+
matplotlib

deploying_service/deploying_pytorch/convert_openvino/utils.py renamed to deploying_service/deploying_pytorch/convert_openvino/convert_resnet34/utils.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
import json
33
import random
44

5-
import cv2
5+
from PIL import Image
66
import numpy as np
77
from compression.api import DataLoader, Metric
8+
from torchvision.transforms import transforms
89

910

1011
def read_split_data(root: str, val_rate: float = 0.2):
@@ -57,7 +58,6 @@ def read_split_data(root: str, val_rate: float = 0.2):
5758

5859
# Custom implementation of classification accuracy metric.
5960
class Accuracy(Metric):
60-
6161
# Required methods
6262
def __init__(self, top_k=1):
6363
super().__init__()
@@ -104,13 +104,17 @@ def get_attributes(self):
104104
'type': 'accuracy'}}
105105

106106

107-
class MyDataSet(DataLoader):
107+
class MyDataLoader(DataLoader):
108108
def __init__(self, cfg, images_path: list, images_label: list, img_w: int = 224, img_h: int = 224):
109109
super().__init__(cfg)
110110
self.images_path = images_path
111111
self.images_label = images_label
112112
self.image_w = img_w
113113
self.image_h = img_h
114+
self.transforms = transforms.Compose([
115+
transforms.Resize(min(img_h, img_w)),
116+
transforms.CenterCrop((img_h, img_w))
117+
])
114118

115119
def __len__(self):
116120
return len(self.images_label)
@@ -123,11 +127,11 @@ def __getitem__(self, index):
123127
if index >= len(self):
124128
raise IndexError
125129

126-
image = cv2.cvtColor(cv2.imread(self.images_path[index]), cv2.COLOR_BGR2RGB)
127-
resized_image = cv2.resize(image, (self.image_w, self.image_h))
130+
img = Image.open(self.images_path[index])
131+
img = self.transforms(img)
128132

129133
# Convert the resized images to network input shape
130134
# [h, w, c] -> [c, h, w] -> [1, c, h, w]
131-
img = np.expand_dims(np.transpose(resized_image, (2, 0, 1)), 0)
135+
img = np.expand_dims(np.transpose(np.array(img), (2, 0, 1)), 0)
132136

133137
return (index, self.images_label[index]), img
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
OpenVINO量化YOLOv5
2+
3+
1. 按照`requirements.txt`配置环境
4+
2. 将YOLOv5转为ONNX
5+
YOLOv5官方有提供导出ONNX以及OpenVINO的方法,但我这里仅导出成ONNX,这里以YOLOv5s为例
6+
```
7+
python export.py --weights yolov5s.pt --include onnx
8+
```
9+
10+
3. ONNX转换为IR
11+
使用OpenVINO的`mo`工具将ONNX转为OpenVINO的IR格式
12+
```
13+
mo --input_model yolov5s.onnx \
14+
--input_shape "[1,3,640,640]" \
15+
--scale 255 \
16+
--data_type FP32 \
17+
--output_dir ir_output
18+
```
19+
20+
4. 量化模型
21+
使用`quantization_int8.py`进行模型的量化,量化过程中需要使用到COCO2017数据集,需要将`data_path`指向coco2017目录
22+
```
23+
├── coco2017: 数据集根目录
24+
├── train2017: 所有训练图像文件夹(118287张)
25+
├── val2017: 所有验证图像文件夹(5000张)
26+
└── annotations: 对应标注文件夹
27+
├── instances_train2017.json: 对应目标检测、分割任务的训练集标注文件
28+
├── instances_val2017.json: 对应目标检测、分割任务的验证集标注文件
29+
├── captions_train2017.json: 对应图像描述的训练集标注文件
30+
├── captions_val2017.json: 对应图像描述的验证集标注文件
31+
├── person_keypoints_train2017.json: 对应人体关键点检测的训练集标注文件
32+
└── person_keypoints_val2017.json: 对应人体关键点检测的验证集标注文件夹
33+
```
34+
35+
5. benchmark
36+
直接利用`benchmark_app`工具测试量化前后的`Throughput`,这里以`CPU: Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz`设备为例
37+
```
38+
benchmark_app -m ir_output/yolov5s.xml -d CPU -api sync
39+
```
40+
output:
41+
```
42+
Latency:
43+
Median: 59.56 ms
44+
AVG: 63.30 ms
45+
MIN: 57.88 ms
46+
MAX: 99.89 ms
47+
Throughput: 16.79 FPS
48+
```
49+
50+
```
51+
benchmark_app -m quant_ir_output/quantized_yolov5s.xml -d CPU -api sync
52+
```
53+
output:
54+
```
55+
Latency:
56+
Median: 42.97 ms
57+
AVG: 46.56 ms
58+
MIN: 41.18 ms
59+
MAX: 95.75 ms
60+
Throughput: 23.27 FPS
61+
```

0 commit comments

Comments
 (0)