Roadmap
- 2022.6.20: 飞桨算子性能优化方向已发邮件至 ext_paddle_oss@baidu.com ,如果你对本方向感兴趣而未收到邮件,请发送邮件至 ext_paddle_oss@baidu.com 反馈。
OP性能是飞桨框架重要功能之一,通过 OP benchmark,我们发现有些OP性能不够好,没有充分利用硬件算力。 石墨表格《PFCC-Roadmap》之【飞桨 OP 性能优化】 为当前在Paddle中部分性能需要优化的案例,我们内部在不断地进行优化。你如果对这方面有兴趣,欢迎参加此项活动。
目前主要以CUDA编程为主,若对手写Kernel的概念了解不多,请详细阅读 CUDA 编程模型概述 。我们通常使用以下方法对GPU算子进行性能优化:
- 数据向量化读写:GPU kernel 的性能瓶颈常被划分为计算瓶颈compute-bound和访存瓶颈memory-bound,当前硬件架构不断更新,算力不断提高,算力与带宽的差距越来越大,导致越来越多的 kernel 性能受制于访存瓶颈。用户可采用常见的
int4,float4
等向量化类型实现数据的向量化读写操作,详见 CUDA相关文档 。当然,鼓励采用通用化的数据类型表示方法 AlignedVector ,以适应不同的向量化读写规则,具体使用案例见 gelu_funcs.h .
快速计算方法:针对前面提到的计算瓶颈问题,我们提供一些基础的优化策略供参考:
快速整型除法:GPU kernel中难免需要计算线程的索引 (index) 进而完成计算,部分索引计算时可能涉及除法,若出现连续除法或取模计算,如
int index = a/b/c
,计算性能难免受到影响。出现此类时,推荐采用 FastDivmod 方法完成计算索引计算,使用方法详见 pooling.cu .warp计算加速工具 :CUDA内置了一套warp级别的shuffle操作指令,能够提升计算效率。Paddle基于此提供了一套可加速Warp级和block级运算的指令库 math_cuda_utils.h ,可加速warp内或block内的最大值、最小值、求和等操作.
内置intrinsic:CUDA内部提供了多种intrinsic计算方法,如针对 float16类型 的向量级计算
__hadd2
(详见 CUDA相关文档 ),灵活运用这类计算可以解决这类case的性能不足问题。除此之外,建议谨慎使用_expf,_fdivide
等 intrinsic ,这类计算通过牺牲精度以提升性能,但是Paddle作为核心训练框架,OP精度对最终的模型收敛性会有影响.循环展开:采用
#pragma unroll
指令,编译器会展开具有已知循环次数的小循环加速循环的执行效率.合理的线程配置策略:GPU Kernel通常需要设置线程配置参数,以确定执行kernel时可分配的计算资源,选择合理的配置参数,能够优化计算Kernel的性能,影响线程配置的因素主要有以下几个方面:
为了将bank冲突将到最低,应尽量使每个block含有的线程数是64的倍数;
block的数量是应当是流处理器(SM) 的2倍以上,避免当某个block中线程被同步时,对应的硬件SM闲置;
block中的线程数应该设置成Warp尺寸的整数倍,且不超过最大线程数的规定。 一个block中设置的线程过多会导致每个线程可利用的寄存器变少,单寄存器变少时因访问溢出寄存器数据(溢出的数据在设备存储器中)致计算变慢,甚至调用失败。
推荐采用 gpu_launch_config.h 中的线程配置方法选择较为合理的配置参数,若有更好的线程设置策略,欢迎补充。
- 高性能计算库:飞桨内置了一套模块化的高性能计算组件库 kps ,可以模块化、高性能地完成GPU Kernel实现及优化。此外,若采用如
cublas
等高性能计算库能获得显著的性能收益,也欢迎使用,cublas
库使用示例见 matmul_kernel_impl.h ,cudnn
库的使用示例见conv_kernel.cu,thrust
库使用示例见coalesced_kernel.cu.
1条答案
按热度按时间eyh26e7m1#
附录
【方向说明】
【参与指南】:
【提交流程】
【提交内容】
【合入标准】
【技术要求】
【参考内容】