<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何對GPU中的矩陣乘法(GEMM)進行優化

perfxlab ? 來源:澎峰科技PerfXLab ? 2023-05-25 09:03 ? 次閱讀

本篇文章主要是介紹如何對GPU中的矩陣乘法(GEMM)進行優化。目前針對GEMM的優化,網絡上已經有非常多的教程和示例了。大部分的重要資料我都看了看。但總的來說,還是不夠接地氣,然后理解起來還是會比較費解。所以希望寫這么一篇文章,盡可能地去把GPU的GEMM優化說清楚,說明白。然后讓小白讀者也能通過這么一兩篇文章去更好地了解GEMM優化的相關技術。

不像上次的reduce優化一樣,能一篇文章說完。這次的GEMM優化會分為三個部分。第一個部分只說優化思路和分析,沒有任何代碼,這么做考慮也是為了減輕讀者的負擔,看代碼太累,盡可能地讓讀者先明白原理,為什么要這么做。第二個部分是對代碼的詳細解析,這個里面就是一行一行地去分析代碼。因為之前的很多博客進行了分析,但是代碼本身并沒有開源,或者說開源了代碼,但沒有解析,看起來太累了。我希望提供一個盡可能詳細的代碼解析,讀者看完之后能明白相關優化技巧,并且可以直接把代碼拿去驗證使用。第三個部分主要涉及到匯編,最重要的是說明在NV的卡上,怎么去解決寄存器的bank沖突來獲取極致的性能。

本篇文章是GEMM優化的第一個部分,在這篇文章中,只說優化思路和分析。

前言

在高性能領域,對于矩陣乘(GEMM)的優化是一個非常重要的課題。GEMM可以非常廣泛地應用于航空航天、流體力學等科學計算領域,這也是之前HPC的主要應用場景。后來深度學習開展地如火如荼,由于對高算力的需要,也成為HPC的主要應用場景之一。這些年涌現了一系列的深度學習模型。模型里面最耗時的東西,包括卷積、全連接層、attention,都可以轉換成GEMM操作。所以說,GEMM優化的重要性,怎么突出都不過分。

目前網上能找到的針對GEMM優化的資料主要有這么幾個方面:(1)論文,目前針對GPU進行GEMM優化的論文非常多,這里主要推薦Understanding the GPU Microarchitecture和Fast implementation of dgemm on fermi gpu以及Dissecting the NVIDIA Volta GPU Architecture via Microbenchmarking。這幾篇論文在業界都比較有影響力,就是代碼開源方面做的不算太好。(2)官方博客,主要是CUTLASS和NervanaSystems-SGEMM優化。還有前段時間曠視發的文章CUDA矩陣乘法優化,寫的都很詳細。(3)github的一些demo,代碼量不大,看起來比較舒服。我是看了這兩個:

demo1 :

https://github.com/Cjkkkk/CUDA_gemm

demo2 :

https://github.com/yzhaiustc/Optimizing-SGEMM-on-NVIDIA-Turing-GPUs

demo1代碼寫的好理解一些,但是優化工作沒做完全,沒有做到prefetch。demo2是效果很好,11個優化技巧,不斷逼近cublas。但是代碼真的看起來比較難受,最重要的很多參數寫死了,不好去調。 總而言之,目前列舉的上述資料存在著這么兩個問題:(1)文檔方面,讀起來還是比較費勁,對于小白來說,還是不夠簡單不夠傻,看起來太累了;(2)代碼方面,要么是沒公開代碼,要么是代碼太多了,看不下去;還有的就是代碼可讀性很強,但是優化工作還不是特別深,或者就是代碼優化做的很好,但是可讀性差了。方方面面總是有點欠缺,所以希望能夠寫一篇盡可能地在文檔上簡單明了,在代碼上詳細且可讀性好的文章。當然,這是一個逐步迭代的過程,所以這篇文章也會持續進行更新哈。 本篇文章主要是采納了cutlass的行文思路,主要介紹GEMM中的數據分塊和如何在多級存儲進行數據搬運。這也是HPC優化的核心思想,怎么樣讓數據放在更近的存儲上來掩蓋計算的延時,從而減少存儲墻的影響。文章分為四個方面進行敘述,首先介紹在global memory層面如何進行分塊以及數據搬運,隨后介紹在shared memory層面如何進行分塊以及數據搬運,而后介紹在register層面如何進行分塊以及避免bank沖突,最后介紹如何進行prefetch以更好地掩蓋訪存時延。

