精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

斯坦福讓“GPU高速運(yùn)轉(zhuǎn)”的新工具火了,比FlashAttention2更快

人工智能 新聞
我們未來工作的一個(gè)重要方向是利用我們對(duì)硬件的了解來幫助我們?cè)O(shè)計(jì)與之匹配的AI。

AI算力資源越發(fā)緊張的當(dāng)下,斯坦福新研究將GPU運(yùn)行效率再提升一波——

內(nèi)核只有100行代碼,讓H100比使用FlashAttention-2,性能還要提升30%。

怎么做到的?

研究人員從“硬件實(shí)際需要什么?如何滿足這些需求?”這兩個(gè)問題出發(fā),設(shè)計(jì)了 一個(gè)嵌入式CUDA DSL工具,名為ThunderKittens(暫且譯為雷貓)。

雷貓可簡(jiǎn)化AI內(nèi)核的編寫,同時(shí)充分利用底層硬件能力。

圖片

具體來說,雷貓的主要抽象是寄存器和共享內(nèi)存中的小型張量塊(tile),和目前GPU中對(duì)小矩陣乘法的優(yōu)化相匹配。

通過操作這些tile,開發(fā)者可相對(duì)簡(jiǎn)單地編寫代碼,充分利用張量核心、異步數(shù)據(jù)傳輸和共享內(nèi)存等硬件特性。

使用雷貓實(shí)現(xiàn)的注意力機(jī)制內(nèi)核,代碼量少且能實(shí)現(xiàn)很高的硬件利用率,性能超過直接使用底層庫(如Cutlass)。

詳細(xì)討論過程以及雷貓是怎么設(shè)計(jì)出的,研究人員以“GPUs Go Brrr”為題,發(fā)在了斯坦福Hazy Research的Blog網(wǎng)站上。

圖片

網(wǎng)友們對(duì)此討論也十分熱烈。

有網(wǎng)友表示讀這篇Blog時(shí),讓他想起了初次了解超標(biāo)量CPU架構(gòu)時(shí)的驚訝感受:

GPU真的達(dá)到了新高度。

圖片

還有網(wǎng)友表示:

這篇文章重新點(diǎn)燃了我在CS 149并行編程課中所感受到的快樂。

圖片

H100里有什么?

斯坦福研究人員以H100為例,探討了優(yōu)化GPU的方法。

首先,回顧一下H100的硬件細(xì)節(jié),這對(duì)于接下來的討論非常重要。

圖片

一個(gè)H100 SXM GPU包含:

(1)80GB的HBM3內(nèi)存,帶寬為3TB/s(實(shí)際帶寬略低)。

(2)50MB的L2緩存,帶寬為12TB/s,在GPU上分為兩個(gè)25MB的部分,通過交叉開關(guān)連接(這個(gè)交叉開關(guān)表現(xiàn)不佳)。

(3)132個(gè)流式多處理器(SM),每個(gè)包含:

  • 高達(dá)227KB的共享內(nèi)存位于256KB的L1緩存中(這些加起來的帶寬大約33TB/s)。
  • 一個(gè)張量?jī)?nèi)存加速器(TMA)——這是英偉達(dá)Hopper架構(gòu)中的一種新硬件組件,可進(jìn)行異步地址生成和內(nèi)存獲取,還能促進(jìn)片上內(nèi)存網(wǎng)絡(luò)。
  • 4個(gè)子單元,每個(gè)含:一個(gè)warp scheduler;512個(gè)向量寄存器(每個(gè)包含32個(gè)4字節(jié)的詞);一個(gè)用于執(zhí)行矩陣乘法的張量核心;一組內(nèi)置指令,如求和、乘法等,這些指令能夠并行操作這些向量寄存器。

除了這些,一個(gè)GPU還包括內(nèi)存控制器、指令緩存……但對(duì)于這項(xiàng)研究而言不重要。

重要的是,所有的計(jì)算都發(fā)生在流式多處理器中,大部分計(jì)算是在寄存器中。

H100 GPU擁有989 TFLOPs的半精度矩陣乘法計(jì)算能力,以及約60 TFLOPs的“其他”計(jì)算能力。因此,每個(gè)周期內(nèi)張量核心被使用時(shí),至少能達(dá)到94%的硬件利用率。而張量核心不被使用時(shí),硬件的利用率不會(huì)超過6%。

換句話說:

H100的利用率=張量核心活躍周期的百分比+/- 6%。

圖片

所以要充分發(fā)揮H100的能力,關(guān)鍵是保持張量核心持續(xù)運(yùn)算

榨干H100,要注意什么?

然鵝,要保持張量核心持續(xù)運(yùn)行并不容易。

研究人員發(fā)現(xiàn)GPU硬件具有一些特性,對(duì)于保持矩陣乘法的運(yùn)行非常重要:

  • WGMMA指令雖然是必要的,但使用起來頗為麻煩。
  • 共享內(nèi)存的速度并不如預(yù)期的快,使用時(shí)還需格外注意。
  • 生成地址的成本較高。
  • 保持高占用率對(duì)于提升性能是有益的,寄存器至關(guān)重要。

這些特性在非H100 GPU上也有所適用,在H100上更加典型,就拿RTX 4090來說,相比H100處理起來簡(jiǎn)單得多。

圖片

所以接下來還是以H100為例,展開探討這幾點(diǎn)特性。

WGMMA指令

