【雕爷学编程】MicroPython动手做(10)——零基础学MaixPy之神经网络KPU2

news/2024/5/19 5:29:48

KPU的基础架构
让我们回顾下经典神经网络的基础运算操作:
卷积(Convolution):1x1卷积,3x3卷积,5x5及更高的卷积
批归一化(Batch Normalization)
激活(Activate)
池化(Pooling)
矩阵运算(Matrix Calculate):矩阵乘,加
对于基础的神经网络结构,仅具备1,2,3,4 四种操作;
对于新型网络结构,比如ResNet,在卷积结果后会加一个变量,就需要使用第五种操作,矩阵运算。
对于MAIX的主控芯片K210来说,它内置实现了 卷积,批归一化,激活,池化 这4钟基础操作的硬件加速,但是没有实现一般的矩阵运算,所以在实现的网络结构上有所限制。
对于需要额外操作的网络结构,用户必须在硬件完成基础操作后,手工插入CPU干预的处理层实现,会导致帧数降低,所以建议用户优化自己的网络结构到基础网络形式。
所幸的是,该芯片的第二代将支持通用矩阵计算,并固化更多类型的网络结构。
在KPU中,上述提到的4种基础操作并非是单独的加速模块,而是合成一体的加速模块,有效避免了CPU干预造成的损耗,但也丧失了一些操作上的灵活性。
从standalone sdk/demo 以及 Model Compiler 中分析出 KPU加速模块的原理框图如下,看图即懂。

在这里插入图片描述

#MicroPython动手做(10)——零基础学MaixPy之神经网络KPU
#实验程序之一:运行人脸识别demo(简单演示)
#模型下载地址:http://dl.sipeed.com/MAIX/MaixPy/model/face_model_at_0x300000.kfpkg
下载后模型文件夹内有二个文件

在这里插入图片描述
在这里插入图片描述

打开kflash_gui
使用kfpkg将 二个模型文件 与 maixpy 固件打包下载到 flash

在这里插入图片描述
打包kfpkg时出错,好像是文件地址范围不同…

在这里插入图片描述

尝试多次一直不行,两者不兼容。后来干脆不打包了,只烧录模型文件kfpkg(原来烧录过MaixPy固件V0.4.0),没想到可以了,这下明白了,固件和模型分开烧录也行。

在这里插入图片描述

#MicroPython动手做(10)——零基础学MaixPy之神经网络KPU
#实验程序之一:运行人脸识别demo(简单演示)
#模型下载地址:http://dl.sipeed.com/MAIX/MaixPy … l_at_0x300000.kfpkg

#MicroPython动手做(10)——零基础学MaixPy之神经网络KPU
#实验程序之一:运行人脸识别demo(简单演示)
#模型下载地址:http://dl.sipeed.com/MAIX/MaixPy ... l_at_0x300000.kfpkgimport sensor
import image
import lcd
import KPU as kpulcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.run(1)
task = kpu.load(0x300000) #使用kfpkg将 kmodel 与 maixpy 固件打包下载到 flash
anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025)
a = kpu.init_yolo2(task, 0.5, 0.3, 5, anchor)
while(True):img = sensor.snapshot()code = kpu.run_yolo2(task, img)if code:for i in code:print(i)a = img.draw_rectangle(i.rect())a = lcd.display(img)
a = kpu.deinit(task)

在这里插入图片描述
串口输出了大量数据

在这里插入图片描述