一、從global memory到shared memory

假設有矩陣A、B,需要計算矩陣A和B的乘,即矩陣C。A、B、C三個矩陣的維度分別為,,,且三個矩陣中的數據都是單精度浮點數。對于C中每一個元素,C[i][j],可以看作是A的一行和B的一列進行一次歸約操作。采用最naive的GEMM算法,在GPU中,一共開啟個線程,每個線程需要讀取矩陣A的一行與矩陣B的一列,而后將計算結果寫回至矩陣C中。因而,完成計算一共需要從global memory中進行次讀操作和次寫操作。大量的訪存操作使得GEMM效率難以提高,因而考慮global memory中進行分塊,并將矩陣塊放置到shared memory中。其示意圖如下: 5fe8a226-fa8c-11ed-90ce-dac502259ad0.jpg 對global memory進行分塊的GEMM算法示意圖見上圖右側。首先將A、B、C三個矩陣劃分為多個維度為?,,?的小矩陣塊。三個矩陣形成?,,?的小矩陣網格。其中,,,。隨后在GPU中開啟??個block,每個block負責C中一個維度為??的小矩陣塊的計算。計算中一共有K次迭代,每一次迭代都需要讀取A中一個維度為??的小矩陣塊和B中一個維度為??的小矩陣塊,并將其放置在shared memory中。因而,完成C中所有元素的計算一共需要從global memory中讀取?,即??個單精度浮點數。相比于naive的GEMM算法,訪存量減少為原來的?。通過global memory中分塊算法極大地減少了對global memory的訪存量。并且,相比于naive算法,對global進行分塊可以更充分地利用數據局部性。在naive算法中,每一個線程都需要直接從global memory中取數,其時延非常長,計算性能非常差。而進行分塊后,將維度為?,?的小矩陣塊先存儲到shared memory之中。而后計算單元進行計算時可以直接從shared memory中取數,大大減少了訪存所需要的時延。

二、從shared memory到register

隨后,我們進一步考慮從shared memory到register的過程。在這里,只分析一個block中的計算。當進行K輪迭代中某一輪迭代時,GPU將維度為,的小矩陣塊存儲到shared memory中,而后各個線程將shared memory中的數據存入register中進行計算。 601b8984-fa8c-11ed-90ce-dac502259ad0.jpg不對shared memory分塊時,一個block中含有個線程,每一個線程負責C中一個元素的計算。則一個block一共需要對shared memory進行次讀操作。而后考慮對shared memory進行分塊,對的小矩陣進行再一次劃分,將其劃分為多個維度為的子矩陣。則一個block需要負責個子矩陣。其中,,。隨后,在一個block中開啟個線程,每個線程負責一個維度為的子矩陣的計算。在計算中,一個block一共需要從shared memory讀取,即個單精度浮點數。相比于未分塊的算法,對于shared memory中的訪存量減少為原來的。并且,由于將數據放入register中,可以直接對數據進行運算,減少了從shared memory中取數的時延。

三、register分塊