H100引入了一套新的指令集,名為“warp group matrix multiply accumulate”(在PTX中為wgmma.mma_async,在SASS中為HGMMA/IGMMA/QGMMA/BGMMA)

要理解這些指令的特點(diǎn),需回顧以往張量核心的使用方式。

早期GPU中的張量核心指令如wmma.mma.sync和mma.sync,要求SM一個(gè)子單元內(nèi)的32個(gè)線程的一個(gè)warp同步傳輸數(shù)據(jù)塊至張量核心并等待結(jié)果。

wgmma.mma_async指令則不同。它允許128個(gè)連續(xù)線程跨SM所有子單元協(xié)作同步,并從共享內(nèi)存及寄存器(可選)異步啟動(dòng)矩陣乘法。這使得這些warp在等待矩陣乘法結(jié)果時(shí)可以處理其他任務(wù)。

研究人員通過微觀基準(zhǔn)測(cè)試,發(fā)現(xiàn)這些指令是充分發(fā)揮H100計(jì)算能力所必需的。沒有這些指令,GPU的峰值利用率大約只有63%。

他們推測(cè),這是由于張量核心需要從本地資源維持一個(gè)深度硬件pipeline。

然而,這些指令的內(nèi)存布局極其復(fù)雜。未重排的共享內(nèi)存布局合并性差,需要額外的L2帶寬。重排的內(nèi)存布局記錄不準(zhǔn)確,研究人員花費(fèi)了大量時(shí)間才弄明白。

圖片

最終發(fā)現(xiàn),這些布局只適用于特定矩陣形狀,并與wgmma.mma_async指令的其他部分不兼容,例如硬件僅在未重排的布局下轉(zhuǎn)置子矩陣。

此外,未重排的wgmma布局內(nèi)存合并性差且有bank conflicts。盡管TMA和L2緩存在如flash attention這類內(nèi)核上能較好地掩蓋這些問題,但要充分利用硬件,必須精心控制內(nèi)存請(qǐng)求的合并和避免bank conflicts。

盡管有這些問題,但這些指令對(duì)于充分利用H100是必不可少的。沒有它們,GPU的潛在性能就損失了37%。

共享內(nèi)存

共享內(nèi)存的單次訪問延遲約為30個(gè)周期(這也與研究人員觀察的相符),這看似不多,但在這段時(shí)間內(nèi),SM的張量核心幾乎能完成兩次完整的32x32方陣乘法。

以前的研究,如Flash Attention,研究人員更多關(guān)注的是HBM-SRAM的瓶頸。但隨著HBM速度的提升和張量核心的快速發(fā)展,即使是共享內(nèi)存的相對(duì)較小延遲也變得尤為關(guān)鍵。

由于共享內(nèi)存被分為32個(gè)獨(dú)立的存儲(chǔ)單元,處理不當(dāng)可能會(huì)引發(fā)bank conflicts,即同一個(gè)內(nèi)存bank同時(shí)被多個(gè)請(qǐng)求訪問,這種情況會(huì)導(dǎo)致請(qǐng)求被序列化。研究人員實(shí)驗(yàn)后認(rèn)為,這會(huì)顯著拖慢內(nèi)核速度,且wgmma與mma指令需要的寄存器布局容易受到bank conflicts的影響。

解決方法是通過各種“重排”模式調(diào)整共享內(nèi)存的配置,避免bank conflicts,但細(xì)節(jié)要處理得當(dāng)。

此外研究人員發(fā)現(xiàn),盡可能避免在寄存器和共享內(nèi)存之間的移動(dòng)數(shù)據(jù)非常重要??赡艿脑?,可使用內(nèi)置硬件(如wgmma和TMA指令)進(jìn)行異步數(shù)據(jù)傳輸。實(shí)在沒法子了,再使用warp進(jìn)行同步數(shù)據(jù)傳輸。

地址生成

H100還有一個(gè)有趣的特性,其張量核心和內(nèi)存都足夠快,以至于僅生成用于獲取數(shù)據(jù)的內(nèi)存地址就占用了芯片的大量資源,特別是加入復(fù)雜的交錯(cuò)或重排模式時(shí),這種情況更為明顯。

研究人員表示,英偉達(dá)提供了張量?jī)?nèi)存加速器(TMA),似乎就是已經(jīng)意識(shí)到了這個(gè)問題。

TMA允許用戶在全局和共享內(nèi)存中指定多維張量布局,命令其異步提取張量的一部分,并在完成后觸發(fā)一個(gè)屏障。這大大節(jié)省了地址生成的開銷,并簡(jiǎn)化了pipelines的構(gòu)建。

研究人員認(rèn)為,TMA對(duì)于充分發(fā)揮H100的潛力至關(guān)重要,可能比wgmma.mma_async更為關(guān)鍵。

它不僅節(jié)省了寄存器資源和指令派發(fā),還提供了如異步在全局內(nèi)存上執(zhí)行歸約等實(shí)用功能——這在處理復(fù)雜的反向內(nèi)核時(shí)尤其有用。

雖然TMA的重排模式解讀有一定難度,需要進(jìn)行一些逆向工程,但研究人員表示,相比之下,他們?cè)谶@上面遇到的問題要少得多。

占用率

占用率指的是在GPU的相同執(zhí)行硬件上同時(shí)調(diào)度的線程數(shù)。每個(gè)周期,SM的某一子單元的warp scheduler會(huì)嘗試向準(zhǔn)備就緒的warp線程發(fā)出指令。

