TVM优化GPU机器翻译

背景

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

将Transformer用作NMT系统的关键技术,相对于基于经典RNN / LSTM的模型具有同等(甚至更高)的精度,对于高效的离线训练更为友好。尽管Transformer在离线训练阶段很友好,打破了跨时间步长的依赖性,但在线推理效率不高。在生产环境中,已经发现,初始版本的Transformer的推理速度约为1.5倍至2倍,比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上获得的一些指标。

输入形状

[
批,M,N,K]

核心

理论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实施远非效率。因此,使用TVM为NMT工作负载生成有效的批处理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_y和vthread_x)都设置为1。

寻找number_thread的最佳组合

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

输入形状[批处理,特征,M,N,K]

num_thread_y,num_thread_x

num_vthread_y,num_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_y,num_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 BatchMatmul+ Transpose(另购):541.9
  • TVM BatchMatmul:37.62美元
  • TVM BatchMatmul+ Transpose(融合):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. thinkphp5 ztree树形菜单

    教程:http://makaidong.com/zjfjava/4074_5873678.html 下载:https://github.com/zTree/zTree_v3

  2. LA3989女士的选择

    题意:       给你n个男士n个女士,然后给你每个男士中女士的排名,和每个女士中每个男士在他们心中的排名,问你是否可以组成稳定的舞伴,如果存在以下情况(1)男生u和女生v不是舞伴,他们喜欢对方的程 ...

  3. Python脚本破解压缩文件口令(zipfile)

    环境:Windows python版本2.7.15 Python中操作zip压缩文件的模块是 zipfile . 相关文章:Python中zipfile压缩文件模块的使用 我们破解压缩文件的口令也是用 ...

  4. 论文解读丨基于局部特征保留的图卷积神经网络架构(LPD-GCN)

    摘要:本文提出一种基于局部特征保留的图卷积网络架构,与最新的对比算法相比,该方法在多个数据集上的图分类性能得到大幅度提升,泛化性能也得到了改善. 本文分享自华为云社区<论文解读:基于局部特征保留 ...

  5. 实时计算框架:Flink集群搭建与运行机制

    一.Flink概述 1.基础简介 Flink是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算.Flink被设计在所有常见的集群环境中运行,以内存执行速度和任意规模来执行计算.主要特性包 ...

  6. PowerDesigner16安装和使用

    安装 安装参考链接:PowerDesigner安装教程 因为这个博主已经操作的很详细了,这边就不做过多的赘述. 使用 新建模型 选择物理模型 调出面板Palette 建表 最终的效果(一般不在数据库层 ...

  7. Mybatis-Plus02 CRUD

    先将快速开始01看完,再看这个文档 配置日志 我们所有的sql现在都是不可见的,我们希望知道它是怎么执行的,所以我们就必须看日志,开发的时候打开,上线的时候关闭 在application.proper ...

  8. Educational Codeforces Round 92 (Rated for Div. 2)

    A.LCM Problem 题意:最小公倍数LCM(x,y),处于[l,r]之间,并且x,y也处于[l,r]之间,给出l,r找出x,y; 思路:里面最小的最小公倍数就是基于l左端点的,而那个最小公倍数 ...

  9. React中diff算法的理解

    React中diff算法的理解 diff算法用来计算出Virtual DOM中改变的部分,然后针对该部分进行DOM操作,而不用重新渲染整个页面,渲染整个DOM结构的过程中开销是很大的,需要浏览器对DO ...

  10. Java_常用类API之一

    Math类 Math类中包含一些对数据进行数学运算的方法,而该类中的方法全都是静态的.像这样的类称之为工具类. 1 public static int abs(int a) 2 对一个数据求绝对值 3 ...