【ncnn android】算法移植(六)——onnx2ncnn源码阅读理解/设计思路

本文主要是介绍【ncnn android】算法移植(六)——onnx2ncnn源码阅读理解/设计思路,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一篇写道:onnx2ncnn的时候,不支持sigmoid,upsample层,于是想着阅读onnx2ncnn的源码。目的:

  • 理解ncnn中onnx2ncnn的主要流程
  • 自定义upsample层(最高要求)

1. 相关资料

  1. Open Neural Network Exchange - ONNX ,onnx的文档
  2. https://github.com/Tencent/ncnn,注意ncnn的不同版本代码是不一样,这里以20180704为准。

2. 主要流程

2.1 ncnn.param保存网络结构参数的格式

2.2 onnx关键api

  1. graph
    GraphProto: graph定义了模型的计算逻辑以及带有参数的node节点,组成一个有向图结构;
    const onnx::GraphProto& graph = model.graph();
    关键属性
    在这里插入图片描述
  • initializer:好像是预训练的权重
  1. node
    NodeProto: 网络有向图的各个节点OP的结构,通常称为层,例如conv,relu层;
    const onnx::NodeProto& node = graph.node(i);
    关键属性
    在这里插入图片描述

  2. attribute
    AttributeProto:各OP的参数,通过该结构访问,例如:conv层的stride,dilation等;
    const onnx::AttributeProto& attr = node.attribute(i);
    在这里插入图片描述

  3. tensor
    TensorProto: 序列化的tensor value,一般weight,bias等常量均保存为该种结构;

// batchnorm
const onnx::TensorProto& scale = weights[node.input(1)];
const onnx::TensorProto& B = weights[node.input(2)];
const onnx::TensorProto& mean = weights[node.input(3)];
const onnx::TensorProto& var = weights[node.input(4)];

一些疑问

  • node.attribute怎么确定?比如conv,batchnorm有不同的参数
    猜想: 在pytorch2onnx中是不是又具体的定义或代码?

  • 比如batchnorm又多个预训练权重的保存顺序
    猜想: 还是在pytorch2onnx中定义的

4. 一些例子

主要分为两类,无结构参数,如batchnorm,直接保存到bin文件中(注意各个参数的顺序);第二类,有结构参数,无预训练权重。就需要将结构参数保存到ncnn.param网络结构参数中。

4.1 batchnorm

float epsilon = get_node_attr_f(node, "epsilon", 1e-5f);const onnx::TensorProto& scale = weights[node.input(1)];
const onnx::TensorProto& B = weights[node.input(2)];
const onnx::TensorProto& mean = weights[node.input(3)];
const onnx::TensorProto& var = weights[node.input(4)];int channels = get_tensor_proto_data_size(scale);fprintf(pp, " 0=%d", channels);		// batchnorm的通道数fwrite_tensor_proto_data(scale, bp);	// batchnorm的缩放变量
fwrite_tensor_proto_data(mean, bp);		// 均值

4.2 pooling

pooling层是没有预训练的参数,但是有很多类型(maxpool,averagepool),和网络参数(kernel_size, pads)等。

std::string auto_pad = get_node_attr_s(node, "auto_pad");//TODO
std::vector<int> kernel_shape = get_node_attr_ai(node, "kernel_shape");
std::vector<int> strides = get_node_attr_ai(node, "strides");
std::vector<int> pads = get_node_attr_ai(node, "pads");int pool = op == "AveragePool" ? 1 : 0;
int pad_mode = 1;if (auto_pad == "SAME_LOWER" || auto_pad == "SAME_UPPER")
{
// TODO
pad_mode = 2;
}fprintf(pp, " 0=%d", pool);if (kernel_shape.size() == 1) {
fprintf(pp, " 1=%d", kernel_shape[0]);
} else if (kernel_shape.size() == 2) {
fprintf(pp, " 1=%d", kernel_shape[1]);
fprintf(pp, " 11=%d", kernel_shape[0]);
}if (strides.size() == 1) {
fprintf(pp, " 2=%d", strides[0]);
} else if (strides.size() == 2) {
fprintf(pp, " 2=%d", strides[1]);
fprintf(pp, " 12=%d", strides[0]);
}if (pads.size() == 1) {
fprintf(pp, " 3=%d", pads[0]);
} else if (pads.size() == 2) {
fprintf(pp, " 3=%d", pads[1]);
fprintf(pp, " 13=%d", pads[0]);
} else if (pads.size() == 4) {
fprintf(pp, " 3=%d", pads[1]);
fprintf(pp, " 13=%d", pads[0]);
fprintf(pp, " 14=%d", pads[3]);
fprintf(pp, " 15=%d", pads[2]);
}fprintf(pp, " 5=%d", pad_mode);

reference

  1. https://blog.csdn.net/SilentOB/article/details/102863944

这篇关于【ncnn android】算法移植(六)——onnx2ncnn源码阅读理解/设计思路的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1056867

相关文章

MyBatis设计SQL返回布尔值(Boolean)的常见方法

《MyBatis设计SQL返回布尔值(Boolean)的常见方法》这篇文章主要为大家详细介绍了MyBatis设计SQL返回布尔值(Boolean)的几种常见方法,文中的示例代码讲解详细,感兴趣的小伙伴... 目录方案一:使用COUNT查询存在性(推荐)方案二:条件表达式直接返回布尔方案三:存在性检查(EXI

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

8种快速易用的Python Matplotlib数据可视化方法汇总(附源码)

《8种快速易用的PythonMatplotlib数据可视化方法汇总(附源码)》你是否曾经面对一堆复杂的数据,却不知道如何让它们变得直观易懂?别慌,Python的Matplotlib库是你数据可视化的... 目录引言1. 折线图(Line Plot)——趋势分析2. 柱状图(Bar Chart)——对比分析3

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Python MCPInspector调试思路详解

《PythonMCPInspector调试思路详解》:本文主要介绍PythonMCPInspector调试思路详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录python-MCPInspector调试1-核心知识点2-思路整理1-核心思路2-核心代码3-参考网址

Android NDK版本迭代与FFmpeg交叉编译完全指南

《AndroidNDK版本迭代与FFmpeg交叉编译完全指南》在Android开发中,使用NDK进行原生代码开发是一项常见需求,特别是当我们需要集成FFmpeg这样的多媒体处理库时,本文将深入分析A... 目录一、android NDK版本迭代分界线二、FFmpeg交叉编译关键注意事项三、完整编译脚本示例四

Android与iOS设备MAC地址生成原理及Java实现详解

《Android与iOS设备MAC地址生成原理及Java实现详解》在无线网络通信中,MAC(MediaAccessControl)地址是设备的唯一网络标识符,本文主要介绍了Android与iOS设备M... 目录引言1. MAC地址基础1.1 MAC地址的组成1.2 MAC地址的分类2. android与I

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

Android 实现一个隐私弹窗功能

《Android实现一个隐私弹窗功能》:本文主要介绍Android实现一个隐私弹窗功能,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 效果图如下:1. 设置同意、退出、点击用户协议、点击隐私协议的函数参数2. 《用户协议》、《隐私政策》设置成可点击的,且颜色要区分出来res/l

spring IOC的理解之原理和实现过程

《springIOC的理解之原理和实现过程》:本文主要介绍springIOC的理解之原理和实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、IoC 核心概念二、核心原理1. 容器架构2. 核心组件3. 工作流程三、关键实现机制1. Bean生命周期2.