[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

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吧

cpp 复制代码
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计算

cpp 复制代码
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实现,还会关注其他的内容!

相关推荐
编程圈子3 小时前
电机驱动开发学习21. R3_2 双相扇区电流采样与第三相重构
驱动开发·学习·重构
chnyi6_ya3 小时前
论文阅读笔记 | The Script is All You Need: 对话到电影级视频生成的 Agentic 框架
论文阅读·笔记
听雨入夜4 小时前
CMake构建学习笔记-libxml库的构建
笔记·学习
iiiiii114 小时前
【论文阅读笔记】Reparameterization Proximal Policy Optimization (RPO):将PPO的稳定性引入可微分强化学习
论文阅读·人工智能·笔记·深度学习·机器学习·机器人·具身智能
for_ever_love__4 小时前
iOS: 网络管理单例
学习·ios·objective-c
不在逃避q4 小时前
一步一步学习使用LiveBindings()TListView进阶使用(),打造天气预报程序
服务器·数据库·学习
鱼子星_5 小时前
【C++】深入剖析list:list及其双向迭代器实现
开发语言·数据结构·c++·笔记·stl·list
知识分享小能手5 小时前
高等数学学习教程,从入门到精通,微分中值定理与导数的应用(5)
学习·机器学习·概率论
520拼好饭被践踏5 小时前
JAVA+Agent学习day25
java·开发语言·学习
魔术师Dix6 小时前
StartGame:Unity TDD 外部工程指南
学习·游戏·unity·c#·测试驱动开发