基于凌蒙派RK3568部署人脸识别系统

一、项目背景


(一)、AIStudio方案调研

AIStudio中搜了一圈,和人脸识别系统有关的项目大致有两个类型,典型代表如下:

(二)、方案优缺点分析

项目一通过将带检测的图片和数据库中的图片拼接,送入神经网络进行检测,得到了不错的效果。但是,他有一个很明显的缺点,即数据库中存在大量数据时,这种方法需要和数据库中的每一张图片进行拼接然后送入网路进行计算。显然,这种方法效果还不错,但是会消耗大量的时间,实际上并没有很好的办法进行落地。

项目二意识到了项目一的问题,用的思路是先用MTCNN提取出人脸关键信息,然后送入ArcFace中提取特征,最后计算两幅图片特征向量的差值,得到最后的结果。其缺点我认为存在两点:

  • 第一点是训练问题。MTCNN非常难训练,一次要训练3个模型。并且原项目中没有给出训练好的MTCNN,我尝试将output中的best模型转换成PaddleINferenceDemo中的Backbone模型,精度十分的差,直接导致人脸检测出现故障,更不用提人脸识别了。
  • 第二点是项目二采用的特征相似度计算方式是直接相减,这样的办法对阈值处理很不友好。我测试了一下,从网络上随机找了一个明星在化妆前和化妆后的两张图片,送入网络提取特征后,如果使用原项目的相似度计算方式,只有31.92%的相似度。

(三)、我的方案简介

由方案对比可见,AIStudio中并没有效果不错的人脸识别系统。而人脸识别系统作为现在AI落地最成功的项目之一,AIStudio缺少这部分内容属实可惜。由此,我设计了基于 SCRFD模型 + AdaFace模型 的人脸检测系统,解决了项目一和项目二的痛点问题,并且成功在RK3568上落地,想为AIStudio的人脸识别方向做出一些贡献。

二、项目价值


(一)、AIStudio生态

AIStudio平台是面向AI学习者的人工智能学习与实训社区。对于AIStudio而言,人脸识别系统不但很适合新手学习,而且适合在嵌入式设备上部署,能向开发者展示完整的AI项目的创作流程。这个项目将提供一个效果不错的人脸识别方案,为初学者提供一个可用的人脸识别demo,符合AIStudio的定位。

(二)、硬件生态

今年5月,飞桨携手NVIDIA、Intel、瑞芯微、Arm、Imagination等国内外硬件厂商联合发布“硬件生态共创计划”。不同于其他项目部署于成熟的平台,这个项目将最终部署于瑞芯微电子最新的性价比芯片RK3568。因此,这个项目将丰富PaddlePaddle的硬件生态,展现PaddlePaddle在RK平台上落地的能力。

(三)、应用场景

该项目主要针对人的正脸进行识别,可以应用于教育,安防等等一系列需要认证人脸或者识别身份信息的领域,展示了Paddle框架在基础人脸识别任务上的能力。该项目可以配合活体检测和假体攻击方面的防御措施,做到更精确的识别。目前只是第一个版本,后续如果有这方面的支持,将持续更新这个项目。

三、基于飞桨的技术应用情况


  • 利用FastDeploy部署SCRFD人脸检测模型。
  • 利用PaddleClas训练自己修改过的AdaFace模型。PaddleClas原仓库不能直接训练AdaFace,我优化了其中的细节,已经在AIStudio开源。
  • 利用Paddle2ONNX将Paddle静态图文件转换成ONNX文件。

四、技术思路


基于深度学习的人脸识别系统,一般可以用下面的图片来概述其工作过程:
在这里插入图片描述

由上图可知,人脸识别的过程大致可以分为两个部分:

  • 第一个部分是人脸检测,其又可以分为人脸检测和人脸关键点定位两种方案。
    • 人脸检测器(Face Detector):定位人脸在图像中的位置,直接截取图片
    • 人脸关键点检测器(Facial Landmark Detector):提供关键点坐标,归一化坐标系对齐后,提取人脸
  • 人脸识别,人脸识别一般采用特征对比的方法进行识别。这种方法一般是对两张人脸进行特征提取后,计算其特征相似度来判断两张图片是否属于同一个人

