开源深度学习框架研究(1)

MNN:

MNN Kit:提供推理以及训练的API接口,用于算法应用集成和调用。

Python 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个样本,计算前向传播,计算损失函数,根据epochiteration更新学习率,计算后向传播;

对接后端

对接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进行转换;

 

 后面持续更新~~

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值