TVM优化GPU机器翻译

背景

神经机器翻译(NMT)是一种自动化的端到端方法,具有克服传统基于短语的翻译系统中的弱点的潜力。最近,阿里巴巴集团正在为全球电子商务部署NMT服务。

将Transformer用作NMT系统的关键技术,相对于基于经典RNN / LSTM的模型具有同等(甚至更高)的精度,对于高效的离线训练更为友好。尽管Transformer在离线训练阶段很友好,打破了跨时间步长的依赖性,但在线推理效率不高。在生产环境中,已经发现,初始版本的Transformer的推理速度约为1.52倍,比LSTM版本慢。已经进行了一些优化来提高推理性能,例如图形级op融合,循环不变节点运动。观察到的一个特殊挑战是,批处理matmul是Transformer中的主要性能热点,而cuBLAS中的当前实现并未得到很好的优化。

下面的结果表明TVM生成内核(与调度表优化)带来至少13X批量MATMUL计算加速,futher加快算子融合功能。

批处理Matmul

为什么批量Matmul

在Transformer中,批处理matmul广泛用于multi-head attention计算。使用matmul批处理,关注层中multiple heads并行运行,帮助提高硬件的计算效率。

在推理阶段对Transformer模型进行了全面的分析,结果表明,批量matmul计算贡献了约30%的GPU内核执行时间。使用nvprof,对cuBLAS批处理matmul内核进行一些第一性原理分析,可以清楚地表明,当前的实现方式表现不佳,并且观察到了一些有趣的现象。

什么是批量matmul

通常,批量矩阵计算对一批矩阵执行乘法。批处理被认为是“统一的”,即所有实例具有相同的维度(M,N,K),前导维度(lda,ldb,ldc),以及各自的A,B和C矩阵的转置。

批量matmul计算,可以更具体地描述如下:

void BatchedGemm(input A, input B, output C, M, N, K, batch_dimension) {
  for (int i = 0; i < batch_dimension; ++i)  {
    DoGemm(A[i],B[i],C[i],M,K,N)
  }
}

批处理matmul形状

在语言翻译任务中,在其它工作负载中,批处理matmul的形状显着小于常规matmul计算。Transformer中的形状与输入语句的长度和解码器步长有关。通常小于30。

对于批处理尺寸,给定一定的推断批处理大小,这是一个固定的数字。例如,如果将16用作光束大小为4的批大小,则批大小为16 * 4 * #head(多头注意中的头数,通常为8)。矩阵M,K,N的形状,在[1,最大解码长度]或[1,最大编码长度]的范围内。

cuBLAS batch matmul的性能问题

首先,对批处理matmul内核进行了理论上的FLOP分析。结果非常有趣:所有批处理Matmul的计算强度都有限(少于1个TFLOP)。

然后,通过nvprof剖析了具有多种形状的matmul批处理cuBLAS性能。下表显示了在带有CUDA8.0的NVIDIA M40 GPU上获得的一些指标。

输入形状

[
批,MNK]

核心

理论FLOP

nvprof观察到的FLOP

理论FLOPs /

观察到的FLOPs

[512、17、17、128]

maxwell_sgemmBatched_128x128_raggedMn_tn

18939904

2155872256

0.87%

[512、1、17、128]

maxwell_sgemmBatched_128x128_raggedMn_tn

1114112

2155872256

0.052%

[512,17,1,128]

maxwell_sgemmBatched_128x128_raggedMn_tn

1114112

2155872256

0.052%

[512,30,30,128]

maxwell_sgemmBatched_128x128_raggedMn_tn

58982400

2155872256

2.74%

即使具有不同的形状(M,N,K不同),所有maxwell_sgemmBatched_128x128_raggedMn_tn调用,也执行相同数量的FLOP,这比理论值大得多。可以推断出,所有这些不同的形状都可以被填充成一定的形状。在所有这些形状中,即使在最佳情况下,理论上的FLOP仍然仅是实际执行的FLOP的2.74%,因此,大多数计算都是相当多余的。同样,另一个cuBLAS内核maxwell_sgemmBatched_64x64_raggedMn_tn的调用显示相同的现象。

显然,cuBLAS的批量matmul实施远非效率。因此,使用TVMNMT工作负载生成有效的批处理matmul内核。

批量matmul计算

