0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于cutlass GTC2020的slides

jf_pmFSk4VX 来源:GiantPandaCV 2024-01-04 16:28 次阅读

what are tensorcores

a164fdfc-aa37-11ee-8b88-92fbcf53809c.png

TensorCore是一个硬件概念,主要是用于加速矩阵乘操作运算(我们也叫MMA,Matrix Multiply Add),执行的是:

D = A * B + C

同时也支持多种输入类型,数值累加类型。

a183b3a0-aa37-11ee-8b88-92fbcf53809c.png

编程层次上,TensorCore处于Warp(连续的32个threads)这一层,一个WARP内持有A, B, C, D四个操作数的数据。

a19a1802-aa37-11ee-8b88-92fbcf53809c.png

上图是Ampere架构支持的MMA指令,支持多种尺寸,数据类型。

Slides下面就是介绍各种尺寸的MMA,我们可以结合代码跑一下

S8 * S8 + S32 Code

使用TensorCore的时候,对数据排布是有特殊要求的。MMA指令是在一个WARP内执行,所以各个线程对应取数据的位置也是有特殊的映射关系

首先来个简单的 int8 x int8 = int32 的(8x16 matmul 16x8 = 8x8)运算,Slides里的排布是这样:

a1b71d80-aa37-11ee-8b88-92fbcf53809c.png

每个线程持有 A的4x8bit = 32bit 数据,B的4x8bit = 32bit 数据,C/D的 2x32bit = 64bit 数据

我们假设使用的矩阵为:

a1dae51c-aa37-11ee-8b88-92fbcf53809c.png

我们把线程映射跟元素写到一块:

a208a006-aa37-11ee-8b88-92fbcf53809c.png

而由于tensor core instruction is TN layout.

这里还是沿用blas计算库的说法,blas库里,会将 a x b = c -> b_T x a_T = c_T,这里的T说的是B矩阵是transpose的,也即A矩阵是RowMajor, B矩阵是ColMajor.

所以实际上应该是:

a230b014-aa37-11ee-8b88-92fbcf53809c.png

可以看到跟A矩阵是完全一样了,后面取元素的时候两个矩阵寄存器所使用的index是一致的

这里使用的代码是slides里的example。

a24e7fcc-aa37-11ee-8b88-92fbcf53809c.png

先简单写个初始化的kernel:

#include"stdio.h"
#include"stdint.h"

__global__voidset_value(int8_t*x,int32_telem_cnt){
for(inti=0;i< elem_cnt; i++){
        x[i] = static_cast(i%8);
}
}

接下来是TensorCore运算的kernel,需要注意的是这里用的都是int32类型,而我们执行的是 s8 x s8 = s32 的计算,调用的时候需要reinterpret_cast下。

