阿里巴巴机器翻译团队:将TVM引入TensorFlow中以优化GPU上的神经机器翻译

本文涉及的产品
语种识别,语种识别 100万字符
文档翻译,文档翻译 1千页
文本翻译,文本翻译 100万字符
简介: 神经机器翻译(NMT)是自动翻译的端到端方法,这个方法具有克服传统短语翻译系统缺点的潜力。阿里巴巴机器翻译团队在此基础上,利用TVM又有了新的突破!

译者注:TVM 是由华盛顿大学在读博士陈天奇等人提出的深度学习自动代码生成方法,该技术能够自动为大多数计算硬件生成可部署优化代码,其性能可与当前最有供应商提供的优化计算库相比,且可以适应新型专用加速器后端。项目链接:https://github.com/dmlc/tvm

作者:

这是阿里巴巴集团机器翻译团队和PAI-Blade团队贡献的博客。

背景:

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

目前,我们正在利用Transformer [1]作为我们NMT系统的主要骨干,因为它对于经典的基于RNN/LSTM模型的高效离线训练具有较高的准确度,因此它成为了系统的核心。尽管Transformer对于离线训练阶段很友好,因为它在时间跨度上打破了依赖性,但对于在线推理来说效率并不高。在我们的生产环境中,已经发现Transformer的初始版本的推理速度在1.5X2X左右,这比LSTM的版本慢。我们已经进行了几次优化以提高推理性能,例如图层级操作融合,循环不变节点运动[3]。我们观察到一个特殊挑战是批量matmul是提升Transformer的性能的关键点,但目前在cuBLAS中的实现并没有得到很好的优化。

7a91ca1a13292516aa4ca60335a27d6b0a384c0d

下面表明TVM生成内核(与优化安排表),结果带来了至少13X加速批量MATMUL计算,并启用了futher,这也加快了与运营商的融合。

d98cad2bf9e4a810a557b86bc80a1caf1af63720

批量Matmul

为什么批量matmul?

在Transformer中,批量matmul被广泛用于计算多头注意力(multi-head attention)。使用批量matmul,注意力层中的多个头可以并行运行,这有助于提高硬件的计算效率。

cf1122f1a1aafbcaf061340936355c9d32e92c13

我们在推理阶段对Transformer模型进行了彻底分析,结果表明批量matmul计算占GPU内核执行时间的30%左右。使用nvprof [2]对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的形状(shape)

在语言翻译任务中,批量matmul的形状明显小于其他工作中的正常matmul计算。Transformer中的形状与输入句子的长度和解码器步骤的长度有关。通常情况下,它都是小于30。

至于batch dimension,其大小是一个固定的数字。例如,如果beam size为4的批量尺寸使用16,批量尺寸大小为16 * 4 *head(多头注意的头数,通常为8)。矩阵M,K,N的形状(shape)在[1,最大解码长度]或[1,最大编码长度]。

cuBLAS的批量matmul的性能问题

首先,我们对批量matmul核进行理论FLOPs分析。结果非常有趣:所有批量matmul的计算强度都小于1 TFLOPs。

然后我们通过nvprof分析具有多个形状的批量matmul的cuBLAS性能。下表显示了使用CUDA8.0的NVIDIA M40 GPU获得的一些指标。

344b12d39ac9304c9e1c704bfaee29cc335c2c0a

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

很明显,cuBLAS的批量执行效率远远不够。因此,我们使用TVM为我们的NMT工作负载生成高效的批处理内核。

批量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')

Schedule优化

在对批量matmul计算进行声明之后,我们需要仔细设计我们自己的计划来充分挖掘其性能潜力。

调整块/线程的参数

我们将批量matmul的外部尺寸进行融合,即op维度的BB和FF进行融合,通常在批量matmul计算中称为“批量”维度。然后我们将外部和内部维度按因子(number_thread * vthread)分解。

  # 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中不需要stridged模式,因此虚拟线程数(vthread_yvthread_x)都被设置为1。

寻找number_thread的最佳组合

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

d3298742091c790ac6e8518fcfc733dd1fb3f9c3

