RetinaFace.md 4.87 KB
Newer Older
lijian6's avatar
Update  
lijian6 committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# RetinaFace人脸检测器

## 模型简介

RetinaFace是一个经典的人脸检测模型(https://arxiv.org/abs/1905.00641),采用了SSD架构。

![image-20221215140647406](../Images/RetinaFace_01.png)

本示例采用了如下的开源实现:https://github.com/biubug6/Pytorch_Retinaface,作者提供了restnet50 和mobilenet0.25两个预训练模型,本示例使用了mobilenet0.25预训练模型,将mobilenet0.25预训练模型下载下来后,保存到Pytorch_Retinaface工程的weights目录。

## 模型转换

通过下面的步骤可以将mobilenet0.25预训练转换成onnx文件:

1. 修改data/config.py:将cfg_mnet中的'pretrain': True,修改为'pretrain': False,

2. 执行如下命令就可以将weights目录下的mobilenet0.25_Final.pth模型转换为onnx文件了

   ```
   # 进入Pytorch_Retinaface工程根目录
   cd <path_to_Pytorch_Retinaface>
   
   # 转换模型
   python convert_to_onnx.py
   ```

   注意:如果需要修改模型的输入大小,可以修改args.long_side参数,默认为640x640。

   模型转换成功后,会在当前目录生成FaceDetector.onnx文件,利用该模型就可以使用MIGraphX进行推理了,本示例在samples工程中的Python/RetinaFace目录中提供了已经修改好的代码,在该目录下执行python convert_to_onnx.py可以直接生成onnx文件。

## 推理

Pytorch_Retinaface工程提供了原始Pytorch版本的推理测试代码detect.py,我们只需要将其中使用Pytorch推理的部分转换为MIGraphX推理就可以了,samples工程中的Python/RetinaFace/detect.py文件为已经转换好的推理代码,下面我们看一下是如何转换的:

1. 将加载模型部分修改为migraphx的方式加载

   ```
   # 加载模型
   model = migraphx.parse_onnx("./FaceDetector.onnx")
   ```

2. 模型加载成功后,需要通过model.compile进行编译,可以通过device_id设置使用哪一块设备

   ```
   model.compile(t=migraphx.get_target("gpu"),device_id=0)
   ```

3. 编译成功后,就可以输入图像进行推理了,由于本示例使用的onnx模型的输入大小是640x640,所以对于输入图像需要先resize到640x640

   ```
   # resize到onnx模型输入大小
   image_path = "./curve/test.jpg"
   img_raw = cv2.imread(image_path, cv2.IMREAD_COLOR)
   img_raw = cv2.resize(img_raw, (640,640))
   ```

4. 预处理部分跟作者的代码保持一致即可,这部分不需要修改

5. 下面是最关键的一步,将pytorch推理net(img)转换为MIGraphX推理migraphx_run(model,args.cpu,img),其中migraphx_run实现如下:

   ```
   def migraphx_run(model,cpu,data_tensor):
       # 将输入的tensor数据转换为numpy
       if cpu:
           data_numpy=data_tensor.cpu().numpy()
           device = torch.device("cpu")
       else:
           data_numpy=data_tensor.detach().cpu().numpy()
           device = torch.device("cuda")
       
       img_data = np.zeros(data_numpy.shape).astype("float32")
       for i in range(data_numpy.shape[0]):
           img_data[i, :, :, :] = data_numpy[i, :, :, :]
   
       # 执行推理
       result = model.run({model.get_parameter_names()[0]: migraphx.argument(img_data)})
   
       # 将结果转换为tensor
       result0=torch.from_numpy(np.array(result[0], copy=False)).to(device)
       result1=torch.from_numpy(np.array(result[1], copy=False)).to(device)
       result2=torch.from_numpy(np.array(result[2], copy=False)).to(device)
   
       return (result0,result1,result2)
   ```

   首先需要将tensor数据转换为numpy,转换好的数据保存在img_data中,然后通过{model.get_parameter_names()[0]: migraphx.argument(img_data)}创建MIGraphX的输入数据,并使用model.run执行推理,result为推理返回的结果,然后通过torch.from_numpy的方式转换为tensor类型并返回,为了保持与Pytorch推理结果的格式一致,转换的时候需要注意输出结果的顺序,MIGraphX的输出结果顺序与onnx中保持一致,可以通过netron (https://netron.app/) 查看:

   ![image-20221215200807445](../Images/RetinaFace_04.png)

   所以第一个输出结果对应pytorch结果中的loc,第二个对应conf, 第三个对应landms,所以返回的结果是(result0,result1,result2)。

6. 推理执行成功后,需要执行后处理才能得到最终的检测结果,由于我们模型推理输出的格式与原始的Pytorch模型输出是一致的,所以后处理可以直接使用原来的,不需要修改。

## 运行示例

1. 参考《MIGraphX教程》中的安装方法安装MIGraphX并设置好PYTHONPATH
2. 安装Pytorch
3. 安装依赖:

```
# 进入migraphx samples工程根目录
cd <path_to_migraphx_samples> 

# 进入示例程序目录
cd Python/RetinaFace

# 安装依赖
pip install -r requirements.txt
```

4. 运行示例:

```
python detect.py
```

会在当前目录生成检测结果图像test.jpg
![image-20221215202711987](../Images/RetinaFace_05.png)