在這里,我們考慮最后一層,即register中的計算,并且只分析一個thread。在完成以上的過程后,對于一個線程而言,它現在擁有:個A矩陣的寄存器值,個B矩陣的寄存器值,以及個C矩陣的寄存器值。通過這些寄存器的值,需要計算個數。這需要條FFMA指令。 這個時候會涉及到寄存器的bank conflict。在NV的GPU中,每個SM不僅會產生shared memroy之間的bank 沖突,也會產生寄存器之間的bank沖突。這一點對于計算密集型的算子十分重要。像shared memory一樣,寄存器的Register File也會被分為幾個bank,如果一條指令的的源寄存器有2個以上來自同一bank,就會產生沖突。指令會重發射,浪費一個cycle。PS:這個地方是從曠視的博客中看的。然后對于maxwell架構的GPU而言,bank數為4,寄存器id%4即所屬bank。 我們假設對這個thread來說,、。并且計算C的寄存器以一種非常naive的情況分配,如下圖左側所示。則需要產生16條FFMA指令,列舉如下:

FFMA R0, R16, R20, R0 FFMA R1, R16, R21, R1 ……

604de352-fa8c-11ed-90ce-dac502259ad0.jpg

可以從中看出,這會產生大量的register bank沖突,所以需要對參與計算的寄存器重新進行分配和排布,如上圖右側所示。在有些地方,這種方式也可以叫做register分塊。

四、數據的prefetch

最后,我們來講講如何通過對數據進行prefetch來減少訪存的latency。我們再來回顧GEMM的過程,并且仔細地看看這個訪存的latency到底是怎么導致的。對于一個block而言,需要計算一個的矩陣塊,這個時候需要進行K次迭代,每次迭代都需要先將來自A和B的兩個小塊送到shared memory中再進行計算。而從global中訪存實際上是非常慢的,所以導致了latency。雖然GPU中可以通過block的切換來掩蓋這種latency,但是由于分配的shared memory比較多,活躍的block并不太多,這種延時很難被掩蓋。對于一個thread,需要計算一個的小矩陣,但是必須先將數據從shared memory傳到寄存器上,才能開始進行計算。所以導致了每進行一次迭代,計算單元就需要停下來等待,計算單元不能被喂飽。

為此,需要進行數據的Prefetch來盡可能地掩蓋這種latency。思想也比較簡單,需要多開一個buffer,進行讀寫分離。示意圖如下。當block進行第2輪迭代時,需要對A2和B2進行計算,在計算單元進行計算的同時,我們將A3和B3提前放置到shared memory。而后,在進行第3輪迭代時,就可以直接對shared memory中的A3和B3進行計算,而不需要等待從global memory搬運到shared memory的時間。寄存器上的Prefetch也是同理。

607caea8-fa8c-11ed-90ce-dac502259ad0.jpg

總結

GEMM的優化思想,基本上就是這么幾方面的內容。希望大家通過介紹能夠對GEMM的優化有一個比較直觀且具體的理解。

審核編輯:彭靜
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 寄存器
    +關注

    關注

    30

    文章

    5093

    瀏覽量

    117912
  • gpu
    gpu
    +關注

    關注

    27

    文章

    4446

    瀏覽量

    126886
  • 代碼
    +關注

    關注

    30

    文章

    4566

    瀏覽量

    66967
  • 澎峰科技
    +關注

    關注

    0

    文章

    35

    瀏覽量

    3075

原文標題:深入淺出GPU優化系列:GEMM優化(一)

