在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

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

3天內不再提示

OneFlow elementwise模板

jf_pmFSk4VX ? 來源:GiantPandaCV ? 2023-01-08 15:25 ? 次閱讀

0x0. 前言

如題所述,本篇文章推薦和講解一下OneFlow ElementWise模板,FastAtomicAdd,OneFlow UpsampleNearest2d模板的用法以及原理。但OneFlow ElementWise模板的用法和原理在【BBuf的CUDA筆記】一,解析OneFlow Element-Wise 算子實現 已經講過了,所以這篇文章里不再贅述,主要講解后面2個。我將上述三個算法的實現都分別抽出來放到了 https://github.com/BBuf/how-to-optim-algorithm-in-cuda 這個工程的 elementwise/FastAtomicAdd/UpsampleNearest2D 三個文件夾中,并且三個算法的實現都分別只用一個.cu文件進行整理,使用nvcc編譯可以使用,有需要的同學請自取。

0x1. OneFlow elementwise模板

將 oneflow 的 elementwise 模板抽出來方便大家使用,這個 elementwise 模板實現了高效的性能和帶寬利用率,并且用法非常靈活。完整實驗代碼見 https://github.com/BBuf/how-to-optim-algorithm-in-cuda/blob/master/elementwise/elementwise.cu,原理講解請看:【BBuf 的CUDA筆記】一,解析OneFlow Element-Wise 算子實現 。這里以逐點乘(z = x * y,其中x,y,z是形狀完全一樣的Tensor)為例,性能和帶寬的測試情況如下 (A100 PCIE 40G):

優化手段 數據類型 耗時(us) 帶寬利用率
naive elementwise float 298.46us 85.88%
oneflow elementwise float 284us 89.42%
naive elementwise half 237.28us 52.55%
oneflow elementwise half 140.74us 87.31%

可以看到無論是性能還是帶寬,使用 oneflow 的 elementwise 模板相比于原始實現都有較大提升。

涉及到的主要優化技術有向量化數據訪問,選取合適的GridSize和BlockSize,循環展開和Grid-Stride Loops等技巧。

模板代碼和用法詳見:https://github.com/BBuf/how-to-optim-algorithm-in-cuda/blob/master/elementwise/elementwise.cu

0x2. FastAtomicAdd

眾所周知,atomicAdd是CUDA中非常昂貴的操作,特別是對于half類型來說 atomicAdd 巨慢無比,慢到如果一個算法需要用到 atomicAdd,那么相比于用 half ,轉成 float ,再 atomicAdd,再轉回去還要慢很多。但是我們有時候不得不去執行half類型的原子加,這個時候怎么能提升性能呢?

PyTorch給出了一個快速原子加的實現(我這里魔改了一下,去掉了一些不需要的參數,完整測試代碼見 https://github.com/BBuf/how-to-optim-algorithm-in-cuda/blob/master/FastAtomicAdd/fast_atomic_add_half.cu ):

//FastAddisreferencedfrom
//https://github.com/pytorch/pytorch/blob/396c3b1d88d7624938a2bb0b287f2a19f1e89bb4/aten/src/ATen/native/cuda/KernelUtils.cuh#L29
template<typenameT,typenamestd::enable_if<std::is_same::value>::type*=nullptr>
__device____forceinline__voidFastSpecializedAtomicAdd(T*base,size_toffset,
constsize_tlength,Tvalue){
#if((defined(CUDA_VERSION)&&(CUDA_VERSION
atomicAdd(reinterpret_cast(base)+offset,static_cast(value));
#else
//Accountsforthechancebasefallsonanodd16bitalignment(ie,not32bitaligned)
__half*target_addr=reinterpret_cast<__half*>(base+offset);
boollow_byte=(reinterpret_cast<std::uintptr_t>(target_addr)%sizeof(__half2)==0);

if(low_byte&&offset1)){
__half2value2;
value2.x=value;
value2.y=__float2half_rz(0);
atomicAdd(reinterpret_cast<__half2*>(target_addr),value2);

}elseif(!low_byte&&offset>0){
__half2value2;
value2.x=__float2half_rz(0);
value2.y=value;
atomicAdd(reinterpret_cast<__half2*>(target_addr-1),value2);

}else{
atomicAdd(reinterpret_cast<__half*>(base)+offset,static_cast<__half>(value));
}
#endif
}

