KPU

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

  • KPU 具备以下几个特点:
    • 支持主流训练框架按照特定限制规则训练出来的定点化模型
    • 对网络层数无直接限制,支持每层卷积神经网络参数单独配置,包括输入输出通道数目、输入输 出行宽列高
    • 支持两种卷积内核 1x1 和 3x3
    • 支持任意形式的激活函数
    • 实时工作时最大支持神经网络参数大小为 5.5MiB 到 5.9MiB
    • 非实时工作时最大支持网络参数大小为(Flash 容量-软件体积)

例程

运行人脸检测

模型下载地址:http://dl.sipeed.com/MAIX/MaixPy/model , 下载face_model_at_0x300000.kfpkg

完整例程: face_find

运行特征图

模型下载地址:http://dl.sipeed.com/MAIX/MaixPy/model , 下载face_model_at_0x300000.kfpkg

该模型是8bit定点模型,约380KB大小,层信息为:

1 2        :160x120
3 4 5 6	   :80x60
7 8 9 10   :40x30
11~16      :20x15
import sensor
import image
import lcd
import KPU as kpu
index=3  
lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.run(1)
task=kpu.load(0x300000)
img=image.Image()
info=kpu.netinfo(task)
layer=info[index]
w=layer.wo()
h=layer.ho()
num=int(320*240/w/h)
list=[None]*num
x_step=int(320/w)
y_step=int(240/h)
img_lcd=image.Image()
while True:
    img=sensor.snapshot()
    fmap=kpu.forward(task,img,index)
    for i in range(0,num):
        list[i]=kpu.fmap(fmap,i)
    for i in range(0,num):
        list[i].stretch(64,255)
    for i in range(0,num):
        a=img_lcd.draw_image(list[i],((i%x_step)*w,(int(i/x_step))*h))
       lcd.display(img_lcd)
    kpu.fmap_free(fmap)

模块方法

load

从flash或者文件系统中加载模型

KPU.load(offset, file_path)

参数

offsetfile_path 参数只能二选一,不需要关键词,直接传参即可

  • offset: 模型在 flash 中的偏移大小,如 0xd00000 表示模型烧录在13M起始的地方, 0x300000表示在 Flash 3M的地方
  • file_path: 模型在文件系统中为文件名, 如 “/sd/xxx.kmodel”
返回

如果正确加载,会返回返回值, 否则会抛出错误, 请看抛出的错误提示, 另外错误代码参考这里

如果发现错误代码是小于 2000 的值, 则是固件版本太低,需要更新固件版本

  • kpu_net: kpu 网络对象

load_flash

与 load 方法作用相同,

kpu.load_flash(model_addr, is_dual_buf, batch_size, spi_speed)

参数

  • model_addr:Flash addr 经过预处理的模型烧录到 flash 中的偏移地址。注意,这里需要预处理模型文件说明
  • is_dual_buf0,单一缓冲区加载,使用较少的 RAM 和较慢的速度动态加载该模型文件; 1,开启双缓冲加载,需要更大的 RAM, 运行速度相对较快。
  • batch_size:将 is_dual_buf 设置为 1 时,需要设置 load batch_size,建议值为 0x4000~0x10000,可以测试出模型的最佳值。如果 is_dual_buf 为 0 则设置为 0
  • spi_speed:使用 SPI flash 加载模型文件时,我们会暂时将 flash 设置为高速模式,并设置所需的 spi 时钟频率。该值应 <= 80000000(实际频率,设值可能不等于实际频率。)

返回值

  • kpu_net: kpu 网络对象

init_yolo2

yolo2网络模型传入初始化参数, 只有使用yolo2时使用

KPU.init_yolo2(kpu_net, threshold, nms_value, anchor_num, anchor)

比如:

