0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

ARM NEON在矩陣&向量計(jì)算中的加速概述

冬至子 ? 來(lái)源:內(nèi)核工匠 ? 作者:Toby Zhang ? 2023-12-01 10:37 ? 次閱讀

一、概述

NEON是ARM上使用的一種SIMD(Single Instruction Multiple Data – 單指令多數(shù)據(jù))指令集??蓪?shí)現(xiàn)64位/128位的并行計(jì)算。簡(jiǎn)單理解就是一個(gè)計(jì)算指令,可以指定4個(gè)Float和4個(gè)Float并行計(jì)算(也可以是其他數(shù)據(jù)類型,但是必須包含在64位/128位內(nèi)),得到4個(gè)Float結(jié)果。而不是一次只能一個(gè)Float和一個(gè)Float的計(jì)算。

比如在RGB顏色轉(zhuǎn)灰色時(shí),計(jì)算公式為:Gray = R *0.299 + G *0.587 + B * 0.114,計(jì)算過(guò)程是由3個(gè)float乘法,2個(gè)加發(fā)組成,共有5個(gè)計(jì)算指令;如果直接使用NEON指令,就是可以直接通過(guò)一個(gè)指令計(jì)算完成,提升80%的理論性能。

矩陣計(jì)算就更為明顯,在4x4的矩陣和4個(gè)元素的向量相乘時(shí),有16個(gè)float乘法和12個(gè)加法計(jì)算;NEON可以4個(gè)指令直接計(jì)算,提升的性能更明顯。

當(dāng)然,這種計(jì)算需要是一種矩陣或者像素計(jì)算密集型的場(chǎng)景,比如RGB圖片轉(zhuǎn)黑白色,不通過(guò)GPU加速,而是通過(guò)CPU計(jì)算的場(chǎng)景;有多個(gè)3D模型,每幀需要為每個(gè)3D模型進(jìn)行矩陣計(jì)算等等。

二、NEON在矩陣&向量中的計(jì)算示例

向量的點(diǎn)積運(yùn)算示例(這里向量以4個(gè)元素為例,前3個(gè)元素通常表示3D空間的xyz坐標(biāo),第4個(gè)元素w用于齊次坐標(biāo);也可以表示顏色的RGBA)。兩個(gè)向量分別是:,,向量的點(diǎn)積計(jì)算公式:。對(duì)應(yīng)的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指令有兩種實(shí)現(xiàn)方式,一種就是示例中的Intrinsics指令,另外一種就是直接使用NEON的匯編指令,嵌入到C語(yǔ)言代碼中。我們這里只是以Intrinsics指令為例,匯編指令在原理上一樣。

三、示例代碼中APIs的說(shuō)明

3.1 ARM NEON向量寄存器

向量寄存器用來(lái)存放向量數(shù)據(jù),每個(gè)向量元素的類型必須相同。這個(gè)向量寄存器有128位,AArch64有32個(gè)這個(gè)寄存器,AArch32/Armv7有16個(gè)這個(gè)寄存器。

每個(gè)寄存器可以表示2個(gè)double float類型數(shù)據(jù)(每個(gè)數(shù)據(jù)占用64位),4個(gè)float類型數(shù)據(jù)(每個(gè)數(shù)據(jù)占用32位),8個(gè)short類型數(shù)據(jù)(每個(gè)數(shù)據(jù)占用16位),16個(gè)byte類型數(shù)據(jù)(每個(gè)數(shù)據(jù)占用8位)。數(shù)據(jù)類型可以是整形,也可以是浮點(diǎn)數(shù),只要占用位數(shù)對(duì)齊,類型統(tǒng)一即可。

image.png

3.2 示例說(shuō)明

