-
Notifications
You must be signed in to change notification settings - Fork 2.1k
python
MNN Python API可以使用源码安装,也可以直接使用pip安装预编译whl包;pip安装用法如下:
# 外部版本安装
pip install MNN==$version
# 公司内部版本安装
pip install -i https://artifacts.antgroup-inc.cn/simple/ MNN-Internal==$versionMNN在C++的基础上,增加了Python扩展。扩展单元包括两个部分:
- MNN:负责推理,训练,图像处理和数值计算
- MNNTools:对MNN的部分工具进行封装,包括:mnn,mnnconvert和mnnquant
MNNTools提供目前主要是2个工具,用法可以参考mnnconvert和mnnquant
Python中的Module API与C++中的函数名略有区别,用法相似。主要数据类型如下:
基本推理流程如下:
import MNN.nn as nn
import MNN.cv as cv
import MNN.numpy as np
import MNN.expr as expr
# 配置执行后端,线程数,精度等信息;key-value请查看API介绍
config = {}
config['precision'] = 'low' # 当硬件支持(armv8.2)时使用fp16推理
config['backend'] = 0 # CPU
config['numThread'] = 4 # 线程数
rt = nn.create_runtime_manager((config,))
# 加载模型创建_Module
net = nn.load_module_from_file('mobilenet_v1.mnn', ['data'], ['prob'], runtime_manager=rt)
# 读取图片
image = cv.imread('cat.jpg')
# 转换为float32, 形状为[224,224,3]
image = cv.resize(image, (224, 224), mean=[103.94, 116.78, 123.68], norm=[0.017, 0.017, 0.017])
# 增加batch HWC to NHWC
input_var = np.expand_dims(image, 0)
# NHWC to NC4HW4
input_var = expr.convert(input_var, expr.NC4HW4)
# 执行推理
output_var = net.forward(input_var)
# NC4HW4 to NHWC
output_var = expr.convert(output_var, expr.NHWC)
# 打印出分类结果, 282为猫
print("output belong to class: {}".format(np.argmax(output_var)))
# output belong to class: 282不建议使用该API执行推理,建议使用Module API
Python中Session API的函数名与用法与C++基本一样。使用的主要数据类型如下:
- Interpreter 解释器,持有模型资源
- Session 会话,持有推理资源
- Tensor 用来描述输入输出数据
- CVImageProcess 图像处理模块
- CVMatrix 用来描述图像的仿射变换
基本推理流程如下:
- 创建Interpreter
- 创建Session
- 获取Session的输入输出
- 使用ImageProcess/cv进行图像处理(可选)
- 拷贝数据到输入Tensor
- 执行resize(可选)
- 执行Session
- 获取输出Tensor数据
import MNN
import MNN.cv as cv
import MNN.numpy as np
import MNN.expr as expr
# 创建interpreter
interpreter = MNN.Interpreter("mobilenet_v1.mnn")
# 创建session
config = {}
config['precision'] = 'low'
config['backend'] = 'CPU'
config['thread'] = 4
session = interpreter.createSession(config)
# 获取会话的输入输出
input_tensor = interpreter.getSessionInput(session)
output_tensor = interpreter.getSessionOutput(session)
# 读取图片
image = cv.imread('cat.jpg')
dst_height = dst_width = 224
# 使用ImageProcess处理第一张图片,将图片转换为转换为size=(224, 224), dtype=float32,并赋值给input_data1
image_processer = MNN.CVImageProcess({'sourceFormat': MNN.CV_ImageFormat_BGR,
'destFormat': MNN.CV_ImageFormat_BGR,
'mean': (103.94, 116.78, 123.68, 0.0),
'filterType': MNN.CV_Filter_BILINEAL,
'normal': (0.017, 0.017, 0.017, 0.0)})
image_data = image.ptr
src_height, src_width, channel = image.shape
input_data1 = MNN.Tensor((1, dst_height, dst_width, channel), MNN.Halide_Type_Float, MNN.Tensor_DimensionType_Tensorflow)
#设置图像变换矩阵
matrix = MNN.CVMatrix()
x_scale = src_width / dst_width
y_scale = src_height / dst_height
matrix.setScale(x_scale, y_scale)
image_processer.setMatrix(matrix)
image_processer.convert(image_data, src_width, src_height, 0, input_data1)
# 使用cv模块处理第二张图片,将图片转换为转换为size=(224, 224), dtype=float32,并赋值给input_data2
image = cv.imread('TestMe.jpg')
image = cv.resize(image, (224, 224), mean=[103.94, 116.78, 123.68], norm=[0.017, 0.017, 0.017])
input_data2 = np.expand_dims(image, 0) # [224, 224, 3] -> [1, 224, 224, 3]
# 合并2张图片到,并赋值给input_data
input_data1 = expr.const(input_data1.getHost(), input_data1.getShape(), expr.NHWC) # Tensor -> Var
input_data = np.concatenate([input_data1, input_data2]) # [2, 224, 224, 3]
input_data = MNN.Tensor(input_data) # Var -> Tensor
# 演示多张图片输入,所以将输入resize到[2, 3, 224, 224]
interpreter.resizeTensor(input_tensor, (2, 3, 224, 224))
# 重新计算形状分配内存
interpreter.resizeSession(session)
# 拷贝数据到输入Tensor
input_tensor.copyFrom(input_data)
# 执行会话推理
interpreter.runSession(session)
# 从输出Tensor拷贝出数据
output_data = MNN.Tensor(output_tensor.getShape(), MNN.Halide_Type_Float, MNN.Tensor_DimensionType_Caffe)
output_tensor.copyToHostTensor(output_data)
# 打印出分类结果: 282为猫,385为象
output_var = expr.const(output_data.getHost(), [2, 1001])
print("output belong to class: {}".format(np.argmax(output_var, 1)))
# output belong to class: array([282, 385], dtype=int32)Python的cv和numpy接口,其中cv是对C++中tools/cv实现的封装;numpy则是对expr接口的封装;这两个接口主要为了提高MNN的易用性,与opencv与numpy做到了再接口上的部分兼容,在用法和思路上基本一致。主要数据类型如下:
-
Var
cv中的图像,numpy中的ndarray
cv和numpy主要用作模型的前后处理部分,和一些数值计算任务。比如从图片直接读取数据后一般需要执行颜色空间变换,数据类型变换,缩放,裁剪等操作,这些可以用cv模块函数实现;模型输出的结果可能需要做一些额外的变换和计算,这些可以用numpy模块函数实现。
使用cv与numpy中的函数做前后处理,执行模型推理的例子
import MNN
import MNN.cv as cv
import MNN.numpy as np
# 加载模型
net = MNN.nn.load_module_from_file('mobilenet_v1.mnn', ["data"], ["prob"])
# cv模块图片处理
image = cv.imread('cat.jpg')
image = cv.resize(image, (224, 224))
# 类似ndarray的数值运算
image = image - (103.94, 116.78, 123.68)
image = image * (0.017, 0.017, 0.017)
input_var = np.expand_dims(image, 0)
input_var = MNN.expr.convert(input_var, MNN.expr.NC4HW4)
output_var = net.forward(input_var)
output_var = MNN.expr.convert(output_var, MNN.expr.NHWC)
# 类似numpy操作的后处理
print("output belong to class: {}".format(np.argmax(output_var)))cv模块提供了与OpenCV相似的接口函数,具备基础的图像处理能力,目前支持的cv函数60个。
| 函数名 | 功能 |
|---|---|
| haveImageReader | 是否可读(解码) |
| haveImageWriter | 是否可写(编码) |
| imdecode | 从内存解码为Mat |
| imencode | 编码Mat到内存中 |
| imread | 读图片 |
| imwrite | 写图片 |
| 函数名 | 功能 |
|---|---|
| blur | 均值滤波,平滑模糊 |
| boxFilter | 盒子滤波, |
| dilate | 膨胀 |
| filter2D | 2d卷积 |
| GaussianBlur | 高斯模糊 |
| getDerivKernels | 求导数,实际为Sobel/Scharr |
| getGaborKernel | 获取Gabor核 |
| getGaussianKernel | 获得高斯核 |
| getStructuringElement | 获取结构化元素用于形态学操作 |
| Laplacian | 边缘检测滤波 |
| pyrDown | 高斯平滑+下采样 |
| pyrUp | 上采样+高斯平滑 |
| Scharr | 边缘检测滤波 |
| sepFilter2D | 2个一维kernel做滤波 |
| Sobel | 边缘检测滤波 |
| spatialGradient | 梯度,实际为Sobel |
| sqrBoxFilter | 平方后滤波 |
| 函数名 | 功能 |
|---|---|
| getAffineTransform | 仿射变换 |
| getPerspectiveTransform | 透视变换 |
| getRectSubPix | 截取矩形区域 |
| getRotationMatrix2D | 旋转矩阵 |
| invertAffineTransform | 仿射变换矩阵求逆 |
| resize | 图片放缩 |
| warpAffine | 仿射变换 |
| warpPerspective | 透视变换 |
| 函数名 | 功能 |
|---|---|
| blendLinear | 线性混合2个图像 |
| threshold | 逐像素阈值化 |
| 函数名 | 功能 |
|---|---|
| arrowedLine | 画箭头 |
| circle | 画圆 |
| drawContours | 画轮廓 |
| fillPoly | 填充多边形 |
| line | 画线段 |
| rectangle | 画矩形 |
| 函数名 | 功能 |
|---|---|
| cvtColor | 颜色空间转换 |
| cvtColorTwoPlane | YUV420到RGB的转换 |
| 函数名 | 功能 |
|---|---|
| findContours | 轮廓检测 |
| contourArea | 计算轮廓的面积 |
| convexHull | 计算点集的凸包 |
| minAreaRect | 最小外接矩形 |
| boundingRect | 计算点集的最小外接矩形 |
| connectedComponentsWithStats | 计算图像的连通域 |
| boxPoints | 计算矩形的四个顶点坐标 |
| 函数名 | 功能 |
|---|---|
| calcHist | 计算直方图 |
| 函数名 | 功能 |
|---|---|
| Rodrigues | 旋转矩阵转换为旋转向量 |
| solvePnP | 计算2d到3d的映射 |
| 函数名 | 功能 |
|---|---|
| copyTo | 带mask的拷贝 |
| bitwise_and | 带mask按位与 |
| bitwise_or | 带mask按位或 |
| bitwise_xor | 带mask按位异或 |
| hconcat | 水平方向拼接 |
| vconcat | 垂直方向拼接 |
| mean | 求均值 |
| flip | 翻转 |
| rotate | 旋转 |
numpy函数170个,函数列表如下:
| 函数名 | 功能 |
|---|---|
| empty | 空数组 |
| empty_like | 空数组like |
| eye | 对角线2d数组 |
| identity | 对角线2d数组 |
| ones | 全1数组 |
| ones_like | 全1数组like |
| zeros | 全0数组 |
| zeros_like | 全0数组like |
| full | 填充 |
| full_like | 填充like |
| array | 创建数组 |
| asarray | 创建数组 |
| asanyarray | 创建数组 |
| ascontiguousarray | 创建数组 |
| asmatrix | 创建2d数组 |
| copy | 拷贝数组 |
| arange | 范围创建 |
| linspace | 区间创建 |
| logspace | log区间创建 |
| geomspace | log区间创建 |
| meshgrid | 坐标矩阵 |
| mat | 矩阵 |
| 函数名 | 功能 |
|---|---|
| copyto | 拷贝至 |
| shape | 获取形状 |
| reshape | 改变形状 |
| ravel | 拉平 |
| flat | 拉平 |
| flatten | 拉平 |
| moveaxis | 移动维度 |
| rollaxis | 轮转维度 |
| swapaxes | 交换维度 |
| T | 转置 |
| transpose | 转置 |
| atleast_1d | 至少1维 |
| atleast_2d | 至少2维 |
| atleast_3d | 至少3维 |
| broadcast_to | 广播 |
| broadcast_arrays | 数组广播 |
| expand_dims | 增加维度 |
| squeeze | 压缩1维度 |
| asfarray | 转浮点 |
| asscalar | 转标量 |
| concatenate | 连接 |
| stack | 连接 |
| vstack | 垂直连接 |
| hstack | 水平连接 |
| dstack | 深度连接 |
| column_stack | 列连接 |
| row_stack | 行连接 |
| split | 切分 |
| array_split | 数组切分 |
| dsplit | 深度切分 |
| hsplit | 水平切分 |
| vsplit | 垂直切分 |
| tile | 重复堆叠 |
| repeat | 重复 |
| reshape | 变形 |
| 函数名 | 功能 |
|---|---|
| nonzero | 非0元素坐标 |
| where | 条件选取 |
| unravel_index | 反拉平坐标 |
| 函数名 | 功能 |
|---|---|
| dot | 点乘 |
| vdot | 点乘 |
| inner | 内积 |
| matmul | 矩阵乘 |
| 函数名 | 功能 |
|---|---|
| all | 全部非0 |
| any | 任意非0 |
| logical_and | 与 |
| logical_or | 或 |
| logical_not | 否 |
| logical_xor | 异或 |
| array_equal | 相等 |
| array_equiv | 相等 |
| greater | 大于 |
| greater_equal | 大于等于 |
| less | 小于 |
| less_equal | 小于等于 |
| equal | 等于 |
| not_equal | 不等 |
| API | 功能 |
|---|---|
| sin | 正弦 |
| cos | 余弦 |
| tan | 正切 |
| arcsin | 反正弦 |
| arccos | 反余弦 |
| arctan | 反正切 |
| hypot |
| | arctan2 | | | sinh | | | cosh | | | tanh | | | arcsinh | | | arccosh | | | arctanh | | | around | | | round_ | | | rint | | | floor | | | ceil | | | trunc | | | prod | 积 | | sum | 和 | | nanprod | 积 | | nansum | 和 | | exp | e指数 | | expm1 | e指数-1 | | exp2 | 2指数 | | log | 对数 | | log10 | 10对数 | | log2 | 2对数 | | log1p | x+1对数 | | logaddexp | exp对数 | | logaddexp2 | 2指数对数 | | sinc | | | signbit | | | copysign | | | frexp | | | ldexp | | | add | 加 | | reciprocal | 倒数 | | positive | 取正 | | negative | 取负 | | multiply | 乘 | | divide | 除 | | power | 指数 | | subtract | 减 | | true_divide | 除 | | floor_divide | 除 | | float_power | 指数 | | fmod | 模 | | mod | 模 | | modf | 模 | | remainder | 余 | | divmod | 除,余 | | convolve | 卷积 | | clip | 缩小范围 | | sqrt | 平方根 | | cbrt | 立方根 | | square | 平方 | | absolute | 绝对值 | | fabs | 绝对值 | | sign | 符号 | | maximum | 取大 | | minimum | 取小 | | fmax | 取大 | | fmin | 取小 |
| 函数名 | 功能 |
|---|---|
| pad | 扩充 |
| 函数名 | 功能 |
|---|---|
| random | 随机数 |
| rand | 随机数 |
| randn | 随机数 |
| randint | 随机定点数 |
| 函数名 | 功能 |
|---|---|
| sort,lexsort,argsort | 排序 |
| argmax | 最大值坐标 |
| nanargmax | 最大值坐标 |
| argmin | 最小值坐标 |
| nanargmin | 最小值坐标 |
| argwhere | 非0坐标 |
| flatnonzero | 非0元素 |
| count_nonzero | 非0总数 |
| 函数名 | 功能 |
|---|---|
| amin | 最小值 |
| amax | 最大值 |
| nanmin | 最小值 |
| nanmax | 最大值 |
| ptp | 范围 |
| average | 均值 |
| mean | 均值 |
| std | 标准差 |
| var | 方差 |
| nanmean | 均值 |
| nanstd | 标准差 |
| nanvar | 方差 |