//DoAxB+C=D.
__global__voidtensor_core_example_8x8x16(int32_t*D,
uint32_tconst*A,
uint32_tconst*B,
int32_tconst*C){
//ComputethecoordinatesofaccessestoAandBmatrices
intouter=threadIdx.x/4;//morndimension
intinner=threadIdx.x%4;//kdimension
//Computethecoordinatesfortheaccumulatormatrices
intc_row=threadIdx.x/4;
intc_col=2*(threadIdx.x%4);
//Computelinearoffsetsintoeachmatrix
intab_idx=outer*4+inner;
intcd_idx=c_row*8+c_col;

//IssueTensorCoreoperation
asmvolatile("mma.sync.aligned.m8n8k16.row.col.s32.s8.s8.s32{%0,%1},{%2},{%3},{%4,%5};
"
:"=r"(D[cd_idx]),"=r"(D[cd_idx+1])
:"r"(A[ab_idx]),"r"(B[ab_idx]),"r"(C[cd_idx]),"r"(C[cd_idx+1]));
}
最后打印输出结果:
__global__voidprintMatrix(int32_t*result,constintm,constintn){
for(introw=0;row< m; row++){
        for(int col = 0; col < n; col++){
            printf("Row id: %d, Col id: %d, result is: %d 
", row, col, result[row * n + col]); 
        }
    }
}

int main(){
    int8_t* a; 
    int8_t* b; 
    int32_t* c; 
    int32_t* d; 

    const int32_t m = 8; 
    const int32_t k = 16; 
    const int32_t n = 8; 

    cudaMalloc(&a, m * k * sizeof(int8_t)); 
    cudaMalloc(&b, k * n * sizeof(int8_t)); 
    cudaMalloc(&c, m * n * sizeof(int32_t)); 
    cudaMalloc(&d, m * n * sizeof(int32_t)); 

    set_value<<<1, 1>>>(a,m*k);
set_value<<<1, 1>>>(b,k*n);
cudaMemset(c,0,sizeof(int32_t)*m*n);
cudaMemset(d,0,sizeof(int32_t)*m*n);

tensor_core_example_8x8x16<<<1, 32>>>(reinterpret_cast(d),
reinterpret_cast(a),
reinterpret_cast(b),
reinterpret_cast(c));

printMatrix<<<1, 1>>>(d,m,n);
cudaDeviceSynchronize();
cudaFree(a);
cudaFree(b);
cudaFree(c);
cudaFree(d);
}

举一反三

下面我们也可以举一反三,写下 f16*f16+fp32的 tensorcore程序,对应的指令是 16 x 8 x 8,不过线程持有的数据跟前面的例子有些不同,需要改下

a28d0c6a-aa37-11ee-8b88-92fbcf53809c.png

#include"stdio.h"
#include"stdint.h"
#include"cuda_fp16.h"

template
__global__voidset_value(T*x,int32_telem_cnt){
for(inti=0;i< elem_cnt; i++){
        x[i] = static_cast(i%8);
}
}

__global__voidtensor_core_example_16x8x8(float*D,
uint32_tconst*A,
uint32_tconst*B,
floatconst*C){
//ComputethecoordinatesofaccessestoAandBmatrices
intouter=threadIdx.x/4;//morndimension
intinner=threadIdx.x%4;//kdimension
//Computethecoordinatesfortheaccumulatormatrices
intc_row=threadIdx.x/4;
intc_col=2*(threadIdx.x%4);
//Computelinearoffsetsintoeachmatrix
intab_idx=outer*4+inner;
intcd_idx=c_row*8+c_col;

//IssueTensorCoreoperation
asmvolatile("mma.sync.aligned.m16n8k8.row.col.f32.f16.f16.f32{%0,%1,%2,%3},{%4,%5},{%6},{%7,%8,%9,%10};
"
:"=f"(D[cd_idx]),"=f"(D[cd_idx+1]),"=f"(D[cd_idx+64]),"=f"(D[cd_idx+1+64])
:
"r"(A[ab_idx]),"r"(A[ab_idx+32]),
"r"(B[ab_idx]),
"f"(C[cd_idx]),"f"(C[cd_idx+1]),"f"(C[cd_idx+64]),"f"(C[cd_idx+1+64])
);
}

__global__voidprintMatrix(float*result,constintm,constintn){
for(introw=0;row< m; row++){
        printf("Row id: %d, result is: ", row); 
        for(int col = 0; col < n; col++){
            printf("%f ", static_cast(result[row*n+col]));
}
printf("
");
}
}

intmain(){
half*a;
half*b;
float*c;
float*d;

constint32_tm=16;
constint32_tk=8;
constint32_tn=8;

cudaMalloc(&a,m*k*sizeof(half));
cudaMalloc(&b,k*n*sizeof(half));
cudaMalloc(&c,m*n*sizeof(float));
cudaMalloc(&d,m*n*sizeof(float));

set_value<<<1, 1>>>(a,m*k);
set_value<<<1, 1>>>(b,k*n);
cudaMemset(c,0,sizeof(float)*m*n);
cudaMemset(d,0,sizeof(float)*m*n);

tensor_core_example_16x8x8<<<1, 32>>>(reinterpret_cast(d),
reinterpret_cast(a),
reinterpret_cast(b),
reinterpret_cast(c));

printMatrix<<<1, 1>>>(d,m,n);
cudaDeviceSynchronize();
cudaFree(a);
cudaFree(b);
cudaFree(c);
cudaFree(d);
}

可以看到不同的MMA指令会对应不同的矩阵规模,不同的数据类型。在CUTLASS,上述的这些MMA被统一到一个模板里:

a2a0ea00-aa37-11ee-8b88-92fbcf53809c.png

实际使用的话,只需对应实例化MMA模板即可:

a2c3b792-aa37-11ee-8b88-92fbcf53809c.png

DATA Movement

下面几张Slides谈论的是矩阵乘中数据搬运的部分,以及新架构引入的LDMatrix指令。

a2d7a81a-aa37-11ee-8b88-92fbcf53809c.png

这张Slide还是以S8 x S8 + S32的mma为例,前面我们也推导过,一个WARP完成 8x16 matmul 16x8, 那么一个WARP加载A矩阵和B矩阵一共需要 (8x16 + 16x8) = 256B,FLOPS计算如下:

C矩阵一共8*8=64个元素
每个元素需要16次乘法和加法,
FLOPS=64*16*2=2048

两者一除得到计算访存比为 8flops/byte。

那么我们再看下Ampere架构白皮书里面标注的设计规格,A100的Int8 tensorcore算力是624TFLOPS(312是FP16,int8对应翻一倍),80GB A100的HBM速度为1.6TB/s,那么其理想计算访存比是 400flops/byte

相较两者访存比,可以看到使用了TensorCore后,访存成为了瓶颈,这也是为什么数据搬运在优化GEMM里是很重要的一环。

这里我觉得是作为一种理想情况的估算,实际情况可能更复杂,需要考虑缓存命中率等(参考知乎李少侠的文章)

因此cutlass抽象了一套高效的数据搬运流程,过往很多GEMM优化文章都有介绍,就不赘述了:

a2ee7c7a-aa37-11ee-8b88-92fbcf53809c.png

其中在Ampere架构里面,新引入了AsyncCopy机制,也就是在Global Memory 到 SharedMemory 这一个环节。以往我们需要从Global Memory读取到线程寄存器,再从寄存器里存储到SharedMemory,但有了这个指令后,我们可以一步到位,从GlobalMemory -> SharedMemory,一定程度减轻了寄存器压力。(如果你常profile GEMM应该能有所体会)

a30b3ee6-aa37-11ee-8b88-92fbcf53809c.png

并且它是一种异步操作,意味着我们可以提前发射出好几轮(在cutlass里往往称为Stage)数据预取的指令,以实现延迟隐藏(我搬我的,你算你的)。

而另外一个比较特殊的指令则是LDMatrix,这个指令是用在SharedMemory到Register的过程。

为了尽可能打满带宽,在GlobalMemory->SharedMemory这一环节中,每个线程都是以128bit的访问粒度去存储。而前面也提到TensorCore对应每个线程对数据有不同的索引这也就导致每个线程需要的元素在SharedMemory上是不连续的

a3313254-aa37-11ee-8b88-92fbcf53809c.png

以Slides为例,我们看T0线程,它需要T0,T8,T16,T24对应SharedMemory的第一个元素。在没有LDMatrix之前,它需要对应四次LDS32操作,而如果我们调用LDMatrix,可以一个指令就完成上述的操作:

a34f32d6-aa37-11ee-8b88-92fbcf53809c.png

下面我们简单提一下Cutlass的crosswise Layout(我看的不是很明白)。通常来说为了避免BankConflict,我们常见的做法是Padding多一个元素,让Warp内线程访问错开,但是这样肯定是带来了SharedMemory浪费。而Cutlass提出了一种新的Layout,通过一系列很复杂的异或操作算出来了一个索引,最终大概长这样:

a364fda0-aa37-11ee-8b88-92fbcf53809c.png

这里每个线程存了128bit数据,也就是占了4个bank。还是以刚刚线程0所需的数据为例,可以看到T0 T8 T16 T24都是错开到不同的Bank上(其他线程同理)

下面是一个LDMatrix的example

PS:我不知道我写的对不对,至少从结果上看还挺合理,如果有错也麻烦指正

LDMatrix example

#include"stdio.h"
#include"stdint.h"
#include"cuda_fp16.h"

#defineLDMATRIX_X4(R0,R1,R2,R3,addr)
asmvolatile("ldmatrix.sync.aligned.x4.m8n8.shared.b16{%0,%1,%2,%3},[%4];
"
:"=r"(R0),"=r"(R1),"=r"(R2),"=r"(R3)
:"r"(addr))


template
__global__voidset_value(T*x,int32_telem_cnt){
for(inti=0;i< elem_cnt; i++){
        x[i] = static_cast(i%8);
}
}

//从CUTLASS里抄的
__device__uint32_tcast_smem_ptr_to_uint(voidconst*constptr){
//WeprefertousethenewCVTAintrinsicsiftheyareavailable,otherwisewewillfallbackto
//thepreviousinternalintrinsicsiftheyareavailable.
#ifCUTE_CVTA_GENERIC_TO_SHARED_ACTIVATED
//
//ThisNVVMintrinsicconvertsanaddressinsharedmemorytoaplain
//unsignedinteger.Thisisnecessarytopasstosharedmemoryinstructions
//ininlinePTX.
//
//InCUDA11andbeyond,thisreplaces__nvvm_get_smem_pointer()[onlyavailablein10.2].
//
//__device__size_t__cvta_generic_to_shared(void*ptr);

///CUTEhelpertogetSMEMpointer
returnstatic_cast(__cvta_generic_to_shared(ptr));

#elifCUTE_NVVM_GET_SMEM_POINTER_ACTIVATED

return__nvvm_get_smem_pointer(ptr);

#elifdefined(__CUDA_ARCH__)

uint32_tsmem_ptr;

asm(
"{.reg.u64smem_ptr;cvta.to.shared.u64smem_ptr,%1;cvt.u32.u64%0,smem_ptr;}
"
:"=r"(smem_ptr):"l"(ptr));

returnsmem_ptr;

#else


(void)ptr;
printf("ERROR:cast_smem_ptr_to_uintnotsupportedbutused.
");
return0;

#endif
}

__global__voidldmatrix_example(uint32_t*x,
uint32_t*y){
constint32_trow_tid=threadIdx.x/8;
constint32_tcol_tid=threadIdx.x%8;
uint32_tRegisterLoad[4];
uint32_tRegisterTensorcore[4];
__shared__halfsmem[4][64];
*reinterpret_cast(RegisterLoad)=*reinterpret_cast((x+threadIdx.x*4));

half*half_register_load_ptr=reinterpret_cast(RegisterLoad);
if(threadIdx.x==0){
printf("ThreadIdx:%d,Valueis:%f,%f,%f,%f,%f,%f,%f,%f.
",threadIdx.x,
static_cast(half_register_load_ptr[0]),static_cast(half_register_load_ptr[1]),
static_cast(half_register_load_ptr[2]),static_cast(half_register_load_ptr[3]),
static_cast(half_register_load_ptr[4]),static_cast(half_register_load_ptr[5]),
static_cast(half_register_load_ptr[6]),static_cast(half_register_load_ptr[7]));
}

int32_txor_idx=threadIdx.x;
if(row_tid==1){
xor_idx^=1;
}

if(row_tid==2){
xor_idx^=2;
}

if(row_tid==3){
xor_idx^=3;
}

constint32_tstore_smem_row_tid=xor_idx/8;
constint32_tstore_smem_col_tid=xor_idx%8;

//if(threadIdx.x==0){
printf("ThreadIdx:%d,XorIdxis:%d,store_smem_row_tidis:%d,store_smem_col_tidis:%d.
",threadIdx.x,xor_idx,store_smem_row_tid,store_smem_col_tid*8);
//}

half*smem_ptr=&(smem[store_smem_row_tid][store_smem_col_tid*8]);//smem[store_smem_row_tid][store_smem_col_tid*4];

*reinterpret_cast(smem_ptr)=*reinterpret_cast(RegisterLoad);

__syncthreads();

if(threadIdx.x==0||threadIdx.x==8||threadIdx.x==16||threadIdx.x==24){
printf("ThreadIdx:%d,SMEMValueis:%f,%f,%f,%f,%f,%f,%f,%f.
",threadIdx.x,
static_cast(smem[0][0]),static_cast(smem[0][1]),
static_cast(smem[0][2]),static_cast(smem[0][3]),
static_cast(smem[0][4]),static_cast(smem[0][5]),
static_cast(smem[0][6]),static_cast(smem[0][7]));
}

uint32_taddr=cast_smem_ptr_to_uint(smem_ptr);
LDMATRIX_X4(RegisterTensorcore[0],RegisterTensorcore[1],RegisterTensorcore[2],RegisterTensorcore[3],addr);

half*half_register_tensorcore_ptr=reinterpret_cast(RegisterTensorcore);

if(threadIdx.x==0){
printf("AfterLDMATRIX,ThreadIdx:%d,Valueis:%f,%f,%f,%f,%f,%f,%f,%f.
",
threadIdx.x,
static_cast(half_register_tensorcore_ptr[0]),static_cast(half_register_tensorcore_ptr[1]),
static_cast(half_register_tensorcore_ptr[2]),static_cast(half_register_tensorcore_ptr[3]),
static_cast(half_register_tensorcore_ptr[4]),static_cast(half_register_tensorcore_ptr[5]),
static_cast(half_register_tensorcore_ptr[6]),static_cast(half_register_tensorcore_ptr[7]));
}

}

__global__voidprintMatrix(half*result,constintm,constintn){
for(introw=0;row< m; row++){
        printf("Row id: %d, result is: ", row); 
        for(int col = 0; col < n; col++){
            printf("%f ", static_cast(result[row*n+col]));
}
printf("
");
}
}

intmain(){
half*x;
half*y;

constint32_tm=16;
constint32_tk=16;
constint32_tn=8;

cudaMalloc(&x,m*k*sizeof(half));
cudaMalloc(&y,m*k*sizeof(half));

set_value<<<1, 1>>>(x,m*k);
cudaMemset(y,0,sizeof(half)*m*k);

ldmatrix_example<<<1, 32>>>(reinterpret_cast(x),
reinterpret_cast(y));

//printMatrix<<<1, 1>>>(y,m,k);
cudaDeviceSynchronize();
cudaFree(x);
cudaFree(y);
}

对于 cast_smem_ptr_to_uint 这个函数我也不是很清楚,我从元戎启行的矩阵转置Blog里摘了一段:

需要额外注意的是,共享内存的地址并不是全局同步地址(GenericAddress),因此在使用共享内存地址读取或写入数据前,要经过一次内置函数__cvta_generic_to_shared,当然也可以自己手写PTX

xor 换算索引 example

foriinrange(8,16):
print(i,i^1)

foriinrange(16,24):
print(i,i^2)

foriinrange(24,32):
print(i,i^3)s
    审核编辑:黄飞

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    31

    文章

    5334

    浏览量

    120217
  • 数据类型
    +关注

    关注

    0

    文章

    236

    浏览量

    13615
  • 线程
    +关注

    关注

    0

    文章

    504

    浏览量

    19674
  • Warp
    +关注

    关注

    0

    文章

    9

    浏览量

    9582

原文标题:乱谈CUTLASS GTC2020 SLIDES

文章出处:【微信号:GiantPandaCV,微信公众号:GiantPandaCV】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    KITA2GTC3325VTRBSTOBO1开发板运行的是什么系统?

    请告知KITA2GTC3325VTRBSTOBO1 开发板运行的是什么系统(RTOS 或·····)?开发板的整个Demo code从哪里可以得到?
    发表于 02-01 06:10

    【限时领取精美礼品】报名2022 GTC大会,与行业大咖探索 AI 前沿科技

    NVIDIA GTC22 将于 3 月 21 日至 24 日线上举办。NVIDIA 创始人兼首席执行官黄仁勋将带来囊括众多新闻发布的主题演讲。电子发烧友平台作为NVIDIA 初创加速计划的生态伙伴
    发表于 03-18 11:06

    【中奖公示】恭喜在GTC22直播间中奖幸运鹅~快来登记领奖吧~

    请以下用户尽快填写兑奖信息,我们将在7个工作日内发出奖品,感谢参与~戳这里>>GTC2022直播兑奖处
    发表于 03-23 14:12

    NVIDIA安培GPU或在明年3月底的GTC2020大会上推出

    从16nm Pascal到12nm Turing,NVIDIA最近两代的GPU一直停留在16/12nm节点上,对最新的7nm工艺似乎没啥兴趣,反正友商从14nm到7nm工艺的显卡都打不过NVIDIA显卡,老黄确实不着急。
    发表于 11-09 10:06 2551次阅读

    NVIDIA GTC或公布新一代Ampere安培架构的GPU 将基于台积电7nm工艺

    2020年的NVIDIA GTC大会将在3月22到26日举行,届时NVIDIA发布新一代Ampere安培架构的GPU应该没跑了,要知道GTC大会上已经有两三年没发布真正的新一代GPU了,等的黄花菜都凉了。
    的头像 发表于 01-04 10:13 3121次阅读

    英伟达将在GTC 2020至少展示6款机器人

    除了显卡之外,老黄近几年也越来越关注AI与机器人,在下月举行的GTC 2020上,英伟达宣布将至少展示6款机器人,它们高矮胖瘦各不同,具备不同的功能。
    的头像 发表于 02-25 11:50 2289次阅读

    NVIDIA GTC 2020大会如期举行 官方表示将对场馆进行全面消毒

    最近由于疫情的影响,一些大型展会、会议都在取消或者推迟,最严重的当然是MWC 2020展会取消。3月底还有NVIDIA的GTC大会,不过官方表示还在路上。
    的头像 发表于 03-03 09:06 1480次阅读

    NVIDIA取消GTC发布会,下一代安培跳票了

    全球蔓延的新冠疫情打乱了各种日常节奏,大量的发布会纷纷延期或取消。NVIDIA GTC 2020图形开发者大会更是一波三折、命运多舛。
    的头像 发表于 03-17 08:38 2431次阅读

    NVIDIA宣布暂时停止分享GTC 2020的相关新闻 下一代“安培”核心正式跳票

    全球蔓延的新冠疫情打乱了各种日常节奏,大量的发布会纷纷延期或取消。NVIDIA GTC 2020图形开发者大会更是一波三折、命运多舛。
    的头像 发表于 03-17 08:55 2125次阅读

    使用CUTLASS实现高性能矩阵乘法

      CUTLASS 实现了高性能卷积(隐式 GEMM )。隐式 GEMM 是作为 GEMM 的卷积运算的公式。这允许 Cutslass 通过重用高度优化的 warp-wide GEMM 组件和以下组件来构建卷积。
    的头像 发表于 04-15 10:03 2898次阅读

    MAX25400GTC/V+ MAX25400GTC/V+ - (Maxim Integrated) - 专用 IC

    电子发烧友网为你提供()MAX25400GTC/V+相关产品参数、数据手册,更有MAX25400GTC/V+的引脚图、接线图、封装手册、中文资料、英文资料,MAX25400GTC/V+真值表,MAX25400
    发表于 11-16 20:01
    MAX25400<b class='flag-5'>GTC</b>/V+ MAX25400<b class='flag-5'>GTC</b>/V+ - (Maxim Integrated) - 专用 IC

    GTC23 | GTC 大会今日开幕!主题演讲将于明日全球首播!

    万众瞩目的 GTC23 今日开幕 主题演讲将于 3 月 21 日全球首播 GTC23 于 3 月 20 日至 23 日举行,本届大会将举办超过 650 场由技术、商业、学术和政府领域领导者主持的会议
    的头像 发表于 03-21 14:10 463次阅读

    GTC 2023:阿里巴巴CUTLASS优化探索推荐系统中的应用

    以TensorFlow为backend ,算子数量多;此前,我们通过算子融合(类Faster Transformer),CUDA Graph等手段已经取得了不错的性能提升;利用CUTLASS进一步优化Attention和MLP计算, 可进步提升资源利用率。
    的头像 发表于 03-24 17:06 2233次阅读
    <b class='flag-5'>GTC</b> 2023:阿里巴巴<b class='flag-5'>CUTLASS</b>优化探索推荐系统中的应用

    MAX14839GTC+T - (Maxim Integrated) - 接口 - 传感器和探测器接口

    电子发烧友网为你提供Maxim(Maxim)MAX14839GTC+T相关产品参数、数据手册,更有MAX14839GTC+T的引脚图、接线图、封装手册、中文资料、英文资料,MAX14839GTC+T真值表,MAX14839
    发表于 07-05 18:52
    MAX14839<b class='flag-5'>GTC</b>+T - (Maxim Integrated) - 接口 - 传感器和探测器接口

    详解CUTLASS的工作原理

    嗨,我们要开始了。我叫马修·尼斯利。我是NVIDIA的深度学习compiler PM,今天我将介绍一些针对NVIDIA Tensorcores的使用方法。首先我要讲一下Cutlass。我会给你一些
    的头像 发表于 12-26 09:49 1893次阅读
    详解<b class='flag-5'>CUTLASS</b>的工作原理