{“x”:0, “y”:31, “w”:107, “h”:145, “value”:0.611305, “classid”:0, “index”:0, “objnum”:1}
{“x”:0, “y”:31, “w”:107, “h”:145, “value”:0.500000, “classid”:0, “index”:0, “objnum”:1}
{“x”:1, “y”:31, “w”:107, “h”:144, “value”:0.500000, “classid”:0, “index”:0, “objnum”:1}
{“x”:0, “y”:31, “w”:107, “h”:145, “value”:0.556360, “classid”:0, “index”:0, “objnum”:1}
{“x”:13, “y”:34, “w”:83, “h”:139, “value”:0.556360, “classid”:0, “index”:0, “objnum”:1}
{“x”:0, “y”:31, “w”:107, “h”:145, “value”:0.500000, “classid”:0, “index”:0, “objnum”:1}
{“x”:0, “y”:31, “w”:107, “h”:145, “value”:0.500000, “classid”:0, “index”:0, “objnum”:1}
{“x”:0, “y”:31, “w”:107, “h”:145, “value”:0.556360, “classid”:0, “index”:0, “objnum”:1}
{“x”:0, “y”:31, “w”:107, “h”:145, “value”:0.500000, “classid”:0, “index”:0, “objnum”:1}
{“x”:15, “y”:36, “w”:83, “h”:111, “value”:0.556360, “classid”:0, “index”:0, “objnum”:1}
{“x”:13, “y”:33, “w”:83, “h”:139, “value”:0.556360, “classid”:0, “index”:0, “objnum”:1}
{“x”:14, “y”:47, “w”:83, “h”:111, “value”:0.500000, “classid”:0, “index”:0, “objnum”:1}
{“x”:0, “y”:31, “w”:107, “h”:144, “value”:0.556360, “classid”:0, “index”:0, “objnum”:1}
{“x”:13, “y”:32, “w”:83, “h”:139, “value”:0.500000, “classid”:0, “index”:0, “objnum”:1}
{“x”:14, “y”:32, “w”:83, “h”:139, “value”:0.611305, “classid”:0, “index”:0, “objnum”:1}
{“x”:0, “y”:31, “w”:107, “h”:144, “value”:0.556360, “classid”:0, “index”:0, “objnum”:1}

KPU是通用的神经网络处理器,它可以在低功耗的情况下实现卷积神经网络计算,时时获取被检测目标的大小、坐标和种类,对人脸或者物体进行检测和分类。KPU模块方法:

  1. 加载模型
    从flash或者文件系统中加载模型
    import KPU as kpu
    task = kpu.load(offset or file_path)

参数
offtset: 模型在 flash 中的偏移大小,如 0xd00000 表示模型烧录在13M起始的地方
file_path: 模型在文件系统中为文件名, 如 “/sd/xxx.kmodel”

返回
kpu_net: kpu 网络对象

  1. 初始化yolo2网络
    为yolo2网络模型传入初始化参数
    import KPU as kpu
    task = kpu.load(offset or file_path)
    anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025)
    kpu.init_yolo2(task, 0.5, 0.3, 5, anchor)

参数
kpu_net: kpu 网络对象
threshold: 概率阈值
nms_value: box_iou 门限
anchor_num: 锚点数
anchor: 锚点参数与模型参数一致

  1. 反初始化
    import KPU as kpu
    task = kpu.load(offset or file_path)
    kpu.deinit(task)

参数
kpu_net: kpu_load 返回的 kpu_net 对象

  1. 运行yolo2网络
    import KPU as kpu
    import image
    task = kpu.load(offset or file_path)
    anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025)
    kpu.init_yolo2(task, 0.5, 0.3, 5, anchor)
    img = image.Image()
    kpu.run_yolo2(task, img)

参数
kpu_net: kpu_load 返回的 kpu_net 对象
image_t:从 sensor 采集到的图像

返回
list: kpu_yolo2_find 的列表

  1. 网络前向运算(forward)
    计算已加载的网络模型到指定层数,输出目标层的特征图
    import KPU as kpu
    task = kpu.load(offset or file_path)
    ……
    fmap=kpu.forward(task,img,3)

参数
kpu_net: kpu_net 对象
image_t: 从 sensor 采集到的图像
int: 指定计算到网络的第几层

返回
fmap: 特征图对象,内含当前层所有通道的特征图

  1. fmap 特征图
    取特征图的指定通道数据到image对象
    img=kpu.fmap(fmap,1)

参数
fmap: 特征图 对象
int: 指定特征图的通道号】

返回
img_t: 特征图对应通道生成的灰度图

  1. fmap_free 释放特征图
    释放特征图对象
    kpu.fmap_free(fmap)

参数
fmap: 特征图 对象

返回

  1. netinfo
    获取模型的网络结构信息
    info=kpu.netinfo(task)
    layer0=info[0]

参数
kpu_net: kpu_net 对象

返回
netinfo list:所有层的信息list, 包含信息为:
index:当前层在网络中的层数
wi:输入宽度
hi:输入高度
wo:输出宽度
ho:输出高度
chi:输入通道数
cho:输出通道数
dw:是否为depth wise layer
kernel_type:卷积核类型,0为1x1, 1为3x3
pool_type:池化类型,0不池化; 1:2x2 max pooling; 2:…
para_size:当前层的卷积参数字节数

