nn模块==maixpy3

本文详细介绍了MaixPy3中的maix.nn模块,包括模型加载、前向推理、后处理以及应用模块。通过实例展示了如何加载模型、处理图像、使用Yolo2解码器进行物体检测。此外,还提到了MUD文件的作用,它是模型统一描述文件,简化了模型运行的Python代码。
摘要由CSDN通过智能技术生成
maix.nn介绍
  • 从maixhub下载,这里以边缘处检测模型为例子,需要先下载模型
  • 准备一张 224 x 224 分辨率的图像, 比如这里放到了开发板文件系统的/root/test.png位置
  • 运行代码, 将下面的代码保存到开发板的test_model.py中, 然后运行python test_model.py
# 其中最重要的就是m = nn.load和m.forward()两个函数, 
# 即加载模型, 和进行模型前向推理
from maix import nn,display
from PIL import Image
import numpy as np


# =============================================准备工作
test_jpg="/root/test.png"

model={
	"param":"/root/models/sobel_int8.param",
	"bin":"/root/models/sobel_int8.bin"	
}

input_size=(224,224,3)
output_size=(222,222,3)

options={
	"model_type":"awnn"
	"inputs":{
		"input0":input_size
	},
	"outputs":{
		"output0":output_size
	},
	"mean":[127.5,127.5,127.5],
	"norm":[0.0078125,0.00748125,0.0078125],
}

# ============================================加载模型
print("-- load model:",model)
m=nn.load(model,opt=options)
print("-- load ok")

print("-- read image")
img = Image.open(test_jpg).resize(input_size[:2])
print("-- read iamge")

print("-- forward model with image as input")
out=m.forward(img,quantize=True)
print("-- forward ok")

out=out.astype(np.float32).reshape(output_size)
out=(np.abs(out)*255/out.max()).astype(np.uint8)
img2=Image.fromarray(out,mode="RGB")

display.show(img2)
方法 maix.nn.load()
  • 加载模型,返回maix.nn.Model对象
# =============================================================参数
# model_path:模型路径,包含了字符串和字典两种形式
# 字典形式:
	{
		"param":"/root/models/sobel_int8.param",
		"bin":"/root/models/sobel_int8.bin"
	}
# 字符串形式:
model_path="/root/mud/sobel_int8.mud"#mud文件是模型统一描述文件

# opt:设置项,字典形式,包括了:
# 		model_type:模型类别,目前仅支持awnn
# 	 	inputs:输入层,字典形式,关键字是层名称,为字符串,如果是加密模型,需要使用整型;值是层形状,为一个tuple类型:(h,w,c)目前只支持单层输入层
# 例如:
# 未加密模型
"inputs":{
	"input0":(224,224,3)
}
# 加密模型
"inputs":{
	0:(224,224,3)
}

# outputs:输出层,其解释同上

# mean:如果在forward使参数standardize=True(默认为True),则会使用这个参数对输入数据进行归一化,计算方法为(x - mean) * norm;格式为list

# norm:当model_path选择字符串格式时,此项opt不用进行复制默认None
类maix.nn.Model
  • 包含一系列神经网络操作,maix.nn.load()会返回其对象
# maix.nn.Model.forward() 
# 		只能由具体的对象调用,不能类直接调用

# 参数
# input:输入,可以是_maix_image的Image对象,也可以是HWC排列的bytes对象

# standardize: int 类型,默认为1, 当load()加载字典类型时, opt 的mean,norm参数对数据进行标准化;当load()加载字符串类型时,会根据mud文件自动进行标准化;置为0时不会对输入数据进行处理

# layout: "hwc" 或者 "chw", 默认设置为 "hwc"

# debug: int 类型,默认为0,该值不为0时会打印debug信息和forward的推理耗时

# 返回值:
# 特征图, 如果是单层输出, 是一个浮点类型的 numpy.ndarray 对象, 如果是多层输出, 会是一个list对象, 包含了多个numpy.ndarray对象.