template<typenameT,typenamestd::enable_ifstd::is_same::value>::type*=nullptr>
__device____forceinline__voidFastSpecializedAtomicAdd(T*base,size_toffset,
constsize_tlength,Tvalue){
atomicAdd(base+offset,value);
}

template
__device____forceinline__voidFastAdd(T*base,size_toffset,constsize_tlength,Tvalue){
FastSpecializedAtomicAdd(base,offset,length,value);
}

也就是把half類型的原子加轉換成half2類型的原子加,為了驗證這個快速原子加相比于half類型的原子加以及pack 2個half 到 half2再執行原子加的性能表現,我實現了三個算法(.cu文件)。它們都是針對half數據類型做向量的內積,都用到了atomicAdd,保證數據的長度以及gridsize和blocksize都是完全一致的。具體如下:

  1. https://github.com/BBuf/how-to-optim-algorithm-in-cuda/blob/master/FastAtomicAdd/atomic_add_half.cu 純half類型的atomicAdd。
  2. https://github.com/BBuf/how-to-optim-algorithm-in-cuda/blob/master/FastAtomicAdd/atomic_add_half_pack2.cu half+pack,最終使用的是half2類型的atomicAdd。
  3. https://github.com/BBuf/how-to-optim-algorithm-in-cuda/blob/master/FastAtomicAdd/fast_atomic_add_half.cu 快速原子加,雖然沒有顯示的pack,但本質上也是通過對單個half補0使用上了half2的原子加。

下面展示3個腳本通過ncu profile之后的性能表現:

原子加方式 性能(us)
純half類型 422.36ms
pack half2類型 137.02ms
fastAtomicAdd 137.01ms

可以看到使用pack half的方式和直接使用half的fastAtomicAdd方式得到的性能結果一致,均比原始的half的原子加快3-4倍。

接下來驗證一下是否存在warp分支分化問題,對比了一下fastAtomicAdd和pack half2的ncu匯編代碼,并未發現不同類型的指令:

fastAtomicAdd 計算部分:

73b53cd4-8efc-11ed-bfe3-dac502259ad0.png在這里插入圖片描述

atomicAddhalfpack2計算部分:

73d9bce4-8efc-11ed-bfe3-dac502259ad0.png在這里插入圖片描述

每一種指令的類型都能在兩份代碼中找到,初步判斷不會因為fastAtomicAdd實現中的下述if語句存在線程分化問題。

73fe983e-8efc-11ed-bfe3-dac502259ad0.png圖片

綜上所述,使用FastAtomicAdd可以大幅度提升half數據類型原子加的性能并且不需要手動Pack,使用方法更加簡單。

模板代碼和用法詳見:https://github.com/BBuf/how-to-optim-algorithm-in-cuda/blob/master/FastAtomicAdd/fast_atomic_add_half.cu

0x3. Oneflow Upsample模板