过去的经验中得知,找到最好的组合(num_thread_y,num_thread_x)是通过强力搜索的方法。在蛮力搜索之后,可以找到当前形状(shape)的最佳组合,经过暴力破解,我们找到了其在当前计算中是num_thread_y= 8num_thread_x= 32

将matmul与其他运算融合

通常,现有的“黑盒子”cuBLAS库的调用扮演着通常使用的“op fusion”优化策略边界的角色。但是,对于生成的高效批量matmul内核,融合边界很容易被破坏,而不仅仅是单元操作,从而可以获得更好的性能改善。

从计算图中可以看到,一个批量matmul总是跟着一个广播加法运算操作或一个转置操作。通过将“加法”或“转置”运算与批量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')

Fusion的性能

选择[batch = 64,head = 8,M = 1,N = 17,K = 128]的形状(shape)来详细说明生成的代码的性能。选择17作为序列长度,因为它是我们生产场景中的平均输入长度。测试结果如下:

· tf-r1.4 BatchMatmul:513.9 us

· tf-r1.4 BatchMatmulTranspose(separate):541.9 us

· TVM BatchMatmul:37.62us

·TVM BatchMatmulTranspose(fused):38.39 us

我们可以看到通过内核融合优化带来了1.7倍的提速。

与Tensorflow集成

在我们的工作中,批量matmul的输入形状是有限的。通过这些预定义的形状,我们可以提前生成高度优化的CUDA内核(固定形状计算可以带来最佳的优化潜力)。同时,还会生成适用于大多数形状的一般批量matmul内核,以便为没有相应的提前生成内核的形状提供回退机制。

Tensorflow框架中集成了针对特定形状生成的高效内核和回退机制的内核。我们开发了融合op,比如BatchMatMulTranspose或BatchMatMulAdd,以便使用TVM的运行时,API为特定输入形状启动特定的生成内核或者调用回退内核。图形优化通过自动替换原始批量matmul +加法/转置模式与融合操作。同时,通过结合更激进的图形优化通道,我们正试图利用TVM为长尾操作模式生成更高效的融合内核,从而进一步加速端到端性能。

总结

在阿里巴巴内部,我们发现TVM是为开发高性能GPU内核以满足我们内部需求的高效工具。在这篇博客中,我们以NMT Transformer模型为例,用TVM来说明了我们的优化策略。首先,通过第一性原理分析找出Transformer模型的问题。然后我们使用TVM生成高度优化的CUDA内核来取代CUBLAS版本(13X加速观察)。接下来,我们利用TVM的内核融合机制融合批量matmul的前/后操作,进一步提升性能(提升了1.7倍的性能)。基于这些生成的内核,开发了一个图形优化通道,用TVM融合内核自动替换原始计算模式,以确保最终用户的优化是透明的,因为作为AI基础架构提供者,我们发现优化策略的透明度对于普及其优化策略是非常重要的。

最后,所有的这些优化都以松散耦合的方式集成到TensorFlow中,将TVM与不同深度学习框架进行不同程度的集成。此外,还有一项工作是将TVM作为TensorFlow的代码后端,我们希望将来可以向社区分享更多结果。

资源

1TVM实现融合批量matmul +转置计算

参考

[1] Attention is All You Need

[2] nvprof is Your Handy Universal GPU Profiler

[3] Add Loop Invariant Node Motion Optimization in GraphOptimizer

数十款阿里云产品限时折扣中,赶紧点击领劵开始云上实践吧!

本文由北邮@爱可可-爱生活老师推荐,阿里云云栖社区组织翻译。

文章原标题《Bringing TVM into TensorFlow for Optimizing Neural Machine Translation on GPU》

作者:阿里巴巴机器翻译平台团队

译者:虎说八道,审校:袁虎。

文章为简译,更为详细的内容,请查看原文

