栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

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

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

开源深度学习框架研究(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个样本,计算前向传播,计算损失函数,根据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 &inputs, const std::vector &outputs) {

    mNpuBackend->setNetworkInput(inputs, mOp);

    auto opName = mOp->name()->str();

    auto type = mOp->main_as_ReductionParam()->operation();

    auto xOp = mNpuBackend->getInputOps(mOp);

    vector origAxis;

    vector 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();

            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(axis.size())}), ge::FORMAT_ND, ge::DT_INT32);

        ge::TensorPtr constTensor = std::make_shared();

        constTensor->SetTensorDesc(fdesc);

        constTensor->SetData((uint8_t *)(axis.data()), axis.size()*sizeof(float));

        mConstAxis.set_attr_value(constTensor);

    }

    if(type == ReductionType_MAXIMUM) {

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

 

 后面持续更新~~

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/580436.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号