五、技术细节以及做出的改进


(一)、模型选型

检测器方案

由技术思路可以看到,人脸检测一般有人脸检测器和人脸关键点检测器两种方案。本着我全部都要的原则,现在的模型一般是将这两种方案融合进一个模型之中。下面介绍我在检测器方案上的选型。

  • 方案一(MTCNN): 目前常见的人脸检测器是MTCNN。它将检测任务分成三个模型进行推理,取得了不错的效果。但是,MTCNN是利用三个模型来检测人脸,这就意味着三个模型是相互耦合的,这就让MTCNN变的难以训练。

  • 方案二(BlazeFace): PaddleDetection中有一个模型叫BlazeFace,这个模型也能对人脸进行快速的检测并且得到很不错的效果。但是这个模型在关键点检测上效果不是特别好,因此也不考虑这个模型。

  • 方案三(YuNet): 最近,libfacedetection对YuNet模型进行了更新,这个模型可以在CPU设备上得到高速且不错的检测效果。因此我将检测器换成了YuNet,其在WIDER Face数据集上的表现如下:

    ModelAP_easyAP_mediumAP_hard#ParamsParams RatioMFlopsFroward (ms)
    YuNet(Ours)0.8850.8770.762850061.0x13610.6

    表面上看YuNet推理速度和精度都不错,很适合作为检测器对象。但是,在实践过程中我发现,YuNet存在很多次的误检测,因此这个模型被我放弃了。

  • 我的方案(SCRFD): SCRFD是一种高效的轻量级高精度人脸检测方法,其精度如下:

    NameEasyMediumHardFLOPsParams(M)Infer(ms)
    SCRFD_500M90.5788.1268.51500M0.573.6
    SCRFD_1G92.3890.5774.801G0.644.1
    SCRFD_2.5G93.7892.1677.872.5G0.674.2
    SCRFD_10G95.1693.8783.0510G3.864.9
    SCRFD_34G96.0694.9285.2934G9.8011.7
    SCRFD_500M_KPS90.9788.4469.49500M0.573.6
    SCRFD_2.5G_KPS93.8092.0277.132.5G0.824.3
    SCRFD_10G_KPS95.4094.0182.8010G4.235.0

    可以看到,这个模型的精度和速度都很适合让它作为人脸识别的检测器。经过实际测试,这个模型在速度上接近YuNet,精度上超过YuNet,因此我选择SCRFD作为人脸识别的检测器。
    FastDeploy提供了SCRFD的onnx推理代码,可以作为部署在RK系列板子上的参考代码。


识别器方案

  • 方案一(ArcFace): 在FastDeploy提供了ArcFace模型,但是最小的ArcFace模型大小都达到了92M,非常不适合在硬件上部署。

  • 方案二(AdaFace): 在PaddleClas提供了AdaFace模型,其精度全面超越ArcFace,和ArcFace模型一样,其模型大小并不合适再硬件上部署。

  • 我的方案(MobileFacenet + AdaFace): MobileFacenet是专门针对人脸识别优化过的轻量级神经网络,我将它作为AdaFace的backbone,在精度丢失3%的情况下,将模型的大小缩小了将近20倍。

(二)、人脸对齐