KPU寄存器配置说明
芯片厂家没有给出寄存器手册,我们从kpu.c, kpu.h, Model Compiler中分析各寄存器定义。KPU的寄存器配置写在 kpu_layer_argument_t 结构体中,我们取standalone demo中的kpu demo中的gencode.c来分析.(https://github.com/kendryte/kend … pu/gencode_output.c)

//层参数列表,共16层kpu_layer_argument_t la[] __attribute__((aligned(128))) = {
//0{
.kernel_offset.data = {.coef_row_offset = 0,                //固定为0.coef_column_offset = 0        //固定为0
},
.image_addr.data = {                //图像输入输出地址,一个在前,一个在后,下一层运算的时候翻过来,可以避免拷贝工作。.image_dst_addr = (uint64_t)0x6980,        //图像输出地址,int((0 if idx & 1 else (img_ram_size - img_output_size)) / 64).image_src_addr = (uint64_t)0x0                //图像加载地址
},
.kernel_calc_type_cfg.data = {.load_act = 1,                        //使能激活函数,必须使能(硬件设计如此),不使能则输出全为0.active_addr = 0,                        //激活参数加载首地址,在kpu_task_init里初始化为激活折线表.row_switch_addr = 0x5,        //图像宽占用的单元数,一个单元64Byte.  ceil(width/64)=ceil(320/64)=5.channel_switch_addr = 0x4b0,                        //单通道占用的单元数.  row_switch_addr*height=5*240=1200=0x4b0.coef_size = 0,                        //固定为0.coef_group = 1                        //一次可以计算的组数,因为一个单元64字节,//所以宽度>32,设置为1;宽度17~32,设置为2;宽度<=16,设置为4
},
.interrupt_enabe.data = {.depth_wise_layer = 0,        //常规卷积层,设置为0.ram_flag = 0,                        //固定为0.int_en = 0,                                //失能中断.full_add = 0                                //固定为0
},
.dma_parameter.data = {        //DMA传输参数.dma_total_byte = 307199,                //该层输出16通道,即 19200*16=308200.send_data_out = 0,                        //使能输出数据.channel_byte_num = 19199                //输出单通道的字节数,因为后面是2x2 pooling, 所以大小为160*120=19200
},
.conv_value.data = {                //卷积参数,y = (x*arg_x)>>shr_x.arg_x = 0x809179,                //24bit        乘法参数.arg_w = 0x0,.shr_x = 8,                                //4bit        移位参数.shr_w = 0
},
.conv_value2.data = {                //arg_add = kernel_size * kernel_size * bw_div_sw * bx_div_sx =3x3x?x?.arg_add = 0
},
.write_back_cfg.data = {        //写回配置.wb_row_switch_addr = 0x3,                //ceil(160/64)=3.wb_channel_switch_addr = 0x168,        //120*3=360=0x168.wb_group = 1                                                //输入行宽>32,设置为1
},
.image_size.data = {        //输入320*240,输出160*120.o_col_high = 0x77,.i_col_high = 0xef,.i_row_wid = 0x13f,.o_row_wid = 0x9f
},
.kernel_pool_type_cfg.data = {.bypass_conv = 0,                //硬件不能跳过卷积,固定为0.pad_value = 0x0,                //边界填充0.load_para = 1,                //硬件不能跳过归一化,固定为1.pad_type = 0,                //使用填充值.kernel_type = 1,                //3x3设置为1, 1x1设置为0.pool_type = 1,                //池化类型,步长为2的2x2 max pooling.dma_burst_size = 15,        //dma突发传送大小,16字节;脚本中固定为16.bwsx_base_addr = 0,        //批归一化首地址,在kpu_task_init中初始化.first_stride = 0                //图像高度不超过255;图像高度最大为512},
.image_channel_num.data = {.o_ch_num_coef = 0xf,        //一次性参数加载可计算的通道数,16通道。4K/单通道卷积核数//o_ch_num_coef = math.floor(weight_buffer_size / o_ch_weights_size_pad)       .i_ch_num = 0x2,                //输入通道,3通道 RGB.o_ch_num = 0xf                //输出通道,16通道
},
.kernel_load_cfg.data = {.load_time = 0,                //卷积加载次数,不超过72KB,只加载一次.para_size = 864,                //卷积参数大小864字节,864=3(RGB)*9(3x3)*2*16.para_start_addr = 0,        //起始地址.load_coor = 1                //允许加载卷积参数
}
},//0层参数结束……
};上表中还有些结构体内容没有填充,是在KPU初始化函数中填充:```kpu_task_t* kpu_task_init(kpu_task_t* task){
la[0].kernel_pool_type_cfg.data.bwsx_base_addr = (uint64_t)&bwsx_base_addr_0;        //初始化批归一化表
la[0].kernel_calc_type_cfg.data.active_addr = (uint64_t)&active_addr_0;                //初始化激活表
la[0].kernel_load_cfg.data.para_start_addr = (uint64_t)¶_start_addr_0;         //初始化参数加载
……        //16层参数,逐层计算
task->layers = la;
task->layers_length = sizeof(la)/sizeof(la[0]);        //16层
task->eight_bit_mode = 0;                                        //16bit模式
task->output_scale = 0.12349300010531557;        //输出的缩放,偏置
task->output_bias = -13.528212547302246;
return task;
}```