# maix.nn.Model.del()
# 删除对象, 内存回收时会自动调用这个函数, 会释放模型占用的资源
del m
模块maix.nn.decoder
  • nn后处理模块,集成了常见的模型的后处理,使用forward进行模型推理得到特征图输出,使用这个模块下的方法对输出的特征图进行后处理
# 类maix.nn.decoder.Yolo2
# YOLO V2的后处理模块,使用时需要创建一个对象,调用run方法对模型推理输出进行解码得到物体的坐标和类别
# 下面的python伪代码
class Yolo2:
	def __init___(self,class_num,anchors,net_in_size=(224,224),net_out_size=(7,7))
		pass
	
	def run (self,fmap,nms=0.3,,threshold=0.5,img_size=None)
		boxes=[]
		probs=[]
		for x,y,w,h,_probs in valid_results:
			if img:
				x*=img_size[0]
				y*=img_size[1]
				w*=img_size[2]
				h*=img_size[3]
				x,y,w,h=int(x),int(y),int(w),int(h)
			boxes.append([x,y,w,h])#item type is float if img_size==0,else int type
			probs=append([max_probs_index,_probs])#probs is list type,item type is float
		return [boxes,probs]
	
# 使用时:
from maix.nn import decoder

labels=["A","B","C"]
anchors=[1.19,1.98,2.79,4.59,4.53,8.92,8.06,5.29,10.32,10.65]		

...

out=m.forwar(img,layout="hwc")
boxes,probs=yolo2_decoder.run(out,thres=0.5,nms=0.3,img_size=(img.width,img.height))
for i,box in enumerate(boxes):
	class_id=probs[i][0]
	prob=probs[i][1][class_id]
	disp_str="{}:{:.2f}%".format(labels[class_id],prob*100)
	print("final box:{},{}".format(box,disp_str))

# maix.nn.decoder.Yolo2.init()
# 构造对象时会自动调用
# 参数:
# 		class_num:类别数量
#		anchors:预选框,list类型,数量为偶数,必须要和训练你时使用的anchors相同,也就是说跟模型绑定的参数
#      	net_in_size:网络输入层分辨率
# 		net_out_size:网络输出层分辨率

# maix.nn.decoder.Yolo2.run()
# 执行解码(后处理),只能对象进行调用,不能类直接调用
# 参数:
# 		fmap:网路输出的特征图,一般是forward函数的结果
# 		nms:非极大值印制,原来去掉重复的框,IOU(两个框的重叠区域)大于这个的值就只取概率最大的一个,取值范围:[0,1],默认值为0.3
# 		threshold:置信度阈值,大于这个值才认为物体有效,取值范围:[0,1],默认0.5
# 		img_size:源图像大小,tuple类型,比如(320,240),这会使返回值的box坐标自动计算为相对于源图的坐标,并且类型为整型,默认None则不会计算,box返回相对值(百分比),浮点类型,范围[0,1]

# 返回值
# [box,probs],list类型。可以参考上面的使用例子,其中:
# 		boxes:list类型,每个元素也是一个list,包含[x,y,w,h],分别代表了框左上角坐标,以及框的宽高
# 		probs:list类型,每个元素也是一个list,包含[max_prob_idx,all_classes_probs]
# 			all_classes_probs:list类型,包含了该框所有类别的置信度
#			max_prob_idx:整型,代表了all_classes_probs中最大值的下标,取值范围:[0,classes_num-1]
模块maix.nn.app
  • 应用模块,包含了一些有意思的应用模块
# 模块maix.nn.app.classifier
# 自学习分类器(视觉),无需训练模型,只使用特征提取模型,在运行时学习多个物体特征,然后即可对物体进行分类识别。适用于简单分类场景
# maix.nn.app.classifier的python伪代码:
class Classifier:
	def __init__(self.model,class_num,sample_num,feature_len,input_w,input_h):
		pass
	def add_class_img(self,img):
		return idx
	def add_sample_img(self,img):
		return idx
	def trian(self):
		return idx,min_dist
	def save(self,path):
		pass
def load(model,path):
	return Classifier()

