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

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

3天内不再提示

ARM NEON在矩阵&向量计算中的加速概述

冬至子 来源:内核工匠 作者:Toby Zhang 2023-12-01 10:37 次阅读

一、概述

NEON是ARM上使用的一种SIMD(Single Instruction Multiple Data – 单指令多数据)指令集。可实现64位/128位的并行计算。简单理解就是一个计算指令,可以指定4个Float和4个Float并行计算(也可以是其他数据类型,但是必须包含在64位/128位内),得到4个Float结果。而不是一次只能一个Float和一个Float的计算。

比如在RGB颜色转灰色时,计算公式为:Gray = R *0.299 + G *0.587 + B * 0.114,计算过程是由3个float乘法,2个加发组成,共有5个计算指令;如果直接使用NEON指令,就是可以直接通过一个指令计算完成,提升80%的理论性能。

矩阵计算就更为明显,在4x4的矩阵和4个元素的向量相乘时,有16个float乘法和12个加法计算;NEON可以4个指令直接计算,提升的性能更明显。

当然,这种计算需要是一种矩阵或者像素计算密集型的场景,比如RGB图片转黑白色,不通过GPU加速,而是通过CPU计算的场景;有多个3D模型,每帧需要为每个3D模型进行矩阵计算等等。

二、NEON在矩阵&向量中的计算示例

向量的点积运算示例(这里向量以4个元素为例,前3个元素通常表示3D空间的xyz坐标,第4个元素w用于齐次坐标;也可以表示颜色的RGBA)。两个向量分别是:,,向量的点积计算公式:。对应的NEON加速代码如下:

image.png

类似vdupq_n_f32、vld1q_f32、vmlaq_f32、vadd_f32、vget_lane_f32等等APIs,都是ARM NEON的intrinsics指令,C格式的API。并且这些APIs都定义在arm_neon.h头文件中。ARM NEON指令有两种实现方式,一种就是示例中的Intrinsics指令,另外一种就是直接使用NEON的汇编指令,嵌入到C语言代码中。我们这里只是以Intrinsics指令为例,汇编指令在原理上一样。

三、示例代码中APIs的说明

3.1 ARM NEON向量寄存器

向量寄存器用来存放向量数据,每个向量元素的类型必须相同。这个向量寄存器有128位,AArch64有32个这个寄存器,AArch32/Armv7有16个这个寄存器。

每个寄存器可以表示2个double float类型数据(每个数据占用64位),4个float类型数据(每个数据占用32位),8个short类型数据(每个数据占用16位),16个byte类型数据(每个数据占用8位)。数据类型可以是整形,也可以是浮点数,只要占用位数对齐,类型统一即可。

image.png

3.2 示例说明

在计算时,第一步是要把C代码中定义的数据(数组的形式存在,在运行栈中,或者在堆中)加载到向量寄存器中,第二步通过寄存器进行并行计算,第三步把结果写入到指定寄存器,第四步寄存器结果写入C代码对应的变量中(即C语言的栈或者堆中)。

image.png

第一步:vld1q_f32的意思就是把” A + k”地址指向的内容加载到向量寄存器。f32的意思是,一个值是32位。这个命令是从指定地址,连续复制数据到寄存器,并填满寄存器。比如,这里一个数据是32位,一个寄存器128位,也就是这个命令会连续填充4个f32值。说明:这里是多对(“K”个)向量进行点积计算。

第二步:vmlaq_f32意思是把两个寄存器中,并行4个通道的4个f32分别对应相乘,同时把结果和保存结果的寄存器对应通道进行累加。

第三步:vget_high_f32、vget_low_f32是取寄存器的高位和低位(按照f32的type,分别有2个通道),vadd_f32就是获取高位2通道和低位2通道分别相加,存到一个float32x2_t数据格式用(f32类型,2通道)。vpadd_f32中的p是pairwise,意思是将参数两个向量的相邻数据进行计算,这里就是r自己的2个相邻通道相加。

第四步:vget_lane_f32比较简单,就是获取第一个参数寄存器中指定通道的值。这里就是第0通道的值。并写会到一个float值中。

四、点积的推广

这里的点积相对比较复杂,考虑到了一些通用性。这里使用了一个for循环,当只是计算两个4元素向量的点积时,可以把for循环去掉,vmlaq_f32由vmull_f32替换即可。vmull_f32的原型:Result_t vmull_type(Vector_t N, Vector_t M),Result_t可以是float32x4_t,M和N就是left_vec和right_vec。

如果进行叉乘,则不需要进行第三步,直接返回一个float32x4_t的类型数据即可。

如果计算矩阵(4x4)和向量(4通道)相乘,就是计算点积4次,并且结果分别放到float32x4_t类型的4个通道中。

如果是矩阵(4x4)相乘则是4个叉乘。

这四种情况可以自己根据上方点积的计算方式,独立写出。

五、数据类型和函数指令说明

其实NEON Intrinsics指令中,对使用的变量类型、函数定义做了扩展,便于记忆和理解。

1.比如下方的数据类型:

image.png

A. int是数据类型,可以是int/uint/float/poly等等。

B. 后边几个数字由‘x’号链接,第一个数字就是每个元素的大小,这里是bit,而非Byte,可以是8/16/32/64。

C. 第二个数字是通道。比如表示颜色的RGBA,就是4通道,每个通道可以用一个byte表示(这里其实就是int8类型)。表示3D空间坐标,可以是xyz,就是3通道。如果是一个2D平面,就是一个xy,2通道了。

D. 最后一个数字表示有多少个。比如一个3D空间坐标xyz,一个四边形有4个顶点,这里就可以表示4(这个值通常是一个2的次幂数)。

