A1000学习笔记
记录自己学习A1000的时候的笔记
一、ubuntu安装bstnnx docker环境
1.导入镜像
从BST项目空间中下载文件,将bsnn_release_4.2.0中的所有文件下载到主目录中的toolchain文件夹中,进入终端导入image
docker load -i ./bsnn_tools_docker_4.2.0.tar
2.创建容器
创建container
方法一(黑芝麻):
./run_docker_container.sh --root --keep --network=host
方法二:
docker exec -it bsnn-tools-container-stk-4.2.0 /bin/bash
可选(容器改名):
docker rename old_container new_container
3.使用jupyter
打开jupyter服务,可视化查看方便一点
jupyter notebook list
4.申请并部署license文件
ubuntu查看MAC地址:ifconfig
用企业邮箱,联系黑芝麻技术人员,提供MAC地址得到license文件。
部署license文件:
docker cp license.lic bsnn-tools-container-stk-4.2.0:/workspace/license.lic
修改/workspace/tools/Net-FW/utilities/script/xtensa_setup.sh文件的license地址
export XTENSAD_LICENSE_FILE='/workspace/license.lic'
至此,基于toolchain docker 转换工具链bsnn_release_4.2.0的bstnnx docker环境就安装完成。
二、yolov5训练onnx转换
使用代码为黑芝麻网站中的 yolov5 float 文件。其中的bst_yolov5工程已经修改了训练方式和激活函数,并且添加了opt优化。
1.环境与数据集检查
datasets路径中有coco128数据集
环境按照requirements.txt中的配置(清华源:-i https://pypi.tuna.tsinghua.edu.cn/simple)
2.模型训练
python train.py --data coco128.yaml --weights yolov5n.pt --img 640 --epochs 300
结果会保存在 runs/trian/exp 中。将weights中的 best.pt 拷贝到 bst_yolov5/yolov5中,并重命名yolov5n.pt
可能遇到的问题:训练出现AttributeError: 'FreeTypeFont' object has no attribute 'getsize'报错
原因:新版本的 Pillow删除了该getsize 功能,降级到 Pillow 9.5 就可以解决
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple Pillow==9.5
3.onnx转换 并 验证
yolov5 float中的export.py代码与官网中的有所改动。
转换代码:
python export.py --weights yolov5n.pt --include=onnx
验证代码(保存路径 yolov5/runs/val/exp2):
python val.py --weights yolov5n.onnx --data coco128.yaml --img 640
测试代码(保存路径 yolov5/runs/detect/exp ):
python detect.py --weights yolov5n.onnx --source test.jpg
三、toolchain模型转换
1.准备toolchain工具模型转换所需的文件
新建一个yolov5_bstnnx文件夹,要包含下列文件
1)inputs_jpg
2)image_process_config
{
"source_image_format": "RGB", // 输入图像的颜色格式
"target_image_format": "RGB", // 目标图像的颜色格式
"mean": [0, 0, 0], // 均值 (mean),通常用于归一化
"scale": [0.00390625, 0.00390625, 0.00390625] // 缩放因子 (scale)
}
3)run.yaml
# 目标推理设备(比如 AI 加速器)
device_engine: A1000B0
# 量化后的模型名称
model_name: yolov5n
# ONNX 格式的浮点模型路径
model_path: /workspace/models/yolov5_bstnnx/yolov5n.onnx
# 量化校准数据集(用于 PTQ 量化)
input_data_set_path: /workspace/models/yolov5_bstnnx/inputs_jpg
# 数据读取方法
data_reader_method: image_folder_data_reader
# 归一化计算方式
# mean = mean; scale = np.floor(std/2**-12 + 0.5) * 2**-12 -> std=1/255 -> scale = 0.00390625
image_process_config: /workspace/models/yolov5_bstnnx/image_process_config.json
# 量化时使用的校准数据量
size_limit: 500
# 是否启用自动 PTQ(Post Training Quantization)
auto_ptq: /workspace/models/yolov5_bstnnx/task_info_for_autoptq.yaml
# 量化和优化后的输出目录
result_dir: /workspace/models/yolov5_bstnnx/auto_ptq_yolov5n
# 量化 & 编译的优先级范围
priority_range: 100-1200
# General stage settings
stage:
- stage_name: pre_processing_stage
priority: 100
- stage_name: graph_optimization_stage
priority: 200
- stage_name: quantization_stage
priority: 300
- stage_name: graph_partition_stage
priority: 400
- stage_name: section_binding_stage
priority: 500
- stage_name: code_generation_stage
priority: 600
- stage_name: code_compilation_stage
priority: 700
- stage_name: run_emulation_stage
profiling_mode: 2
priority: 800
- stage_name: hardware_testing_stage
XTSC_NET_SIM: True
generate_rbf_only: True
priority: 1100
- stage_name: report_generation_stage
priority: 1200
- stage_name: userland_stage
priority: 1500
4)task_info_for_autoptq.yaml
task_settings:
# 设置量化方式,使用 per-channel KL 量化:
# - per-channel: 每个通道独立量化,提升精度
# - KL(Kullback-Leibler 散度): 计算最优量化范围,使量化数据与原数据分布最接近
quantization_method: ["weight_perchannel_kl"]
# 是否将部分 int8 卷积转换为 int16,提升计算精度,但会增加计算量
# - [[]] 表示不转换,全部保持 int8
# - 例如: [[], ["/model.24/m.0/Conv", "/model.24/m.1/Conv"]] 可指定某些层用 int16
convert_int8conv_to_int16: [[]]
# 量化过程中,不可调整的激活层范围(-1, 0, 1),默认值不变
unadjustable_activations_last_n: [-1, 0, 1]
# 设置激活量化校准方法(决定如何计算 scale & zero-point):
# - minmax: 直接取最小-最大值,可能受异常值影响
# - kl: 使用 KL 散度优化量化范围,适用于复杂模型
# - percentile_0.999: 99.9% 分位数截断,忽略 0.1% 极端值,减少异常值影响
calibration_method: ["minmax", "kl", "percentile_0.999"]
# 下面是其他可选的校准方法(已注释掉),可以尝试不同分位数:
# calibration_method: ["minmax", "kl", "percentile_0.999", "percentile_0.998", "percentile_0.997", "percentile_0.996", "percentile_0.995"]
# 是否自动更新任务:
# - false(默认): 需要手动调整任务队列
# - true: 允许自动调整 `task_order` 并追加新任务,适用于实验调优
auto_update: false
# 任务队列的模式(已注释),可用于自定义量化任务顺序:
# task_order_schema:
# ["index", "quantization_method", "convert_int8conv_to_int16",
# "unadjustable_activations_last_n", "calibration_method"]
5)yolov5n.onnx文件
2.将yolov5_bstnnx文件夹 复制到 模型转换容器
运行bsnn-tools-container-stk-4.2.0容器,将yolov5_bstnnx拷贝到bsnn-tools-container-stk-4.2.0容器中,我已将bsnn-tools-container-stk-4.2.0容器改名为bsnn_4.2(更简洁):
docker cp yolov5_bstnnx bsnn_4.2:/workspace/models/
3.进行模型转换
在容器中运行指令:
bstnnx_run --config models/yolov5_bstnnx/run.yaml
把结果/workspace/auto_ptq_yolov5n/1100_HardwareTestingStage/yolov5n.hw_test_config拷贝回ubuntu中:
docker cp bsnn_4.2:/workspace/auto_ptq_yolov5n/1100_HardwareTestingStage/yolov5n.hw_test_config /home/chy/文档/BSNN相关
四、基于转换后的模型文件,创建编译cmake工程
1.查看黑芝麻cmake工程demo
其中:
1)3rdparty和usr两个文件夹是bst-bsnn相关库文件等;
2)yolov5model是通过toolchain转换后1100_HardwareTestingStage 后缀.hw_test_config中 得到的weights.bin、.meta、.lib三个文件;
3)src中就是检测程序;
4)start_yolov5m.sh是后面在开发板上运行用到的运行脚本。
2.创建自己的cmake工程
新建一个yolov5demo文件夹,将demo中的3rdparty、usr、src、CMakeLists.txt直接拷贝进来,并新建一个yolov5n_model文件夹,将前面yolov5n.hw_test_config中weights.bin,及fw_integration中.meta、.lib文件,拷贝到cmake工程yolov5demo/yolov5n_model中并重命名::
3.修改代码
如果用的是其他的yolov5模型,请去修改cmakelist.txt里的对应部分。
修改src/main.cpp ,五显示器,所以注释了cv显示部分,增加检测结果图片保存
#include <iostream>
#include <opencv2/opencv.hpp>
#include "bsnn_model_load.h"
#include "drmshow.h"
#include "image_process.h"
#include <string.h>
using namespace std;
int main(int argc, char* argv[])
{
// std::string in_image_path = "./000000000139.jpg";
std::string in_image_path = "./fad_video.avi"; // 默认输入视频路径
std::string bsnn_model_path = "./model"; // 定义 BSNN 模型路径
cv::Mat img, input_image; // 定义 OpenCV 矩阵用于存储原始图像和处理后的输入图像
// asic_type_check();
// 如果命令行参数提供了输入文件路径,则覆盖默认路径
if(2 <= argc) {
in_image_path = argv[1];
}
// 如果命令行参数提供了模型路径,则覆盖默认路径
if(3 <= argc) {
bsnn_model_path = argv[2];
}
// 打开视频文件或图片
cv::VideoCapture capture(in_image_path);
BSNN_MODEL bsnn_model(bsnn_model_path); // 加载 BSNN 模型
Timer time, fps; // 定义计时器用于测量 FPS 和时间消耗
while (true)
{
// step 1 图片预处理
capture >> img; // 读取视频帧
if(img.empty()) // 如果读取失败(视频播放结束)
{
printf("img.empty = %d\n",img.empty()); // 输出错误信息
capture.release(); // 释放视频流
capture.open(in_image_path); // 重新打开视频文件
continue;
}
// 重置计时器
time.reset();
fps.reset();
preprocess(img, input_image); // 对图像进行预处理
size_t input_img_len = 3 * IMG_HEIGHT * IMG_WIDTH; // 计算输入图像的字节大小(RGB 三通道)
// 更改图片在内存中的存储方式为WHD
if (!input_image.isContinuous())
printf("-> input image is not continuous in memory...");
uchar input_buf[input_img_len] = {0}; // 创建存储输入图像数据的缓冲区
// 调整输入图像数据的排列方式,从 HWC (height, width, channel) 转换为 CHW (channel, height, width)
for (int c = 0; c < 3; c++)
{
for (int i = 0; i < IMG_HEIGHT; i++)
{
for (int j = 0; j < IMG_WIDTH; j++)
{
input_buf[c * IMG_HEIGHT * IMG_WIDTH + i * IMG_WIDTH + j] = input_image.data[3 * (i * IMG_WIDTH + j) + c];
}
}
}
cout << "-> preprocess time : " << time.elapsed() << endl; // 输出预处理时间
// step 2 模型推理
time.reset();
bsnn_model.Run(input_buf, input_img_len); // 运行模型推理
auto bsnn_output = bsnn_model.GetModelOutput(); // 获取模型推理结果
// 计算推理 FPS(帧率),并输出模型推理时间
printf("-> lite engine inference FPS: %.2f\n", 1.0 / time.elapsed() * 1000);
cout << "-> bsnn model inference time : " << time.elapsed() << endl;
// step 3 后处理
time.reset();
std::vector<ObjInfo> result; // 定义存储目标检测结果的向量
process_output(bsnn_output.get(), result); // 解析模型输出,提取检测到的目标信息
// cout << "-> The number of objects detected: " << result.size() << endl;
cout << "-> post process time : " << time.elapsed() << endl;
draw_bboxes(img, result);
cv::imwrite("./inferresult.jpg",img);
bsnn_model.ReleaseOutputBuffer();
// printf("-> full flow FPS: %.2f\n", 1.0 / fps.elapsed() * 1000);
cv::Mat show_img;
cv::resize(img, show_img, cv::Size(1280, 720));
//cv::imshow("img", show_img);
//cv::waitKey(1);
}
return 0;
}
4.编译工程
启动a1000b-sdk-fad-2.3.1.2容器(我改名为sdk_2.3.1.2),将yolov5demo拷贝到容器中:
docker cp yolov5demo sdk_2.3.1.2:opt/bstos/2.3.1.2/sysroots/aarch64-bst-linux/usr/include/src
容器中编译
cd yolov5demo
mkdir build
cd build
cmake ..
make
五、开发板运行
1.将编译好的yolov5demo从容器拷贝回ubuntu
docker cp sdk_2.3.1.2:opt/bstos/2.3.1.2/sysroots/aarch64-bst-linux/usr/include/src/yolov5demo /home/chy/文档/BSNN相关
2.整合运行文件
在yolov5demo中新建一个yolov5demo_run文件夹
1)app文件夹
将yolov5demo中的build文件夹中的可执行文件yolov5n拷贝到app文件夹
2)yolov5n文件夹
将yolov5n_model文件夹的三个文件拷贝到app文件夹
3)datasets文件夹
4)运行脚本文件
创建start_yolov5s.sh
#!/bin/sh
mkdir -p /run/user/1000
export XDG_RUNTIME_DIR="/run/user/1000"
echo 0 > /sys/devices/platform/vsp@1/enable && weston --tty=1 &
./app/yolov5n ./datasets/fad_video.avi ./yolov5n
3.运行
1)拷贝
把yolov5demo_run文件夹从ubuntu拷贝到开发板。并把yolov5demo中的 usr/lib64 文件夹下的文件,cp到开发板 /usr/lib 文件夹下
2)运行
cd /userdata/yolov5demo_run
chmod +x start_yolov5n.sh
./start_yolov5n.sh