# 类Classifier
# 使用时需要指定类别数量,通过add_class_img函数传入物体图像来获得物体的特征值,然后通过add_sample_img获取这个类别的图像,用以对开始采集的图像特征值进行优化,sample的图像和开始采集的类被图像可以有一定的差异,但是不要相差太大,采集的顺序无所谓
# 然后调用train方法进行训练(其实就是kmeans聚类),就可以得到使用sample图像特征值优化过后的几个分类的特征值
# 最后使用predict就可以对输入图像的类别进行识别

# 构造方法:init(self,model,class_num,sample_num,feature_len,input_w,input_h)
# 参数:
#	model:maix.nn.Model对象,用于获得图片的特征值
#	class_num:要学习的物体类别数量,比如3
#	sample_num:用以学习特征的物体数量,比如3*5->15
#	feature_len:特征值的长度,取决于特征提取模型的输出形状,比如例程使用resnet18_1000分类模型,倒数第二层输出长度是512
# 	input_w:输入的图像的宽度
#	input_h:输入的图像的高度

# 方法:add_class_img(self,img)
# 添加分类图片,会自动调用模型推理获取图片的特征值
# 参数:
#		img:输入图像,可以是pillow的Image对象,也可以是HWC排列的bytes对象
# 返回值:
#		int类型,代表返回成功添加第几个类别的特征值,取值∈[0, class_num)
# 抛出错误: 如果出现错误, 比如添加图片超过类别数量等, 会抛出错误信息

# 方法: add_sample_img(self, img)
# 添加样本图片, 会自动调用模型推理获取图片的特征值
# 参数:
#		img: 输入图像, 可以是Pillow的Image对象, 也可以是HWC排列的bytes对象
# 返回值:
#		int 类型, 代表返回成功添加第几个样本图片的特征值, 取值∈[0, sample_num)
# 抛出错误:
#		如果出现错误, 比如添加图片超过设置的样本数量等, 会抛出错误信息

#	方法: train(self)
#	训练样本(本质上是聚类分类), 需要在add_class_img和add_sample_img完成后才能调用,否则会出现误差
#	抛出错误: 如果出现错误, 比如类别或者样本采集未完成, 会抛出错误信息

#	方法: predict(self, img)
#	预测给定的图片所属的类别
#	参数:
#			img: 输入图像, 可以是Pillow的Image对象, 也可以是HWC排列的bytes对象
#	返回值:
#			idx: int 类型, 代表给定的图片的特征和这个分类最接近, 取值∈[0, sample_num)
#			min_dist: 图片的特征和idx类别的特征的距离, 距离越小则代表和该类越相似
#			抛出错误: 如果出现错误, 比如参数错误等, 会抛出错误

# 方法: save(self, path)
# 保存当前的特征值参数到文件, 方便断电保存并下次加载使用
# 参数:
#		path:保存的路径,字符串
#		抛出错误:保存出错,会抛出错误信息   

# 方法 load(model, path)
# 加载保存的特征值参数文件,获得类Classifier的对象,加载完成后可直接使用predict函数
# 参数:
#		model:maix.nn.Model对象,用于获得图片的特征值,需要和保存的时候使用的模型相同
# 		path:保存参数的路径
# 返回值:
#		获得类Classifier的对象

# 模块maix.nn.app.face
# 人脸识别模块,这里有一个Face_Recognier类提供了人脸识别的简单封装,推荐使用
# 类FaceRecongnize
# 伪代码:
class FaceRecognize:
	def __init__(self,model_detect,model_fea,fea_len,input_shape,threshold,nms,max_face_num)
		pass
	def get_faces(self, img, std_img = False):
    	return [ prob, [x,y,w,h], [[x,y], [x,y], [x,y], [x,y], [x,y]], feature]
	def compare(self, feature_a, feature_b):
		return score
# 这里有一个Face_Recognizer类提供了人脸识别的简单封装, 推荐使用

# 构造方法: init(self, model_detect, model_fea, fea_len, input_shape, threshold, nms, max_face_num)
# 参数
#		model_detect: 检测模型, maix.nn.Model 对象
#		model_fea: 特征提取模型, maix.nn.Model 对象
#		fea_len: 人脸特征的长度,比如 256
#		input_shape: 输入图像的形状,(w, h, c)格式, 比如(224, 224, 3)
#		threshold: 人脸检测阈值, 默认0.5
#		nms: 人脸检测非极大值抑制值,即用来防止重复框一个人脸, 默认0.3
#		max_face_num: 支持的同时框的人脸数量,取1或者更多

