0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

自定义算子开发

地平线机器人 2022-04-07 16:11 次阅读

地平线工具链中已经支持了丰富的算子,在大多数情况下,您的模型应该可以通过使用hb_mapper工具完成转换并顺利部署到地平线芯片上。 少部分算子不支持情况下,我们建议您先尝试下替换算子的可能性,这样有利于将地平线芯片能力充分发挥出来。

自定义算子目前只提供CPU算子开发能力,可自定义onnx算子以及caffe算子。一个完整的自定义算子应用过程包括注册算子、算子实现、含自定义算子模型转换和运行含自定义op模型四个阶段。

1 自定义onnx算子

1.1 将含有自定义算子的pytorch模型导出ONNX

使用torch.onnx.register_custom_op_symbolic注册自定义算子,再导出onnx模型。有以下几处配置参数需要注意:

1. register_custom_op_symbolic函数的第一个参数'::adaptive_avg_pool2d'为pytorch对应操作符名称,若填写错误,则会导致自定义算子注册失败

2. 操作域必须设置为horizon.custom,算子类型为PyOp

3. class_name_s需要与算子实现文件中的类名相对应

4. module_s与算子实现文件名相同,若算子实现文件在当前目录的子目录(custom_op)中,要将相对路径包含进去:"custom_op/sample_custom"

5. 必须指定input_types_i、output_types_i、output_shape_s三个参数

6. 注意指定opset_version为10或11

参考代码:

import torch

from horizon_nn.horizon_onnx.onnx_pb import TensorProto

from torch.onnx.utils import register_custom_op_symbolic

#prepare your model and input_data

def horizon_pool(g, input, output_size):

return g.op(

'horizon.custom::PyOp', #required, ! must be 'horizon.custom' domain !

input,

class_name_s="GlobalAveragePool", #required ! must match the class def name in sample_custom python file !

compute_s="compute", #optional, 'compute' by default

module_s="sample_custom",#required ! must match the file name of the "op_register_files" !

input_types_i=[TensorProto.FLOAT], #required

output_types_i=[TensorProto.FLOAT],#required

output_shape_s=["1, 1024, 1, 1"]) #required

register_custom_op_symbolic('::adaptive_avg_pool2d',

horizon_pool,

opset_version=11)

torch.onnx.export(model, input_data, "custom_op.onnx", opset_version=11)

1.2 算子实现

对应上一节注册自定义算子时配置的算子实现文件(class_name需要保持一致)。

#sample_custom.py

import numpy as np

from horizon_nn.custom import op_implement_register

@op_implement_register("CustomIdentity")

class CustomIdentity(object):

def __init__(self, kernel_size, threshold):

self._kernel_size = kernel_size

self._default_threshold = threshold

def compute(self, X):

return X

@op_implement_register("GlobalAveragePool")

class GlobalAveragePool(object):

def __init__(self):

pass

def compute(self, X):

return np.nanmean(X, axis=(2, 3)).reshape(-1, 1024, 1, 1)

2 自定义caffe算子

2.1 修改prototxt

在原始模型文件中,将自定义算子对应的类型标记为"Custom" ,并设置custom_param。params 是算子的传入参数,指定方式为‘param_name’:param_value, 多个参数之间使用 \n 分隔。

layer {

name: "hr_op"

type: "Custom"

bottom: "res3d_in"

top: "res3d"

custom_param {

kind: "CustomIdentity"

shape {

dim: 1

dim: 512

dim: 28

dim: 28

}

params: "'kernel_size': 10 \n'threshold': 0.5"

}

}

2.2 算子实现

相比于onnx模型,caffe模型的自定义算子实现还需要提供该算子的输出尺寸。

#sample_custom.py

from horizon_nn.custom.op_registration import op_implement_register, op_shape_infer_register

@op_implement_register("CustomIdentity")

class CustomIdentity(object):

def __init__(self, kernel_size, threshold):