研究人員認(rèn)為,英偉達(dá)采用這種模型可以更容易地保持硬件的滿負(fù)荷運(yùn)行。例如,當(dāng)一個(gè)線程warp等待執(zhí)行矩陣乘法時(shí),另一個(gè)可以被指派執(zhí)行使用快速指數(shù)運(yùn)算的指令。

在某些方面,H100對(duì)占用率的依賴程度低于前幾代硬件。

它的異步特性使得即使單一指令流也能使多個(gè)硬件部分同時(shí)持續(xù)運(yùn)行,包括讀取內(nèi)存、執(zhí)行矩陣乘法、進(jìn)行共享內(nèi)存的歸約,同時(shí)還能在寄存器上進(jìn)行計(jì)算。

但高占用率容易隱藏缺陷或同步問題,一個(gè)設(shè)計(jì)良好的pipeline即使在占用率不高的情況下也能運(yùn)行得相當(dāng)快。

據(jù)研究人員觀察,英偉達(dá)在設(shè)計(jì)GPU時(shí)確實(shí)考慮到了占用率。且由于存在足夠多的同步操作和足夠多的錯(cuò)誤可能性,根據(jù)他們的經(jīng)驗(yàn),提高占用率通常能顯著增加硬件的實(shí)際利用率。

此外,相比H100,A100和RTX 4090更依賴同步指令調(diào)度,占用率更重要。

用雷貓優(yōu)化GPU

鑒于以上情況,如何才能更輕松地編寫所需的內(nèi)核類型,同時(shí)充分發(fā)揮硬件的全部潛力?

雷貓(ThunderKittens)登場(chǎng)了。

這是一個(gè)嵌入在CUDA中的DSL,本是斯坦福研究人員設(shè)計(jì)出來給自己內(nèi)部使用的,后來發(fā)現(xiàn)還真挺好使。

Ps:起這么個(gè)名,一是他們覺得小貓很可愛,二來他們覺得大伙兒在代碼中輸入kittens::會(huì)很有趣。

具體來說,雷貓包含四種模板類型:

  • 寄存器tiles:在寄存器文件上表示二維張量。
  • 寄存器向量:在寄存器文件上表示一維張量。
  • 共享tiles:在共享內(nèi)存中表示二維張量。
  • 共享向量:在共享內(nèi)存中表示一維張量。

tiles通過高度、寬度和布局進(jìn)行參數(shù)化;寄存器向量通過長(zhǎng)度和布局進(jìn)行參數(shù)化;而共享向量?jī)H通過長(zhǎng)度進(jìn)行參數(shù)化,通常不會(huì)遇到bank conflicts問題。

此外,研究人員提供了一系列操作來處理這些張量,既可在warp級(jí)別使用,也可用于多個(gè)warp協(xié)作,包含初始化器,如將共享向量清零;一元操作,如exp;二元操作,如mul;行/列操作,例如行求和。

雷貓作為一個(gè)嵌入到CUDA中的庫,其提供的抽象層在遇到不支持的功能時(shí)能夠很好地處理。如果雷貓缺少某些功能,可以直接擴(kuò)展它來實(shí)現(xiàn)你想要的效果。

以Tri的flash attention算法為例,在實(shí)際應(yīng)用中,即使是使用英偉達(dá)的Cutlass庫,實(shí)現(xiàn)起來也是相當(dāng)復(fù)雜。

以下是一個(gè)在RTX 4090上使用雷貓編寫的簡(jiǎn)單flash attention內(nèi)核的示例。

總共約60行CUDA代碼,硬件利用率達(dá)到了75%。代碼復(fù)雜性主要在于算法本身,而非交織模式或寄存器布局。

#define NUM_WORKERS 16 // This kernel uses 16 workers in parallel per block, to help issue instructions more quickly.