#  获取人脸信息: get_faces(self, img, std_img = False)
#  获取人脸信息, 包括位置和特征值等
#  参数:
#		img: 输入图像, 分辨率需要和检测模型的输入相同, 比如224 x 224, 可以是PIL.Image.Image对象, 或者bytes对象
#		std_img: 取值True或者False, 选择是否返回纠正过的标准人脸图片
# 返回值: 返回一个 list 对象,[ prob, box, landmarks, feature, std_img ],其中std_img根据构造函数的参数std_img决定是否存在
#		prob: 检测到人脸的概率, 比设置的threshold大
#		box: 人脸框, 值为[x,y,w,h] , 分别代表左上角坐标和框的宽高
#		landmarks: 人脸关键点, 共5个点, 格式[[x,y], [x,y], [x,y], [x,y], [x,y]],分别代表了左眼、右眼、鼻子、左嘴角、右嘴角的坐标
#		feature: 人物脸的特征值, 一个list,list中的项目值类型为float(未来有可能会有feature为bytes的可选项)
#		std_img: 人脸图像,PIL.Image.Image对象, 只有当构造函数的参数std_img为True时才会有这个返回值

# 对比人脸特征: compare(self, feature_a, feature_b)
# 对比两个人脸特征值相似度,并返回相似度百分比
# 参数:
#		feature_a: get_faces函数的返回值, 一个list对象或者bytes对象
#		feature_b: get_faces函数的返回值, 一个list对象或者bytes对象
# 返回值: 
#		返回两个人脸特征值的对比相似度分数(百分比),取值范围 ∈ [0.0, 100.0]
MUD文件
  • MUD 文件是模型统一描述文件,全称 model universal description file ;mud 文件可以简化模型运行 Python 代码,还可以使得不同平台的模型文件使用同一份代码运行
# 文件形式
# 文件以 .mud 为后缀,严格按照 INI 的格式进行解析

# 文件内容
# MUD 文件是按照既定顺序和内容进行解读。不同的 MUD 文件之间结构都非常类似,由若干段落(section)组成,在每个带括号的标题下面,是若干个以单个单词开头的关键词(keyword)和一个等号,等号右边的就是关键字对应的值(value); section部分通常用[]进行声明,
# 例如:
[basic]
type =awnn
param=/root/models/awnn_retinaface.param
bin=/root/model/awnn_retinaface.bin

[inputs]
input0=224,224,3,127.5,127.5,127.5,0.0078125,1.0078125,0.0078125

[outputs]
output0=1,4,2058
output1=1,2,2058
output2=1,10,2058

[extra]
outputs_scale=
inputs_scale=

# section & keywords
# [basic]: 基础参数段,包含了模型模型类型、模型参数、模型结构三种文件
#			type:不同目标平台的标识,如R329称为aipu,V831代称为awnn
#			bin:V831,R329 平台模型的参数二进制文件
#			param:V831的模型结构文件,R329融合了模型参数和模型结构故此项置为空
#
# [inputs] :输入信息段
#			input :输入节点名称,输入个数随模型而定,其前三个参数定义为 H,W,C ,后两个的参数以此是mean,norm
# [outputs] :输出信息段		
# 			output :输出节点名称,输出节点个数根据模型而定,其参数定义为 H,W,C 	
# [extra]:额外的参数段,一般是不同平台额外的参数。
#			inputs_scale:输入层在量化后的scale值,按照输入顺序排列 ,如inputs_scale = input0_scale , input1_scale, input2_scale ……
#			outputs_scale:输出层在量化后的scale值,按照输出顺序排列,如outputs_scale = ouput0_scale , output1_scale , output2_scale …… (目前仅R329需要)

参考链接:https://wiki.sipeed.com/soft/maixpy3/zh/api/maix/nn.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栋哥爱做饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值