# 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 # 转换模型 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 # 进入示例程序目录 cd Python/RetinaFace # 安装依赖 pip install -r requirements.txt ``` 4. 运行示例: ``` python detect.py ``` 会在当前目录生成检测结果图像test.jpg ![image-20221215202711987](../Images/RetinaFace_05.png)