SP7350 模型训练及平台部署
以Yolov8数据标注以及模型训练并部署到SP7350平台上为例,介绍在SP7350平台上开发AI demo的流程
硬件要求:虚拟机内存至少需要达到8G以上
Miniconda环境安装
1、Miniconda 下载
为了管理不同项目的依赖关系和环境配置,避免冲突和确保项目的独立性,可以通过miniconda创建一个新的工作环境,防止与本地环境冲突。
比如可以在conda环境下安装新的python版本,这样就不会与本地环境的python冲突,在conda下安装软件包,也只能在当前环境下生效,避免与本地环境的冲突。可以方便的对软件以及安装包进行一个管理。
通过以下命令下载:
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh
通过chmod +x 修改文件的权限,然后直接运行脚本文件,按照提示顺序执行即可完成安装。
安装完成后关闭终端,重新打开终端执行conda info即可得到如下信息,表示成功进入conda环境
2、Miniconda 环境搭建
搭建yolo训练工作环境
创建环境:
conda create -n yolov8 python=3.10
通过create -n yolov8的方式创建一个名为yolov8的conda环境,然后再通过python=3.10在创建环境的时候安装对应的python版本,因为yolov8需要的python版本最低为3.7,所以这里以3.10为例安装。
启动环境:
执行以下命令切换到刚才创建的yolov8的环境,可以通过conda env list查看当前的环境
conda activate yolov8
模型训练
1、Yolov8环境安装:
Conda切换到yolov8环境
通过命令进入到创建的yolov8 conda工作环境
conda activate yolov8
Yolov8 ultralytics安装
ultralytics库提供了接口和函数来调用yolov8模型,进行模型的训练检测等功能。可以通过pip install ultralytics 的方式来安装ultralytics 库。在命令后面添加的-i xxxx选项,可以使用国内镜像源来加快下载速度
pip install ultralytics -i https://mirrors.aliyun.com/pypi/simple
安装完成可以通过命令 yolo check检查是否安装正确
2、数据标注
数据标注的软件可以用labelimg和X-AnyLabeling来实现,对于简单的矩形框标注,推荐使用labelimg,而对于复杂的OBB或者是多边形标注,则可以使用X-AnyLabeling。
labelimg标注
1、安装labelimg
pip install labelimg -i https://mirrors.aliyun.com/pypi/simple
2、打开labelimg
通过命令行执行: labelImg
如果打开时报错信息如下,则是缺少对应的依赖库,可以通过以下命令
sudo apt install libxcb-xinerama0
通过菜单栏 view-->勾选 Auto save mode 设置自动保存
将准备好标注的图像通过共享文件夹传到ubuntu环境下,点击Open Dir打开存放图像的文件夹,并点击标注模式切换到YOLO选项,这样保存下来的文件类型就是yolo对应的格式。
Tips:
安装labelimg后,如果使用时会出现异常,需要手动修改相关代码。
当打开软件选择图片后,缩放图片时会弹出报错信息如下:
修改方式:
修改 /home/ubuntu/miniconda3/envs/yolov8/lib/python3.10/site-packages/labelImg/labelImg.py文件内下面3处代码,添加int强制转换
当进行标注的时候,报错如下:
这个错误同样是类型转换时出错,在出错的地方加上强制转换,将float转换为int类型。
修改文件/home/ubuntu/miniconda3/envs/yolov8/lib/python3.10/site-packages/libs/canvas.py
3、数据标注
点击左边栏的”Create RectBox”或者按快捷键”W”,拖动鼠标选中标注物体,然后再弹出的输入框输入标签名,依次对每个图片进行标注
标注完成后输出文件夹内有名字相同的图片和txt文件,对应的txt文件里面数据格式如下,分别表示类别名的index,以及每个框的x,y,width,heigh信息
X-AnyLabeling标注
X-AnyLabeling可以从https://github.com/CVHub520/X-AnyLabeling/releases下载
X-AnyLabeling-CPU是为windows环境下设计的应用,而X-Anylabeliing-Linux-CPU则是在linux环境下的运行应用,如果是在ubuntu环境下运行,则需要下载Linux版本。下载后直接运行 ./X-AnyLabeling-Linux-CPU,会打开软件窗口,然后左上角选择包含图片的文件夹,会将所有图片加入到列表内
然后通过快捷键’W’或者是左边工具栏的”矩形框”,即可开始标注,矩形框选择完成后,会弹出输入标签的菜单,输入对应的标签名
依次处理后,在图片的文件夹内会生成对应名字的json格式文件
将json格式转换为yolo的labeling格式,通过菜单栏export选择YOLO-Hbb选项
弹出一个窗口,需要选择classes.txt文件。classes.txt文件里面包含了标签的名字,因此先创建一个classes.txt文件,里面的内容按照标注的标签顺序排列。比如X-AnyLabeling里面标签的顺序是helmet/aa,则classes.txt里面也需要按照这个顺序排序
选择classes.txt后,会弹出一个提示窗口,需要选择生成的yolo格式的txt文件放置的位置(默认放置在/home/ubuntu/Desktop/labels),以及是否需要将图片和txt文本放在一起,这里以默认为主
确认后会生成一个labels目录,里面包括了yolo格式的txt文件,内容和之前通过labelimg标注的输出一致
3、数据训练
1、下载预训练模型
从https://github.com/ultralytics/assets/releases/ 内下载预训练模型yolov8s.pt,或者是从ultralytics官网上下载https://docs.ultralytics.com/models/yolov8/#supported-tasks-and-modes,点击对应的模型即可下载
2、数据准备
创建一个新文件夹(以yolov8文件夹名字为例),其中包含下载的yolov8s.pt模型文件、一个yaml配置文件,以及一个名为dataset的文件夹,该文件夹内存放了图片和相应的标签txt文件。
1、yaml文件:
这里测试只有1个helmet,所以按照下面的配置生成一个yaml文件
train: /home/ubuntu/yolov8/dataset/images/train/
val: /home/ubuntu/yolov8/dataset/images/val/
nc: 1
names: ['helmet']
如果有多个labe的话,则nc和names需要修改,以2个label为例:
train: /home/ubuntu/yolov8/dataset/images/train/
val: /home/ubuntu/yolov8/dataset/images/val/
nc: 2
names: ['helmet','person']
参数解释:
train: 表示需要训练的图片文件夹路径
val: 表示需要用来验证的图片文件件路径
nc: number class,也就是在标注过程中标签的类别数量
names: 标注时的标签名列表
2、Dataset目录
Dataset文件夹包含了images和labels两个子文件夹,每个子文件夹内又分别包含train和val两个文件夹。在images文件夹的train子文件夹中存放的图片,其数量和文件名必须与labels文件夹中对应的train子文件夹中的标签文件相匹配。
其中目录格式为:
├── dataset
├── images
│ ├── train
│ │ ├── helmet_1.jpeg
│ │ ├── helmet_2.jpeg
│ │ └── helmet_3.jpeg
│ └── val
│ ├── helmet_4.jpg
│ └── helmet_5.jpg
└── labels
├── train
│ ├── helmet_1.txt
│ ├── helmet_2.txt
│ └── helmet_3.txt
└── val
├── helmet_4.txt
└── helmet_5.txt
其中images和labels文件夹的位置必须在同一个目录下,因为后续处理过程中,查找lables的时候是直接替换images为labels,所以dataset下的文件目录必须按照上面的方式放置.
为了提高训练的准确率,数据集的数量必须足够多,而且需要考虑到不同状态下的情况,比如光线的影响,大小的影响,方向的影响等。
3、模型训练
在终端中使用以下命令开始训练:
yolo detect train data=/home/ubuntu/yolov8/my_yolov8.yaml model=yolov8s.pt epochs=10 device=cpu batch=8
参数解释:
model:指定预训练模型的路径,也就是刚才下载的yolov8s.pt的路径
data:指定数据集配置文件的路径,上面生成的yaml文件路径
epochs:指定训练的轮数,即模型对整个数据集的遍历次数,数值越大,训练后的精度越高
device: 0表示使用GPU(默认), cpu表示使用cpu
batch: 指的是在每次参数更新时处理的样本数量。大小的选择对模型的性能、训练速度、收敛效果等都有显著影响。太大对GPU或者内存需求比较大,所以需要根据个人电脑配置情况来决定,如果不做配置,默认为16
训练结束后可视化中间结果和训练完成的模型结果在runs/detect/train目录下面
4、模型测试
训练成功后模型路径为:runs/train/exp/weights/best.pt,可以通过yolo命令验证模型的识别情况,使用下面命令验证,测试结果存放在runs/detect/exp下。
yolo detect predict model=/home/ubuntu/yolov8/runs/detect/train/weights/best.pt source=img_test
参数说明
Model:指定使用测试的模型文件
Source:需要测试的文件或者路径,可以是单个文件,或者是整个文件夹
从结果中可知,helmet_1.jpeg检测到7个目标文件,helmet_2.jpeg检测到5个目标文件,helmet_3.jpeg检测到1个目标文件,最终结果放置在runs/detect/predict文件夹内
模型的测试不准确,识别率不高等情况,与模型训练时的参数,数据集的多少以及标注等都有一定的关系。
pt转onnx模型
为了提高模型的可移植性和兼容性、优化性能以及便于模型部署,需要将pt模型转换成onnx模型,yolo提供脚本转换
安装所需的相关依赖库:
pip install onnx onnxoptimizer onnxruntime onnxslim -i https://mirrors.aliyun.com/pypi/simple
执行模型转换命令:
yolo export model=/home/ubuntu/yolov8/runs/detect/train/weights/best.pt format=onnx imgsz=640
其中imgsz决定了生成的onnx模型的输入尺寸,这个需要根据具体项目的输入来配置,yolov8默认的输入是640*640,这里保持不变
转换完成后最终输出文件为: runs/train/exp/weights/best.onnx
然后可以通过https://netron.app/ 查看器来查看onnx的目录结构,需要重点了解的是模型的输入和输出参数,比如通过netron打开生成的best.onnx文件,点击第一个节点【images】,右边列表显示输入和输出信息
参数解释
INPUTS 中 tensor: float32[1, 3, 640, 640] :
1 表示批次大小(batch size),即一次输入模型的图像数量为 1 张。
3 表示图像的通道数,一般彩色图像为 3 通道(对应 RGB 三个通道)。
640 分别表示图像的高度和宽度,即输入模型的图像尺寸要求为 640×640 像素
OUTPUTS中tensor: float32[1, 5, 8400]:
1 同样是批次大小,和输入相对应,即一次推理输出的结果对应 1 张输入图像。
5 一般表示每个检测框相关的信息数量,常见的是包含目标的置信度以及 4 个坐标值(如中心点坐标和宽高信息)
8400 表示检测框的数量,这里 8400 个检测框是模型在特定设置下对输入图像生成的可能的目标检测框数量。
通过模型的输入输出可知,该模型需要的输入为1张RGB 3通道的图片,图片的分辨率必须是640*640的分辨率,如果图片的输入分辨率不对,则模型在处理图片过程中可能会出现异常,或者是输出结果完全不正确,因此在处理前需要将图片转为模型要求的输入格式(RGB通道和分辨率)
onnx模型转nb模型
SP7350内置NPU硬件模块,可以通过NPU进行对模型的加速处理,因此为了能在SP7350平台上部署使用模型文件,需要将生成的onnx模型文件转换为SP7350可识别的nb模型,这样才可以发挥NPU的硬件加速功能。
针对模型的转换,提供了Docker环境,通过docker可以简化转换操作,而无需进行繁琐的环境配置和软件安装等操作
Docker安装
安装依赖包
sudo apt install apt-transport-https ca-certificates curl software-properties-common
添加秘钥
添加 Docker 官方的 GPG 密钥,以确保下载的软件包是来自 Docker 官方且未被篡改
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
添加 Docker 软件源
将 Docker 的官方软件源添加到系统中,以便后续安装 Docker 相关软件包
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
更新软件包
再次更新软件包列表,让系统识别新添加的 Docker 软件源中的软件包
sudo apt update
安装 Docker Engine
安装 Docker 的核心组件 Docker Engine
sudo apt install -y docker-ce docker-ce-cli containerd.io
添加用户组
将当前用户添加到docker组,这样就可以避免每次执行命令时添加sudo操作。其中ubuntu是个人的用户名
sudo usermod -aG docker ubuntu
安装测试
然后可以通过docker --version测试是否正常
docker --version
模型转换
准备工程环境
创建一个新的文件夹
mkdir nb_out && cd nb_out
拷贝onnx到文件夹内
将之前生成的runs/train/exp/weights/best.onnx文件复制到该文件夹中。将onnx复制到文件夹后修改任意名字,这里以yolov8s为例
cp /home/ubuntu/yolov8/runs/detect/train/weights/best.onnx yolov8s.onnx
拷贝图片到文件夹内
选择一个图片放到文件夹内,这个图片要求分辨率必须和模型的输入尺寸一致,从上面模型网络查看器所知,模型的输入尺寸是640*640,因此我们需要将图片的分辨率也转换为640*640
1、Windows下可以通过电脑自带的画图工具来调整图像大小
2、Ubuntu下通过imagemagick来调整,首先通过
sudo apt install imagemagick
安装ImageMagick,然后执行下面的命令,即可将图片转换640*640分辨率
convert helmet_1.jpeg -resize 640x640! helmet_1.jpeg
图片的分辨率修改为模型输入分辨率后,拷贝到当前文件夹内
dataset.txt文件夹
将刚才放到文件夹内图片的名字写入到dataset.txt内。
假如图片名字是helmet_1.jpeg,则执行下面命令生成dataset.txt文件并将图片名字写入到dataset.txt内
echo ./helmet_1.jpeg > dataset.txt
此时该文件夹内的文件如下,包含3个文件:
模型转换
1、创建docker别名
alias npu='sudo docker run -it --rm -u $(id -u):$(id -g) -v /:/mnt -w /mnt$(pwd) registry.cn-chengdu.aliyuncs.com/sunmedia/npu:slim npu'
执行以上命令,会创建一个npu的别名,用来代替sudo docker xxxxx的命令,同时第一次执行会从registry.cn-chengdu.aliyuncs.com/sunmedia/npu:slim下抓取提供的docker镜像
2、模型转换
npu yolov8s.onnx "/model.22/Sigmoid_output_0 /model.22/Mul_2_output_0"
第三个参数为模型输出的节点名称,添加这个参数是为了提高模型的精度,因为如果直接使用模型的最终输出节点,一个输出里面包含了0--1范围的置信度的结果以及0--640范围的边框结果,直接将这两个数据同时输入到同一个软件流程中进行处理,由于数据范围差异过大,可能会导致处理结果的精度降低。
不同模型的输出节点不同,具体可以参考代码snnf/snnf_release/nnmodels/sources/models/official中各种模型范例给出的节点。
节点的选取和模型的后处理(postprocess)相关,如果节点选取和参考模型范例的不同,则对应的后处理流程也不同,不能直接使用参考模型范例的流程。因此为了方便后续的功能开发,模型转换时节点的选取和顺序也必须按照软件中的一致,这样就可以做到和示例代码的流程一致,直接使用默认的模型后处理流程,比如yolov8的示例代码使用的是右边这2个节点
通过模型可视化工具查看最后【concat】节点的的输入即为模型转换时需要的2个节点名称
预下载的yolo预下载的yolo模型可能会更新导致节点名称和代码的不一致,我们只要选择对应的节点即可,按照模型查看器的节点作为转换时的输入参数。
正常执行以上命令后会生成2个yml和json文件
3、模型量化
选择模型量化参数,目前我们支持的量化参数主要为常用的int8和int16。量化参数不同主要体现在模型大小、推理速度、精度以及存储上,因此需要根据实际运用来选择量化参数。
npu yolov8s.onnx 16
执行完成后,会生成一个yolov8s_16.nb文件,这个就是我们最终所需要的模型文件
模型部署
上面的所有操作都是在ubuntu虚拟即上实现的,后续模型的部署主要似乎将模型转换后的nb文件应用在SP7350的平台上,所以后续的操作都是基于SP7350平台
配置平台环境
gcc、make、cmake安装
进入平台的console后,执行make和gcc,查看当前系统中是否已经安装了编译相关的工具
如果提示找不到当前命令,则需要通过apt install的方式安装gcc以及make等编译相关的tool
sudo apt install build-essential cmake
opencv安装
如果提示找不到opencv的相关头文件,原因是系统里没有安装opencv,需要通过apt install安装opencv
sudo apt install libopencv-dev
SDK下载编译
下载SDK
在平台上执行下载snnf_release和NPU sdk
git clone https://gitee.com/sunplus-group/snnf.git
解压SDK
首先是将分割的snnf sdk合并为一个
cat snnf_release.part.* > snnf_release.tar.gz
删除无用的分割文件
rm -rf snnf_release.part.*
通过以下命令解压
tar -xf snnf_release.tar.gz && tar -xf NPUSdk-6.4.18.5.tar.xz
解压后生成sdk和snnf_release文件夹
snnf_release: Snnf的sdk代码,里面包括了多种模型的处理流程以及使用sample
sdk: 编译snnf代码时所需要的NPU相关依赖文件
修改代码
因为生成的nb模型是基于YoloV8s官方的预处理模型来转换的,我们与SDK中yolov8模型的处理流程主要差异体现在物体识别的类别和数量上(确保转换模型时节点的选取是按照软件中模型初始化流程中的顺序和节点名选取),因此我们只需要修改Yolov8s代码关于类别的部分即可(后续SDK版本会提供模型差异部分的配置文件,如果基于官方的yolo模型转换,则无需修改任何代码)
主要差异点在于
官方模型的类别是80个,但是新生成的模型只包含1个类别,因此只需要修改snnf/nnmodels/sources/models/official/yoloV8s_detection/sources/YoloV8sDetectionPostProcess.h中的MAX_CLASS_LABEL_NUM为训练模型的类别数量即可
类别名字差异
Yolov8s默认支持80个类别,拥有80个label name,而我们只有一个label name为helmet的类别,因此我们需要修改snnf/nnmodels/sources/models/official/yoloV8s_detection/sources/YoloV8sDetectionModel.cpp里面的label name,以匹配我们模型所包含的类别名称
代码编译
进入snnf_release目录以编译snnf SDK。默认情况下,snnf SDK会对所有模型进行编译,这可能导致初次编译耗时较长。为了优化这一过程,我们可以通过编辑snnf_release目录下的make_config.mk文件来配置需要编译的模型。下图红色框内列出的是默认情况下可以禁用的模型。
配置完成后进入到snnf_release下执行
sunplus@ubuntu ~/s/snnf_release> ./snnf_build.sh
编译整个工程,编译完成后的log信息如下图所示
模型测试
可以通过snnf SDK提供的sample来测试模型,文件路径为:
/home/sunplus/snnf/snnf_release/release/samples/single_model/singleModelTest.cpp
需要修改的是下图2个部分:
在模型选择方面,目前我们仅支持Yolov5和Yolov8模型的测试。您可以选择Yolov5或Yolov8进行测试。图中通过双斜杠屏蔽的代码是专为Yolov5模型测试设计的,而下方的代码则适用于Yolov8模型测试。只需更改模型存储路径即可。该路径是相对于/home/sunplus/snnf/snnf_release/release目录的,建议使用绝对路径以确保准确性。
关于测试图片的路径,测试图片的分辨率并不需要与模型输入完全一致。在软件处理流程中,图片会在输入模型之前根据模型的输入要求自动进行resize调整。图片路径也应基于/home/sunplus/snnf/snnf_release/release目录来设定。同样建议使用绝对路径,以避免因路径问题导致图片无法找到的错误。
编译测试文件
按照上面的流程修改测试代码后,需要针对sample代码进行编译,进入到snnf_release/resease目录下,执行
sunplus@ubuntu ~/s/s/release> ./snnf_build_sample.sh --c3v
即可编译sample下面的4个测试代码。如果只想单独编译某个测试代码,可以在修改snnf_build_sample.sh文件里面的这部分代码,只保留需要测试的部分即可。
#!/bin/bash
# configure samples list
samples=(
"single_model"
"sequential_model"
"yolov8s_map"
"tracking"
)
sample运行
首先需要添加snnf到环境变量里面,进入到release目录下面执行
sunplus@ubuntu ~/s/s/release> source snnf_env.sh
然后执行以下命令运行测试程序
sunplus@ubuntu ~/s/s/release> ./bin/snnf_single_model
执行结束后的log信息如下
sunplus@ubuntu ~/s/s/release> ./bin/snnf_single_model
1737862166749|7f89ee7040|T|common: [app]the result: (box: 573.4600 0.0000 330.0254 800.0000) --> label: 0(helmet), confidence: 0.58, fin: false
1737862166749|7f89ee7040|T|common: [app]the result: (box: 678.4893 141.9646 85.1904 53.0981) --> label: 0(helmet), confidence: 0.56, fin: true
box: 573.4600 0.0000 330.0254 800.0000 表示检测到物体的坐标,这四个数值分别代表物体的x坐标、y坐标以及宽度和高度。
label: 0(helmet) 表示检测到物体的类别名称。
confidence: 0.58 表示检测到物体的置信度,数值越高,意味着物体检测的准确性越高。
fin: false/true 表示针对当前图片的物体检测是否已经完成。在软件的处理流程中,图片上的每个物体都会被逐一检测处理。当所有物体都检测完毕,fin的值将返回true。
因此,通过这些信息,我们可以得知图片中被检测到的物体类别及其坐标。当fin为true时,表示对图片的检测已完成,即可针对图片中物体识别后进行后续的处理。