ncnn conv5x5s1_neon的非NEON实现解析

函数:  static void conv5x5s1_neon(const Mat& bottom_blob, Mat& top_blob, const Mat& _kernel, const Mat& _bias, const Option& opt)

说明:这个卷积实现有三个分支,

  • 使用NEON aarch64指令的分支,
  • 使用NEON arm32指令的分支:
  • 不使用NEON指令的分支;

当然,NEON aarch64指令的分支性能最高,代码也更难懂一些。

输入:

  • Bottom_blob:;
  • _kernel:
  • _bias:
  • opt

输出:

  •  Top_blob:;

返回值:void

非NEON实现的处理过程:

它并没有像caffe那样先进行按列展开,然后调用openblas的GEMM的方式完成。而是,采用最原始的4层嵌套循环,完成kernel在bottom blob data上滑动完成,具体如下所示:

  1. 因为输出的每个channel的Mat,是由该channel对应的kernel在输入的blob data上滑动得到的;因此,该输出的每个channel的Mat之间是相互独立的。所以,可以采用openmp进行并行化处理。也把不同output channel的遍历放在嵌套循环的最顶层;因此,当前channel对应的kernel,记为kernel_curOutChs, 相对于kernel起始地址的偏移为:(CurOutChannelNum)*(MaxInChannelNum)*5*5。
  2. 因为输入 的channel与当前kerne(记为kernel_curOutChs)的channel(记为kernel_curOutChs_curInChs)是对应的,但是,对于当前output channel的当前位置的value是所有input channel与对应的kernel_curOutChs_curInChs窗口点乘后求和得到的。因此,对于output 结果来说,不同input channel之间有求和的关联关系,因此不能并行化。因此,把不同input channel的遍历放在了第二层。当前input channel的kernel(kernel_curOutChs_curInChs)对应于当前output channel kernel(kernel_curOutChs)的起始位置偏移为:CurInChannelNum * 25;
  3. 遍历output h,再嵌套遍历output w,进行滑动窗口计算。

因此,从上面的实现上可以看到,如果不采用NEON方式去实现的话,它的性能是很差的,比caffe采用列展开然后openblas矩阵相乘还要差的多。

所以,NCNN的价值在于NEON的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值