在計(jì)算時(shí),第一步是要把C代碼中定義的數(shù)據(jù)(數(shù)組的形式存在,在運(yùn)行棧中,或者在堆中)加載到向量寄存器中,第二步通過(guò)寄存器進(jìn)行并行計(jì)算,第三步把結(jié)果寫入到指定寄存器,第四步寄存器結(jié)果寫入C代碼對(duì)應(yīng)的變量中(即C語(yǔ)言的?;蛘叨阎校?/p>

image.png

第一步:vld1q_f32的意思就是把” A + k”地址指向的內(nèi)容加載到向量寄存器。f32的意思是,一個(gè)值是32位。這個(gè)命令是從指定地址,連續(xù)復(fù)制數(shù)據(jù)到寄存器,并填滿寄存器。比如,這里一個(gè)數(shù)據(jù)是32位,一個(gè)寄存器128位,也就是這個(gè)命令會(huì)連續(xù)填充4個(gè)f32值。說(shuō)明:這里是多對(duì)(“K”個(gè))向量進(jìn)行點(diǎn)積計(jì)算。

第二步:vmlaq_f32意思是把兩個(gè)寄存器中,并行4個(gè)通道的4個(gè)f32分別對(duì)應(yīng)相乘,同時(shí)把結(jié)果和保存結(jié)果的寄存器對(duì)應(yīng)通道進(jìn)行累加。

第三步:vget_high_f32、vget_low_f32是取寄存器的高位和低位(按照f(shuō)32的type,分別有2個(gè)通道),vadd_f32就是獲取高位2通道和低位2通道分別相加,存到一個(gè)float32x2_t數(shù)據(jù)格式用(f32類型,2通道)。vpadd_f32中的p是pairwise,意思是將參數(shù)兩個(gè)向量的相鄰數(shù)據(jù)進(jìn)行計(jì)算,這里就是r自己的2個(gè)相鄰?fù)ǖ老嗉印?/p>

第四步:vget_lane_f32比較簡(jiǎn)單,就是獲取第一個(gè)參數(shù)寄存器中指定通道的值。這里就是第0通道的值。并寫會(huì)到一個(gè)float值中。

四、點(diǎn)積的推廣

這里的點(diǎn)積相對(duì)比較復(fù)雜,考慮到了一些通用性。這里使用了一個(gè)for循環(huán),當(dāng)只是計(jì)算兩個(gè)4元素向量的點(diǎn)積時(shí),可以把for循環(huán)去掉,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。

如果進(jìn)行叉乘,則不需要進(jìn)行第三步,直接返回一個(gè)float32x4_t的類型數(shù)據(jù)即可。

如果計(jì)算矩陣(4x4)和向量(4通道)相乘,就是計(jì)算點(diǎn)積4次,并且結(jié)果分別放到float32x4_t類型的4個(gè)通道中。

如果是矩陣(4x4)相乘則是4個(gè)叉乘。

這四種情況可以自己根據(jù)上方點(diǎn)積的計(jì)算方式,獨(dú)立寫出。

五、數(shù)據(jù)類型和函數(shù)指令說(shuō)明

其實(shí)NEON Intrinsics指令中,對(duì)使用的變量類型、函數(shù)定義做了擴(kuò)展,便于記憶和理解。

1.比如下方的數(shù)據(jù)類型:

image.png

A. int是數(shù)據(jù)類型,可以是int/uint/float/poly等等。

B. 后邊幾個(gè)數(shù)字由‘x’號(hào)鏈接,第一個(gè)數(shù)字就是每個(gè)元素的大小,這里是bit,而非Byte,可以是8/16/32/64。

C. 第二個(gè)數(shù)字是通道。比如表示顏色的RGBA,就是4通道,每個(gè)通道可以用一個(gè)byte表示(這里其實(shí)就是int8類型)。表示3D空間坐標(biāo),可以是xyz,就是3通道。如果是一個(gè)2D平面,就是一個(gè)xy,2通道了。

D. 最后一個(gè)數(shù)字表示有多少個(gè)。比如一個(gè)3D空間坐標(biāo)xyz,一個(gè)四邊形有4個(gè)頂點(diǎn),這里就可以表示4(這個(gè)值通常是一個(gè)2的次冪數(shù))。