在人脸检测完之后,我们一般需要利用关键点进行人脸对齐。常见的方案如下:

  • 方案一(skimage): 常见的人脸对齐算法一遍使用skimage库来计算相似矩阵,如下:

    from skimage import transform as trans
    
    def estimate_norm(lmk):
             tform = trans.SimilarityTransform()
             src = np.array([[38.2946, 51.6963],
                             [73.5318, 51.5014],
                             [56.0252, 71.7366],
                             [41.5493, 92.3655],
                             [70.7299, 92.2041]], dtype=np.float32)
             tform.estimate(lmk, src)
             M = tform.params[0:2, :]
             return M
    

    但是,skimage在Arm架构的低算力板子上,编译起来十分费劲。

  • 我的方案(opencv): 我利用opencv复现了一份人脸对齐代码。如下:

    def norm_crop(img, landmark, image_size=112):
     """
     人脸对齐函数
     Args:
         img: 输入的人脸图片,建议为opencv读取的图片
         landmark: 五个人脸关键点,输入时建议reshape成[-1,2]
         image_size: 对齐后图片的尺寸
     Returns: 对齐后的人脸图片
     """
    
     def transformation_from_points(points1, points2):
         points1 = points1.astype(np.float64)
         points2 = points2.astype(np.float64)
         c1 = np.mean(points1, axis=0)
         c2 = np.mean(points2, axis=0)
         points1 -= c1
         points2 -= c2
         s1 = np.std(points1)
         s2 = np.std(points2)
         points1 /= s1
         points2 /= s2
         U, S, Vt = np.linalg.svd(points1.T * points2)
         R = (U * Vt).T
         return np.vstack([np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T)), np.matrix([0., 0., 1.])])
    
     img_size = np.array([112, 112])
     coord5point = np.array([(0.31556875000000000, 0.4615741071428571),
                             (0.68262291666666670, 0.4615741071428571),
                             (0.50026249999999990, 0.6405053571428571),
                             (0.34947187500000004, 0.8246919642857142),
                             (0.65343645833333330, 0.8246919642857142)])
     coord5point = coord5point * img_size
     pts1 = np.float64(np.matrix([[point[0], point[1]] for point in landmark]))
     pts2 = np.float64(np.matrix([[point[0], point[1]] for point in coord5point]))
     M = transformation_from_points(pts1, pts2)
     warped = cv2.warpAffine(img, M[:2], (image_size, image_size))
     return warped
    

(三)、模型相似度计算

常见的相似度计算方法有如下几种方案:

  • 方案一(欧几里得相似度): 欧几里得相似度采用欧式距离公式作为衡量两个序列是否相似的标准,其缺点是当数据集出现异常值(即数据不是很规范)的时候,欧几里德距离表现不"稳定"。

  • 方案二(余弦相似度): 余弦相似度根据两个向量的夹角作为衡量两个序列是否相近的标准,它缓解了欧几里得相似度的缺点,但是如果数值极度极端,则还会出现一样的问题。

  • 我的方案(皮尔逊相似度): 皮尔逊相似度基于余弦相似度,它相当于让序列在进行相似度计算前先减去它们的平均值,然后再进行相似度计算,有效的解决了余弦相似度出现的不稳定问题。

(四)、数据库方案对比

  • 方案一(基于图片): 由技术思路可以知道,数据库可以以图片作为数据。但是,这样做,在每一次开启识别系统时,都需要对图片做一次特征提取操作,非常花费时间。

  • 我的方案(基于特征): 我的方案是让提取出来的特征作为数据库的数据。每次运行系统,直接读取保存的特征文件,不经过网络处理,节约时间成本。

六、模型训练


项目的模型我都已经转换好了,如果你只是想学习部署,可以忽略这个部分,直接跳转至“模型部署部分-下载”下载我转换好的模型文件即可。

(一)、检测器

检测器无需训练,我直接使用了FastDeploy转换好的ONNX模型。

(二)、识别器

识别器训练针对PaddleClas做了非常多的改进,篇幅有限,详情请参考【PaddleClas】手把手让你训练自己的人脸识别模型

七、部署前的准备工作


在将模型部署到RK3568上之前,我们需要在PC上做一下准备工作,这部分将会教会你如何将ONNX文件转换成RKNN文件。

(一)、工具链与源代码下载

由于github网速并不稳定,我这里将需要下载的东西全部上传到了百度网盘。

链接: https://pan.baidu.com/s/1zH17-V0Az0dyXqBObWmETA?pwd=qhrp 提取码: qhrp 
--来自百度网盘超级会员v5的分享

(二)、PC