self._kernel_size = kernel_size

self._default_threshold = threshold

def compute(self, X):

return X

@op_shape_infer_register("CustomIdentity")

def infer_shape(inputs_shape):

"""Infer the output shapes of the custom operator.

Arguments:

input_shapes: A list of input shapes.

Returns:

Return a list of custom operator's output shapes.

"""

outputs_shape = inputs_shape

return outputs_shape

3 含自定义算子的模型转换

在模型转换配置文件中,添加自定义算子相关参数,示例如下:

poYBAGJOnKmALm2DAAI_kfFzMYs348.png

custom_op_method固定使用 register

op_register_files自定义算子计算的实现文件,如果有多份实现,使用 ‘;’ 将各个文件分开即可。

4 含自定义算子的模型推理

想将包含自定算子的.bin模型顺利部署到开发板上,还需要提供自定义算子的C++代码实现。 您可以使用下文提供的模板进行修改:

头文件:

// custom_identity.h

#ifndef ADVANCED_SAMPLES_CUSTOM_IDENTITY_H_

#define ADVANCED_SAMPLES_CUSTOM_IDENTITY_H_

#include

#include

#include "dnn/hb_dnn.h"

#include "dnn/plugin/hb_dnn_layer.h"

#include "dnn/plugin/hb_dnn_ndarray.h"

namespace hobot {

namespace dnn {

Layer *CustomIdentity_layer_creator();

class CustomIdentity : public Layer {

public:

CustomIdentity() = default;

~CustomIdentity() override = default;

public:

int32_t Init(const Attribute &attributes) override;

int32_t Forward(const std::vector &bottomBlobs,

std::vector &topBlobs,

const hbDNNInferCtrlParam *inferCtrlParam) override;

std::string GetType() const override { return "CustomIdentity"; }

private:

std::string module_;

};

} // namespace dnn

} // namespace hobot

#endif

cpp文件:

// custom_identity.cpp

#include "custom_identity.h"

namespace hobot {

namespace dnn {

Layer *CustomIdentity_layer_creator() { return new CustomIdentity; }

int32_t CustomIdentity::Init(const Attribute &attributes) {

// unused attribute, just demonstrating

attributes.GetAttributeValue(&module_, "module");

return 0;

}

int32_t CustomIdentity::Forward(const std::vector &bottomBlobs,

std::vector &topBlobs,

const hbDNNInferCtrlParam *inferCtrlParam) {

const NDArray *input = bottomBlobs[0];

NDArray *out = topBlobs[0];

const auto *input_data = input->Dptr();

auto *out_data = out->Dptr();

uint32_t size = input->Size();

for (uint32_t i = 0U; i < size; i++) { 

out_data[i] = input_data[i];

}

return 0;

}

} // namespace dnn

} // namespace hobot

将以上两个文件放在当前工程目录下之后,编写infer代码时仅需要在加载模型之前增加对算子的注册即可,注册可参考以下代码:

//infer.cpp

#include "custom_identity.h"

// register custom layer

hbDNNRegisterLayerCreator("CustomIdentity",

hobot::dnn::CustomIdentity_layer_creator)

本文转载自地平线开发者社区:https://developer.horizon.ai
原作者:颜值即正义
原文链接:https://developer.horizon.ai/forumDetail/71036525692881018

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 算子
    +关注

    关注

    0

    文章

    15

    浏览量

    7239
  • 模型转换
    +关注

    关注

    0

    文章

    3

    浏览量

    5160
