目录
- 准备代码、权重、数据集
- 配置环境
- 准备数据
- 标注数据
- 训练模型
- 转换模型
- 验证模型
- 准备校准数据
- 转换为板上模型
- 模型精度分析
- 上板
之前训练自己模型的时候使用的是博主 bubbling的1.0分支的代码,博主的 博客比较详细,使用的是VOC2007数据集,可以快速上手根具需要训练自己的模型。不过最近需要将yolov5的模型部署到旭日X3派的开发板上,参考教程和社区帖子一阵折腾,成功转换模型并运行了,就是检测的结果很不理想(后续补坑,看看么个事儿)。猜想可能是版本问题,模型后处理过程不同导致,决定按教程里面,使用 官方2.0分支训练部署模型试试。
准备代码、权重、数据集
在准备放置yolov5工程的文件目录打开终端,使用命令:
git clone https://github.com/ultralytics/yolov5 # clone repo
cd yolov5
git reset --hard 5e970d4 # last commit before v2.0
或者直接在官方2.0分支页面Assets下点击下载Sources code(zip)并解压。接着下载yolov5l/m/s/x.pt这些预训练权重文件(分别对应大/中/小/较大),建议先使用yolov5s.pt试试,下载后放在解压后的yolov5-2.0文件夹下的weights文件夹下。
配置环境
conda create -n yolo python=3.8.10
在yolov5工程文件夹中右键打开终端,使用创建的yolo环境
conda activate yolo
安装依赖:
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
然后运行一下命令,对/inference/images中的图片作一个检测:
python detect.py --weights weights/yolov5s.pt --img 416 --conf 0.4 --source inference/images/
可以看到/inference/output文件中已有结果。
准备数据
在yolov5-2.0/data文件夹下打开终端:
bash get_coco2017.sh
没有魔法大概率连接不了下载coco数据集的网站,可以使用百度网盘下载一个coco128数据集,可以看到coco128数据集中的图片文件的存放和/data/coco128.yaml中train:描述的路径一致,coco128中labels中存放为yolo格式的.txt标注文件,文件名称和images中的图片一一对应。
可以将自己的数据集图片存放在yolov5-2.0/data/coco128/images/train2017中。
修改/data/coco128.yaml中的train:和val:为./data/coco128/images/train2017/nc:为自己标注的类别数量,names:为标注时使用的标签名称。
标注数据
在yolo环境中使用清华源镜像安装标注工具labelImg
(yolo)xxx:~$ pip install labelImg -i https://pypi.tuna.tsinghua.edu.cn/simple
安装成功后,运行labelImg
(yolo)xxx:~$ labelImg
打开目录选择yolov5-2.0/data/coco128/images/train2017;改变存放目录选择yolov5-2.0/data/coco128/labels/train2017(标注产生的文件将保存在此位置);格式选择YOLO;点击创建区块,使用矩形框选要识别检测的物体并给定标签:xxx;点击查看,可勾选自动保存模式;滑动鼠标滚轮可对待标注图片进行放大缩小。
训练模型
数据准备好后,运行下列命令进行训练:
python train.py --img 640 --batch 16 --epochs 100 --data ./data/coco128.yaml --cfg ./models/yolov5s.yaml --weights ./weights/yolov5s.pt
训练过程中可能出现如下错误:
1.
from google.protobuf.pyext import _message
TypeError: bases must be types
protobuf版本太高,降低版本
pip install protobuf==3.19.6 -i https://pypi.tuna.tsinghua.edu.cn/simple
运行命令后可能会提示tensorboard x.xx.xx requires protobuf>=x.xx.xx,根据提示将上述命令中坂本改为protobuf>=x.xx.xx的版本即可,若有其他冲突,可改变提示其他库的版本。
b[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image)
RuntimeError: a view of a leaf Variable that requires grad is being used in an in-place operation.
修改yolov5-2.0/models/yolo.py"的131行左右,将in _initialize_biases修改为如下:
def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class frequency
# cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1.
m = self.model[-1] # Detect() module
for mi, s in zip(m.m, m.stride): # from
b = mi.bias.view(m.na, -1) # conv.bias(255) to (3,85)
with torch.no_grad():
b[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image)
b[:, 5:] += math.log(0.6 / (m.nc - 0.99)) if cf is None else torch.log(cf / cf.sum()) # cls
mi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True)
即增加with torch.no_grad():
禁用梯度运算。
3.
image = image.resize((scaled_width, scaled_height), Image.ANTIALIAS)
AttributeError: module 'PIL.Image' has no attribute 'ANTIALIAS'
在pillow的高版本中,'ANTIALIAS’方法被弃用了,可将Image.ANTIALIAS
修改为Image.LANCZOS
,或者降低pillow版本
pip install pillow==9.5.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
训练好的模型权重文件保存在run/exp0/weights,分为best.pt和last.pt,分别为最小损失模型权重和最后一个世代模型权重。
转换模型
选择runs/exp2/weights/best.pt进行转换,修改yolov5-2.0中/models/export.py中第48行为:
torch.onnx.export(model, img, f, verbose=False, opset_version=11, input_names=['images'],
output_names=['classes', 'boxes'] if y is None else ['output'])
opset_version由12修改为11,yolo.py第29行修改为:
x[i] = x[i].permute(0, 2, 3, 1).contiguous()
然后运行命令:
export PYTHONPATH="$PWD"
python models/export.py --weights ./runs/exp2/weights/best.pt --img-size 640 --batch-size 1
如没有安装onnx和coremltoos,则会出现如下提示信息:
ONNX export failure: No module named 'onnx'
CoreML export failure: No module named 'coremltools'
可使用命令进行安装:
pip install onnx==1.7.0 coremltools -i https://pypi.tuna.tsinghua.edu.cn/simple
onnx的版本好像没有特别限制,1.11.0试了也可以,估计是版本不要太高,然后和环境中已有的安装库不冲突即可。
转换完成后,best.onnx会在best.pt同级文件目录下。
将best.onnx复制到OE开发包即horizon_xj3_open_explorer_v2.5.2-py38_20230331文件夹的/ddk/samples/ai_toolchain/horizon_model_convert_sample/01_common/model_zoo/mapper/detection/yolov5_onnx_optimized文件路径下。
打开终端,进入OE包首层路径
cd horizon_xj3_open_explorer_v2.5.2-py38_20230331
也可先进入OE包即horizon_xj3_open_explorer_v2.5.2-py38_20230331文件夹,右键选择打开终端。
然后激活horizon_bpu环境
conda activate horizon_bpu
在OE包中创建data文件夹,/data 为数据集文件目录,如果该目录不存在会导致加载问题,创建好后再运行命令:
bash run_docker.sh data/ cpu
成功
Docker version is v2.5.2
Dataset path is /home/tjuqz/horizon_xj3_open_explorer_v2.5.2-py38_20230331/data
OpenExplorer package path is /home/tjuqz/horizon_xj3_open_explorer_v2.5.2-py38_20230331
Unable to find image 'openexplorer/ai_toolchain_ubuntu_20_xj3_cpu:v2.5.2' locally
v2.5.2: Pulling from openexplorer/ai_toolchain_ubuntu_20_xj3_cpu
Digest: sha256:e47c6d874426d1bea80b681a8e867ea43b9236aa2b54979d95706eb5f42b85b5
Status: Downloaded newer image for openexplorer/ai_toolchain_ubuntu_20_xj3_cpu:v2.5.2
root@1ff840d9d93f:/open_explorer#
下面我们主要使用/ddk/samples/ai_toolchain/horizon_model_convert_sample/04_detection/03_yolov5s/mapper下的示例进行操作,在终端运行:
root@1ff840d9d93f:/open_explorer# cd ddk/samples/ai_toolchain/horizon_model_convert_sample/04_detection/03_yolov5s/mapper
验证模型
使用hb_mapper checker后面跟对应参数对模型进行验证,修改上面提到的03_yolov5s/mapper下01_check.sh中语句onnx_model="../../../01_common/model_zoo/mapper/detection/yolov5_onnx_optimized/best.onnx"
,即改为要验证的模型,接着运行命令:
bash 01_check.sh
命令行出现:
...
...
INFO End model checking....
无其他错误提示信息,应该是没有问题的,模型检查过程中的输出信息保存在hb_mapper_checker.log文件中,可查看具体输出信息。
准备校准数据
将自己训练模型使用的数据(选择了50张作为校准数据)放在/ddk/samples/ai_toolchain/horizon_model_convert_sample/01_common/calibration_data/coco文件夹中。
在上面提到的03_yolov5s/mapper下修改preprocess.py第23行修改为PadResizeTransformer(target_size=(640, 640)),(640,640)为训练时使用的图片输入大小,可根据自己情况修改。
然后运行02_preprocess.sh
root@1ff840d9d93f:/open_explorer/ddk/samples/ai_toolchain
/horizon_model_convert_sample/04_detection/03_yolov5s
/mapper# bash 02_preprocess.sh
终端出现:
write:./calibration_data_bgr_f32/1.bgr
write:./calibration_data_bgr_f32/2.bgr
write:./calibration_data_bgr_f32/3.bgr
write:./calibration_data_bgr_f32/5.bgr
write:./calibration_data_bgr_f32/6.bgr
write:./calibration_data_bgr_f32/7.bgr
转换后的数据文件夹为calibration_data_bgr_f32
转换为板上模型
在上面提到的03_yolov5s/mapper下修改yolov5s_config.yaml中第16行为:onnx_model: '../../../01_common/model_zoo/mapper/detection/yolov5_onnx_optimized/best.onnx'
,第37行为:output_model_file_prefix: 'best_640x640_nv12'
然后可运行如下命令进行转换:
root@1ff840d9d93f:/open_explorer/ddk/samples/ai_toolchain
/horizon_model_convert_sample/04_detection/03_yolov5s
/mapper# bash 03_build.sh
终端出现提示信息:
...
INFO End Model Convert
转换的过程中的输出信息保存在hb_mapper_makertbin.log文件中,可查看具体输出信息;转换后的模型保存在model_output文件夹下。
模型精度分析
在上面提到的03_yolov5s/mapper下修改coco_metric.py中第22行为:
class_names = [
"xxx",
]
其中xxx为训练数据时采用的数据集标注时给的标签。
修改postprocess.py第30行为:yolov5s_config.NUM_CLASSES = 1
,
第57行为:
model_output[0] = model_output[0].reshape([1, 80, 80, 3,
6]).transpose([0, 3, 1, 2, 4])
model_output[1] = model_output[1].reshape([1, 40, 40, 3,
6]).transpose([0, 3, 1, 2, 4])
model_output[2] = model_output[2].reshape([1, 20, 20, 3,
6]).transpose([0, 3, 1, 2, 4])
04_inference.sh第16和20行改为quanti_model_file="./model_output/best_640x640_nv12_quantized_model.onnx"
,original_model_file="./model_output/best_640x640_nv12_original_float_model.onnx"
,第33行改为infer_image="../../../01_common/test_data/det_images/666.jpg"
,其中666.jpg为测试你模型效果的图片,存放在OE包/ddk/samples/ai_toolchain/horizon_model_convert_sample/01_common/test_data/det_images下。
运行:
bash 04_inference.sh
可以看到mapper下生成demo.jpg为测试图片的检测结果(教程中提到测试结果应该大致和上板运行效果无异,不过我在板上运行,识别效果还是有些偏差)。
上板
然后可以将model_output下best_640x640_nv12.bin复制到开发板上运行,参见上一篇文章,不再赘述。