- 2024-12-19
-
发表了主题帖:
【嵌入式AI挑战营,进阶】从零开始在RV1106上部署人脸识别应用
本帖最后由 junan007 于 2024-12-19 19:19 编辑
# 一、开发环境的搭建
从包装上看此次活动提供的板子是幸狐LuckFox Pico Max,随板卡一起还有一个3百万像素的摄像头,这样极大的方便了我们进行测试,另外,官方还赠送了一颗带双面胶的钮扣电池。板卡的做工较精良,采用双面设计,核心的部件都在板子的正面,背面是一颗华邦电子的闪存,PCB板上引出了板子支持的GPIO口,同时官方还提供了原理图,动手能力强的可以根据自已项目的实际情况,调整布局,设计出自已的板子。当然,如果提供的是带无线、蓝牙模块和8G存储的就更香了。
1、硬件连接
将摄像头取出,插入板子上网卡后的插槽中,使用USB Type-C线与主机相连后,从板子上指示灯可以看出板子正在启动。
2、系统烧录
根据官方的资料显示,建议到手之后自行烧录新的系统镜像,而且推荐使用buildroot系统,以下描述均默认使用buildroot系统。
首先安装板卡驱动程序[https://files.luckfox.com/wiki/Luckfox-Pico/Software/DriverAssitant_v5.12.zip](https://files.luckfox.com/wiki/Luckfox-Pico/Software/DriverAssitant_v5.12.zip)
下载烧录工具[https://files.luckfox.com/wiki/Luckfox-Pico/Software/SocToolKit.zip](https://files.luckfox.com/wiki/Luckfox-Pico/Software/SocToolKit.zip)
下载官方固件文件[https://pan.baidu.com/s/1Mhf5JMpkFuZo_TuaGSxBYg?pwd=2sf8](https://pan.baidu.com/s/1Mhf5JMpkFuZo_TuaGSxBYg?pwd=2sf8),根据你想使用的系统下载对应的的固件文件,后续你也可以根据自已的需要重新编译系统固件。
上述工具和数据准备好后,在未通电的情况下,按住板子上的BOOT按钮,再连到主机上通电启动。打开准备好的烧录工具,按照官方教程中描述的方法进行系统烧录,如图所示:
3、网络连接
LuckFox Pico Max带了一块网卡,但是我主机上只有一块网卡,而且连到了公司的内网环境,为了减少不必要的麻烦,决定使用NDIS虚拟网卡与板卡直连,开发板默认的IP地址为172.32.0.93,只需要将安装完驱动后多出的虚拟网卡IP地址设置为和它相同的网段,就可以连接了,如172.32.0.100。
使用系统自带的ssh终端命令或者其它支持SSH协议的工具进行连接,默认用户root的密码为luckfox
4、摄像头测试
默认的镜像中自启动了一个官方的IPC应用程序rkipc,在官方资料的摄像头接入部份有详细的描述[https://wiki.luckfox.com/zh/Luckfox-Pico/CSI-Camera](https://wiki.luckfox.com/zh/Luckfox-Pico/CSI-Camera),根据文件中的描述,使用支持RTSP协议的播放器对默认的视频流进行播放rtsp://172.32.0.93/live/0,正常的话即可查看到视频
5、SDK编译
根据后续的使用情况,需要对板卡的SDK进行编译,官方推荐使用Ubuntu 22.04系统进行编译,可以使用虚拟机或者WSL。我使用的是WSL Ubuntu 20.04,其编译的过程与官方文档所描述的基本相同,但需要注意以下几个问题:
- SDK源码文件需要复制到WSL系统的原生系统目录下进行编译,不能直接使用Windows系统映射过来的路径(/mnt/d/xxx此种形式)。否则在编译内核阶段出现‘Documentation/KBuild: is a directory’的错误信息而无法正常编译。
- WSL会自动将Windows的PATH环境变量值映射到WSL系统中,会造成编译时提示PATH变量中包含空格的错误信息,可以在命令行中简单粗暴的export PATH=””,或者unset PATH,也可以修改/etc/wsl.conf文件(没有可以手工创建一个)。在其中添加或修改为以下的内容:
```jsx
[interop]
appendWindowsPath=false
```
之后在Windows终端下执行wsl -t Ubuntu-20.04 结束wsl进程后,重新再进入wsl的ubuntu系统,即可生效。
- 编译好的固件在output/image下,其它demo程序、脚本等在output/out下,可以根据需要把要测试的程序复制到板子上进行测试,或者使用编译后的固件重新烧录。
至此本地编译环境搭建基本完成。
# 二、Insightface环境构建
活动建议但不限定使用Insightface框架进行模型的部署,为此花了些时间研究了一下Insightface的SDK,从官方的文档中看其SDK支持RV1109和RV1126系列,没有明确标记支持RV1106,但还是抱着试一试的想法对其SDK进行了一些尝试,整体过程如下,感兴趣的可以参考一下。
1、从github上下载Insightface源代码
```bash
git clone https://github.com/deepinsight/insightface.git
```
2、复制构建脚本
```bash
cd insightface/cpp-package/inspireface/command
cp build_cross_rv1109rv1126_armhf.sh build_cross_rv1106.sh
```
3、修改构建脚本中的部份内容如下:
```bash
# 此路径为板卡提供的交叉编译工具链,根据情况进行修改
export ARM_CROSS_COMPILE_TOOLCHAIN=/opt/toolchain/arm-rockchip830-linux-uclibcgnueabihf
cmake -DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_SYSTEM_VERSION=1 \
-DCMAKE_SYSTEM_PROCESSOR=armv7 \
-DCMAKE_C_COMPILER=$ARM_CROSS_COMPILE_TOOLCHAIN/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc \
-DCMAKE_CXX_COMPILER=$ARM_CROSS_COMPILE_TOOLCHAIN/bin/arm-rockchip830-linux-uclibcgnueabihf-g++ \
-DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -flax-vector-conversions" \
-DCMAKE_C_FLAGS="${CMAKE_C_FLAGS} -std=gnu99" \
-DTARGET_PLATFORM=armlinux \
-DISF_BUILD_LINUX_ARM7=ON \
-DISF_ENABLE_RKNN=ON \
-DISF_RK_DEVICE_TYPE=RV1106 \
-DISF_BUILD_WITH_SAMPLE=ON \
-DISF_BUILD_WITH_TEST=ON \
-DISF_ENABLE_BENCHMARK=OFF \
-DISF_ENABLE_USE_LFW_DATA=OFF \
-DISF_ENABLE_TEST_EVALUATION=OFF \
-DISF_BUILD_SHARED_LIBS=ON ${SCRIPT_DIR}
```
4、编译SDK
```bash
// 下载并初始化第三方库
cd ..
git clone https://github.com/HyperInspire/3rdparty.git
cd 3rdparty
git pull
// 确保下载第三方库的过程中未出错,根据你的网络情况,可能需要魔法梯子才能正常下载
git submodule update --init --recursive
// 开始编译
bash command/build_cross_rv1106.sh
```
5、成功编译后,会在build目录下找到生成的SDK及测试程序。事与愿违,你可能会和我一样碰到下面的这些问题,记录供参考:
- 未定义的ssize_t类型错误。解决方法:修改出错cpp对应的h头文件,增加#include 头文件的包含。
- rknn_init函数参数不匹配错误,解决方法:打开出错的cpp文件,修改函数调用的代码,在最后一个参数0后面再加上一个默认参数NULL ,共有四处。
- 开启编译测试程序开关(ISF_BUILD_WITH_TEST=ON、DISF_BUILD_WITH_SAMPLE=ON)后,在链接时可能会出现undefined reference to ‘__isoc99_fscanf’等错误信息,此时你需要将3rdparty下的OpenCV版本替换,我使用的是女装大佬倪神的Opencv-mobile for luckfox-pico版本,省去了自已编译的时间[https://github.com/nihui/opencv-mobile/releases/latest/download/opencv-mobile-4.10.0-luckfox-pico.zip](https://github.com/nihui/opencv-mobile/releases/latest/download/opencv-mobile-4.10.0-luckfox-pico.zip "https://github.com/nihui/opencv-mobile/releases/latest/download/opencv-mobile-4.10.0-luckfox-pico.zip"),下载后将其解压到cpp-package/inspireface/3rdparty/inspireface-precompile/opencv下,同时修改/cpp-package/inspireface/CMakeLists.txt文件的134,135行,将对应的变量指向新的OpenCV位置。
6、在修改了上述的错误后,就可以正常编译并得到可运行在板卡buildroot系统上的C++ SDK和测试程序。可惜在使用测试程序加载官方模型时出现模型无效的问题,Insightface官方回复SDK没有适配RV1106,只能使用CPU版本,但在关闭RKNN加速后问题依然存在[https://github.com/deepinsight/insightface/issues/2704](https://github.com/deepinsight/insightface/issues/2704),后来确认是模型文件的版本问题,替换了另一个版本的模型文件后,测试程序正常加载。
7、之后可以在示例程序的基础上完成应用层的开发。
# 三、Retinaface、Facenet模型的应用
以下操作均在本地主机上完成,如果你需要训练自已的模型,建议主机上有一块性能不是太差的Nvidia显卡,同时安装好显卡驱动以及对应的CUDA和cuDnn库,略过。如果你没有GPU显卡,也可以使用其他人提供的预训练模型。
1、人脸检测训练环境的搭建
```bash
git clone https://github.com/bubbliiiing/retinaface-pytorch.git
cd retinaface-pytorch
python -m venv venv // 创建一个虚拟环境,你也可以使用conda之类的来管理虚拟环境
venv\scripts\active.bat // 激活虚拟环境
pip install - r requirements.txt // 安装retinaface-pytorch库依赖
```
2、下载或构建自已的训练数据,并将其放置到data文件夹下,修改train.py文件中的参数,如:training_dataset_path数据集标签文件的路径,backbone网络主干结构等。确认无误后执行下列的指令进行模型的训练:
```jsx
python train.py
```
完成训练后,可以在model_data下得到完成训练的Pytorch pth模型文件。
3、人脸检测模型的转换
完成训练后的模型为Pytorch专有格式,如果要在RV1106上使用,需要先转换为ONNX格式,可以使用下列的脚本进行转换:
```python
from nets.retinaface import RetinaFace
from utils.config import cfg_mnet
import torch
model_path='model_data/Retinaface_mobilenet0.25.pth' # 上一步完成训练的模型文件路径
model=RetinaFace(cfg=cfg_mnet,pretrained = False) # 创建一个模型对象
device = torch.device('cpu')
model.load_state_dict(torch.load(model_path,map_location=device),strict=False) # 模型权重参数加载
net=model.eval()
example=torch.rand(1,3,640,640) # 导出时需要执行一次模型前向,使用随机或任意样本即可
torch.onnx.export(model,(example),'model_data/retinaface.onnx',verbose=True,opset_version=9) # 导出为ONNX格式
```
保存为export.py后,执行python export.py,即可得到onnx格式的模型文件。
4、人脸特征提取训练环境搭建
```bash
git clone https://github.com/bubbliiiing/facenet-pytorch.git
cd facenet-pytorch
python -m venv venv // 创建一个虚拟环境,你也可以使用conda之类的来管理虚拟环境
venv\scripts\active.bat // 激活虚拟环境, 你可以使用retinaface训练时的虚拟环境,但为了防止库冲突,建议分开
pip install - r requirements.txt // 安装facenet-pytorch库依赖
```
5、下载或构建自已的训练数据,将其放置到datasets目录下,需要注意目录的结构和标签文件的内容。确认无误后与检测模型一样执行python train.py进行模型训练。
6、人脸特征模型的转换
与人脸检测模型一样训练完成后的模型也需要先转换为ONNX格式,脚本如下:
```bash
from nets.facenet import Facenet
from torch import onnx
import torch
model_path='model_data/facenet_mobilenet.pth' # 模型文件路径
model = Facenet(backbone="mobilenet",mode="predict",pretrained=True) # 模型初始化
device = torch.device('cpu')
model.load_state_dict(torch.load(model_path, map_location=device), strict=False)
example=torch.rand(1,3,160,160) # 给定一个输入
torch.onnx.export(model,example,'model_data/facenet.onnx',verbose=True,opset_version=9) # 导出
```
保存为export.py后,执行python export.py, 得到facenet.onnx
7、模型精简和调整
上述导出的ONNX的模型计算图中存在一些冗余的运算符,可以将模型的结构进行简化,优化后的模型更益于部署。可能通过使用onnx-simplifier工具来完成
```bash
// 安装onnx-simplifier
pip install onnx-simplifier
// 对模型进行简化
python -m onnxsim facenet.onnx facenet_simple.onnx
```
8、ONNX模型转换为RKNN模型
- 安装RKNN-Toolkit2,根据你Python的版本选择安装的RKNN依赖和安装包
```bash
git clone https://github.com/rockchip-linux/rknn-toolkit2
# Python-3.10
pip install -r rknn-toolkit2/packages/x86-64/requirements_cp310-2.3.0.txt # 依赖库
pip install rknn-toolkit2/packages/rknn_toolkit2-2.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64 # 安装包
```
- 模型转换,使用下列的脚本对模型进行转换,脚本如下:
```python
import sys
from rknn.api import RKNN
def parse_arg():
if len(sys.argv) < 5:
print("Usage: python3 {} [onnx_model_path] [dataset_path] [output_rknn_path] [model_type]".format(sys.argv[0]));
exit(1)
model_path = sys.argv[1]
dataset_path= sys.argv[2]
output_path = sys.argv[3]
model_type = sys.argv[4]
return model_path, dataset_path, output_path,model_type
if __name__ == '__main__':
model_path, dataset_path, output_path, model_type= parse_arg()
# Create RKNN object
rknn = RKNN(verbose=False)
# Pre-process config
print('--> Config model')
if model_type == 'Retinaface':
rknn.config(mean_values=[[104, 117, 123]], std_values=[[1, 1, 1]], target_platform='rv1103',
quantized_algorithm="normal", quant_img_RGB2BGR=True,optimization_level=0)
print("Use retinaface mode")
else:
rknn.config(mean_values=[[0, 0, 0]], std_values=[[255, 255, 255]], target_platform='rv1103')
print('done')
# Load model
print('--> Loading model')
ret = rknn.load_onnx(model=model_path)
if ret != 0:
print('Load model failed!')
exit(ret)
print('done')
# Build model
print('--> Building model')
ret = rknn.build(do_quantization=True, dataset=dataset_path)
if ret != 0:
print('Build model failed!')
exit(ret)
print('done')
# Export rknn model
print('--> Export rknn model')
ret = rknn.export_rknn(output_path)
if ret != 0:
print('Export rknn model failed!')
exit(ret)
print('done')
# Release
rknn.release()
```
使用方法:
python convert.py
其中:数据集文件只需要提供少量的样本图片作为参考,可以从训练数据中抽取。当中记录图片的绝对或相对地址,一个样本一行。
完成后的模型即为RKNN模型,需要注意的是有些ONNX模型中的算子可能RKNN NPU并不支持,这个时候就需要在你的应用程序中去实现这部份。这些算子一般都可以在网上找到代码实现,可以结合官方05_RKNN_Compiler_Support_Operator_List_v1.6.0.pdf文档和 Netron工具进行查看,对于不熟悉网络实现的小伙伴来说,还是有些难度的。所以在模型选择的时候尽量选取NPU支持的网络主干,并在导出ONNX模型后进行精简,能省去不少的麻烦。
至此,得到了可部署于RV1106板卡上的模型文件。
# 四、应用层的整合
官方文档中有许多视觉应用的例子可供参考,可以看出使用RKMPI方式的性能要高于OpenCV,虽然倪神的Opencv-mobile中已经增加了RKNN的支持,但为了减少不必要的麻烦,在RKMPI和RKNN示例程序的基础上进行了修改,基本的代码已经提交到Github上[https://github.com/junanxia/rkface](https://github.com/junanxia/rkface),代码中实现了基本的人脸检测和识别,因为显示屏被其它项目占用,所以就简单的直接在视频上进行了结果OSD叠加,其中只放置了数字和字母的字模。受OSD刷新的影响,多人时看上去不太明显。在人脸识别的过程中,尝试过进行人脸对齐,但对效果的提升并不大(也有可能我的实现有问题),为了减少性能开销,未启用对齐。在相似性计算上简单的使用了余弦相似度,所以程序中的阀值设置比较重要,这部份有提升空间,后续有时间的话会再进行一些改造。
程序的faces目录下为预定义的128维人脸特征,是facenet模型结果归一化后的32位浮点数,你也可以使用图片的方式,只需在程序加载时执行一次特征计算后进行保存。最后程序的运行效果:
[localvideo]8919f287c9b602c91b57fd3ae2cbaa88[/localvideo]
以上,仅供参考!
- 2024-11-21
-
回复了主题帖:
入围名单公布:嵌入式工程师AI挑战营(进阶)的挑战者们,领取板卡啦
个人信息已确认,领取板卡,可继续完成任务
- 2024-11-20
-
回复了主题帖:
嵌入式工程师AI挑战营(进阶):在RV1106部署InsightFace算法的多人实时人脸识别实战
申请理由:
1、InsightFace是由旷视开源的、基于Pytorch和MXNet框架的2D&3D深度人脸分析工具箱。当中实现了先进的人脸识别、人脸检测和人脸对齐算法,并针对训练和部署进行了优化。该库提供了C/C++ SDK,支持不同的操作系统和硬件后端,如CPU、GPU、NPU等,应用层开发可以很快速便捷的进行部署。
2、本人多年C++开发,从事视频检测、视频识别相关领域的工作,有幸参与过大型OCR自动化处理工程的实际落地,对于TensorRT、NCNN、TNN等框架在不同应用场景下的使用有一定的经验,曾在Nvidia Jetson Nano、树莓派平台上移植过目标检测、行为分析等模型,但因为其它诸多的因素,还未使用过RV系列的平台,希盼能借此活动对国产硬件平台做进一步的了解,并在后续实际的项目中进行推广和使用。
基本的思路如下:
1、在RV1106开发板中部署平台支持的Linux操作系统,如适用于嵌入式硬件的Buildroot系统等。
2、使用RV1106平台支持的交叉编译工具链对需要使用到的环境依赖进行编译,主要涉及到Opencv、RKNN等
3、摄像头的基本调试,主要测试驱动是否正常,视频帧能否正常获取等。
3、使用预训练模型对RV1106进行硬件能力评估,根据评估情况结合项目中功能指标的要求,挑选适合的网络主干,如ResNet、MobileNet、DenseNet等。
4、使用RKNN-Toolkit对模型进行转换、量化等优化工作,根据其性能表现、内存表现选取最终的模型结构及适合的模型精度(int4、int8、int16精度选择)。
5、将选取的模型应用到系统中,系统主体流程简述为:使用Opencv从摄像头中获取单帧图像(根据情况适当的进行抽帧)->使用模型对人脸进行检测、对齐->使用基本的分类算法对人脸进行分类输出->结果数据合成输出。
应用场景:
门禁打卡
-
点评了资料:
超图解 ESP32 深度实作 (赵英杰)