相关文章
|
1月前
|
人工智能 语音技术 UED
仅用4块GPU、不到3天训练出开源版GPT-4o,这是国内团队最新研究
【10月更文挑战第19天】中国科学院计算技术研究所提出了一种名为LLaMA-Omni的新型模型架构,实现与大型语言模型(LLMs)的低延迟、高质量语音交互。该模型集成了预训练的语音编码器、语音适配器、LLM和流式语音解码器,能够在不进行语音转录的情况下直接生成文本和语音响应,显著提升了用户体验。实验结果显示,LLaMA-Omni的响应延迟低至226ms,具有创新性和实用性。
52 1
|
3月前
|
持续交付 测试技术 jenkins
JSF 邂逅持续集成,紧跟技术热点潮流,开启高效开发之旅,引发开发者强烈情感共鸣
【8月更文挑战第31天】在快速发展的软件开发领域,JavaServer Faces(JSF)这一强大的Java Web应用框架与持续集成(CI)结合,可显著提升开发效率及软件质量。持续集成通过频繁的代码集成及自动化构建测试,实现快速反馈、高质量代码、加强团队协作及简化部署流程。以Jenkins为例,配合Maven或Gradle,可轻松搭建JSF项目的CI环境,通过JUnit和Selenium编写自动化测试,确保每次构建的稳定性和正确性。
62 0
|
3月前
|
缓存 开发者 测试技术
跨平台应用开发必备秘籍:运用 Uno Platform 打造高性能与优雅设计兼备的多平台应用,全面解析从代码共享到最佳实践的每一个细节
【8月更文挑战第31天】Uno Platform 是一种强大的工具,允许开发者使用 C# 和 XAML 构建跨平台应用。本文探讨了 Uno Platform 中实现跨平台应用的最佳实践,包括代码共享、平台特定功能、性能优化及测试等方面。通过共享代码、采用 MVVM 模式、使用条件编译指令以及优化性能,开发者可以高效构建高质量应用。Uno Platform 支持多种测试方法,确保应用在各平台上的稳定性和可靠性。这使得 Uno Platform 成为个人项目和企业应用的理想选择。
66 0
|
3月前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
83 0
|
3月前
|
TensorFlow 算法框架/工具 异构计算
【Tensorflow 2】查看GPU是否能应用
提供了检查TensorFlow是否能应用GPU的方法。
22 2
|
3月前
|
机器学习/深度学习 自然语言处理 算法
Seq2Seq模型在机器翻译任务中如何优化以提高翻译质量?
Seq2Seq模型在机器翻译任务中如何优化以提高翻译质量?
|
4月前
|
Linux TensorFlow 算法框架/工具
安装GPU版本的TensorFlow
【7月更文挑战第3天】安装GPU版本的TensorFlow。
231 1
|
4月前
|
机器学习/深度学习 TensorFlow API
Keras是一个高层神经网络API,由Python编写,并能够在TensorFlow、Theano或CNTK之上运行。Keras的设计初衷是支持快速实验,能够用最少的代码实现想法,并且能够方便地在CPU和GPU上运行。
Keras是一个高层神经网络API,由Python编写,并能够在TensorFlow、Theano或CNTK之上运行。Keras的设计初衷是支持快速实验,能够用最少的代码实现想法,并且能够方便地在CPU和GPU上运行。
|
6月前
|
机器学习/深度学习 并行计算 TensorFlow
TensorFlow与GPU加速:提升深度学习性能
【4月更文挑战第17天】本文介绍了TensorFlow如何利用GPU加速深度学习, GPU的并行处理能力适合处理深度学习中的矩阵运算,显著提升性能。TensorFlow通过CUDA和cuDNN库支持GPU,启用GPU只需简单代码。GPU加速能减少训练时间,使训练更大、更复杂的模型成为可能,但也需注意成本、内存限制和编程复杂性。随着技术发展,GPU将继续在深度学习中发挥关键作用,而更高效的硬件解决方案也将备受期待。
|
6月前
|
机器学习/深度学习 TensorFlow 调度
优化TensorFlow模型:超参数调整与训练技巧
【4月更文挑战第17天】本文探讨了如何优化TensorFlow模型的性能,重点介绍了超参数调整和训练技巧。超参数如学习率、批量大小和层数对模型性能至关重要。文章提到了三种超参数调整策略:网格搜索、随机搜索和贝叶斯优化。此外,还分享了训练技巧,包括学习率调度、早停、数据增强和正则化,这些都有助于防止过拟合并提高模型泛化能力。结合这些方法,可构建更高效、健壮的深度学习模型。
下一篇
无影云桌面