文章出處:【微信號:perfxlab,微信公眾號:perfxlab】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Mali GPU編程特性及二維浮點矩陣運算并行優化詳解

    本文針對Mali-T604 GPU論述了基于OpenCL的Linux平臺上進行通用計算并行優化的方法,論述了Mali-T604 GPU的硬件特點,并基于OpenCL設計了二維
    發表于 08-07 17:12 ?2271次閱讀
    Mali <b class='flag-5'>GPU</b>編程特性及二維浮點<b class='flag-5'>矩陣</b>運算并行<b class='flag-5'>優化</b>詳解

    FPGA 超越 GPU,問鼎下一代深度學習主引擎

    四個int6打包到一個DSP模塊,研究了FPGA的Int6 GEMM。對于本來不支持Int6 的GPU,他們使用了Int8 GPU 的峰值性能進行
    發表于 04-27 14:10

    講解矩陣運算的放縮,乘法和轉置

    第22章 DSP矩陣運算-放縮,乘法和轉置矩陣本期教程主要講解矩陣運算的放縮,乘法和轉置。目錄
    發表于 08-11 06:05

    主要講解矩陣運算的放縮,乘法和轉置

    第22章 DSP矩陣運算-放縮,乘法和轉置矩陣本期教程主要講解矩陣運算的放縮,乘法和轉置。目錄
    發表于 08-11 08:41

    解讀最佳實踐:倚天 710 ARM 芯片的 Python+AI 算力優化

    更好的性能,或者更好的性價比。所以說如何整合 Python+AI 的相關軟件使其發揮最好的性能成為了我們關注的重點。下文的分享整體分為兩部分,一部分是介紹我們進行優化工作,主要是跟矩陣乘法
    發表于 12-23 16:02

    對FPGA與ASIC/GPU NN實現進行定性的比較

    不是最經濟實惠的方式。而在FPGA上在針對于相同的 NN進行優化后,在速度方面可以接近高端GPU,但它需要更多工程化的工作量。因此,在早期NN模型探索階段,為了快速周轉地試驗NN模型,使用高端最先
    發表于 02-08 15:26

    Adreno GPU 矩陣乘法——第1講:OpenCL優化

    我們在SGEMM采用的相同原理進行有效實現。 一般來說,我們對Adreno GPU優化的MM實現比簡單實現至少快兩個數量級。 接下來? 在下一篇文章中,我將給出這些概念背后的OpenCL代碼清單。
    發表于 09-18 19:15 ?1611次閱讀

    使用英特爾ComposerXE 2015在C++中進行矩陣乘法

    矩陣乘法:使用英特爾?數學核心函數庫和C++測試英特爾?ComposerXE 2015
    的頭像 發表于 11-12 06:42 ?2711次閱讀

    使用英特爾數學核心函數庫優化三重嵌套循環矩陣乘法

    我們使用英特爾?數學核心函數庫(MKL)在Linux *上優化了三重嵌套循環矩陣乘法的版本。
    的頭像 發表于 11-07 06:04 ?3374次閱讀

    基于GPU的稀疏矩陣存儲格式優化綜述

    基于GPU的稀疏矩陣存儲格式優化綜述
    發表于 06-11 11:45 ?18次下載

    使用CUTLASS實現高性能矩陣乘法

      CUTLASS 實現了高性能卷積(隱式 GEMM )。隱式 GEMM 是作為 GEMM 的卷積運算的公式。這允許 Cutslass 通過重用高度優化的 warp-wide
    的頭像 發表于 04-15 10:03 ?2350次閱讀

    頂級FPGA和GPU的PK

    首先,文章使用GPU最擅長處理的工作負載:通用矩陣乘(GEMM)來跑GPU的benchmark(什么是GEMM請移步https://spat
    發表于 08-16 09:22 ?2363次閱讀

    CUDA矩陣乘法優化手段詳解

    單精度矩陣乘法(SGEMM)幾乎是每一位學習 CUDA 的同學繞不開的案例,這個經典的計算密集型案例可以很好地展示 GPU 編程中常用的優化技巧。本文將詳細介紹 CUDA SGEMM
    的頭像 發表于 09-28 09:46 ?1608次閱讀

    在TensorFlow中對Tensor進行拆和裝

    TensorCore改進的方向就是針對矩陣乘法GEMM,General Matrix Mulitiplicaiton)運算進行優化。
    的頭像 發表于 12-29 09:24 ?571次閱讀

    NVIDIA Hopper GPU上的新cuBLAS12.0功能和矩陣乘法性能

    NVIDIA Hopper GPU 上的新 cuBLAS 12.0 功能和矩陣乘法性能
    的頭像 發表于 07-05 16:30 ?1806次閱讀
    NVIDIA Hopper <b class='flag-5'>GPU</b>上的新cuBLAS12.0功能和<b class='flag-5'>矩陣</b><b class='flag-5'>乘法</b>性能
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>