using namespace kittens; // this kernel only handles headdim=64 for simplicity. Also n should be a multiple of 256 here.
__global__ void attend_ker64(int n, const bf16* __restrict__ __q__, const bf16* __restrict__ __k__, const bf16* __restrict__ __v__, bf16* __o__) {

    auto warpid        = kittens::warpid();
    auto block_start   = blockIdx.x*(n*64);
    const bf16 *_q = __q__ + block_start, *_k = __k__ + block_start, *_v = __v__ + block_start;
          bf16 *_o = __o__ + block_start;

    extern __shared__ alignment_dummy __shm[]; // this is the CUDA shared memory
    shared_allocator al((int*)&__shm[0]);

    // K and V live in shared memory -- this is about all that will fit.
    st_bf_1x4<ducks::st_layout::swizzle> (&k_smem)[NUM_WORKERS] = al.allocate<st_bf_1x4<ducks::st_layout::swizzle>, NUM_WORKERS>();
    st_bf_1x4<ducks::st_layout::swizzle> (&v_smem)[NUM_WORKERS] = al.allocate<st_bf_1x4<ducks::st_layout::swizzle>, NUM_WORKERS>();

    // Initialize all of the register tiles.
    rt_bf_1x4<> q_reg, k_reg, v_reg; // v_reg need to be swapped into col_l
    rt_fl_1x1<> att_block;
    rt_bf_1x1<> att_block_mma;
    rt_fl_1x4<> o_reg;
    rt_fl_1x1<>::col_vec max_vec_last, max_vec; // these are column vectors for the attention block
    rt_fl_1x1<>::col_vec norm_vec_last, norm_vec; // these are column vectors for the attention block

    int qo_blocks = n / (q_reg.rows*NUM_WORKERS), kv_blocks = n / (q_reg.rows*NUM_WORKERS);

    for(auto q_blk = 0; q_blk < qo_blocks; q_blk++) {

        // each warp loads its own Q tile of 16x64, and then multiplies by 1/sqrt(d)
        load(q_reg, _q + (q_blk*NUM_WORKERS + warpid)*q_reg.num_elements, q_reg.cols);
        mul(q_reg, q_reg, __float2bfloat16(0.125f)); // temperature adjustment

        // zero flash attention L, M, and O registers.
        neg_infty(max_vec); // zero registers for the Q chunk
        zero(norm_vec);
        zero(o_reg);

        // iterate over k, v for these q's that have been loaded
        for(auto kv_idx = 0; kv_idx < kv_blocks; kv_idx++) {

            // each warp loads its own chunk of k, v into shared memory
            load(v_smem[warpid], _v + (kv_idx*NUM_WORKERS + warpid)*q_reg.num_elements, q_reg.cols);
            load(k_smem[warpid], _k + (kv_idx*NUM_WORKERS + warpid)*q_reg.num_elements, q_reg.cols);
            __syncthreads(); // we need to make sure all memory is loaded before we can begin the compute phase

            // now each warp goes through all of the subtiles, loads them, and then does the flash attention internal alg.
            for(int subtile = 0; subtile < NUM_WORKERS; subtile++) {

                load(k_reg, k_smem[subtile]); // load k from shared into registers

                zero(att_block); // zero 16x16 attention tile
                mma_ABt(att_block, q_reg, k_reg, att_block); // Q@K.T

                copy(norm_vec_last, norm_vec);
                copy(max_vec_last,  max_vec);

                row_max(max_vec, att_block, max_vec); // accumulate onto the max_vec
                sub_row(att_block, att_block, max_vec); // subtract max from attention -- now all <=0
                exp(att_block, att_block); // exponentiate the block in-place.

                sub(max_vec_last, max_vec_last, max_vec); // subtract new max from old max to find the new normalization.
                exp(max_vec_last, max_vec_last); // exponentiate this vector -- this is what we need to normalize by.
                mul(norm_vec, norm_vec, max_vec_last); // and the norm vec is now normalized.

                row_sum(norm_vec, att_block, norm_vec); // accumulate the new attention block onto the now-rescaled norm_vec
                div_row(att_block, att_block, norm_vec); // now the attention block is correctly normalized

                mul(norm_vec_last, norm_vec_last, max_vec_last); // normalize the previous norm vec according to the new max
                div(norm_vec_last, norm_vec_last, norm_vec); // normalize the previous norm vec according to the new norm

                copy(att_block_mma, att_block); // convert to bf16 for mma_AB

                load(v_reg, v_smem[subtile]); // load v from shared into registers.
                rt_bf_1x4<ducks::rt_layout::col> &v_reg_col = swap_layout_inplace(v_reg); // this is a reference and the call has invalidated v_reg

                mul_row(o_reg, o_reg, norm_vec_last); // normalize o_reg in advance of mma_AB'ing onto it
                mma_AB(o_reg, att_block_mma, v_reg_col, o_reg); // mfma onto o_reg with the local attention@V matmul.
            }
            __syncthreads(); // we need to make sure all warps are done before we can start loading the next kv chunk
        }

        store(_o + (q_blk*NUM_WORKERS + warpid)*q_reg.num_elements, o_reg, q_reg.cols); // write out o. compiler has an issue with register usage if d is made constexpr q_reg.rows :/
    }
}

關(guān)于TMA、WGMMA、交織模式和描述符的復(fù)雜性,這里展示了一個(gè)使用雷貓編寫的,針對(duì)H100的FlashAttention-2算法的前向傳遞示例。