http://www.mrgr.cn/p/88027515

相关文章

使用 OpenCV 进行图像模糊度检测(拉普拉斯方差方法)

写在前面 工作中遇到&#xff0c;简单整理人脸识别中&#xff0c;对于模糊程度较高的图像数据&#xff0c;识别率低&#xff0c;错误率高。虽然使用 AdaFace 模型&#xff0c;对低质量人脸表现尤为突出。但是还是需要对 模糊程度高的图像进行丢弃处理当前通过阈值分类&#xff…

达梦DM数据库目录结构介绍

数据库安装目录 下图展示为 DM8 数据库目录。 /dm8/bin 目录存放 DM 数据库的可执行文件&#xff0c;例如 disql 命令、dminit 命令、dmrman 工具等。 /dm8/desktop 存放 DM 数据库各个工具的桌面图标。 /dm8/doc 存放 DM 数据库用户手册。 /dm8/drivers 存放连接 DM 数据库的…

【论文笔记】神经网络压缩调研

神经网络压缩调研 背景现有的深度模型压缩方法NetWork Prunning 网络剪枝设计结构化矩阵知识蒸馏权值共享Parameter Quantization&#xff08;参数量化&#xff09;量化和二进制化伪量化Architecture Design&#xff08;Depth Separable Convolution&#xff09;分解卷积 背景 …

Baumer工业相机堡盟工业相机如何通过BGAPI SDK获取相机当前实时帧率(C++)

Baumer工业相机堡盟工业相机如何通过BGAPISDK里函数来计算相机的实时帧率&#xff08;C&#xff09; Baumer工业相机Baumer工业相机的帧率的技术背景Baumer工业相机的帧率获取方式CameraExplorer如何查看相机帧率信息在BGAPI SDK里通过函数获取相机帧率 Baumer工业相机通过BGAP…

算法通关村第三关——不简单的数组增删改查

线性表基础 线性表概念 线性表就是具有相同特征数据元素的一个有限序列&#xff0c;其中包含元素的个数称为线性表的长度 线性表类型 从不同的角度看&#xff0c;线性表有不同的分类 语言实现角度 顺序表有两种实现方式 一体式 分离式 一体式结构 一体式&#xff1a;存储信息…

Vue3通透教程【十六】TS编译配置

文章目录 &#x1f31f; 写在前面&#x1f31f; 初始化配置文件⭐ target⭐ module⭐ lib⭐ types/node⭐ include⭐ outDir&#x1f31f; 写在最后 &#x1f31f; 写在前面 专栏介绍&#xff1a; 凉哥作为 Vue 的忠实 粉丝输出过大量的 Vue 文章&#xff0c;应粉丝要求开始更…

ARM将常数加载到寄存器方法之LDR伪指令

一、是什么&#xff1f; LDR Rd,const伪指令可在单个指令中构造任何32位数字常数,使用伪指令可以生成超过MOV和MVN指令 允许范围的常数. 实现原理: (1)如果可以用MOV或MVN指令构造该常数,则汇编程序会生成适当的指令 (2)如果不能用MOV或MVN指令构造该常数,则汇编程序会执行下列…

Java maven的下载解压配置(保姆级教学)

mamen基本概念 Maven项目对象模型(POM)&#xff0c;可以通过一小段描述信息来管理项目的构建&#xff0c;报告和文档的项目管理工具软件。 Maven 除了以程序构建能力为特色之外&#xff0c;还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性&#xff0c;所以…

form-data 提交文件请求远程调用

