# RetinaFace人脸检测器
RetinaFace是目前被广泛使用的一种人脸检测器模型,本示例主要说明了如何在MIGraphX中使用RetinaFace人脸检测器。
## 模型简介
RetinaFace是一个经典的人脸检测模型(https://arxiv.org/abs/1905.00641),采用了SSD架构。
本示例采用了如下的开源实现:https://github.com/biubug6/Pytorch_Retinaface,作者提供了restnet50 和mobilenet0.25两个预训练模型,本示例使用了mobilenet0.25预训练模型,将mobilenet0.25预训练模型下载下来后,保存到Pytorch_Retinaface工程的weights目录。
## 模型转换
通过下面的步骤可以将mobilenet0.25预训练转换成onnx文件:
- 修改data/config.py:将cfg_mnet中的'pretrain': True,修改为'pretrain': False,
- 执行如下命令就可以将weights目录下的mobilenet0.25_Final.pth模型转换为onnx文件了
```
# 进入Pytorch_Retinaface工程根目录
cd
# 转换模型
python convert_to_onnx.py
```
注意:如果需要修改模型的输入大小,可以修改args.long_side参数,默认为640x640。
模型转换成功后,会在当前目录生成FaceDetector.onnx文件,利用该模型就可以使用MIGraphX进行推理了,本示例在samples工程中的Python/RetinaFace目录中提供了已经修改好的代码,在该目录下执行python convert_to_onnx.py可以直接生成onnx文件,注意运行前需要安装依赖,你可以在非DCU环境下执行模型转换,如果需要在DCU环境下安装依赖,依赖安装方法参考下文中运行示例一节中的说明。
## 推理
Pytorch_Retinaface工程提供了原始Pytorch版本的推理测试代码detect.py,我们只需要将其中使用Pytorch推理的部分转换为MIGraphX推理就可以了,samples工程中的Python/RetinaFace/detect.py文件为已经转换好的推理代码,下面我们看一下是如何转换的:
- 将加载模型部分修改为migraphx的方式加载
```
# 加载模型
model = migraphx.parse_onnx("./FaceDetector.onnx")
```
- 模型加载成功后,需要通过model.compile进行编译,可以通过device_id设置使用哪一块设备
```
model.compile(t=migraphx.get_target("gpu"),device_id=0)
```
- 编译成功后,就可以输入图像进行推理了,由于本示例使用的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))
```
- 预处理部分跟作者的代码保持一致即可,这部分不需要修改
- 下面是最关键的一步,将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]: 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]: img_data}创建MIGraphX的输入数据,并使用model.run执行推理,result为推理返回的结果,然后通过torch.from_numpy的方式转换为tensor类型并返回,为了保持与Pytorch推理结果的格式一致,转换的时候需要注意输出结果的顺序,MIGraphX的输出结果顺序与onnx中保持一致,可以通过netron (https://netron.app/) 查看:
所以第一个输出结果对应pytorch结果中的loc,第二个对应conf, 第三个对应landms,所以返回的结果是(result0,result1,result2)。
- 推理执行成功后,需要执行后处理才能得到最终的检测结果,由于我们模型推理输出的格式与原始的Pytorch模型输出是一致的,所以后处理可以直接使用原来的,不需要修改。