这里可以根据实际情况选择自己的数据类型。不过要注意,这里要和128位对齐,符合自己实际数据对齐逻辑,不能超出。

2.函数也有类似的表达方式,例如:

image.png

v表示的AArch32/Armv7的指令

p表示pairwise计算。这里表示的是a和b向量的相邻数据进行两两和操作,如下方的操作方式:

image.png

add就是加法,加减乘除普通计算,还有一些操作,比如加载、存储、移位、逻辑计算、类型转换等等。

q表示试用128位的向量计算器,不然就使用64位向量寄存器。

s8就是数类型了,可以是:u8、s8、u16、s16、u32、s32、f32、f64。

更多的内容可以在底部参考资料中,找到相关内容。

通过数据类型和函数类型,我们就可以根据实际情况,结合这些函数,封装我们自己的加速代码逻辑,达到优化的目的。

六、总结

这里只是对点积计算方式进行了解析,同时对于其他情况的推广。其实对于int、char等类型可以类比计算。对像素、向量、矩阵等等的计算会成倍提升(理论性能提升16、8、4、2倍不等,根据实际类型确定)。特别是在移动端,图形计算、图形处理领域,CPU性能遇到瓶颈,进行性能优化时,NEON指令是一个不错的优化点。

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

    关注

    134

    文章

    8651

    浏览量

    361816
  • 寄存器
    +关注

    关注

    30

    文章

    5028

    浏览量

    117723
  • RGB
    RGB
    +关注

    关注

    4

    文章

    763

    浏览量

    57412
  • C语言
    +关注

    关注

    180

    文章

    7530

    浏览量

    128722
  • NEON技术
    +关注

    关注

    1

    文章

    9

    浏览量

    6046
收藏 人收藏

    评论

    相关推荐

    量计算在神经网络加速器中的实现形式

    引言 神经网络中涉及到大量的张量运算,比如卷积,矩阵乘法,向量点乘,求和等。神经网络加速器就是针对张量运算来设计的。一个神经网络加速器通常都包含一个张
    的头像 发表于 11-02 13:52 2552次阅读
    张<b class='flag-5'>量计算</b>在神经网络<b class='flag-5'>加速</b>器中的实现形式

    gprs流量计算软件

    gprs流量计算软件&amp;nbsp;可以帮你计算你WAP上网时的流量,让你知道上网的流量。[此贴子已经被作者于2008-6-15 22:28:03编辑过]
    发表于 06-15 22:22

    CDMA的容量计算公式

    CDMA的容量计算公式[hide] [/hide]
    发表于 09-18 15:52

    MATLAB变量—标量,向量矩阵

    = [1 2 3](或者x = [1, 2, 3])列向量 &amp;gt;&amp;gt; x = [1; 2; 3]3×3矩阵&amp
    发表于 09-22 15:33

    电感量计算软件

    电感量计算软件,免安装,免注册!好用的顶起来!
    发表于 11-18 14:41

    电池的电量计算

    电池的电量计算电池厂家提供不了开路电压对应容量的OCV表,但是这个项目又必须正确的显示电池的电量,大家是如何做到电量的大概测量的(节省成本不用电量计),用的是开路电压法估算(精度要在80%以上,电池没有负载,同时有准确的OCV
    发表于 08-12 18:37

    Vector向量计算技术与SIMD技术的对比

    长度的寄存器,而不像SIMD那样嵌入操作码。矢量技术的代表就是RISC-VV扩展指令集和ARM的SVE架构。三、Vector向量计算技术的优势相比于传统的SIMD技术,矢
    发表于 09-01 15:09

    柴油发电机容量计算

    柴油发电机容量计算1:asdfssP=2*(P 入 +P 空调 +P照明 +P其他 ...)其中 :P 油机容量P入 电源输入功率P空调空调输入功率P照明照明用电P其他其他需要油机供电设备柴油发电机容量计算2:柴油发电机组容量应该满足稳定
    发表于 09-10 07:19

    Vector向量计算技术与SIMD技术的对比简述

    寄存器是可变长度的寄存器,而不像SIMD那样嵌入操作码。矢量技术的代表就是RISC-VV扩展指令集和ARM的SVE架构。三、Vector向量计算技术的优势相比于传统的SIMD技术,
    发表于 03-09 07:59

    简述ARM SVE的发展以及和NEON的区别来探讨VectorAI的应用

    arm通用架构对AI迈出的重要一步。当前的AI加速器大多都是固定功能,只有gpgpu架构能提供较通用的支持。通过提供对矩阵运算的支持,
    发表于 09-19 15:27

    空心线圈电感量计算

    空心线圈电感量计算:
    发表于 08-07 14:22 454次下载
    空心线圈电感<b class='flag-5'>量计算</b>

    量计算

    量计算
    发表于 05-19 13:44 1597次阅读
    流<b class='flag-5'>量计算</b>机

    常用流量计算软件

    本内容提供了各种方式的流量计算软件工具,包括调节阀计算,蒸汽计算,管道流量计算等等
    发表于 04-18 15:07 159次下载
    常用流<b class='flag-5'>量计算</b>软件

    电感量计算

    电感量计算,个人收集整理了很久的资料,大家根据自己情况,有选择性的下载吧~
    发表于 10-28 09:59 33次下载

    基于Zipf's共生矩阵分解的事件向量计算方法

    中事件表征困难的问题,提出了一种基于zipf’s共生矩阵分解的事件向量计算方法。首先,从开放语料中提取事件元组作为事件标签,并对事件元组进行抽象、剪枝和消歧。然后,利用zipf‘s共生矩阵表示事件的上下文分布,利用主成分分析(
    发表于 05-10 11:24 1次下载