在TVM中,一般的批量Matmul计算可以声明为:

# computation representation
A = tvm.placeholder((batch, M, K), name='A')
B = tvm.placeholder((batch, K, N), name='B')
k = tvm.reduce_axis((0, K), 'k')
C = tvm.compute((batch, M, N),
         lambda b, y, x: tvm.sum(A[b, y, k] * B[b, k, x], axis = k),
         name = 'C')

调度优化

在宣布计算之后,需要精心设计自己的调度表以压缩性能潜力。

块/线程数的调整参数

  # thread indices
  block_y = tvm.thread_axis("blockIdx.y")
  block_x = tvm.thread_axis("blockIdx.x")
  thread_y = tvm.thread_axis((0, num_thread_y), "threadIdx.y")
  thread_x = tvm.thread_axis((0, num_thread_x), "threadIdx.x")
  thread_yz = tvm.thread_axis((0, vthread_y), "vthread", name="vy")
  thread_xz = tvm.thread_axis((0, vthread_x), "vthread", name="vx")
 
  # block partitioning
  BB, FF, MM, PP = s[C].op.axis
  BBFF = s[C].fuse(BB, FF)
  MMPP = s[C].fuse(MM, PP)
  by, ty_block = s[C].split(BBFF, factor = num_thread_y * vthread_y)
  bx, tx_block = s[C].split(MMPP, factor = num_thread_x * vthread_x)
  s[C].bind(by, block_y)
  s[C].bind(bx, block_x)
  vty, ty = s[C].split(ty_block, nparts = vthread_y)
  vtx, tx = s[C].split(tx_block, nparts = vthread_x)
  s[C].reorder(by, bx, vty, vtx, ty, tx)
  s[C].reorder(by, bx, ty, tx)
  s[C].bind(ty, thread_y)
  s[C].bind(tx, thread_x)
  s[C].bind(vty, thread_yz)
  s[C].bind(vtx, thread_xz)

融合了批处理matmul的外部尺寸,即op尺寸的BB和FF,在批处理matmul计算中通常称为“批处理”尺寸。然后将外部和内部尺寸除以(number_thread * vthread)。

在批处理matmul中不需要交错模式,因此虚拟线程号(vthread_yvthread_x)都设置为1。

寻找number_thread的最佳组合

以下结果是在具有CUDA8.0的NVIDIA M40 GPU设备上获得的。

输入形状[批处理,特征,MNK]

num_thread_ynum_thread_x

num_vthread_ynum_vthread_x

