Maix Bit(K210)保姆级入门上手教程系列
Maix Bit(K210)保姆级入门上手教程—环境搭建
Maix Bit(K210)保姆级入门上手教程—外设基本使用
这是K210快速上手系列文章,主要内容是,介绍MaixHub这个线上训练模型的使用,以及如何部署到K210中。
阅读本文的前提:读者对基本的监督式学习有一定的了解,之道学习率、迭代次数、网络模型等有一定的概念。没有的话,自行补充啦或者点这里,阅读官方文档学习相关基础~
本文内容多来自官方文档,目的是为了帮助读者快速上手训练自己的模型,侵权删!
文章目录
- Maix Bit(K210)保姆级入门上手教程系列
- 一、K210硬件介绍
- 1、内存介绍
- 2、KPU介绍
- 二、MaixHub介绍
- 三、获取图片数据
- 1、网上获取
- 2、线下获取
- 四、训练模型
- 五、部署模型
- 1、普通模型部署
- 2、大模型部署
- a、修改gc内存
- b、加载mini的固件
- c、kpu.load_flash加载模型
- 五、参考资料
一、K210硬件介绍
一般来说运行神经网络模型有两种方式。一种是直接通过CPU进行运行,一种是通过KPU或者GPU加速运行。K210中使用KPU的方式加速运行网络模型,使得其运行速度得到加快。
1、内存介绍
MaixPy 中的存储介质主要由 Flash,SD 卡组成,分为三块区域,分别是 MaixPy.bin 固件区,xxx.kmodel 模型区,文件系统区:Flash 上为 spiffs(SPI Flash File System),SD 卡为 Fatfs(FAT file system)。
通常起始于 0x300000,模型文件之所以一般不烧录在 Flash 的文件系统,原因有下:
Flash 中文件系统拥有的内存并不够大,不足以放入大模型,更大的模型可以放入 SD 卡中。直接读取模型文件比经过文件系统读取速率更快。
但是也会有以下原因会将模型烧录在flash中,就是模型本身比较大,就需要烧录到flash中,而不是SD卡中。因为模型大,SD卡加载模型可能会出现内存不足的情况。
内存管理:
在 MaixPy 中, 目前使用了两种内存管理, 一种是 GC(垃圾回收), 另一种是系统堆内存, 两者同时存在。
比如:芯片有 6MiB 内存,加入固件使用了前面的 2MiB, 还剩 4MiB, 默认 GC使用 512KiB, 剩下的给系统堆内存管理。
注意:
GC 内存的总大小是可以设置的, 所以,根据具体的使用情况可以适当修改GC内存大小, 比如:
为了加载更大的模型,可以把 GC内存设置小一点
如果分配新的变量提示内存不足, 可以适当将GC内存设置大一点即可。如果都不够了, 就要考虑缩减固件大小,或者优化代码了。
2、KPU介绍
KPU是通用的神经网络处理器,它可以在低功耗的情况下实现卷积神经网络计算,时时获取被检测目标的大小、坐标和种类,对人脸或者物体进行检测和分类。KPU 实现了 卷积、批归一化、激活、池化 这 4 种基础操作的硬件加速, 但是它们不能分开单独使用,是一体的加速模块。KPU使用也有一些限制。
- K210 有 6MB 通用 RAM 和 2MB KPU 专用 RAM。模型的输入和输出特征图存储在 2MB KPU RAM 中。权重和其他参数存储在 6MB 通用 RAM 中。
加速限制
加速限制比较多,有一些算子是能完全加速,有一些不能,大概知道这个就行了。具体哪些可以,哪些不可以自己上官方查啦~
二、MaixHub介绍
MaixHub网站提供模型训练功能和模型分享功能, 只需要准备好需要训练的数据集, 不需要搭建训练环境和代码, 上传训练数据即可快速训练出模型,方便快速制作你的 AI 应用,或者入门学习 AI 训练的流程和原理。
三、获取图片数据
1、网上获取
获取图片数据,可以自己爬虫获取,也可以从实际运行的开发环境中获取。如果是实际运行的环境获取的话(建议采用这个方式,用自己获取到的图片训练,精度会更高),可以参考下面的代码。如果是爬虫获取,可以参考
百度爬取图片
2、线下获取
我这里写了一个简单从摄像头获取数据的代码,可以参考一下。目前支持两种获取图片的方式,定时获取或者按键获取。
但是由于个人水平实在有限,不能解决python中使用uos.mkdri()创建的目录不能正常使用python进行删除的问题(建议通过相关接口修改字典的内容,因为创建的目录不能正常删除,除非在PC上操作)。
如果出现目录或者文件异常,可能是没有正常关闭文件导致的。可以在PC上面把创建的东西删除就可以。
注意,需要SD卡,文件都是在SD卡中操作的。
基本流程的话,首先调用init()创建索引文件。之后会根据字典的内容创建相应的目录存放文件。例如:init()创建的字典文格式如下。
会自动创建目录/pic/sit/right和/pic/sit/error,之后会自动读取以及保存right或者error的值作为图片名词。
dictx={'sit': {'right': 0, 'error': 0}, 'object': {'portable_battery': 0, 'Instant_noodles': 0,'mouse': 0}}
如果是使用Maix Bit板子,下面代码能直接运行:按键就是开发板上的按键
from machine import Timer from Maix import GPIO from fpioa_manager import fm import sensor, lcd import uos,sys def create_dir(dir,chdir='/sd'): try: if(uos.stat(dir)): print("PATH existed") except: uos.mkdir(dir) # 函数整个字典读取,文件默认名字是index.txt def read_pic_index(file_path='/sd/pic'): uos.chdir('/sd/pic') file = open('index.txt','r+',encoding='utf-8') index= eval(file.read()) #读取的str转换为字典 file.close() return index # 添加一个字典,第一次创建,写key=='none' def add_pic_index(key,dict_value,file_path='/sd/pic'): if(key!='none' ): index = read_pic_index(file_path) file = open('index.txt',"w+",encoding='utf-8') index[key]=dict_value file.write(str(index)) #把字典转化为str file.close() else:# 第一次创建 create_dir('pic',file_path) uos.chdir(file_path) #print(uos.getcwd()) file = open('index.txt',"w+",encoding='utf-8') file.write(str(dict_value)) #把字典转化为str file.close() # 删除一个字典 def del_pic_index(key,file_path='/sd/pic'): import sys global index # 声明全局索引 index = read_pic_index('index.txt') file = open('index.txt','w+') try: del index[str(key)] except KeyError: print('key :'+key +' have been del or without this key') #file.close() else: pass file.write(str(index)) #把字典转化为str file.close() # 打印所有的索引 def print_pic_index(file_path='sd/pic'): cat_index=read_pic_index('index.txt') for key in cat_index: print("key:%s value:%s"%(key,str(cat_index[key]))) # 获取key的索引 def get_pic_key_index(key,file_path='sd/pic'): cat_index=read_pic_index('index.txt') for fkey in cat_index: if fkey==key: return cat_index[key]; # 设置某一个key的index def set_pic_key_index(key,dict_value,file_path='sd/pic'): add_pic_index(key,dict_value,file_path) # 清楚所有的index def clear_pic_index(file_path='sd/pic'): cat_index=read_pic_index(file_path) for key in cat_index: del_pic_index(key,file_path) # 这里解释以下,init()创建一个索引文件,保存标签图片 # 比如,/sd/pic/index.txt中的数据就是dictx的数据,使用前需要先调用init() # 存放图片也跟这个有关系,存放图片的路径会是,/sd/pic/sit/right或者 # /sd/pic/sit/error def init(): # init()执行一次就行了,之后屏蔽掉就OK dictx={'sit': {'right': 0, 'error': 0}, 'object': {'portable_battery': 0, 'Instant_noodles': 0, 'mouse': 0}} try: if uos.stat('/sd/pic'): print("PATH existed") except: uos.mkdir('/sd/pic') add_pic_index('none',dictx) index=read_pic_index() print(index) # 初始化摄像头 def sensor_init(): sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.run(1) sensor.skip_frames() # 获取一帧图片 def get_frame_pic(): img = sensor.snapshot() return img # 获取获取图片计数和图片设置路径 pic_num=1 save_path='' # 保存图片设置 def save_pic(timer): global pic_num global save_path img=get_frame_pic() lcd.display(img) file_name=save_path+'/'+str(pic_num)+'.jpg' print(file_name) img.save(file_name, quality=95) pic_num+=1 #开发板上RST的按键IO KEY=16 # 保存图片,保存的数量,1张图片拍摄的时间间隔(ms),这里使用计时器的方式 # 参数:ikey是字典类标签,iikey是某一个标签 # 参数:num是保存图片数量,file_index_path就是标签保存途径 # 参数:interval是’period‘获取一张图片间隔,推荐300~500ms # 参数:mode是模式,按键’key‘,模式’period‘ # 注意:使用按键的方式,interval将不再起作用 def start_obtain(ikey,iikey,file_index_path='/sd/pic/index.txt',num=100,interval=300,mode='period'): global pic_num global save_path print('sensor_init & lcd') pic_index=get_pic_key_index(ikey,file_index_path) print(pic_index) sensor_init() lcd.init() if mode=='period': if interval
- K210 有 6MB 通用 RAM 和 2MB KPU 专用 RAM。模型的输入和输出特征图存储在 2MB KPU RAM 中。权重和其他参数存储在 6MB 通用 RAM 中。