import KPU as kpu
task = kpu.load(0x300000)
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 网络对象, 即加载的模型对象, KPU.load()的返回值
  • threshold: 概率阈值, 只有是这个物体的概率大于这个值才会输出结果, 取值范围:[0, 1]
  • nms_value: box_iou 门限, 为了防止同一个物体被框出多个框,当在同一个物体上框出了两个框,这两个框的交叉区域占两个框总占用面积的比例 如果小于这个值时, 就取其中概率最大的一个框
  • anchor_num: anchor 的锚点数, 这里固定为 len(anchors)//2
  • anchor: 锚点参数与模型参数一致,同一个模型这个参数是固定的,和模型绑定的(训练模型时即确定了), 不能改成其它值。

返回值

  • successbool类型, 是否成功

deinit

释放模型占用的内存, 立即释放, 但是变量还在,可以使用del kpu_net_object 的方式删除,
另外也可以直接只使用del kpu_net_object来标记对象已被删除,下一次GC进行内存回收或者手动调用gc.collect()时,会自动释放内存

KPU.deinit(kpu_net)

比如:

import KPU as kpu
import gc
task = kpu.load(0x300000)
kpu.deinit(task)
del task
gc.collect()

或者:

import KPU as kpu
import gc
task = kpu.load(0x300000)
del task
gc.collect()

参数

kpu_net: KPU.load() 返回的 kpu_net 对象

返回值

  • successbool 类型, 是否成功

run_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 的列表

forward

计算已加载的网络模型到指定层数,输出目标层的特征图

fmap=KPU.forward(kpu_net, img, end_layer)
import KPU as kpu
task = kpu.load(offset or file_path)
……
fmap=kpu.forward(task,img, 3)

参数

  • kpu_net: kpu_net 对象
  • img: 图像 image.Image 对象
  • end_layer: 指定计算到网络的第几层, 取值从0开始
返回
  • fmap: 特征图对象,内含当前层所有通道的特征图

fmap

取特征图的指定通道数据到image.Image对象

img=KPU.fmap(fmap, channel)

参数

  • fmap: 特征图 对象
  • channel: 指定特征图的通道号, 从0开始
返回
  • img: 特征图对应通道生成的灰度图,类型image.Image

fmap_free

释放特征图对象

KPU.fmap_free(fmap)

参数

  • fmap: 特征图 对象
返回

netinfo

获取模型的网络结构信息

info_list = kpu.netinfo(task)

参数

  • kpu_net: kpu_net 对象, KPU.load()返回值
返回
  • info_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:当前层的卷积参数字节数

set_outputs

success = set_outputs(kput_net, out_idx, width, height, channel)

手动设置输出层形状, 对于 nncase v0.2.0 转换出来的 V4 的 kmodel 模型,
load 之后需要调用此函数手动设置输出层形状, V3 模型不需要

参数

  • kpu_net: kpu_net 对象
  • out_idx: 输出层下表, 从 0 开始, 比如第一层输出层是0
  • width: 层宽度, 如果是一维输出,则为1
  • height: 层高度, 如果是一维输出,则为1
  • channnel: 层通道数,如果是一维输出,则这里为一维输出的长度
返回
  • success: 是否设置成功, 如果不成功,注意看输出的提示信息, 参考错误代码

memtest

打印内存使用情况,包括GC内存和系统堆内存

  • 注意执行这个函数会自动先执行gc.collect()进行内存回收一次,再打印GC剩余内存
  • 系统堆内存只做参考,不一定准确,有时可能出现已经释放了内存,但是显示依然没有释放,以实际能不能分配到内存为准
KPU.memtest()

face_encode

forward 返回的特征图进行量化,更多详情请查看:kpu issue

feature = kpu.face_encode(fmap[:])

参数

fmap[:]list 类型,将 forward 函数返回值转化为列表所得到的

返回值

featurelist 类型,量化后的列表

face_compare

将 face_encode 返回的量化值与已录入的人脸进行比较

score = kpu.face_compare(record_ftrs[j], feature)

参数

record_ftrs[j]list 类型,以录入的人脸数据
featurelist 类型,需要比较的人脸数据, face_encode 的返回值

返回值

scoreint 类型,比较得分(0~100),得分越高相似度越大