這里可以根據(jù)實(shí)際情況選擇自己的數(shù)據(jù)類型。不過(guò)要注意,這里要和128位對(duì)齊,符合自己實(shí)際數(shù)據(jù)對(duì)齊邏輯,不能超出。

2.函數(shù)也有類似的表達(dá)方式,例如:

image.png

v表示的AArch32/Armv7的指令

p表示pairwise計(jì)算。這里表示的是a和b向量的相鄰數(shù)據(jù)進(jìn)行兩兩和操作,如下方的操作方式:

image.png

add就是加法,加減乘除普通計(jì)算,還有一些操作,比如加載、存儲(chǔ)、移位、邏輯計(jì)算、類型轉(zhuǎn)換等等。

q表示試用128位的向量計(jì)算器,不然就使用64位向量寄存器。

s8就是數(shù)類型了,可以是:u8、s8、u16、s16、u32、s32、f32、f64。

更多的內(nèi)容可以在底部參考資料中,找到相關(guān)內(nèi)容。

通過(guò)數(shù)據(jù)類型和函數(shù)類型,我們就可以根據(jù)實(shí)際情況,結(jié)合這些函數(shù),封裝我們自己的加速代碼邏輯,達(dá)到優(yōu)化的目的。

六、總結(jié)

這里只是對(duì)點(diǎn)積計(jì)算方式進(jìn)行了解析,同時(shí)對(duì)于其他情況的推廣。其實(shí)對(duì)于int、char等類型可以類比計(jì)算。對(duì)像素、向量、矩陣等等的計(jì)算會(huì)成倍提升(理論性能提升16、8、4、2倍不等,根據(jù)實(shí)際類型確定)。特別是在移動(dòng)端,圖形計(jì)算、圖形處理領(lǐng)域,CPU性能遇到瓶頸,進(jìn)行性能優(yōu)化時(shí),NEON指令是一個(gè)不錯(cuò)的優(yōu)化點(diǎn)。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • ARM
    ARM
    +關(guān)注

    關(guān)注

    134

    文章

    9028

    瀏覽量

    366496
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5295

    瀏覽量

    119824
  • RGB
    RGB
    +關(guān)注

    關(guān)注

    4

    文章

    797

    瀏覽量

    58338
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7595

    瀏覽量

    135875
  • NEON技術(shù)
    +關(guān)注

    關(guān)注

    1

    文章

    9

    瀏覽量

    6069
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    量計(jì)算在神經(jīng)網(wǎng)絡(luò)加速的實(shí)現(xiàn)形式

    引言 神經(jīng)網(wǎng)絡(luò)涉及到大量的張量運(yùn)算,比如卷積,矩陣乘法,向量點(diǎn)乘,求和等。神經(jīng)網(wǎng)絡(luò)加速器就是針對(duì)張量運(yùn)算來(lái)設(shè)計(jì)的。一個(gè)神經(jīng)網(wǎng)絡(luò)加速器通常都
    的頭像 發(fā)表于 11-02 13:52 ?2858次閱讀
    張<b class='flag-5'>量計(jì)算</b>在神經(jīng)網(wǎng)絡(luò)<b class='flag-5'>加速</b>器<b class='flag-5'>中</b>的實(shí)現(xiàn)形式

    gprs流量計(jì)算軟件

    gprs流量計(jì)算軟件&amp;nbsp;可以幫你計(jì)算你WAP上網(wǎng)時(shí)的流量,讓你知道上網(wǎng)的流量。[此貼子已經(jīng)被作者于2008-6-15 22:28:03編輯過(guò)]
    發(fā)表于 06-15 22:22

    CDMA的容量計(jì)算公式

    CDMA的容量計(jì)算公式[hide] [/hide]
    發(fā)表于 09-18 15:52

    MATLAB變量—標(biāo)量,向量,矩陣

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

    電感量計(jì)算軟件

    電感量計(jì)算軟件,免安裝,免注冊(cè)!好用的頂起來(lái)!
    發(fā)表于 11-18 14:41

    電池的電量計(jì)算

    電池的電量計(jì)算電池廠家提供不了開路電壓對(duì)應(yīng)容量的OCV表,但是這個(gè)項(xiàng)目又必須正確的顯示電池的電量,大家是如何做到電量的大概測(cè)量的(節(jié)省成本不用電量計(jì)),用的是開路電壓法估算(精度要在80%以上,電池沒(méi)有負(fù)載,同時(shí)有準(zhǔn)確的OCV
    發(fā)表于 08-12 18:37

    Vector向量計(jì)算技術(shù)與SIMD技術(shù)的對(duì)比

    長(zhǎng)度的寄存器,而不像SIMD那樣嵌入操作碼。矢量技術(shù)的代表就是RISC-VV擴(kuò)展指令集和ARM的SVE架構(gòu)。三、Vector向量計(jì)算技術(shù)的優(yōu)勢(shì)相比于傳統(tǒng)的SIMD技術(shù),矢
    發(fā)表于 09-01 15:09

    Vector向量計(jì)算技術(shù)與SIMD技術(shù)的對(duì)比簡(jiǎn)述

    寄存器是可變長(zhǎng)度的寄存器,而不像SIMD那樣嵌入操作碼。矢量技術(shù)的代表就是RISC-VV擴(kuò)展指令集和ARM的SVE架構(gòu)。三、Vector向量計(jì)算技術(shù)的優(yōu)勢(shì)相比于傳統(tǒng)的SIMD技術(shù),
    發(fā)表于 03-09 07:59

    簡(jiǎn)述ARM SVE的發(fā)展以及和NEON的區(qū)別來(lái)探討VectorAI的應(yīng)用

    arm通用架構(gòu)對(duì)AI邁出的重要一步。當(dāng)前的AI加速器大多都是固定功能,只有g(shù)pgpu架構(gòu)能提供較通用的支持。通過(guò)提供對(duì)矩陣運(yùn)算的支持,
    發(fā)表于 09-19 15:27

    空心線圈電感量計(jì)算

    空心線圈電感量計(jì)算:
    發(fā)表于 08-07 14:22 ?456次下載
    空心線圈電感<b class='flag-5'>量計(jì)算</b>

    電感量計(jì)算

    電感量計(jì)算: 小巧實(shí)用的綠色軟件,根據(jù)輸入的線圈長(zhǎng)度、線圈直徑、導(dǎo)線直徑、線圈匝數(shù)及工作頻率快速計(jì)算出電感量、自分布電容、空載Q值、自諧振頻率。
    發(fā)表于 08-07 14:54 ?209次下載
    電感<b class='flag-5'>量計(jì)算</b>

    量計(jì)算機(jī)

    量計(jì)算機(jī)
    發(fā)表于 05-19 13:44 ?1688次閱讀
    流<b class='flag-5'>量計(jì)算</b>機(jī)

    常用流量計(jì)算軟件

    本內(nèi)容提供了各種方式的流量計(jì)算軟件工具,包括調(diào)節(jié)閥計(jì)算,蒸汽計(jì)算,管道流量計(jì)算等等
    發(fā)表于 04-18 15:07 ?159次下載
    常用流<b class='flag-5'>量計(jì)算</b>軟件

    電感量計(jì)算

    電感量計(jì)算,個(gè)人收集整理了很久的資料,大家根據(jù)自己情況,有選擇性的下載吧~
    發(fā)表于 10-28 09:59 ?33次下載

    基于Zipf's共生矩陣分解的事件向量計(jì)算方法

    事件表征困難的問(wèn)題,提出了一種基于zipf’s共生矩陣分解的事件向量計(jì)算方法。首先,從開放語(yǔ)料中提取事件元組作為事件標(biāo)簽,并對(duì)事件元組進(jìn)行抽象、剪枝和消歧。然后,利用zipf‘s共生矩陣
    發(fā)表于 05-10 11:24 ?1次下載