文件请求方法 /*** 上传图文消息内的图片 获取url* 富文本内的图片** param file*/public static String uploadMediaGetUrl(File file) throws IOException {if (!file.exists()) {return null;}String responseData null;try {String url "http://localhost:8503/fil…

FFmpeg aresample_swr_opts的解析

ffmpeg option的解析 aresample_swr_opts是AVFilterGraph中的option。 static const AVOption filtergraph_options[] {{ "thread_type", "Allowed thread types", OFFSET(thread_type), AV_OPT_TYPE_FLAGS,{ .i64 AVFILTER_THREAD_SLICE }, 0, INT_MA…

振弦采集仪及在线监测系统完整链条的岩土工程隧道安全监测

振弦采集仪及在线监测系统完整链条的岩土工程隧道安全监测 近年来&#xff0c;随着城市化的不断推进和基础设施建设的不断发展&#xff0c;隧道建设也日益成为城市交通发展的必需品。然而&#xff0c;隧道建设中存在着一定的安全隐患&#xff0c;如地质灾害、地下水涌流等&…

C++STL库中的list

文章目录 list的介绍及使用 list的常用接口 list的模拟实现 list与vector的对比 一、list的介绍及使用 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2. list的底层是双向带头循环链表结构&#xff0c;双向带头循…

【Git】git企业开发命令整理,以及注意点

1.git企业开发过程 业务的分支大概有以下几个&#xff1a; master&#xff1a;代码随时可能上线 develop&#xff1a;代码最新 feature/xxx&#xff1a;实际业务开发分支 release/xxx&#xff1a;预发布分支 fix&#xff1a;修复bug分支 过程大概是这样的&#xff1a; 首…

HTML+CSS+JavaScript:轮播图自动播放

一、需求 轮播图如下图所示&#xff0c;需求是每隔一秒轮播图自动切换一次 二、代码素材 以下是缺失JS部分的代码&#xff0c;感兴趣的小伙伴可以先自己试着写一写 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /&…

【期末课程设计】学生成绩管理系统

因其独特&#xff0c;因其始终如一 文章目录 一、学生成绩管理系统介绍 二、学生成绩管理系统设计思路 三、源代码 1. test.c 2. Student Management System.c 3.Stu_System.c 4.Teacher.c 5.Student Management System.h 前言&#xff1a; 学生成绩管理系统含教师…

Android 第三方库CalendarView

Android 第三方库CalendarView 根据需求和库的使用方式&#xff0c;自己弄了一个合适自己的日历&#xff0c;仅记录下&#xff0c;方便下次弄其他样式的日历。地址 需求&#xff1a; 只显示当月的数据 默认的月视图有矩形的线 选中的天数也要有选中的矩形框 今天的item需要…

浏览器安装selenium IDE插件并进行网页测试记录

Chrome开发者工具插件,谷歌浏览器开发者工具插件推荐下载_安装_教程-扩展迷 去官网直接搜索下载需要的插件就可。 插件下载安装-Chrome-扩展迷 下载好后解压&#xff1a; 打开Chrome谷歌浏览器&#xff1a; 设置>拓展程序>打开"开发者模式”>将下载好的seleni…

python结合tesseract-ocr识别汉字的训练库过程

一、安装python 例如&#xff0c;安装路径为&#xff1a;C:\rtkapp\python-3.8.0 二、安装opencv 三、安装tesseract-ocr 安装完成后&#xff0c;在系统环境变量path中&#xff0c;添加安装路径C:\rtkapp\Tesseract-OCR 四、打开python安装pytesseract 五、安装java运行环境…

状态机实现N位按键消抖

状态机实现N位按键消抖 1、原理 利用状态机实现按键的消抖&#xff0c;具体的原理可参考 (50条消息) 基于FPGA的按键消抖_fpga 按键消抖_辣子鸡味的橘子的博客-CSDN博客 状态机简介&#xff1a; 状态机分类可以主要分为两类&#xff1a;moore和mealy 根据三段式状态机最后…

婚庆服务小程序app开发方案详解

开发一款婚庆行业服务小程序有哪些功能呢&#xff1f; 1、选择分类 选择婚庆、婚车、婚宴、司仪、彩妆、婚庆用品、跟拍、摄影等&#xff0c;筛选出对应的商家 2、选择商家 选择分类后&#xff0c;可以选择商家&#xff0c;查看各个商家的详细介绍情况。 3、选择服务套餐 各…