[NCNN学习笔记]-1

1、前言

本次继续学习NCNN,希望能够坚持,往期学习NCNN的链接如下。

[NCNN学习笔记]-0

2、学习内容

2.1、batchnorm_arm.cpp

这个章节学习NCNN中batchnorm在NEON上的实现。batchnorm的学习可参考链接:https://zhuanlan.zhihu.com/p/93643523

在NCNN中batchnorm的预处理为ncnn-master\src\layer\batchnorm.cpp

int BatchNorm::load_model(const ModelBin& mb)
{
    slope_data = mb.load(channels, 1);
    if (slope_data.empty())
        return -100;

    mean_data = mb.load(channels, 1);
    if (mean_data.empty())
        return -100;

    var_data = mb.load(channels, 1);
    if (var_data.empty())
        return -100;

    bias_data = mb.load(channels, 1);
    if (bias_data.empty())
        return -100;

    a_data.create(channels);
    if (a_data.empty())
        return -100;
    b_data.create(channels);
    if (b_data.empty())
        return -100;
    
    // 通过https://zhuanlan.zhihu.com/p/93643523中的公式,可以很推算出下面的过程
    for (int i = 0; i < channels; i++)
    {
        float sqrt_var = sqrtf(var_data[i] + eps);
        if (sqrt_var == 0.f)
            sqrt_var = 0.0001f; // sanitize divide by zero
        a_data[i] = bias_data[i] - slope_data[i] * mean_data[i] / sqrt_var;
        b_data[i] = slope_data[i] / sqrt_var;
    }
    return 0;
}

通过上面的代码,明白了a_data和b_data的作用,下面就正式开始学习在数据处理过程中的batchnorm吧

int BatchNorm_arm::forward_inplace(Mat& bottom_top_blob, const Option& opt) const
{
    int elembits = bottom_top_blob.elembits();
    int dims = bottom_top_blob.dims;         // 数据维度,最多为4
    int elempack = bottom_top_blob.elempack; // 每个数据可被分为多少组   例如float32x4_t可被分为4组

    if (elempack == 4)    // float32x4_t、int32x4_t、float16x4_t
    {
        // 对一行进行batchnorm
        if (dims == 1 )
        {
            int w = bottom_top_blob.w; 
            #pragma omp parallel for num_threads(opt.num_threads)
            for (int i = 0; i < w; i++)
            {
                float* ptr = (float*)bottom_top_blob + i * 4;   // 每间隔4个数据取一次地址

                float32x4_t _a = vld1q_f32((const float*)a_data + i * 4); 
                float32x4_t _b = vld1q_f32((const float*)b_data + i * 4);

                float32x4_t _p = vld1q_f32(ptr);
                _p = vmlaq_f32(_a, _p, _b);   // _a + _p.*b     y = a_data + b_data * x
                vst1q_f32(ptr, _p);
            }
        }
		 // 对每一行batchnorm
        if (dims == 2)
        {
            int w = bottom_top_blob.w;
            int h = bottom_top_blob.h;

            #pragma omp parallel for num_threads(opt.num_threads)
            for (int i = 0; i < h; i++)
            {
                float32x4_t _a = vld1q_f32((const float*)a_data + i * 4);
                float32x4_t _b = vld1q_f32((const float*)b_data + i * 4);
                float* ptr = bottom_top_blob.row(i);
                for (int j = 0; j < w; j++)  
                {
                    float32x4_t _p = vld1q_f32(ptr);
                    _p = vmlaq_f32(_a, _p, _b);
                    vst1q_f32(ptr, _p);

                    ptr += 4;
                }
            }
        }
		// 针对channel进行batchnorm
        if (dims == 3 || dims == 4)
        {
            int w = bottom_top_blob.w;
            int h = bottom_top_blob.h;
            int d = bottom_top_blob.d;
            int c = bottom_top_blob.c;
            int size = w * h * d;

            #pragma omp parallel for num_threads(opt.num_threads)
            for (int q = 0; q < c; q++)
            {
                float32x4_t _a = vld1q_f32((const float*)a_data + q * 4);
                float32x4_t _b = vld1q_f32((const float*)b_data + q * 4);

                float* ptr = bottom_top_blob.channel(q);

                for (int i = 0; i < size; i++)
                {
                    float32x4_t _p = vld1q_f32(ptr);
                    _p = vmlaq_f32(_a, _p, _b);
                    vst1q_f32(ptr, _p);

                    ptr += 4;
                }
            }
        }

        return 0;
    }
    return 0;
}

2.2、bias_arm.cpp

这个章节学习ncnn中的的bias计算