template<int D>
__global__  __launch_bounds__((NUM_WORKERS)*kittens::WARP_THREADS, 2)
void fwd_attend_ker_dim(int N, const CUtensorMap* tma_q, const CUtensorMap* tma_k, const CUtensorMap* tma_v, CUtensorMap* tma_o) {
    extern __shared__ int __shm[]; // this is the CUDA shared memory
    tma_swizzle_allocator al((int*)&__shm[0]);

    constexpr int tile_width = fwd_attend_ker_tile_dims<D>::tile_width; // constants
    constexpr int qo_height  = fwd_attend_ker_tile_dims<D>::qo_height;
    constexpr int kv_height  = fwd_attend_ker_tile_dims<D>::kv_height;

    st_bf<qo_height, tile_width, layout_q>          (&q_smem)   [NUM_WARPGROUPS] = al.allocate<st_bf<qo_height, tile_width, layout_q>,          NUM_WARPGROUPS>();
    st_bf<kv_height, tile_width, layout_k>          (&k_smem)[2][NUM_WORKERS_KV] = al.allocate<st_bf<kv_height, tile_width, layout_k>, 2,       NUM_WORKERS_KV>();
    st_bf<kv_height, tile_width, layout_v>          (&v_smem)[2][NUM_WORKERS_KV] = al.allocate<st_bf<kv_height, tile_width, layout_v>, 2,       NUM_WORKERS_KV>();

    int tic = 0, toc = 1;

    rt_fl<1, kv_height> att_block;
    rt_bf<1, kv_height> att_block_mma;
    rt_fl<1, qo_height> o_prev;
    col_vec<rt_fl<1, kv_height>> max_vec_last, max_vec;
    col_vec<rt_fl<1, kv_height>> norm_vec_last, norm_vec;

    int warpid      = kittens::warpid();
    int warpgroupid = warpid/kittens::WARPGROUP_WARPS;

    int kv_blocks = N / (NUM_WORKERS_KV*k_smem[0][0].rows);

    __shared__ uint64_t qsmem_barrier, kvsmem_barrier;//, vsmem_barrier;

    int q_phasebit = 0;
    int kv_phasebit = 0;

    if (threadIdx.x == 0) {
        tma::init_barrier<st_bf<qo_height, tile_width, layout_q>, NUM_WARPGROUPS>(qsmem_barrier, 1);
        tma::init_barrier<st_bf<kv_height, tile_width, layout_k>, NUM_WORKERS_KV*2>(kvsmem_barrier, 1); 
    }

    if (warpid == 0) {
        for (int wg = 0; wg < NUM_WORKERS/kittens::WARPGROUP_WARPS; wg++) { // load q
            int tile_idx = (blockIdx.y * NUM_WARPGROUPS * gridDim.x) + (blockIdx.x * NUM_WARPGROUPS) + wg;
            tma::load_async((q_smem[wg]), tma_q, qsmem_barrier, tile_idx); 
        }
        for (int w = 0; w < NUM_WORKERS_KV; w++) { // load k, v      
            int tile_idx = (blockIdx.y * NUM_WORKERS_KV * kv_blocks) + (0 * NUM_WORKERS_KV) + w; 
            tma::load_async((k_smem[tic][w]), tma_k, kvsmem_barrier, tile_idx); 
            tma::load_async((v_smem[tic][w]), tma_v, kvsmem_barrier, tile_idx); 
        }
    }

    neg_infty(max_vec); // zero registers for the Q chunk
    zero(norm_vec);
    zero(o_prev);
    __syncthreads();

    tma::arrive_and_wait(qsmem_barrier, q_phasebit);
    q_phasebit ^= 1;

    if constexpr (D == 64) { warpgroup::mul(q_smem[warpgroupid], q_smem[warpgroupid], __float2bfloat16(0.125f)); } 
    else { warpgroup::mul(q_smem[warpgroupid], q_smem[warpgroupid], __float2bfloat16(0.08838834764f)); }

    for (auto kv_idx = 0; kv_idx < kv_blocks; kv_idx++, tic ^= 1, toc ^= 1) {
        tma::arrive_and_wait(kvsmem_barrier, kv_phasebit);
        kv_phasebit ^= 1;

        __syncthreads();
        if (warpid == 0) {
            tma::set_bytes(kvsmem_barrier, 2 * NUM_WORKERS_KV * k_smem[0][0].num_elements * sizeof(bf16));

            if (kv_idx + 1 < kv_blocks) {
                for (int w = 0; w < NUM_WORKERS_KV; w++) {        
                    int tile_idx = (blockIdx.y * NUM_WORKERS_KV * kv_blocks) + ((kv_idx + 1) * NUM_WORKERS_KV) + w; 
                    tma::load_async((k_smem[toc][w]), tma_k, kvsmem_barrier, tile_idx); 
                    tma::load_async((v_smem[toc][w]), tma_v, kvsmem_barrier, tile_idx);
                }
            }
        }

        warpgroup::mma_fence(att_block);
        warpgroup::mm_ABt(att_block, q_smem[warpgroupid], k_smem[tic][0]);
        warpgroup::mma_commit_group();

        copy(norm_vec_last, norm_vec);
        copy(max_vec_last,  max_vec);

        warpgroup::mma_async_wait();

        row_max(max_vec, att_block, max_vec); // accumulate onto the max_vec
        sub_row(att_block, att_block, max_vec);
        exp(att_block, att_block);

        sub(max_vec_last, max_vec_last, max_vec);
        exp(max_vec_last, max_vec_last);
        mul(norm_vec, norm_vec, max_vec_last);

        row_sum(norm_vec, att_block, norm_vec); // accumulate onto the norm_vec
        div_row(att_block, att_block, norm_vec);

        mul(norm_vec_last, norm_vec_last, max_vec_last);
        div(norm_vec_last, norm_vec_last, norm_vec);

        copy(att_block_mma, att_block); // convert to bf16 for mma
        mul_row(o_prev, o_prev, norm_vec_last); // normalize o_prev in advance of mma'ing onto it

        warpgroup::mma_fence(o_prev);
        warpgroup::mma_AB(o_prev, att_block_mma, v_smem[tic][0]);
        warpgroup::mma_commit_group();
    }

    auto (*o_smem) = reinterpret_cast<st_bf<qo_height, tile_width, layout_o>(*)>(q_smem); // reuse q memory
    warpgroup::store(o_smem[warpgroupid], o_prev); 
    __syncthreads();

    if (warpid % 4 == 0) { // store o
        int tile_idx = (blockIdx.y * NUM_WARPGROUPS * gridDim.x) + (blockIdx.x * NUM_WARPGROUPS) + warpgroupid;
        tma::store_async(tma_o, (o_smem[warpgroupid]), tile_idx); 
        tma::store_commit_group(); 
    }

    tma::store_async_wait();
}

那么,它的表現(xiàn)如何?

這個(gè)內(nèi)核只有100行代碼,實(shí)際上它在H100上的性能比FlashAttention-2高出約30%。雷貓負(fù)責(zé)包裝布局和指令,提供了一個(gè)可以在GPU上使用的迷你pytorch環(huán)境。