在Stable Diffusion的反向擴散過程中使用到了UNet,而UNet中存在大量的UpsampleNearest2D上采樣。PyTorch對于UpsampleNearest都是通用的實現(https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/native/cuda/UpSampleNearest2d.cu#L112-L163) ,這種實現里面存在大量的取模和坐標映射操作(nn_bw_compute_source_index_fn)以及循環統計貢獻等。對于深度學習來說,UpsampleNearest最常用的其實就是2倍上采樣,比如Unet和YOLOv5,所以我們完全可以針對這種情況寫一個特化的Kernel,很輕量的來完成2倍上采樣的計算。下面展示OneFlow中針對2倍上采樣的優化(代碼見:https://github.com/BBuf/how-to-optim-algorithm-in-cuda/blob/master/UpsampleNearest2D/upsample_nearest_2d.cu#L16-L63)

//CUDA:gridstridelooping
#defineCUDA_1D_KERNEL_LOOP(i,n)
for(int32_ti=blockIdx.x*blockDim.x+threadIdx.x,step=blockDim.x*gridDim.x;i

//UpsampleNearest2DKerneliscopyedfromhttps://github.com/Oneflow-Inc/oneflow/blob/master/oneflow/user/kernels/upsample_nearest_kernel.cu#L78
template<typenameT>
structalignas(2*sizeof(T))Pack2X{
Tx;
Ty;
};

template<typenameT>
__global__voidUpsampleNearest2D2XForward(constint32_tin_elem_cnt,constT*in_dptr,
constint32_tin_height,constint32_tin_width,
T*out_dptr){
constint32_tin_hw_size=in_width*in_height;
CUDA_1D_KERNEL_LOOP(index,in_elem_cnt){
constTin_value=in_dptr[index];
constint32_tnc_idx=index/in_hw_size;
constint32_thw_off=index-nc_idx*in_hw_size;//這里是優化掉昂貴的取模運算
constint32_th=hw_off/in_width;
constint32_tw=hw_off-h*in_width;
Pack2Xout_value{in_value,in_value};
Pack2X*out_pack_dptr=reinterpret_cast*>(out_dptr);
out_pack_dptr[nc_idx*in_hw_size*2+h*2*in_width+w]=out_value;
out_pack_dptr[nc_idx*in_hw_size*2+(h*2+1)*in_width+w]=out_value;
}
}

template<typenameT>
__global__voidUpsampleNearest2D2XBackward(constint32_tin_elem_cnt,constT*dy_dptr,
constint32_tdx_height,constint32_tdx_width,
T*dx_dptr){
constint32_tdx_hw_size=dx_height*dx_width;
CUDA_1D_KERNEL_LOOP(index,in_elem_cnt){
Tdx_value=0.0;
constint32_tnc_idx=index/dx_hw_size;
constint32_tdx_hw_off=index-nc_idx*dx_hw_size;
constint32_tdx_h=dx_hw_off/dx_width;
constint32_tdx_w=dx_hw_off-dx_h*dx_width;
constPack2X*dy_pack_dptr=reinterpret_cast<constPack2X*>(dy_dptr);
constPack2Xdy_pack_value1=
dy_pack_dptr[nc_idx*dx_hw_size*2+dx_h*2*dx_width+dx_w];
constPack2Xdy_pack_value2=
dy_pack_dptr[nc_idx*dx_hw_size*2+(dx_h*2+1)*dx_width+dx_w];
dx_value+=dy_pack_value1.x;
dx_value+=dy_pack_value1.y;
dx_value+=dy_pack_value2.x;
dx_value+=dy_pack_value2.y;
dx_dptr[index]=dx_value;
}
}

這個地方比較好理解,我們以前向的UpsampleNearest2D2XForward為例,當我們對一個的矩陣進行2倍上采樣時,可以獲得大小的輸出Tensor,那么輸入和輸出的對應關系如下圖所示:

74222808-8efc-11ed-bfe3-dac502259ad0.png箭頭表示輸入元素和輸出區域的對應關系

也就是輸入的(0, 0)位置對應來輸出的(0, 0), (0, 1), (1, 0), (1, 1)的位置。也就是一個輸入的元素其實是對應來輸出的4個元素,并且這4個元素一定是相鄰的2行或2列。所以我們可以使用Pack技術只用2次賦值就完成輸出Tensor對應位置元素的填寫,進一步提升全局內存訪問的帶寬。

我這里直接使用 oneflow 的腳本對這兩個 kernel 進行進行 profile :

importoneflowasflow

x=flow.randn(16,32,80,80,device="cuda",dtype=flow.float32).requires_grad_()

m=flow.nn.Upsample(scale_factor=2.0,mode="nearest")

y=m(x)
print(y.device)
y.sum().backward()

下面展示了在 A100 上調優前后的帶寬占用和計算時間比較:

框架 數據類型 Op類型 帶寬利用率 耗時
PyTorch Float32 UpsampleNearest2D forward 28.30% 111.42us
PyTorch Float32 UpsampleNearest2D backward 60.16% 65.12us
OneFlow Float32 UpsampleNearest2D forward 52.18% 61.44us
OneFlow Float32 UpsampleNearest2D backward 77.66% 50.56us
PyTorch Float16 UpsampleNearest2D forward 16.99% 100.38us
PyTorch Float16 UpsampleNearest2D backward 31.56% 57.38us
OneFlow Float16 UpsampleNearest2D forward 43.26% 35.36us
OneFlow Float16 UpsampleNearest2D backward 44.82% 40.26us

可以看到基于 oneflow upsample_nearest2d 的前后向的優化 kernel 可以獲得更好的帶寬利用率和性能。

模板代碼和用法詳見:https://github.com/BBuf/how-to-optim-algorithm-in-cuda/blob/master/UpsampleNearest2D/upsample_nearest_2d.cu

0x4. 總結

本篇文章推薦和講解一下OneFlow ElementWise模板,FastAtomicAdd,OneFlow UpsampleNearest2d模板的用法以及原理,并將其整理為最小的可以白嫖的頭文件。相關代碼請訪問 https://github.com/BBuf/how-to-optim-algorithm-in-cuda 這里獲得。


審核編輯 :李倩


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

    關注

    23

    文章

    4626

    瀏覽量

    93151
  • 模板
    +關注

    關注

    0

    文章

    108

    瀏覽量

    20585
  • 代碼
    +關注

    關注

    30

    文章

    4814

    瀏覽量

    68851

原文標題:0x4. 總結

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

收藏 人收藏

    評論

    相關推薦

    如何用VSCODE創建一個LE5010的工程模板

    我想問下,就是怎么用vscode來創建LE5010的工程模板,我看網上的資料很少很少,官方給的SDK有,但是只能SDK里面來寫代碼,所以就想問一問! (有償)
    發表于 12-04 10:01

    圖紙模板中的文本變量

    “ ?文本變量和系統自帶的內置變量,可以幫助工程師靈活、高效地配置標題欄中的信息,而不用擔心模板中的文字對象被意外修改。 ? ” 文本變量的語法 文本變量以?${VARIABLENAME}?的方式
    的頭像 發表于 11-13 18:21 ?208次閱讀
    圖紙<b class='flag-5'>模板</b>中的文本變量

    A0到A4的圖框只要一個圖紙模板就搞定了?

    “ ?圖紙模板規范了圖紙的尺寸大小,同時可以在標題欄顯示與圖紙相關的信息,如產品名稱、版本、日期等。從標準化的角度考慮,公司通常會定義A0~A4的圖紙模板,用于不同的設計場合。KiCad提供了一種
    的頭像 發表于 11-13 18:13 ?527次閱讀
    A0到A4的圖框只要一個圖紙<b class='flag-5'>模板</b>就搞定了?

    摩爾線程開源高性能線性代數模板庫MUTLASS

    近日,摩爾線程宣布開源高性能線性代數模板庫MUTLASS,以便開發者能夠更高效針對摩爾線程全功能GPU的MUSA Core及Tensor Core等單元進行編程,加速基于國產GPU的算子開發以及算法創新。
    的頭像 發表于 11-13 11:53 ?358次閱讀

    手寫圖像模板匹配算法在OpenCV中的實現

    OpenCV中的模板匹配是支持基于NCC相似度查找的,但是不是很好用,一個主要的原因是查找最大閾值,只能匹配一個,自己比對閾值,又導致無法正確設定閾值范圍,所以問題很多。于是我重新寫了純Python版本的NCC圖像模板匹配的代碼實現了一個Python版本的,簡單易用,支持
    的頭像 發表于 11-11 10:12 ?301次閱讀
    手寫圖像<b class='flag-5'>模板</b>匹配算法在OpenCV中的實現

    使用helloword的模板,上傳了IG502但不能運行,為什么?

    我使用helloword的模板,上傳了IG502,但不能運行,請大神幫忙。系統日志如下: sntpc[1226]: ntp request error: 113, No route to host
    發表于 07-24 08:29

    如何使用Vitis自帶的LWIP模板進行PS端千兆以太網TCP通信?

    開發板有兩路千兆以太網,通過RGMII接口連接,本實驗演示如何使用Vitis自帶的LWIP模板進行PS端千兆以太網TCP通信。
    的頭像 發表于 04-28 10:44 ?3686次閱讀
    如何使用Vitis自帶的LWIP<b class='flag-5'>模板</b>進行PS端千兆以太網TCP通信?

    使用SDK5生成工程模板程序時老是出現錯誤是為啥?

    使用st SDK5生成工程模板程序時老是出現這樣的錯誤是為啥?我的SDK:5.0.1STM32CubeMX:4.26.0Keil5:5.25 求助萬能的網友。
    發表于 04-28 08:36

    CW32F003E4芯片入門學習:4.工程模板創建(使用例程或模板)

    模板路徑:CW32F003_StandardPeripheralLib_V1.4ExamplesTemplate
    的頭像 發表于 04-24 14:14 ?427次閱讀
    CW32F003E4芯片入門學習:4.工程<b class='flag-5'>模板</b>創建(使用例程或<b class='flag-5'>模板</b>)

    電源模塊測試數據一鍵導出,自定義報告模板

    NSAT-8000電源模塊測試系統可以便捷、快速地創建多樣化、個性化的報告模板,方便統一匯總、管理、對比數據,為電源模塊的性能分析和評估提供有力支持。
    的頭像 發表于 04-16 14:43 ?353次閱讀

    微軟Visio網頁版新增八個可定制思維導圖模板

    4 月 10 日,微軟發布公告表明,作為Visio Plan 1與Visio Plan 2許可證持有者,如今可以在Web版Visio中暢享思維導圖模板服務。
    的頭像 發表于 04-10 10:07 ?842次閱讀

    TouchGFX的Application Templates模板里面為什么只有2個?

    如題,手邊有一塊F429 Discovery的板子,然后打開touchGFX , 發現模板里面只有兩種類型。我卸載了TouchGFX再重新裝也沒有用。找不到配置的地方,那個online的選項,明明已經連接上了網絡,但是還是顯示灰色,不知道為什么。
    發表于 04-09 06:49

    Altium Designer與Gerber模板的導入指南

    我們在設計完成后,準備輸出Gerber的時候,有時候想用自己的Gerber模板導入PCB進行編輯,那么是如何設置導入的呢?
    的頭像 發表于 03-28 09:41 ?1455次閱讀
    Altium Designer與Gerber<b class='flag-5'>模板</b>的導入指南

    CW32F003E4芯片入門學習:4.工程模板創建(使用例程或模板)

    1.3.1拷貝模板工程和庫文件 模板路徑:CW32F003_StandardPeripheralLib_V1.4ExamplesTemplate 庫文件路徑
    的頭像 發表于 03-27 09:39 ?525次閱讀
    CW32F003E4芯片入門學習:4.工程<b class='flag-5'>模板</b>創建(使用例程或<b class='flag-5'>模板</b>)

    LabVIEW模板匹配位置信息導出

    大家好,我在利用ni vision assistant生成的模板匹配界面時,想要將每一個匹配物體的位置信息導出到word或者Excel,但是他這個匹配個數不確定,怎么樣把匹配到的所有物體信息導出呀?利用哪些編程?謝謝大家了
    發表于 03-11 20:22
    主站蜘蛛池模板: 草草影院www色极品欧美| 在线毛片网| 免费两性的视频网站| 三级全黄a| 日本精品一在线观看视频| 日韩综合色| 欧美日韩国产成人精品| 欧美一区二区三区在线观看免费 | 欧美同性精品xxxx| 5g成人影院| 欧美一区二区三区不卡视频| 久久婷婷婷| 五月婷婷激情视频| 日韩免费三级电影| 久久综合色综合| 人人看人人干| 午夜三级视频| 日本wwww色| 黄色网一级片| 夜夜摸视频网| 国产破苞合集 magnet| 69日本xxxxxxxxx30| 在线天堂bt中文www在线| 韩漫免费网站无遮挡羞羞漫画| 中文字幕成人乱码在线电影| 四虎最新入口| 天堂avwww| 欧美日韩高清一区| 爱爱欧美| 免费观看成年欧美1314www色| 爽爽爽爽爽爽a成人免费视频 | 日本黄大片在线观看| 久久免费手机视频| 788gao这里只有精品| 丁香婷五月| 黄色二级视频| www.久久综合| 午夜日韩| 夜夜夜夜操| se94se亚洲欧美在线| 国产色丁香久久综合|