int Bias_arm::forward_inplace(Mat& bottom_top_blob, const Option& opt) const
{
    int w = bottom_top_blob.w;
    int h = bottom_top_blob.h;
    int d = bottom_top_blob.d;
    int channels = bottom_top_blob.c;
    int size = w * h * d;
    const float* bias_ptr = bias_data;
    #pragma omp parallel for num_threads(opt.num_threads)
    for (int q = 0; q < channels; q++)
    {
        float* ptr = bottom_top_blob.channel(q);  // 第q个channel的数据
        float bias = bias_ptr[q];
        int nn = size >> 2; // 处理4的整数倍的数据
        int remain = size - (nn << 2);     // 剩余处理向量
        float32x4_t _bias = vdupq_n_f32(bias);
        for (; nn > 0; nn--)
        {
            float32x4_t _p = vld1q_f32(ptr);
            float32x4_t _outp = vaddq_f32(_p, _bias);  // x + bias
            vst1q_f32(ptr, _outp);   
            ptr += 4;
        }
        // 剩余向量使用c语言计算
        for (; remain > 0; remain--)
        {
            *ptr = *ptr + bias;
            ptr++;
        }
    }
    return 0;
}
3、总结

本次学习了NCNN中的batchnorm和bias操作,后续准备学习NCNN时不局限于学习NCNN中的NEON实现,还会关注其他的内容!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/464657.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

用Python 3 开发的摄像头拍照程序

在当今数字化的世界中&#xff0c;使用摄像头进行拍照已成为日常生活的重要组成部分。无论是用于个人用途还是专业用途&#xff0c;能够使用电脑摄像头轻松拍照都是一项有用的技能。本文将指导您使用 Python 3 编写一个简单的程序&#xff0c;让您能够使用电脑摄像头拍照并将其…

如果网络不好 如何下载huggingface上的模型

很多朋友网络不太好&#xff0c;有时候上不了huggingface这样的国外网站&#xff1b; 或者网络流量不太够&#xff0c;想要下载一些stable diffusion模型&#xff0c;或者其他人工智能的大模型的时候&#xff0c;看到动辄几个G的模型文件&#xff0c;不太舍得下载&#xff1b;…

9. 综合案例-ATM系统 (1~7节知识综合练习)

ATM系统_综合大练习 今天的任务是对之前所有的学习的知识, 进行一个综合性的大练习. 老师说的好, 键盘敲烂 这个项目我写了大量的注释给大家参考, 如果有同学是跟着我的系列学习的, 一定动手练一练. 下面的代码只要按着敲是可以直接运行起来的, 我也把完整代码上传到了CSDN上…

Fritzing 简单使用

文章目录 1 Fritzing 资源2 Fritzing 简单使用3 添加自已的元器件3.1 面包板3.1.1 新建面包板 svg 文件3.1.2 新建面包板 3.2 原理图3.3 PCB3.4 图标3.5 使用 1 Fritzing 资源 1&#xff09;官网&#xff1a; 开源的电子设计和原型平台&#xff1a;https://fritzing.org/免费开…

机试:砍树修路

问题描述 代码示例&#xff1a; //一坐标轴表示某道路&#xff0c;从0开始 到L&#xff0c;整数位置上都种有一颗树。现在该路修建地铁&#xff0c;要砍掉铁路线路上的树木。例如&#xff1a;L等于10&#xff0c;铺设4条铁路&#xff0c;坐标是1到2,2到3,2到8&#xff0c;3到…

【SpringBoot】解决数据库时间和返回时间格式不一致的问题

先看问题: 类中的属性中有Date类型的属性 数据库表中的数据: 可以看到也没问题 但是在返回实体类对象时,数据类型是这样的: 虽然数据是成功返回了,但这显然不是我们想要的结果.也不符合我们的日常使用习惯. 这个问题虽然前端,后端都能处理,但最好还是后端来进行处理.前端主…

openEuler学习总结1(仅供学习参考)

华为的openEuler内核是源于Linux。 openEuler操作系统安装流程 第一步&#xff1a;开启虚拟化 第二步&#xff1a;安装一个虚拟化软件virtualbox 第三步&#xff1a;镜像 第四步&#xff1a;配置 设置虚拟机所在的目录 把网卡类型选择成桥接网卡 挂载镜像 设置完成&#xff0…

玩转键盘鼠标,自动化你的电脑操作 —— 定时执行专家

简介 “定时执行专家”是一款功能强大的定时任务执行软件&#xff0c;除了支持常见的定时关机、重启、执行程序等功能外&#xff0c;还拥有模拟键盘按键和模拟鼠标操作功能&#xff0c;可以让你轻松实现各种自动化操作。 模拟键盘按键功能可以模拟用户的键盘输入&#xff0c;让…

