MNN:
MNN Kit:提供推理以及训练的API接口,用于算法应用集成和调用。
模型推理:
1)解释器对应模型数据
2)session对应运行时配置信息;多个session对应一个解释器,即一个模型可以采用不同的配置进行推理执行;
3)输入tensor,需要指定输入tensor的format,比如caffe::nchw,tf::NHWC;如果与模型的输入不匹配,内部会进行转换;
4)输出tensor的format也需要指定,如果与模型的输出不一致,会进行准换;
模型训练:
支持将其他框架的模型转化为MNN模型用于训练;也可以使用MNN 表达式API搭建模型;
支持蒸馏训练,训练中量化,以及自定义优化算法;
使用表达式API接口搭建模型的步骤:
1)初始化网络中算子参数;比如卷积的kernel大小、shape等信息;
2)实现onForward计算函数;
3)加载模型结构和模型初始化参数snapshot;
4)设置训练框架参数,创建SGD求解器,设置动量参数等;
5)创建数据集和DataLoader
6)开始训练:加载batchsize个样本,计算前向传播,计算损失函数,根据epoch和iteration更新学习率,计算后向传播;
对接后端
对接HIAI NPU
1)设置模型的输入:
NPUBackend::setNetworkInput,创建data节点,默认的输入format为NCHW;
调用tensorShapeFormat将输入tensor转换成om模型输入的tensor;
tensorShapeFormat对将MNN的shape转化为NCHW的shape,对于小于4为的输入进行补维操作;
2)模型在线编译,并使用模型管家进行load;
NPUBackend::bulidIRModelAndLoad
3)模型推理
NPUBackend::process
输入和输出tensor的维度是从编译之后的模型中获取的;调用如下接口获取
mMgrClient->GetModelIOTensorDim(modelName, mInputDimension, mOutputDimension)
4)算子对接
将MNN算子IR转换到HIAI IR,所有的算子继承NPUCommonExecution,实现onResize接口;
mOp:MNN的op
对接Reduce算子:
对axis进行转换:
ErrorCode NPUReduction::onResize(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) { mNpuBackend->setNetworkInput(inputs, mOp); auto opName = mOp->name()->str(); auto type = mOp->main_as_ReductionParam()->operation(); auto xOp = mNpuBackend->getInputOps(mOp); vector<int64_t> origAxis; vector<int64_t> axis; auto reduct = mOp->main_as_ReductionParam(); if (nullptr != reduct->dim()) { for (int i = 0; i < reduct->dim()->size(); ++i) { origAxis.push_back(reduct->dim()->data()[i]); } }else if(inputs.size() == 2){ for (int i = 0; i < inputs[1]->length(0);++i) { int32_t *reduce_dim = inputs[1]->host<int32_t>(); origAxis.push_back(reduce_dim[i]); } }else{ MNN_ASSERT(false); } axis = convertAxis(origAxis,inputs[0]); mConstAxis = ge::op::Const(opName + "_axis"); { ge::TensorDesc fdesc(ge::Shape({static_cast<long>(axis.size())}), ge::FORMAT_ND, ge::DT_INT32); ge::TensorPtr constTensor = std::make_shared<ge::Tensor>(); constTensor->SetTensorDesc(fdesc); constTensor->SetData((uint8_t *)(axis.data()), axis.size()*sizeof(float)); mConstAxis.set_attr_value(constTensor); } if(type == ReductionType_MAXIMUM) { shared_ptr<hiai::op::ReduceMax> reduction(new hiai::op::ReduceMax(opName)); (*reduction) .set_input_x(*xOp.get()).set_input_axes(mConstAxis) .set_attr_keep_dims(mOp->main_as_ReductionParam()->keepDims()); mNpuBackend->setOutputOps(mOp, {reduction}, outputs); }else if(type == ReductionType_SUM) { shared_ptr<hiai::op::ReduceSum> reduction(new hiai::op::ReduceSum(opName)); (*reduction) .set_input_x(*xOp.get()).set_input_axes(mConstAxis) .set_attr_keep_dims(mOp->main_as_ReductionParam()->keepDims()); mNpuBackend->setOutputOps(mOp, {reduction}, outputs); }else if(type == ReductionType_MEAN) { shared_ptr<hiai::op::ReduceMean> reduction(new hiai::op::ReduceMean(opName)); (*reduction) .set_input_x(*xOp.get()).set_input_axes(mConstAxis) .set_attr_keep_dims(reduct->keepDims()); if(reduct->keepDims() == false) { auto shapeDims = tensorShapeFormat(outputs[0]); shared_ptr<ge::op::Reshape> reshape1(new ge::op::Reshape(opName+"reshape1")); (*reshape1).set_input_tensor(*reduction.get()).set_attr_shape(ge::AttrValue::LIST_INT(shapeDims)); mNpuBackend->setOutputOps(mOp, {reduction,reshape1}, outputs); } else { mNpuBackend->setOutputOps(mOp, {reduction}, outputs); } } else if(type == ReductionType_ANY) { shared_ptr<ge::op::ReduceAll> reduction(new ge::op::ReduceAll(opName)); (*reduction) .set_input_x(*xOp.get()).set_attr_axes(axis) .set_attr_keep_dims(mOp->main_as_ReductionParam()->keepDims()); mNpuBackend->setOutputOps(mOp, {reduction}, outputs); }else{ MNN_ERROR("npu reducton not support type : %d \n", type); } return NO_ERROR; } |
对接unpack、softmax、concat等有axis的算子:
将MNN算子的Axis转为NCHW对应的axis:
对接transpose算子
区分1维、2维、3维、4维场景进行permutation参数的转换,将permutation补充到4维;
对接gatherV2算子
常量输入要转成HCHW进行对接
TNN:
TNN网络的组织,类似Caffe的思想,分为NetStructure和NetResource,NetStructure定义了网络结构,包含每一层算子的信息LayerInfo;
NetResource包含多个Layer的参数和权重数据,每个算子是一个Layer,数据存储在RawBuffer中;
算子Layer的定义:
模型解析:
在ncnn_model_interpreter.cc中,将TNN模型的每一层解析出来,
输入input_shape_map默认保存为NCHW,在后面convert中使用
对接HIAI NPU
1)NpuNetwork::Init
- 创建模型管家;
- 调用HiAIModelInit,如果存在已编译好的模型文件,读入OM模型文件;如果不存在已编译好的模型文件,走IR在线编译生成模型;
- 调用IRInitLayers进行TNN Layer到HIAI IR的转换;
CreateGraphInputs:创建graph的输入data,默认是NCHW
CreateConstOpFromResource:创建常量op
ConvertLayers:调用每个算子的Convert,进行逐层转换;
- 调用load加载模型,调用CheckModelCompatibility检查模型兼容性;
- 调用NpuNetwork::Forward()执行推理
输入数据和权重均采用采用NCHW进行对接
对接Reduce类、softmax算子:
没有对轴进行特殊转换;
对接concat、splitV算子:
对接gather算子:
没有对权重、axis进行转换;
后面持续更新~~