收藏 人收藏

    评论

    相关推荐

    AIBOX-1684X:把大语言模型“装”进小盒子

    AIBOX-1684X支持主流大模型私有化部署,算力高达32TOPS,同时也支持CNN、RNN、LSTM等传统网络架构,支持TensorFNNX和Darknet等深度学习架构,并支持自定义算子开发
    的头像 发表于 04-20 08:02 77次阅读
    AIBOX-1684X:把大语言模型“装”进小盒子

    HarmonyOS开发实例:【自定义Emitter】

    使用[Emitter]实现事件的订阅和发布,使用[自定义弹窗]设置广告信息。
    的头像 发表于 04-14 11:37 615次阅读
    HarmonyOS<b class='flag-5'>开发</b>实例:【<b class='flag-5'>自定义</b>Emitter】

    鸿蒙ArkUI实例:【自定义组件】

    组件是 OpenHarmony 页面最小显示单元,一个页面可由多个组件组合而成,也可只由一个组件组合而成,这些组件可以是ArkUI开发框架自带系统组件,比如 `Text` 、 `Button` 等,也可以是自定义组件,本节笔者简单介绍一下
    的头像 发表于 04-08 10:17 150次阅读

    基于YOLOv8实现自定义姿态评估模型训练

    Hello大家好,今天给大家分享一下如何基于YOLOv8姿态评估模型,实现在自定义数据集上,完成自定义姿态评估模型的训练与推理。
    的头像 发表于 12-25 11:29 1263次阅读
    基于YOLOv8实现<b class='flag-5'>自定义</b>姿态评估模型训练

    博途用户自定义库的使用

    博途官方提供了很多库,比如:基本函数库、通信库、安全库、驱动库等等,用户可以使用库中的函数/函数块来完成具体的控制任务。除了官方的库,我们也可以创建自己的库(用户自定义库)。比如,把项目
    的头像 发表于 12-25 10:08 287次阅读
    博途用户<b class='flag-5'>自定义</b>库的使用

    Android端自定义铃声 MobPush对安卓端自定义铃声的教程

    如何为APP推送设置独特的通知铃声呢?本次带来的是MobPush对安卓端自定义铃声的教程,快来看看吧~
    的头像 发表于 10-21 15:34 812次阅读
    Android端<b class='flag-5'>自定义</b>铃声 MobPush对安卓端<b class='flag-5'>自定义</b>铃声的教程

    如何使用BMLang开发自定义算子

    如何使用BMLang开发自定义算子
    发表于 09-18 06:57

    OpenHarmony应用开发自定义弹窗

    本文转载自《OpenHarmony应用开发自定义弹窗》,作者:zhushangyuan_ ​ 应用场景 在应用的使用和开发中,弹窗是一个很常见的场景,自定义弹窗又因为极高的自由度得以
    发表于 09-06 14:40

    RZ-G2L 技术贴|psplash自定义开机画面

    psplash自定义开机画面:以下方法基于瑞萨RZ/G2L系列HD-G2L-IOT开发板测试.
    的头像 发表于 08-28 16:04 438次阅读
    RZ-G2L 技术贴|psplash<b class='flag-5'>自定义</b>开机画面

    labview超快自定义控件制作和普通自定义控件制作

    labview超快自定义控件制作和普通自定义控件制作
    发表于 08-21 10:32 5次下载

    教程 3:构建自定义配置文件

    教程 3:构建自定义配置文件
    发表于 07-06 18:49 0次下载
    教程 3:构建<b class='flag-5'>自定义</b>配置文件

    教程 2:自定义配置文件示例

    教程 2:自定义配置文件示例
    发表于 07-04 20:50 0次下载
    教程 2:<b class='flag-5'>自定义</b>配置文件示例

    带计时器的自定义锻炼

    电子发烧友网站提供《带计时器的自定义锻炼.zip》资料免费下载
    发表于 06-16 10:29 0次下载
    带计时器的<b class='flag-5'>自定义</b>锻炼

    PyTorch教程6.5之自定义图层

    电子发烧友网站提供《PyTorch教程6.5之自定义图层.pdf》资料免费下载
    发表于 06-05 15:17 0次下载
    PyTorch教程6.5之<b class='flag-5'>自定义</b>图层

    labview自定义控件

    labview自定义精美控件
    发表于 05-15 16:46 9次下载