圖片

△FA2(通過Pytorch實(shí)現(xiàn))與TK在H100 SXM上的多種配置比較

此外,研究人員還發(fā)布了基于線性注意力和其他新架構(gòu)的內(nèi)核。其中基于線性注意力的內(nèi)核的運(yùn)行速度可達(dá)215 TFLOPs,如果考慮到算法中固有的重計(jì)算,速度可超過300 TFLOPs。

盡管線性注意力在理論上效率更高,但此前在實(shí)際硬件上表現(xiàn)并不佳。因此,研究人員認(rèn)為這可能促進(jìn)一系列高吞吐量應(yīng)用的發(fā)展。

圖片

small tile符合AI和硬件發(fā)展趨勢(shì)

最后,雷貓研究團(tuán)隊(duì)總結(jié)了開發(fā)雷貓的一些思考。在他們看來,雷貓之所以有效,是因?yàn)樗哪繕?biāo)并不是試圖做所有事:

CUDA的確比雷貓表達(dá)能力更廣,雷貓小而簡(jiǎn)單,功能有限。但雷貓的small tiles抽象設(shè)計(jì)符合AI和硬件的發(fā)展趨勢(shì)。

雖然雷貓不支持小于16的維度,但研究人員認(rèn)為這并不重要,因?yàn)橛布膊粌A向于支持過小的維度。

如果你的矩陣乘法小于16x16,你確定你正在做的是AI嗎?

從理論出發(fā),研究人員認(rèn)為需要進(jìn)行一種框架轉(zhuǎn)變。

“寄存器當(dāng)然不應(yīng)該像舊CPU那樣32位字。CUDA使用的1024位寬向量寄存器確實(shí)是朝著正確方向邁出的一步。但對(duì)我們來說,寄存器是16x16的數(shù)據(jù)tile。我們認(rèn)為AI需要這樣的設(shè)計(jì),畢竟,它仍然只是矩陣乘法、歸約和重塑。我們認(rèn)為硬件也需要這樣的設(shè)計(jì),小型矩陣乘法迫切需要超出系統(tǒng)級(jí)MMA的硬件支持?!?/p>

研究人員認(rèn)為,應(yīng)該根據(jù)硬件特性來重新定義AI的設(shè)計(jì)理念。例如,循環(huán)狀態(tài)應(yīng)該有多大?應(yīng)該足夠大以適應(yīng)一個(gè)SM。計(jì)算的密度應(yīng)該有多高?不應(yīng)低于硬件的需求。

我們未來工作的一個(gè)重要方向是利用我們對(duì)硬件的了解來幫助我們?cè)O(shè)計(jì)與之匹配的AI。

責(zé)任編輯:張燕妮 來源: 量子位
相關(guān)推薦

2025-08-27 01:00:00

DSPyAI開發(fā)

2012-03-21 21:38:27

蘋果

2013-01-31 09:45:14

斯坦福超級(jí)電腦百萬內(nèi)核

2023-07-18 14:18:00

Attention模型圖像

2024-09-26 10:23:46

2022-12-29 16:41:10

PPT

2009-05-19 09:06:41

Apple斯坦福iPhone

2023-03-14 12:45:32

2025-07-21 11:51:12

模型AI工具

2019-12-16 14:33:01

AI人工智能斯坦福

2021-04-02 15:02:42

開源技術(shù) 工具

2025-09-08 09:10:00

2025-10-28 15:46:19

AIChatGPT算法

2025-10-31 16:06:19

AI參數(shù)微調(diào)

2025-01-17 10:26:19

模型開發(fā)ChatGPT

2025-01-14 12:22:10

2024-04-07 13:40:20

2017-11-28 14:18:29

2020-03-23 14:24:09

Python 開發(fā)編程語言

2023-12-08 13:22:00

數(shù)據(jù)模型
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