运行硬件和软件说明

  • 系统信息: ubuntu
  • 开发库以及部署工具版本:
    • python版本: 3.8
    • rknn_toolkit版本: 1.4.0

安装rknn_toolkit工具

rknn_toolkit简介

RKNN-Toolkit2是一个软件开发工具包,供用户在PC和Rockchip NPU平台(RK3566、RK3568、RK35.88、RK3.588S、RV1103、RV1106)上进行模型转换、推理和性能评估。

使用conda安装合适的环境

  • 下载和安装miniconda这部分略过,自行参考百度下载和安装
  • 创建并进入一个新的环境
    conda create -n rknn2 python=3.8
    conda activate rknn2
    

安装rknn_toolkit

  • 百度网盘或者github仓库中下载1.4.0版本的工具包并解压
  • 下载必要的python包和软件
    • 安装numpy

      pip install numpy==1.16.6
      
    • 安装必要的工具包

      sudo apt-get install libxslt1-dev zlib1g zlib1g-dev libglib2.0-0 libsm6 libgl1-mesa-glx libprotobuf-dev gcc g++
      
    • 安装rknn-toolkit2(目录请按照自己下载的文件配置)

      # 进入安装目录
      cd ~/下载/rknn-toolkit2-master/packages
      # 安装文件
      pip install rknn_toolkit2-1.4.0_22dcfef4-cp38-cp38-linux_x86_64.whl
      

将onnx文件转换成rknn文件

Rockchip并没有提供Paddle2RKNN的API接口函数,因此我们需要先将Paddle模型转换成ONNX模型,再将ONNX模型转换成RKNN。在源代码中,我已经将转换好的模型放在了 tests/project_tests/face_recognition/python/weights 目录下。

在源代码目录下,执行以下命令,即可在weights文件夹下生成rknn文件

# 进入文件夹
cd ./tests/project_tests/face_recognition/python

# 运行代码
python face_recognition_pc.py

(三)、Board

运行硬件和软件说明

  • 硬件信息: 凌蒙派RK3568
  • 系统信息: debian10
  • 开发库以及部署工具版本:
    • python版本: 3.7
    • RKNN-Toolkit-Lite2版本: 1.4.0
    • RKNPU版本: 1.4.0

安装RKNN-Toolkit-Lite2工具

RKNN-Toolkit-Lite2简介

RKNN-Toolkit-Lite2为Rockchip NPU平台(RK3566、RK3568、RK35.88、RK3.588S)提供Python编程接口,帮助用户部署RKNN模型,加速AI应用的实现。

下面进行推理工具的安装,请更根据自己下载的地址修改以下安装过程

安装RKNN-Toolkit-Lite

# 如果系统中没有安装 python3/pip3 等程序,请先通过 apt-get 方式安装
sudo apt update
sudo apt-get install -y python3 python3-dev python3-pip gcc

# 安装依赖模块: opencv-python 和 numpy
sudo apt-get install -y python3-opencv 
sudo apt-get install -y python3-numpy

# 进入Downloads安装 RKNN Toolkit Lite2
cd ~/Downloads/rknn-toolkit2-master
cd ./rknn_toolkit_lite2/packages
pip3 install rknn_toolkit_lite2-1.4.0-cp37-cp37m-linux_aarch64.whl

安装RKNPU驱动