BufferedOutputStream类讲解

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java IO相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…

GEE错误——Line 12: xxx.size is not a function(计算列表长度出现错误)

简介 这里我们再计算研究区面积的时候出现了一个错误,这里的问题是Line 12: points8.size is not a function 主要问题是xxx不是一个数组或者对象,无法调用size方法。这里的问题是我们要获取这个对象的时候出现了问题,也就说你给函数传输的并不是一个对象,而不知道是什么…

基于Springboot+Vue+Sercurity实现的大学生健康管理平台

1.项目介绍 大学生健康档案管理系统&#xff0c;通过电子健康档案管理系统这个平台&#xff0c;可以实现人员健康情况的信息化、网络化、系统化、规范化管理&#xff0c;从繁杂的数据查询和统计中解脱出来&#xff0c;更好的掌握人员健康状况。系统的主要功能包括&#xff1a;…

7.JavaWebHTML:构建数字世界的语言和结构

目录 导语&#xff1a; 第一部分&#xff1a;Web概念与作用 1.1 Web的定义 1.2 Web的作用 1.3 JavaWeb 第二部分&#xff1a;HTML概念与内容 2.1 HTML的定义 2.2 HTML的内容 第三部分&#xff1a;HTML的作用 3.1 HTML的作用 3.2 HTML在现代Web开发中的角色 …

2024.3.15

1.单向循环链表 代码&#xff1a; #include"loop.h" //创建单向循环链表 loop_p create_loop_list() {loop_p H (loop_p)malloc(sizeof(loop));if(HNULL){printf("空间申请失败\n");return NULL;}H->len0;H->nextH;return H; } //创建节点 loop_p…

【晴问算法】入门篇—贪心算法—整数配对

题目描述 有两个正整数集合S、T&#xff0c;其中S中有n个正整数&#xff0c;T中有m个正整数。定义一次配对操作为&#xff1a;从两个集合中各取出一个数a和b&#xff0c;满足a∈S、b∈T、a≤b&#xff0c;配对的数不能再放回集合。问最多可以进行多少次这样的配对操作。 输入描…

C语言数据类型 ---变量的定义

目录 关键字&#xff08;Keywords&#xff09; 标识符&#xff08;Identifiers&#xff09; *命名规则 *常量&#xff08;Constant&#xff09; *变量&#xff08;Variable&#xff09; 变量的定义 小结 变量的4个基本属性 程序设计语言的基本构成要素 自然语言程序设…

【Godot4.0】自定义A*寻路拓展类TileMapAStar2D及其使用

概述 Godot提供的AStar2D和AStarGrid2D基本可以解决所有2D的A*寻路问题&#xff1a; 前者提供了基础的A*寻路支持&#xff0c;但是需要手动处理很多内容后者针对基于方形图块的A*寻路&#xff0c;进行了很多自动化的工作&#xff0c;用起来十分简便。但是不使用于六边形、iso…

人人站CMS后台登不进去解决方案(已解决)

公司有一个网站使用的是人人站CMS&#xff0c;最近发现后台登录不进去&#xff0c;有以下报错 发生以下错误: file get contents(http://www.rrzcms.com/Public/cms/config/config.ison): failed to open stream: HTTP reguest failed! 请求的URL导致内部服务器错误。 如果您反…

3.4 bp,si,di寄存器,寻址方式,寄存器总结

汇编语言 1. [bxidata] 我们可以用[bx]来指明一个内存单元我们也可以用[bxidata]来表示一个内存单元&#xff0c;它的偏移地址为bx中的数值加上idata mount c d:masm c: debug r d 2000:1000 e 2000:1000 12 34 56 78 a mov ax,2000 mov ds,ax mov bx,1000 mov ax,[bx] mov c…

如何创建用户流(User Flow):分步指南

原文作者&#xff1a;Camren Browne&#xff0c;CareerFoundry 翻译&#xff1a;数字营销工兵 (sources: 图片来源于网络&#xff09; 用户流(User Flow)是当今用户体验行业中最有用但被误解的工具之一。资深设计师经常避开它们&#xff0c;而初级设计师则很难抓住它们。 事…

代码算法训练营day7 | 454.四数相加II、383. 赎金信、15. 三数之和、18. 四数之和

day7: 剩下的两题&#xff1a; 15. 三数之和18. 四数之和 15. 三数之和 题目链接 状态&#xff1a; 文档&#xff1a;programmercarl.com 注意&#xff1a; 这和第一题中的四数相加Ⅱ很像&#xff0c;如果用哈希算法的思路就是&#xff1a; 两层for循环就可以确定 a 和b 的数值…