伊人久久亚洲| 在线播放毛片| 日韩高清一级片| 日韩一区视频在线| 中文字幕人妻熟女在线| 日韩性xxx| 樱桃视频在线观看一区| 蜜桃传媒视频第一区入口在线看| 中文字幕在线观看国产| 精品成人在线| 久久精品99无色码中文字幕| 水蜜桃av无码| 欧美一级做一级爱a做片性| 亚洲国产精品久久久男人的天堂| 日韩色妇久久av| 好吊视频一二三区| 六月丁香婷婷久久| 欧美在线日韩在线| 麻豆91精品91久久久| 成人网18免费网站| 日韩高清a**址| 午夜xxxxx| 成人看片毛片免费播放器| 亚洲国产成人porn| 欧美日韩视频免费在线观看| 男同在线观看| 成人av在线网| 91丝袜脚交足在线播放| 中文字幕乱码在线观看| 久久aⅴ国产紧身牛仔裤| 欧美猛交免费看| 免费黄色激情视频| 欧美一二区在线观看| 日韩电影大片中文字幕| 丰满人妻一区二区三区53视频| 朝桐光一区二区| 五月天国产精品| 少妇久久久久久被弄到高潮| 一本一道波多野毛片中文在线| 久久色在线视频| 国内外成人免费视频| 国产成人三级一区二区在线观看一 | av网址在线| 国产精品成人免费在线| 亚洲黄色成人久久久| 日韩有码电影| 26uuu亚洲| 玛丽玛丽电影原版免费观看1977| 欧美视频久久久| 国产成人啪午夜精品网站男同| 91精品久久久久久综合乱菊| 亚洲一区二区视频在线播放| 免费成人在线影院| 国产精品日日摸夜夜添夜夜av| 国产91精品看黄网站在线观看| 国产欧美丝祙| 日本欧美一级片| 波多野结衣啪啪| 日韩高清一区二区| 国产精自产拍久久久久久蜜| 亚洲一区二区人妻| 国产一区二区久久| 亚洲影影院av| www黄色网址| 成人网页在线观看| 激情久久av| 欧美美乳在线| 国产精品久久三| 亚洲国产精品女人| 国产精品一区hongkong| 偷偷要91色婷婷| 日韩欧美在线免费观看视频| 日韩电影精品| 日韩精品中文字幕一区二区三区 | 日韩视频在线视频| 日韩伦理福利| 在线观看成人免费视频| 激情黄色小视频| 亚洲成人影音| 国产视频丨精品|在线观看| 国产熟女一区二区| 91久久国产| 久久久久久免费精品| 成人毛片在线播放| 久色婷婷小香蕉久久| 91一区二区三区| 日本成人一区| 一区免费观看视频| 免费一级特黄毛片| 中文.日本.精品| 日韩亚洲欧美中文三级| 欧美性xxxx图片| 91蜜臀精品国产自偷在线 | 久久人人爽人人爽人人| 亚洲美女视频在线免费观看| 国产精品视频资源| 丰满熟妇乱又伦| 久久久久亚洲蜜桃| 糖心vlog在线免费观看| 色老太综合网| 日韩欧美一二三| 天天操天天舔天天射| 亚洲视频观看| 国产精品入口尤物| 色丁香婷婷综合久久| 国产精品少妇自拍| 无码aⅴ精品一区二区三区浪潮| 日韩有码欧美| 精品一区二区三区电影| 青青青在线免费观看| 日韩精品欧美精品| 国产一区自拍视频| 麻豆传媒在线观看| 在线观看不卡视频| 成人免费毛片日本片视频| 亚洲成人二区| 国产精品美女久久久久av超清| 农村少妇久久久久久久| 综合久久久久综合| www.日日操| 日韩欧美天堂| 欧美精品video| 国产免费一区二区三区最新不卡 | 韩国一区二区三区| 日本视频一区二区在线观看| 2020av在线| 精品久久久网站| 乱h高h女3p含苞待放| 欧美a一区二区| 日本一区高清不卡| 亚洲同志男男gay1069网站| 亚洲国产精品va在线观看黑人| 日本黄色免费片| 日本女优在线视频一区二区| 九九九九精品九九九九| mm视频在线视频| 精品久久久久久久久久久久包黑料| 午夜精品一区二区三级视频| 麻豆精品精品国产自在97香蕉 | 欧美日韩一区二区区别是什么| 欧美国产一级| 国产在线观看精品一区二区三区| av在线资源网| 欧美三区免费完整视频在线观看| 成人乱码一区二区三区av| 在线视频精品| 久久偷窥视频| 黑人巨大亚洲一区二区久 | 色av一区二区| 久久午夜福利电影| 久久一区亚洲| 日韩精品欧美专区| 成人做爰免费视频免费看| 夜夜躁日日躁狠狠久久88av| 黄色av网站免费| 中文字幕av免费专区久久| 一级黄色特级片| 97视频热人人精品免费| 亚洲自拍高清视频网站| 亚洲www色| 亚洲加勒比久久88色综合| 日韩欧美a级片| 91麻豆国产香蕉久久精品| aa免费在线观看| 欧美在线电影| 91欧美日韩一区| 先锋影音在线资源站91| 亚洲国产精品va在线观看黑人| 欧美a∨亚洲欧美亚洲| 久久亚洲免费视频| 国产视频1区2区3区| 女人色偷偷aa久久天堂| 精品乱色一区二区中文字幕| 香蕉成人av| 久久久国产一区二区| 免费看av毛片| 欧洲国内综合视频| 婷婷社区五月天| 不卡的av网站| 三年中国国语在线播放免费| 国产精品久久观看| 国产无套精品一区二区| 三上悠亚国产精品一区二区三区| 久久国产一区二区三区| 亚洲精选一区二区三区| 色呦呦一区二区三区| 国产美女福利视频| 97国产一区二区| 9l视频白拍9色9l视频| 欧美另类亚洲| 欧美午夜欧美| 一区二区免费| 国产精品igao视频| √天堂8在线网| 亚洲无av在线中文字幕| 国内老熟妇对白xxxxhd| 色婷婷激情综合| 无码人妻精品一区二区三区夜夜嗨| 97久久精品人人澡人人爽| 黄色一级片免费的| 噜噜噜躁狠狠躁狠狠精品视频| 中文字幕一区二区中文字幕| 青青一区二区| 亚洲中国色老太| 成人在线视频免费看| 国色天香2019中文字幕在线观看| 91ph在线| 亚洲精选在线观看| 亚洲av无码一区二区三区dv | 性欧美视频videos6一9| 在线国产情侣| 亚洲老头老太hd| 亚洲乱色熟女一区二区三区| 欧美在线视频全部完| 六月丁香在线视频| 亚洲一区中文日韩| av最新在线观看| 国产三级久久久| 三级视频网站在线观看| 国产精一区二区三区| 手机看片福利盒子久久| 欧美亚洲三级| 久久精品视频16| 中文字幕亚洲综合久久五月天色无吗''| 日本一区二区三区视频在线播放| 高清精品xnxxcom| 亚洲自拍欧美另类| 日韩欧美三区| 成人福利在线观看| 国产精品美女午夜爽爽| 国产激情999| 毛片电影在线| 91高清视频免费观看| 黑人另类精品××××性爽| 欧美另类在线播放| aaa大片在线观看| 久久资源免费视频| 免费黄色电影在线观看| 久久精品青青大伊人av| 嫩草在线视频| 精品国内自产拍在线观看| 日本高清中文字幕在线| 自拍偷拍亚洲欧美| 日本成a人片在线观看| 色av中文字幕一区| 青青影院在线观看| 久久精品国产欧美亚洲人人爽| av网站在线免费观看| 国产亚洲综合久久| 国产精品久久久久一区二区国产| 国产亚洲美女久久| 一本一道波多野毛片中文在线| 日日狠狠久久偷偷四色综合免费| 五月天婷婷在线视频| 久久久国产精品亚洲一区| 中文在线免费| 久久久久久亚洲精品中文字幕| 黄色成人在线网| 性欧美在线看片a免费观看| 一区二区乱码| 国产精品男女猛烈高潮激情| 欧美高清免费| 91在线中文字幕| 国产精品99久久免费观看| 九九九九九九精品| 精品国产1区| 国产系列第一页| 好看的日韩av电影| 国产视频一视频二| 日本不卡高清视频| www.偷拍.com| www国产成人| 亚洲综合久久av一区二区三区| 亚洲色图清纯唯美| 91在线看视频| 欧美色精品在线视频| 亚洲国产精品18久久久久久| 亚洲精品乱码久久久久久按摩观| 福利视频在线看| 久久不射热爱视频精品| 男人的天堂免费在线视频| 国产欧美欧洲在线观看| 日本超碰一区二区| 欧美人xxxxx| 久久久人成影片免费观看| 六月丁香激情网| 蓝色福利精品导航| 蜜臀av粉嫩av懂色av| 欧美高清在线一区| 免费毛片在线播放免费| 色噜噜狠狠色综合中国| 朝桐光av在线一区二区三区| 亚洲四色影视在线观看| 影音先锋在线视频| 国产成人综合久久| 成人av综合网| 伊人久久青草| 久久都是精品| 日批视频免费看| 欧美国产日韩在线观看| 国语对白一区二区| 欧美日本在线一区| 丝袜视频国产在线播放| 欧美高清不卡在线| 国产精品亚洲成在人线| 好吊色欧美一区二区三区四区| 99精品全国免费观看视频软件| 日韩精品 欧美| 国产精品一区久久久久| 国产熟女一区二区| 精品色蜜蜜精品视频在线观看| 国产精品区在线观看| 国产一区二区免费| 中文字幕这里只有精品| 成人黄动漫网站免费| 999国产精品永久免费视频app| 无遮挡又爽又刺激的视频| 成人久久视频在线观看| 中文字幕av播放| 欧美日韩国产美女| 国产区视频在线播放| 欧美与黑人午夜性猛交久久久| 成人h动漫精品一区二区器材| 一区不卡视频| 蜜臀av在线播放一区二区三区| 亚洲自拍偷拍一区二区 | 日韩极品视频在线观看| 国产精品综合二区| 一区二区三区四区五区| 欧美日韩一级大片网址| 成年人视频在线免费观看| 日韩免费在线免费观看| 天天躁日日躁狠狠躁欧美| 水蜜桃色314在线观看| 成人午夜av电影| 国产一级视频在线| 欧美tickling挠脚心丨vk| 在线观看电影av| 亚洲影院在线看| 欧美精品九九| 97中文字幕在线观看| 亚洲综合一区二区三区| 精品久久久中文字幕人妻| 欧美精品免费在线| 视频精品一区| 日韩av新片网| av在线播放成人| 天天综合网入口| 日韩精品免费在线观看| 小h片在线观看| 欧美午夜欧美| 久久国产精品99久久人人澡| 自拍偷拍第9页| 欧美一级xxx| 毛片在线导航| 久久精品日产第一区二区三区精品版 | 国产日韩av一区二区| 中文字幕欧美人妻精品| xvideos成人免费中文版| 精品中文字幕一区二区三区| 国产91沈先生在线播放| 99精品久久只有精品| 一二三区免费视频| 中文字幕日韩av综合精品| 伊人久久一区| 成年人网站国产| 91麻豆免费看| 一本色道久久综合精品婷婷| 欧美成人精品三级在线观看| 国产精品白浆| 成年人免费大片| 亚洲乱码日产精品bd| 污视频在线免费观看| 国产精品高潮呻吟久久av无限| 国产精品久久久乱弄| 亚洲视频 中文字幕| 日本道精品一区二区三区| 麻豆影视国产在线观看| 国产精品theporn88| 久久久久久9| 久久高清内射无套| 亚洲精品国产成人| 色婷婷成人网| 国内精品在线观看视频| 中文久久乱码一区二区| 黄色三级网站在线观看| 国产精品久久久久久久美男| 国产精品a级| 成人性生交大片免费看无遮挡aⅴ| 日韩三级高清在线| 国产精品迅雷| 国产精品igao激情视频| 久久众筹精品私拍模特| 国产又大又粗又长| 51色欧美片视频在线观看| 久久久久久久久久久久久久久久久久| www.日本高清| 日韩欧美在线影院| 日本一区二区电影| 2018国产在线|