# 安装完RKNN Toolkit Lite2,我们还需要安装RKNPU2驱动
cd ~/Downloads/rknpu2-master
cd ./runtime/RK356X/Linux/librknn_api/aarch64/
sudo cp ./* /usr/lib

安装pillow库

sudo apt install libxft-dev libjpeg-dev libpng-dev
sudo apt-get install libfreetype6-dev
pip3 install pillow

可能遇到的错误以及解决方案

  • 更新软件包失败时,请使用sudo apt update 不是 sudo apt-get update
  • opencv-python 和 numpy包请不要使用pip进行安装,速度会非常慢
  • 安装pillow时会缺少依赖文件,但是仍然可以成功编译,请按照七、部署前的准备工作中的流程进行安装

(四)、导出rknn文件

安装源代码

ONNX文件是无法调用RK的NPU的,我们需要将ONNX文件转换成RKNN文件。为了方便以后的业务整合,我将这套代码整合成了EasyDeploy库,方便大家下载。到出rknn需要使用UbuntuPC进行导出,安装方法如下:

# 进入文件夹
cd EasyDeployForRK3568
# 安装库
python setup.py install

导出模型

运行以下代码即可导出RKNN模型:

# 进入目标文件夹
cd EasyDeployForRK3568
cd tests/project_tests/face_recognition/python
python face_recognition_pc.py

八、 部署人脸识别系统

(一)、源代码目录介绍与程序结果展示

源代码目录文件夹具体分工介绍:

.
├── database  数据库
├── face_recognition_board.py  人脸识别板子端程序
├── face_recognition_pc.py  人脸识别PC端程序
├── test_images  测试图片
├── test_outputs  测试输出
└── weights  权重文件夹

数据库介绍

数据库是按照文件夹的形式组成的,我这里一共放了3个文件,每一个文件夹都是一个需要识别的人脸

.
├── ml
├── xx
└── zjk

程序结果展示

理论上0.4以上的准确率就可以认定为是一张一样的人脸

原图片人脸识别后的图片

(二)、在板子上安装源代码

安装源代码之前请将PC导出过RKNN的源代码文件夹传到板子上(或者直接下载百度网盘中的源代码,已经包含了转换好的模型文件)。在板子上安装源代码和在PC上有所不同,RK的板子的Python需要使用sudo权限才能安装源代码,安装过程如下

# 进入目标文件夹
# 进入文件夹
cd EasyDeployForRK3568
# 安装库
sudo python3 setup.py install

(三)、运行测试demo

由于时间的关系,提交的第一个版本,demo暂时使用图片作为测试对象。

cd EasyDeployForRK3568
cd tests/project_tests/face_recognition/python
sudo -E python3 face_recognition_board.py

可能遇到的错误以及解决方案

  • 请要不使用 python setup.py install 来安装源代码,这会导致板子使用python2来进行安装。请使用 sudo python3 setup.py install 来安装源代码。

  • 调用NPU时会出现权限问题,因此请使用 sudo -E python3 face_recognition_board.py,代替正常的python face_recognition_board.py来运行程序

九、ERROR,退,退,退,退,退,退

RK3568使用的是Arm架构的debian,因此会有比较多的坑,我将部署过程中遇到的坑进行了汇总整理,方便大家使用。

  • 更新软件包时,请使用sudo apt update 不是 sudo apt-get update
  • opencv-python 和 numpy包请不要使用pip进行安装,速度会非常慢
  • 安装pillow时会缺少依赖文件,但是仍然可以成功编译,请按照七、部署前的准备工作中的流程进行安装
  • 请要不使用 python setup.py install 来安装源代码,这会导致板子使用python2来进行安装。请使用 sudo python3 setup.py install 来安装源代码。
  • 调用NPU时会出现权限问题,因此请使用 sudo -E python3 face_recognition_board.py,代替正常的python face_recognition_board.py来运行程序

总结

开发心得

RK系列的开发版上手难度非常高,不像Edgeboard的开发版简单易用。在这个项目中我几乎将开发过程中所有的坑都提到了,其他RK平台的项目也可以借鉴这个项目进行开发。希望人脸识别教程能让大家熟悉RK平台的落地过程,祝大家国庆节快乐。

做出的贡献

  • AIStudio上提供了AdaFace的训练代码,解决了Aistudio上PaddleClas AdaFace训练环境难以搭建的问题
  • 提供AdaFace的onnx推理代码(python/cpp),准备合入FastDeploy
  • 为FastDeploy提供了MobileFacenet + AdaFace的模型,将目前FastDeploy上的人脸识别模型大小缩小30倍,精度仅仅下降3%

联系我

keyvalue
githubZhengBicheng
邮箱zheng_bicheng@outlook.com
开源项目地址EasyDeployForRK3568

此文章为搬运
原项目链接

Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