精品欧美一区二区三区在线观看 _久久久久国色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)

国产精品久久久久久久久久精爆| 91精品福利在线一区二区三区 | 青青艹视频在线| 韩国av中文字幕| 亚洲狼人综合| 亚洲欧洲日本一区二区三区| 欧美日韩综合一区| 超碰97网站| 欧美成人久久久免费播放| 久久青青色综合| 国产免费播放一区二区| 亚洲精品国产成人久久av盗摄 | 精品人妻在线播放| 国产亚洲一区二区手机在线观看 | 97视频中文字幕| 性の欲びの女javhd| 3344国产永久在线观看视频| 国产精品性做久久久久久| 中文字幕欧美日韩精品| 久久精品网站视频| 青青青手机在线视频观看| 亚洲国产精品久久久天堂| 在线看不卡av| 欧美大香线蕉线伊人久久| 亚洲区免费视频| 天堂网在线最新版www中文网| 国产福利视频一区二区三区| 中文字幕9999| 在线天堂www在线国语对白| 毛片网站在线看| 国产精品三级电影| 国产精品私拍pans大尺度在线| 亚洲激情 欧美| 亚洲伦理一区二区| 在线观看av不卡| 激情伊人五月天| 免费观看a视频| 伊人久久综合| 日韩高清免费在线| 男人亚洲天堂网| 国产高清视频在线播放| 日韩电影免费在线| 色香阁99久久精品久久久| 99热手机在线| 成人免费视频| 精品一区二区在线视频| 欧美大尺度激情区在线播放| 亚洲国产日韩在线一区| 在线网址91| 高清在线成人网| 77777少妇光屁股久久一区| 韩国一区二区三区四区| 最新日本在线观看| 中文字幕日本乱码精品影院| 亚洲wwwav| 精品处破女学生| 欧美精品成人| 日韩电影免费观看在线观看| 91精品啪在线观看国产| 亚洲www免费| 亚洲色图一区二区三区| 国产一级二级三级精品| 精品国产xxx| 久久综合导航| 乱亲女秽乱长久久久| 人妻换人妻a片爽麻豆| 亚洲天堂中文字幕在线观看 | 日韩三级av在线| 亲子伦视频一区二区三区| 欧美性极品少妇精品网站| 日日夜夜精品网站| 国产有码在线观看| 99国产精品视频免费观看一公开| 中文字幕日韩精品在线观看| www.99热| 欧美一区网站| 日韩精品亚洲精品| 亚洲一区日韩精品| 美女高潮在线观看| 亚洲男人都懂的| 欧美精品一区在线发布| 国产女人在线观看| 中文字幕一区二区三区av| 精品国产一区二区三区麻豆小说| 懂色av蜜臀av粉嫩av喷吹| 欧美日韩视频| 2019精品视频| 在线观看黄网址| 婷婷国产精品| 欧美成人伊人久久综合网| 538在线视频观看| 97久久中文字幕| 宅男在线国产精品| www.欧美日本| 九色porny自拍视频在线观看 | 最近中文字幕在线免费观看 | 欧美日韩国产精品一区二区三区四区| 欧美综合激情| 高h调教冰块play男男双性文| 视频一区中文字幕| 91在线直播亚洲| 天天操天天干天天爱| 国产在线麻豆精品观看| 国产极品jizzhd欧美| 日本一区二区三区免费视频| 欧美日韩精品| 国产精品∨欧美精品v日韩精品| 国产又粗又猛又爽| 免费在线欧美视频| 国产精品18久久久久久首页狼 | 亚洲电影免费观看高清完整版在线| 国产肥臀一区二区福利视频| bl在线肉h视频大尺度| 色婷婷激情综合| 九一国产精品视频| 久久天堂影院| 欧美三级欧美一级| 中文文字幕文字幕高清| 另类春色校园亚洲| 精品中文视频在线| 日韩在线观看视频一区二区| 亚洲啊v在线观看| 26uuu国产精品视频| 国产成人三级在线播放| 国产老妇另类xxxxx| 欧美一区二区三区四区在线观看地址| 1769免费视频在线观看| 欧美日韩国产在线播放网站| 在线观看国产一级片| 美女主播精品视频一二三四| 久久亚洲欧美日韩精品专区| 午夜精品免费观看| 日本va欧美va精品发布| 国产免费一区二区三区在线能观看| 日本高清视频网站| 一区二区在线观看免费 | jk漫画禁漫成人入口| 精品日韩中文字幕| 国产麻豆剧传媒精品国产| 亚洲澳门在线| 91理论片午午论夜理片久久| 亚洲精品中文字幕成人片 | 91在线精品播放| 1769在线观看| 国产精品久久毛片| 成人在线观看a| 色天天色综合| 欧美做爰性生交视频| 亚洲婷婷久久综合| 91小视频免费看| 午夜精品美女久久久久av福利| 中文字幕高清在线播放| 国产视频综合在线| 手机看片久久久| 久久久久久久久久久久久夜| 亚洲第一导航| 最爽无遮挡行房视频在线| 欧美欧美欧美欧美首页| 韩国一区二区三区四区| 中文字幕一区二区av| 欧美精品videos另类日本| 成人午夜淫片100集| 激情五月播播久久久精品| 国产欧美一区二区在线播放| 91福利区在线观看| 日韩国产精品亚洲а∨天堂免| 精品在线播放视频| 久久久蜜桃精品| 五月婷婷狠狠操| 国产精品传媒精东影业在线| 91a在线视频| 噜噜噜噜噜在线视频| 一区免费观看视频| 久久人人爽人人片| 夜夜夜久久久| 日韩电影免费观看高清完整| 久久国产精品黑丝| 亚洲福利在线视频| 伊人久久久久久久久久久久| 国产超碰在线一区| 大j8黑人w巨大888a片| 欧洲杯半决赛直播| 88xx成人精品| 国产黄色片在线播放| 欧美美女视频在线观看| 久久久精品国产sm调教| 久久亚洲精华国产精华液| 国产精品无码电影在线观看| 97欧美成人| 欧美精品一区二区三区高清aⅴ| 九九九视频在线观看| 亚洲影院在线| 精品国产电影| 成人网ww555视频免费看| 亚洲精品久久久久久下一站| 人人澡人人澡人人看| 天堂av在线一区| 中文字幕免费高| 成人午夜sm精品久久久久久久| 久久久极品av| 一级久久久久久久| 亚洲一区二区三区不卡国产欧美| 永久免费黄色片| 99久久久久国产精品| 国产精品一国产精品最新章节| а√中文在线8| 欧美乱妇20p| 国产成人无码一区二区三区在线| 国产精品欧美一区喷水| www国产视频| 紧缚奴在线一区二区三区| 久久久久狠狠高潮亚洲精品| 国产精品xvideos88| 亚洲一区二区中文字幕| 男人皇宫亚洲男人2020| 欧美日本高清一区| 国产黄a三级三级看三级| 日韩欧美在线播放| 妺妺窝人体色www在线下载| 高清在线观看日韩| 欧美日韩中文不卡| 久久国产直播| 亚洲国产另类久久久精品极度| 国产精品2023| 欧美一级电影在线| 青青在线视频| 麻豆国产精品va在线观看不卡| 国产在线观看免费网站| 欧美日韩在线播放三区四区| 中文字幕亚洲高清| 亚洲成人综合网站| 自拍偷拍中文字幕| 成年人国产精品| 亚洲欧洲日产国码无码久久99| 午夜日韩在线| 日韩精品福利片午夜免费观看| 无码国模国产在线观看| 97人人模人人爽人人喊中文字| 青青青免费视频在线2| 亚洲第一免费网站| 亚洲AV无码一区二区三区少妇| 欧美妇女性影城| 国产又大又黄的视频| 欧美日本国产一区| 亚洲性在线观看| 一区二区三区成人| 亚洲黄色在线网站| 男人的天堂久久精品| 成年人小视频网站| 日本欧美大码aⅴ在线播放| 日本熟妇人妻中出| 青青草97国产精品免费观看无弹窗版 | 91九色精品国产一区二区| 亚洲欧洲日韩精品| 成人影院在线| 99久热re在线精品996热视频| 亚洲免费看片| 99视频在线免费观看| 亚洲综合色婷婷在线观看| 国产精品三区www17con| 亚洲网址在线观看| 久久久久欧美| 高清久久一区| 91精品国产沙发| 深夜av在线| 国产精品成久久久久三级| 午夜av在线免费观看| 亚洲欧美激情一区| 不卡的日韩av| 欧美亚洲国产一区二区三区 | 国产伦精品一区二区三区88av| 成人sese在线| av网在线播放| 粉嫩aⅴ一区二区三区四区五区| 国产成人av片| 26uuu色噜噜精品一区| 欧美丰满老妇熟乱xxxxyyy| 中文字幕人成不卡一区| 国产乡下妇女做爰视频| 色综合久久综合网欧美综合网| 波多野结衣视频免费观看| 欧美日本视频在线| 欧美一级淫片免费视频魅影视频| 亚洲欧美国产另类| √天堂8在线网| 青青草99啪国产免费| 9999在线精品视频| 国产亚洲情侣一区二区无| 日本a级不卡| 丁香六月激情婷婷| 99视频精品全国免费| 久久手机在线视频| 欧美影院一区| 中文字幕无码不卡免费视频| 韩国精品免费视频| 30一40一50老女人毛片| zzijzzij亚洲日本少妇熟睡| 九九九久久久久久久| 26uuu国产日韩综合| 午夜精品久久久久99蜜桃最新版| 国产免费成人在线视频| 色噜噜在线观看| 亚洲欧美一区二区在线观看| 国产a∨精品一区二区三区仙踪林| 欧美夫妻性生活| 免费毛片在线| 欧美精品久久久久| **欧美日韩在线| 欧洲精品国产| 亚洲精品韩国| 黑人性生活视频| 国产一区91精品张津瑜| 亚洲成人网在线播放| 亚洲午夜激情网页| 国产一区二区在线视频聊天| 亚洲精品中文字幕女同| 欧美黑人猛交的在线视频| 国产精品丝袜视频| 国产a久久精品一区二区三区| 日韩精品在线中文字幕| 国内精品伊人久久久久av一坑| 无码人妻精品一区二区中文| 性久久久久久久| 久久国产视频播放| 精品国产欧美一区二区| 成人午夜在线影视| 国产精品欧美久久久| 91精品麻豆| 亚洲高清在线观看一区| 久久天堂成人| 97伦伦午夜电影理伦片| 午夜精品福利一区二区三区蜜桃| www.四虎在线观看| 久热在线中文字幕色999舞| 欧美男女视频| 亚洲乱码一区二区三区| 日韩精品电影在线| 色一情一交一乱一区二区三区| 日韩欧美高清在线视频| 天天色棕合合合合合合合| 久久久久久久国产精品视频| gogo久久日韩裸体艺术| 欧美高清视频一区二区三区在线观看| 影音先锋中文字幕一区二区| 欧美成人精品一区二区综合免费| 99精品国产热久久91蜜凸| 亚洲 小说 欧美 激情 另类| 精品女厕一区二区三区| 香港一级纯黄大片| 中文字幕亚洲综合久久| 99久久综合国产精品二区| 日韩中文不卡| 久久国产福利国产秒拍| 老熟妻内射精品一区| 91精品欧美福利在线观看| jizz性欧美10| 国产高清自拍一区| 狠狠色狠狠色综合婷婷tag| 国产91对白刺激露脸在线观看| 26uuu亚洲综合色| 中文人妻熟女乱又乱精品| 欧美r级在线观看| 国产www.大片在线| 国产精品无av码在线观看| 久久综合电影| 国产中文字幕免费观看| 91丝袜高跟美女视频| 国产性生活视频| 久久精品男人天堂| 北条麻妃一区二区三区在线| 能在线观看的av| 亚洲欧美影音先锋| 欧美一区二不卡视频| 日韩免费观看高清| 51vv免费精品视频一区二区| 男人天堂手机在线视频| 久久久久国产精品人| 国产又粗又猛又爽又黄视频| 欧美劲爆第一页| 神马电影久久| 免费成人在线视频网站| 国产欧美日韩三级| 99久久国产免费| 色一区av在线| 九色丨蝌蚪丨成人| 一区二区三区视频在线观看免费| 26uuu久久综合| 亚洲字幕av一区二区三区四区| 欧美高清电影在线看| 国产精品久久久久久久久久久久久久久| 激情五月六月婷婷| 久久精品视频一区二区三区| 国产精品天天操| 欧美在线激情网| 欧美aa国产视频| 国产精品无码一区二区三区| 欧美一区二区三区播放老司机| 中文在线8资源库| 亚洲色婷婷久久精品av蜜桃| 国产午夜精品久久久久久免费视|