合肥如何做百度的网站,网页设计与制作项目教程素材,安宁网站建设与制作,wordpress4.95中文版00 简介
用C编写代码的比mircopython要慢很多#xff0c;需要编译开发环境#xff0c;同时使用C更接近底层#xff0c;效率利用率应该也是更高的#xff0c;就是需要学习更多的内容#xff0c;因为从零开始因此比较比较耗时。 注#xff1a;以下为个人角度的理解#x…00 简介
用C编写代码的比mircopython要慢很多需要编译开发环境同时使用C更接近底层效率利用率应该也是更高的就是需要学习更多的内容因为从零开始因此比较比较耗时。 注以下为个人角度的理解不一定正确。
根据官方文档开发的主要流程 1编译开发环境k230_sdk 运行环境ubuntu20.04(用于编译k230能够运行的二进制文件) 2AI 模型开发开发工具众多tensorflow、onnx其他模型转换为onnx格式 3模型转换深度学习开发的模型转换为运行在k230上的模型kmodel格式 4C 编写模型的加载等过程 5上板验证将生成文件加载至SD 卡中并在出口终端查看输出结果
01 开发环境编译
最好参考github上的描述官网的信息有一定的延迟 git clone https://github.com/kendryte/k230_sdk
cd k230_sdk
source tools/get_download_url.sh make prepare_sourcecode
docker build -f tools/docker/Dockerfile -t k230_docker tools/docker
# 如果上一个命令不好用采用下面的命令
# docker pull ghcr.io/kendryte/k230_sdk
docker run -u root -it -v $(pwd):$(pwd) -v $(pwd)/toolchain:/opt/toolchain -w $(pwd) k230_docker /bin/bash
# 下面的任选其一
make CONFk230_canmv_defconfig #编译CanMV-K230 1.0/1.1 板子LinuxRTT双系统镜像
make CONFk230_canmv_only_rtt_defconfig #编译CanMV-K230 1.0/1.1 板子RTT-only系统镜像01studio的linux没搞好仍采用canmv k230 1.0版本
02 AI 模型开发
因为这个是sdk中已经存在的模型mbv2.tflite看起来像是XX模型 模型路径为
cd k230_sdk/src/big/nncase/examples/models将模型用netron打开
03 模型转换
该部分将mbv2.tflite转换为kmodel模型这部分可以参照sdk中的README.md文档 文档路径
cd k230_sdk/src/big/nncase/examples文档中是3个例子下面将具体介绍image_classify模型因为它相对简单易于学习。 README.md文档中需要运行
# 进入sdk目录
cd /path/to/k230_sdk
# 运行docker
docker run -u root -it --rm -v $(pwd):/mnt -v $(pwd)/toolchain:/opt/toolchain -w /mnt ghcr.io/kendryte/k230_sdk:latest /bin/bash安装转换工具nncase
# nncase最好与镜像中的nncase保持一致
pip install -i https://pypi.org/simple nncase2.9.0 nncase-kpu2.9.0模型编译 先看文档中的命令
cd src/big/nncase/examples/
./build_model.shbuild_model.sh中关于image classfy部分
# build image classfy model
python3 ./scripts/mbv2_tflite.py --target k230 --model models/mbv2.tflite --dataset calibration_dataset此处可以参考之前的文章sh命令中的步骤为 1编写模型转换文件mbv2_tflite.py 2设置模型转换的硬件–target k230 3待转换的模型–model models/mbv2.tflite 4代表数据集–dataset calibration_dataset
为什么要进行模型的转换呢 结合官方文档的理解模型转换的过程是一个将浮点模型转换为定点的过程缩小模型加快计算
个人理解以数据存储的角度来看float32是32位的uint8是8位的模型参数的存储量降低到1/4同时提升运算速度可能浮点运算的开销更大达到模型加速的目的而k230是存在kpu它针对AI 模型的计算部分进行加速为便于理解可以类比单单指令流多数据流(SIMD)等技术如果用图片表示例如可以理解将四个顺序执行的加法四条指令周期改为并行的一个指令周期的专用计算单元这里只是类比
当然也有其他模型加速的方法请自行查询
模型转换完成后会在tmp文件夹中显示mbv2_tflite文件夹
将转换后的模型编译成二进制文件
./build_app.sh查看文件描述
#!/bin/bash
set -x# set cross build toolchain
export PATH$PATH:/opt/toolchain/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin/clear
rm -rf out
mkdir out
pushd out
cmake -DCMAKE_BUILD_TYPERelease \-DCMAKE_INSTALL_PREFIXpwd \-DCMAKE_TOOLCHAIN_FILEcmake/Riscv64.cmake \..make -j make install
popd# assemble all test cases
k230_binpwd/k230_bin
mkdir -p ${k230_bin}
if [ -f out/bin/image_classify.elf ]; thenimage_classify${k230_bin}/image_classifyrm -rf ${image_classify}cp -a image_classify/data/ ${image_classify}cp out/bin/image_classify.elf ${image_classify}cp tmp/mbv2_tflite/test.kmodel ${image_classify}
fi关于命令的解读可能需要另开一篇文章重点为.cc文件与cmake文件的理解 其中main.cc文件为可以将它看成是一个hello world的增强型扩展。。。
01 预先定义部分
// 这里是一些定义配置
#include chrono
#include fstream
#include iostream
#include nncase/runtime/interpreter.h
#include nncase/runtime/runtime_op_utility.h#define USE_OPENCV 1
#define preprocess 1#if USE_OPENCV
#include opencv2/highgui.hpp
#include opencv2/imgcodecs.hpp
#include opencv2/imgproc.hpp
#endifusing namespace nncase;
using namespace nncase::runtime;
using namespace nncase::runtime::detail;#define INTPUT_HEIGHT 224
#define INTPUT_WIDTH 224
#define INTPUT_CHANNELS 302 用于读取二进制文件、txt文件的函数部分
template class T
std::vectorT read_binary_file(const std::string file_name)
{std::ifstream ifs(file_name, std::ios::binary);ifs.seekg(0, ifs.end);size_t len ifs.tellg();std::vectorT vec(len / sizeof(T), 0);ifs.seekg(0, ifs.beg);ifs.read(reinterpret_castchar *(vec.data()), len);ifs.close();return vec;
}void read_binary_file(const char *file_name, char *buffer)
{std::ifstream ifs(file_name, std::ios::binary);ifs.seekg(0, ifs.end);size_t len ifs.tellg();ifs.seekg(0, ifs.beg);ifs.read(buffer, len);ifs.close();
}static std::vectorstd::string read_txt_file(const char *file_name)
{std::vectorstd::string vec;vec.reserve(1024);std::ifstream fp(file_name);std::string label;while (getline(fp, label)){vec.push_back(label);}return vec;
}函数输出的softmax函数这个部分好像不能够用kpu加速环节好像采用RVV优化了模型参数暂未深入探究
templatetypename T
static int softmax(const T* src, T* dst, int length)
{const T alpha *std::max_element(src, src length);T denominator{ 0 };for (int i 0; i length; i) {dst[i] std::exp(src[i] - alpha);denominator dst[i];}for (int i 0; i length; i) {dst[i] / denominator;}return 0;
}
04 用于输入通道转换
#if USE_OPENCV
std::vectoruint8_t hwc2chw(cv::Mat img)
{std::vectoruint8_t vec;std::vectorcv::Mat rgbChannels(3);cv::split(img, rgbChannels);for (auto i 0; i rgbChannels.size(); i){std::vectoruint8_t data std::vectoruint8_t(rgbChannels[i].reshape(1, 1));vec.insert(vec.end(), data.begin(), data.end());}return vec;
}
#endif在这里插入代码片05 模型推断部分 static int inference(const char *kmodel_file, const char *image_file, const char *label_file)
{// load kmodelinterpreter interp;std::ifstream ifs(kmodel_file, std::ios::binary);interp.load_model(ifs).expect(load_model failed);// create input tensorauto input_desc interp.input_desc(0);auto input_shape interp.input_shape(0);auto input_tensor host_runtime_tensor::create(input_desc.datatype, input_shape, hrt::pool_shared).expect(cannot create input tensor);interp.input_tensor(0, input_tensor).expect(cannot set input tensor);// create output tensor// auto output_desc interp.output_desc(0);// auto output_shape interp.output_shape(0);// auto output_tensor host_runtime_tensor::create(output_desc.datatype, output_shape, hrt::pool_shared).expect(cannot create output tensor);// interp.output_tensor(0, output_tensor).expect(cannot set output tensor);// set input dataauto dst input_tensor.impl()-to_host().unwrap()-buffer().as_host().unwrap().map(map_access_::map_write).unwrap().buffer();
#if USE_OPENCVcv::Mat img cv::imread(image_file);cv::resize(img, img, cv::Size(INTPUT_WIDTH, INTPUT_HEIGHT), cv::INTER_NEAREST);auto input_vec hwc2chw(img);memcpy(reinterpret_castchar *(dst.data()), input_vec.data(), input_vec.size());
#elseread_binary_file(image_file, reinterpret_castchar *(dst.data()));
#endifhrt::sync(input_tensor, sync_op_t::sync_write_back, true).expect(sync write_back failed);// runsize_t counter 1;auto start std::chrono::steady_clock::now();for (size_t c 0; c counter; c){interp.run().expect(error occurred in running model);}auto stop std::chrono::steady_clock::now();double duration std::chrono::durationdouble, std::milli(stop - start).count();std::cout interp.run() took: duration / counter ms std::endl;// get output dataauto output_tensor interp.output_tensor(0).expect(cannot set output tensor);dst output_tensor.impl()-to_host().unwrap()-buffer().as_host().unwrap().map(map_access_::map_read).unwrap().buffer();float *output_data reinterpret_castfloat *(dst.data());auto out_shape interp.output_shape(0);auto size compute_size(out_shape);// postprogress softmax by cpustd::vectorfloat softmax_vec(size, 0);auto buf softmax_vec.data();softmax(output_data, buf, size);auto it std::max_element(buf, buf size);size_t idx it - buf;// load labelauto labels read_txt_file(label_file);std::cout image classify result: labels[idx] ( *it ) std::endl;return 0;
}带参数的主函数
// 主函数
int main(int argc, char *argv[])
{std::cout case argv[0] built at __DATE__ __TIME__ std::endl;if (argc ! 4){std::cerr Usage: argv[0] kmodel image label std::endl;return -1;}int ret inference(argv[1], argv[2], argv[3]);if (ret){std::cerr inference failed: ret ret std::endl;return -2;}return 0;
}运行完后会出现k230_bin文件夹并查看输出文件夹image_classify 将该文件夹移动到SD 卡中
进入大核运行代码并查看输出内容 注小核会显示登录大核需要输入q退出默认运行的人脸检测程序
发送 q 退出大核运行程序分别 输入
# 进入文件夹
cd /sharefs/image_classify
# 查看文件
ls
# 运行sh
./cpp.sh查看串口中的输出结果 C代码解释篇幅较长见后续文章
待续