时间(us

[64,8,1,17,128]

8,1

32,1

37.62

[64,8,1,17,128]

4,1

32,1

39.30

[64,8,1,17,128]

1,1

32,1

38.82

[64,8,1,17,128]

1,1

256,1

41.95

[64,8,1,17,128]

32,1

1,1

94.61

以往的经验了解到,该方法找到的最佳组合num_thread_ynum_thread_x通过强力搜索。经过蛮力搜索后,可以找到当前形状的最佳组合,在当前计算中为num_thread_y= 8和num_thread_x= 32。

将批处理matmul 与其它算子融合

通常,现有的“黑盒” cuBLAS库,调用扮演着通常使用的“ op Fusion”优化策略的边界的角色。但是,利用所生成的高效批处理matmul核,可以容易地打破融合边界,不仅可以融合元素的操作方式,还可以进一步提高性能。

从计算图可以看出,批处理matmul总是跟在添加操作或转置操作广播之后。通过将“ add”或“ transpose”操作与批处理matmul融合,可以减少内核启动开销和冗余内存访问时间。

批处理matmul和添加融合广播计算,可以声明如下:

# computation representation
A = tvm.placeholder((batch_size, features, M, K), name='A')
# the shape of B is (N, K) other than (K, N) is because B is transposed is this fusion pattern
B = tvm.placeholder((batch_size, features, N, K), name='B')
ENTER = tvm.placeholder((batch_size, 1, M, N), name = 'ENTER')
k = tvm.reduce_axis((0, K), 'k')
C = tvm.compute(
           (batch_size, features, M, N),
           lambda yb, yf, m, x: tvm.sum(A[yb, yf, m, k] * B[yb, yf, x, k], axis = k),
           name = 'C')
D = topi.broadcast_add(C, ENTER)

批处理matmul和转置融合计算可以声明为:

# computation representation
A = tvm.placeholder((batch_size, features, M, K), name='A')
B = tvm.placeholder((batch_size, features, K, N), name='B')
k = tvm.reduce_axis((0, K), 'k')
C = tvm.compute(
           (batch_size, M, features, N),
           lambda yb, m, yf, x: tvm.sum(A[yb, yf, m, k] * B[yb, yf, k, x], axis = k),
           name = 'C')

融合内核性能

选择[batch = 64,heads = 8,M = 1,N = 17,K = 128]的形状,详细说明所生成代码的性能。选择17作为序列长度,这是生产场景中的平均输入长度。

  • TF-R1.4 BatchMatmul:513.9
  • TF-R1.4 BatchMatmulTranspose(另购):541.9
  • TVM BatchMatmul:37.62美元
  • TVM BatchMatmulTranspose(融合):38.39美元

内核融合优化进一步提高了1.7倍的速度。

与Tensorflow集成

批量matmul在工作量中的输入形状是有限的,可以很容易地预先枚举。使用这些预定义的形状,可以提前生成高度优化的CUDA内核(固定形状计算可以带来最佳的优化潜力)。将生成适用于大多数形状的通用批处理matmul内核,为没有相应的提前生成的内核的形状提供回退机制。

针对特定形状生成的高效内核和后备内核已集成到Tensorflow框架中。开发了融合操作,例如BatchMatMulTranspose或BatchMatMulAdd,使用TVM的runtime API生成特定生成的内核,实现某些输入形状或调用后备内核。进行图形优化遍历,用算子融合自动替换原始批处理matmul +添加/转置模式。通过结合更积极的图形优化过程,试图利用TVM为长尾算子模式生成更有效的融合内核,以进一步提高端到端性能。

概括

在阿里巴巴内部,发现TVM是开发高性能GPU内核,满足内部需求的非常有效的工具。以NMT Transformer模型为例来说明使用TVM的优化策略。首先,通过第一性原理分析确定了Transformer模型的热点。然后使用TVM生成高度优化的CUDA内核来取代CUBLAS版本(13X加速观察)。接下来,利用TVM的内核融合机制融合批处理matmul的先前/以下操作,以进一步提高性能(进一步提高1.7倍的性能)。端到端性能提高了1.4。基于这些生成的内核,开发了图优化遍历以自动用TVM融合内核替换原始计算模式,确保优化对最终用户是透明的,作为AI基础设施提供商,发现优化策略的透明性对于推广其优化算法非常重要采用。最后,并非最不重要的一点是,所有这些优化都以松散耦合的方式集成到TensorFlow中,展示了将TVM与不同的深度学习框架集成的潜在方法。此外,正在进行一项将TVM集成为TensorFlow的代码源后端的工作,希望将来能与社区共享更多结果。

TVM优化GPU机器翻译的更多相关文章

  1. TensorFlow+TVM优化NMT神经机器翻译

    TensorFlow+TVM优化NMT神经机器翻译 背景 神经机器翻译(NMT)是一种自动化的端到端方法,具有克服传统基于短语的翻译系统中的弱点的潜力.本文为全球电子商务部署NMT服务. 目前,将Tr ...

  2. TVM 优化 ARM GPU 上的移动深度学习

    TVM 优化 ARM GPU 上的移动深度学习 随着深度学习的巨大成功,将深度神经网络部署到移动设备的需求正在迅速增长.与桌面平台上所做的类似,在移动设备中使用 GPU 既有利于推理速度,也有利于能源 ...

  3. TVM优化Deep Learning GPU算子

    TVM优化Deep Learning GPU算子 高效的深度学习算子是深度学习系统的核心.通常,这些算子很难优化,需要HPC专家付出巨大的努力. 端到端张量IR / DSL堆栈TVM使这一过程变得更加 ...

  4. unity优化-GPU(网上整理)

    优化-GPUGPU与CPU不同,所以侧重点自然也不一样.GPU的瓶颈主要存在在如下的方面: 填充率,可以简单的理解为图形处理单元每秒渲染的像素数量.像素的复杂度,比如动态阴影,光照,复杂的shader ...

  5. GPU 编程入门到精通(五)之 GPU 程序优化进阶

    博主因为工作其中的须要,開始学习 GPU 上面的编程,主要涉及到的是基于 GPU 的深度学习方面的知识.鉴于之前没有接触过 GPU 编程.因此在这里特地学习一下 GPU 上面的编程. 有志同道合的小伙 ...

  6. GPU 编程入门到精通(四)之 GPU 程序优化

    博主因为工作其中的须要,開始学习 GPU 上面的编程,主要涉及到的是基于 GPU 的深度学习方面的知识,鉴于之前没有接触过 GPU 编程.因此在这里特地学习一下 GPU 上面的编程.有志同道合的小伙伴 ...

  7. TVM:一个端到端的用于开发深度学习负载以适应多种硬件平台的IR栈

    TVM:一个端到端的用于开发深度学习负载以适应多种硬件平台的IR栈  本文对TVM的论文进行了翻译整理 深度学习如今无处不在且必不可少.这次创新部分得益于可扩展的深度学习系统,比如 TensorFlo ...

  8. TVM如何训练TinyML

    TVM如何训练TinyML 机器学习研究人员和从业人员对"裸机"(低功耗,通常没有操作系统)设备产生了广泛的兴趣.尽管专家已经有可能在某些裸机设备上运行某些模型,但是为各种设备优化 ...

  9. 桥接PyTorch和TVM

    桥接PyTorch和TVM 人工智能最引人入胜的一些应用是自然语言处理.像BERT或GPT-2之类的模型及其变体,可以获住足够多的文本信息. 这些模型属于称为Transformers的神经网络类体系结 ...

随机推荐

  1. 2.1.4- css 样式规则

    CSS初识 CSS(Cascading Style Sheets) CSS通常称为CSS样式表或层叠样式表(级联样式表),主要用于设置HTML页面中的文本内容(字体.大小.对齐方式等).图片的外形(宽 ...

  2. 【Https】Https为什么能保证安全?

    HTTPS是在HTTP上建立SSL加密层,并对传输数据进行加密,是HTTP协议的安全版. 反观HTTPS协议,它比HTTP协议相比多了以下优势(下文会详细介绍): 数据隐私性:内容经过对称加密,每个连 ...

  3. hdu1671 字典树记录前缀出现次数

    题意:       给你一堆电话号,问你这些电话号后面有没有相互冲突的,冲突的条件是当前这个电话号是另一个电话号的前缀,比如有 123456789 123,那么这两个电话号就冲突了,直接输出NO. 思 ...

  4. maven下载Oracle jar包

    Oracle的jar包由于是收费的,所以当我们使用maven去下载时下载不下来,对于这种情况,可以用以下方式去处理: oracle官网下载应用地址:https://www.oracle.com/dow ...

  5. linux安装MySQL报 error while loading shared libraries: libtinfo.so.5 解决办法

    MySQL服务启动报错 error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No ...

  6. Java对象内存分布

    [deerhang] 创建对象的四种方式:new关键字.反射.Object.clone().unsafe方法 new和反射是通过调用构造器创建对象的,创建对象的时候使用invokespecial指令 ...

  7. 迷失在Mysql的锁世界~

    1.饮料 这是一杯饮料. 这是3杯饮料,每杯饮料的味道各不相同. 但是人类并不称呼[饮料]为[饮料],而是称呼[饮料]为[记录]. 2.红章鱼 这个红色的,长的像章鱼的家伙,我们就叫它红章鱼~ 红章鱼 ...

  8. 团队任务拆解$\alpha$

    项目 内容 班级:2020春季计算机学院软件工程(罗杰 任健) 博客园班级博客 作业要求 团队任务拆解 我们在这个课程中的目标 提升团队管理及合作能力,开发一项满意的工程项目 这个作业对我们实现目标的 ...

  9. CRM系统全方位管理企业

    您在选择一款CRM系统的时候,首先要考虑销售团队的感受和意见.让CRM系统在帮助销售团队优化工作流程的同时,更好地对销售团队进行管理.销售人员每卖出一件商品,要从寻找筛选商机开始,经过沟通客户需求.满 ...

  10. 啥?SynchronousQueue和钟点房一个道理

    今天这篇文章,我们继续讲架构师大刘的故事. 大刘有段时间经常会给一些程序员讲课.这一方面是由于团队培训的需要,一方面也是大刘自身想搞搞凡尔赛,嘚瑟一下自身的实力. 大刘讲课是允许公司任何一个人进去听的 ...