From 690d50a0ce0b8c75d564b9421dbdb82b21cce49c Mon Sep 17 00:00:00 2001 From: BrianQian <47178754+BrianQian1999@users.noreply.github.com> Date: Sun, 5 Mar 2023 21:04:15 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E3=80=90Hackathon=20No.32=E3=80=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为 Paddle 优化 expand_as 前向&反向 op 在 GPU 上的计算性能 --- .../20230305_expand_as_optimization.md | 250 ++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 rfcs/OPs-Perf/20230305_expand_as_optimization.md diff --git a/rfcs/OPs-Perf/20230305_expand_as_optimization.md b/rfcs/OPs-Perf/20230305_expand_as_optimization.md new file mode 100644 index 000000000..84263abfd --- /dev/null +++ b/rfcs/OPs-Perf/20230305_expand_as_optimization.md @@ -0,0 +1,250 @@ +# 标题 + +标题如:Transpose OP性能优化设计文档 +| 基本信息 | 内容 | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| 提交作者 | [Timber-Ye](https://github.com/Timber-Ye)、[BrianQian1999](https://github.com/BrianQian1999) | +| 提交时间 | 2023-03-05 | +| 版本号 | V1.0 | +| 依赖飞桨版本 | 基于PaddleDevelop版本开发 | +| 文件名 | 20220305_expand_as_op_optimization.md
| + + +# 1 背景与意义 + +目前 Paddle 内 `expand_as` 前向和反向算子的 GPU 实现采用 Eigen 组合的模式,缺少 GPU Kernel,性能相对不足,希望实现高性能的 GPU 计算 Kernel,为 Paddle 优化 `expand_as` op 在 GPU 上的计算性能。 + +## 1.1 飞桨现状 + +飞桨框架现有的expand_as前向算子的实现过程为:(1)首先确定每一维将被扩展的次数;(2)直接借助Eigen库的广播方法,调用`funcs::EigenBroadcast`: +``````c++ +funcs::EigenBroadcast, T, Rank>::Eval(place, y, x0, bcast_dims) +`````` +而这一过程已经能够由Eigen库在GPU上实现。 + +后向算子的实现过程与之类似:(1)确定需要进行求和Reduction的维度;(2)借助Eigen库,实现`funcs::EigenBroadcastGrad`: +```c++ +funcs::EigenBroadcastGrad, T, Dims>::Eval(place, x_grad, out_grad0, reduce_dims, reshape_dims); +``` +其内部调用了Eigen库中针对张量的`reshape`以及`sum`方法: +```c++ +out.device(dev) = + in.reshape(reshape_dims).sum(reduce_dims).reshape(out.dimensions()); +``` +首先对被扩展后的高维张量进行reshape,以便后续在指定维度上进行求和,最后再将结果reshape到希望输出的形状,以此达到约归降维的目的。 + +下表列出了paddle框架的expand_as算子在[OP Benchmark](https://github.com/PaddlePaddle/benchmark/tree/master/api/tests_v2)中各种case场景下的OP性能数据。 + +| Case | Device | Data type | src_shape | dst_shape | Paddle Forward (ms) | Paddle Backward (ms) | +| ---- | -------- | --------- | ------------ | -------------- | ---------------------------- | ----------------------------- | +| 0 | V100 32G | Float32 | [1785, 1] | [1785, 128] | 0.074236 | 0.172566 | +| 1 | V100 32G | Float32 | [5, 1, 1] | [5, 128, 128] | 0.082833 | 3.594770 | +| 2 | V100 32G | Float32 | [32, 807, 1] | [32, 807, 807] | 0.427489 | 1.107112 | + +## 1.2 业内方案调研 + +### 1.2.1 Tensorflow + +tensorflow中的`tf.tile` 可以用来在多个维度上重复input tensor,该方法与expand_as功能近似。其过程大致是由高维向低维进行递归扩展,每一次扩展实际上都是在进行一次数据拷贝 ([源码链接:🔗](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/kernels/tile.cc#L88-L97) )。 + +`tf.tile`会创建一个新的张量来保存复制后的张量,由于复制操作涉及大量数据的读写IO运算,计算代价相对较高。 + +### 1.2.2 Pytorch + +Pytorch中存在expand算子,其前向过程同Paddle框架现有方法一致,被视作一次Broadcast([调用位置:🔗](https://github.com/pytorch/pytorch/blob/master/caffe2/operators/expand_op.h#L58-L67)),但Pytorch自身实现了广播过程的GPU Kernel([源码链接:🔗](https://github.com/pytorch/pytorch/blob/master/caffe2/utils/math_gpu.cu#L2781-L2804)): +``````c++ +template +__global__ void BroadcastCUDAKernel( + const int Y_size, + const SimpleArray X_strides, + const SimpleArray Y_dims, + const T alpha, + const T* X, + T* Y) { + CUDA_1D_KERNEL_LOOP(Y_index, Y_size) { + int X_index = 0; + int Y_index_val = Y_index; +#pragma unroll + for (int i = D - 1; i >= 0; --i) { + int d; + FIXED_DIVISOR_DIV_MOD(Y_dims.data[i], Y_index_val, &Y_index_val, &d); + X_index += d * X_strides.data[i]; + } +#if __CUDA_ARCH__ >= 350 || defined(USE_ROCM) + Y[Y_index] = __ldg(X + X_index) * alpha; +#else + Y[Y_index] = X[X_index] * alpha; +#endif + } +} +`````` +该Kernel实现基于ElementWise方式,关键过程是找到`Y_index`与`X_index`之间的映射关系。 + +Expand算子的后向过程同样基于约归求和(ReduceSum)的方法([调用位置:🔗](https://github.com/pytorch/pytorch/blob/master/caffe2/operators/expand_op.h#L108-L116)),其GPU Kernel实现([源码链接:🔗](https://github.com/pytorch/pytorch/blob/b8dfb45ac282a48764c192ac7d27b7d80eed8b2b/caffe2/utils/math/reduce.cu#L104-L135)): +``````c++ +template +__global__ void ReduceTensorCUDAKernel( + const int inner_size, + const SimpleArray X_strides, + const SimpleArray Y_dims, + const Reducer reducer, + const T init, + const T alpha, + const T* X, + T* Y) { + __shared__ typename BlockReduce::TempStorage temp_storage; + const int x = blockIdx.x; + T val = init; + for (int y = threadIdx.x; y < inner_size; y += blockDim.x) { + int X_index = 0; + int Y_index = x * inner_size + y; +#pragma unroll + for (int d = D - 1; d >= 0; --d) { + X_index += Y_index % Y_dims.data[d] * X_strides.data[d]; + Y_index /= Y_dims.data[d]; + } +#if __CUDA_ARCH__ >= 350 || defined(USE_ROCM) + val = reducer(val, __ldg(X + X_index)); +#else + val = reducer(val, X[X_index]); +#endif + } + val = BlockReduce(temp_storage).Reduce(val, reducer); + if (threadIdx.x == 0) { + Y[x] = val * alpha; + } +} +`````` + +该Kernel实现同样基于ElementWise方式,但由于`Y_index`到 `X_index`的映射为一对多,需要申请一块shared memory来记录`Y_index`所对应的所有`X_index`上的数据,并在最后对这块共享内存进行求和,最终赋值给`Y_index`所在位置。 + +另外针对特殊的情况,pytorch中还特别编写了RowwiseReduce([源码链接:🔗](https://github.com/pytorch/pytorch/blob/b8dfb45ac282a48764c192ac7d27b7d80eed8b2b/caffe2/utils/math/reduce.cu#L25-L47))、ColwiseReduce([源码链接:🔗](https://github.com/pytorch/pytorch/blob/b8dfb45ac282a48764c192ac7d27b7d80eed8b2b/caffe2/utils/math/reduce.cu#L49-L72))以及BothEndsReduce([源码链接:🔗](https://github.com/pytorch/pytorch/blob/b8dfb45ac282a48764c192ac7d27b7d80eed8b2b/caffe2/utils/math/reduce.cu#L74-L102))三个特殊的Kernel 实现。 + + +## 1.3 对比分析 + +除了Paddle框架以外,[OP Benchmark](https://github.com/PaddlePaddle/benchmark/tree/master/api/tests_v2)中仅有针对Tensorflow的性能测试,故下表给出的是Tensorflow框架下ExpandAs算子在各类case中的性能。 + +| Case | Device | Data type | src_shape | dst_shape | Tensorflow forward (ms) | Tensorflow backward (ms) | +| ---- | -------- | --------- | ------------ | -------------- | ----------------------- | ------------------------ | +| 0 | V100 32G | Float32 | [1785, 1] | [1785, 128] | 0.150479 | 0.159827 | +| 1 | V100 32G | Float32 | [5, 1, 1] | [5, 128, 128] | 0.104476 | 0.108868 | +| 2 | V100 32G | Float32 | [32, 807, 1] | [32, 807, 807] | 9.223847 | 9.212913 | + +在3个op benchmark case中,Paddle现有的前向算子表现都要优于Tensorflow,并且在case 2中比Tensorflow快20倍以上; + +然而在后向算子中,除case 2外Paddle的性能都要弱于Tensorflow,特别是在case 1中,Tensorflow比Paddle快30倍以上。针对Paddle框架后向算子在case 1中的不佳表现,我们进行了进一步测试: + +| Case | Device | Data type | src_shape | dst_shape | Paddle forward (ms) | Paddle backward (ms) | +| ---- | -------- | --------- | ------------ | -------------- | ----------------------- | ------------------------ | +| 3 | V100 32G | Float32 | [16, 1, 1] | [16, 807, 807] | 0.271686 | 254.208616 | +| 4 | V100 32G | Float32 | [32, 1, 1] | [32, 256, 256] | 0.097565 | 18.539683 | + +综上可见,在整体上Paddle的前向算子性能更优,后向算子的表现各有优劣。另外,Tensorflow中前向后向算子的性能差距不大,而在Paddle中,前向算子的性能要远好于后向算子,也就是说**后向算子有很大的优化空间**。而所降维数空间越大,进行约归求和的数据量也就越大,这应该是导致Paddle后向算子性能存在如此差异的主要原因。 + +# 2 设计方案与性能预期 + +计划替代Paddle中所使用的Eigen库,借鉴Pytorch,采用ElementWise方式来优化expand as前向后向op。 + +## 2.1 关键模块与性能提升点 + +新增模块包含ExpandAs算子前向以及后向各自的GPU Kernel,着重提升后向过程的运算效率。 + +## 2.2 前向优化 + +ExpandAs算子的前向过程基本类似广播机制,即在需要进行扩展的维度上进行数据拷贝。从并行编程ElementWise的角度来看,可以令每一个线程处理输出张量上的每一个元素,通过Index的映射关系找出该元素在输入张量上的对应位置,然后读取数据完成赋值即可。 + +## 2.2.1 Host端计算流程 + +Host端主要是准备Index映射所需要的数据,主要包括输入、输出张量的维数、每一维的尺寸、每一维的步长等。在这之后进行Kernel Launch即可。 + +``````c++ +... +auto x_shape_dim = x.dims(); // 输入张量在每一维上的尺寸 +auto x_stride_dim = phi::stride(x_shape_dim); // 输入张量在每一维上的步长 + +for(int i=0; i + <<>>(in_data, + out_data, + rank, + out_numel, + d_indexInfo); +`````` +## 2.2.2 Device端计算流程 + +Device端计算流程主要为以ElementWise方式寻找in_idx和out_idx之间的映射关系。某个线程在确定对应的索引之后,按照索引去global memory当中的输入张量中取值,然后赋值给输出张量的对应位置。 + +前向GPU Kernel当中的各个线程之间完全独立,无需申请共享内存。 + +``````c++ +int in_idx, out_idx; + +CUDA_KERNEL_LOOP_TYPE(idx, N, int64_t) { + in_idx = idx; + out_idx = f(in_idx); + out_tensor[out_idx] = in_tensor[in_idx]; +} + +`````` + +## 2.3 后向优化 + +ExpandAs算子的后向过程基本类似约归求和过程,即将所要进行reduce的维度上的所有元素进行求和。从并行编程ElementWise的角度来看,可以令每一个Thread Block处理输出张量上的每一个元素,通过Index的映射关系找出该元素在输入张量上所对应的所有位置,然后利用Paddle内封装好的Warp级操作,调用接口快速进行Block内的全部数据的求和,最后完成赋值即可。 + +## 2.2.1 Host端计算流程 + +同样的,后向的Host端主要是准备Index映射所需要的数据,包括输入、输出张量的维数、每一维的尺寸、每一维的步长等。在这之后进行Kernel Launch即可。 + +## 2.2.2 Device端计算流程 + +Device端计算流程主要为以ElementWise方式寻找in_idx和out_idx之间的映射关系。由于后向属于ReductionSum过程,因此可调用Paddle封装好的CUDA工具,快速求取Block内数据之和,然后将结果赋值给输出张量的对应位置。 + +``````c++ +int in_idx = blockIdx.x, out_idx; +T val = 0; + +for(int i = threadIdx.x; i < acc_N; i += blockDim.x){ + out_idx = f(in_idx, i); + tmp += out_grad[out_idx]; +} + +__syncthreads(); +T result = funcs::BlockReduceSum(val, FULL_MASK); + +if(threadIdx.x == 0) in_grad[in_idx] = result; + +`````` + +# 3 测试和验收的考量 + +参考:[算子性能优化验收标准](http://agroup.baidu.com/paddle-perf/md/article/4892913) + + +# 4 可行性分析和排期规划 + +时间和开发排期规划,主要milestone + +| No. | 开发内容 | 预期时间 | +|---|---|---| +| 1 | 理清Paddle中OP设计思路,同类产品中最佳设计方案 | 2023-03-05 | +| 2 | 完成优化设计文档 | 2023-03-05 | +| 3 | expand_as优化实现 | 2023-03-10 | +| 3 | 完成代码开发工作,并通过线程CI测试 | 2023-03-15 | + + + +# 5 影响面 + +需要进一步讨论的问题,开放性问题,有争议问题;对其他模块是否有影响。 + + +# 附件及参考资料 + +[1]. [OP Benchmark使用指南](https://github.com/PaddlePaddle/benchmark/blob/master/api/README.md) From f7c7bd2ac6f58abaf9fc03df16331b8a3448547f Mon Sep 17 00:00:00 2001 From: BrianQian <47178754+BrianQian1999@users.noreply.github.com> Date: Sun, 12 Mar 2023 02:24:51 +0100 Subject: [PATCH 2/5] Update 20230305_expand_as_optimization.md --- rfcs/OPs-Perf/20230305_expand_as_optimization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/OPs-Perf/20230305_expand_as_optimization.md b/rfcs/OPs-Perf/20230305_expand_as_optimization.md index 84263abfd..71844ebdc 100644 --- a/rfcs/OPs-Perf/20230305_expand_as_optimization.md +++ b/rfcs/OPs-Perf/20230305_expand_as_optimization.md @@ -123,7 +123,7 @@ __global__ void ReduceTensorCUDAKernel( ## 1.3 对比分析 -除了Paddle框架以外,[OP Benchmark](https://github.com/PaddlePaddle/benchmark/tree/master/api/tests_v2)中仅有针对Tensorflow的性能测试,故下表给出的是Tensorflow框架下ExpandAs算子在各类case中的性能。 +除了Paddle框架以外,[OP Benchmark](https://github.com/PaddlePaddle/benchmark/tree/master/api/tests_v2)中还有针对Tensorflow的静态图测试脚本,下表给出的是Tensorflow框架下ExpandA | Case | Device | Data type | src_shape | dst_shape | Tensorflow forward (ms) | Tensorflow backward (ms) | | ---- | -------- | --------- | ------------ | -------------- | ----------------------- | ------------------------ | From 0ca9b90fe16be2f623c31ea99d941c6265388b20 Mon Sep 17 00:00:00 2001 From: BrianQian <47178754+BrianQian1999@users.noreply.github.com> Date: Sun, 12 Mar 2023 02:26:52 +0100 Subject: [PATCH 3/5] Update 20230305_expand_as_optimization.md --- rfcs/OPs-Perf/20230305_expand_as_optimization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/OPs-Perf/20230305_expand_as_optimization.md b/rfcs/OPs-Perf/20230305_expand_as_optimization.md index 71844ebdc..8e81886fc 100644 --- a/rfcs/OPs-Perf/20230305_expand_as_optimization.md +++ b/rfcs/OPs-Perf/20230305_expand_as_optimization.md @@ -123,7 +123,7 @@ __global__ void ReduceTensorCUDAKernel( ## 1.3 对比分析 -除了Paddle框架以外,[OP Benchmark](https://github.com/PaddlePaddle/benchmark/tree/master/api/tests_v2)中还有针对Tensorflow的静态图测试脚本,下表给出的是Tensorflow框架下ExpandA +除了Paddle框架以外,[OP Benchmark](https://github.com/PaddlePaddle/benchmark/tree/master/api/tests_v2)中还有针对Tensorflow的静态图测试脚本,下表给出的是Tensorflow框架下ExpandAs算子在各类case中的性能: | Case | Device | Data type | src_shape | dst_shape | Tensorflow forward (ms) | Tensorflow backward (ms) | | ---- | -------- | --------- | ------------ | -------------- | ----------------------- | ------------------------ | From 0b79d39da14102eb4c250bb6f60a3ea20b3dd9b0 Mon Sep 17 00:00:00 2001 From: Hanchiao <46010859+Timber-Ye@users.noreply.github.com> Date: Tue, 14 Mar 2023 18:27:21 +0800 Subject: [PATCH 4/5] Update 20230305_expand_as_optimization.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 开头表格中的文件名写错了 --- rfcs/OPs-Perf/20230305_expand_as_optimization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/OPs-Perf/20230305_expand_as_optimization.md b/rfcs/OPs-Perf/20230305_expand_as_optimization.md index 8e81886fc..acc1c8d7d 100644 --- a/rfcs/OPs-Perf/20230305_expand_as_optimization.md +++ b/rfcs/OPs-Perf/20230305_expand_as_optimization.md @@ -7,7 +7,7 @@ | 提交时间 | 2023-03-05 | | 版本号 | V1.0 | | 依赖飞桨版本 | 基于PaddleDevelop版本开发 | -| 文件名 | 20220305_expand_as_op_optimization.md
| +| 文件名 | 20230305_expand_as_op_optimization.md
| # 1 背景与意义 From 4a18652b2dfc92db9eb05372bd9f933c49ea20e3 Mon Sep 17 00:00:00 2001 From: Hanchiao <46010859+Timber-Ye@users.noreply.github.com> Date: Thu, 16 Mar 2023 20:07:12 +0800 Subject: [PATCH 5/5] Update 20230305_expand_as_optimization.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充了fp16输入数据类型在paddle baseline以及tensorflow上的性能测试结果,并重新对两个框架的表现进行了对比分析。 --- .../20230305_expand_as_optimization.md | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/rfcs/OPs-Perf/20230305_expand_as_optimization.md b/rfcs/OPs-Perf/20230305_expand_as_optimization.md index acc1c8d7d..f502a2947 100644 --- a/rfcs/OPs-Perf/20230305_expand_as_optimization.md +++ b/rfcs/OPs-Perf/20230305_expand_as_optimization.md @@ -1,12 +1,12 @@ # 标题 标题如:Transpose OP性能优化设计文档 -| 基本信息 | 内容 | -| ------------------------------------------------------------ | ------------------------------------------------------------ | +| 基本信息 | 内容 | +| --------------------------------------------------------- | ------------------------------------------------------------ | | 提交作者 | [Timber-Ye](https://github.com/Timber-Ye)、[BrianQian1999](https://github.com/BrianQian1999) | | 提交时间 | 2023-03-05 | -| 版本号 | V1.0 | -| 依赖飞桨版本 | 基于PaddleDevelop版本开发 | +| 版本号 | V1.0 | +| 依赖飞桨版本| 基于PaddleDevelop版本开发 | | 文件名 | 20230305_expand_as_op_optimization.md
| @@ -33,13 +33,16 @@ out.device(dev) = ``` 首先对被扩展后的高维张量进行reshape,以便后续在指定维度上进行求和,最后再将结果reshape到希望输出的形状,以此达到约归降维的目的。 -下表列出了paddle框架的expand_as算子在[OP Benchmark](https://github.com/PaddlePaddle/benchmark/tree/master/api/tests_v2)中各种case场景下的OP性能数据。 +下表列出了paddle框架的expand_as算子在[OP Benchmark](https://github.com/PaddlePaddle/benchmark/tree/master/api/tests_v2)中各种case场景下的OP性能数据(测试环境:Tesla V100-32G, CUDA 11.2)。 -| Case | Device | Data type | src_shape | dst_shape | Paddle Forward (ms) | Paddle Backward (ms) | -| ---- | -------- | --------- | ------------ | -------------- | ---------------------------- | ----------------------------- | -| 0 | V100 32G | Float32 | [1785, 1] | [1785, 128] | 0.074236 | 0.172566 | -| 1 | V100 32G | Float32 | [5, 1, 1] | [5, 128, 128] | 0.082833 | 3.594770 | -| 2 | V100 32G | Float32 | [32, 807, 1] | [32, 807, 807] | 0.427489 | 1.107112 | +| Case | Data type | src_shape | dst_shape | Paddle Forward (ms) | Paddle Backward (ms) | Total(ms) | +| ---- | --------- | ------------ | -------------- | ---------- | ----------------------|--------------| +| 0 | float32 | [1785, 1] | [1785, 128] | 0.074236 | 0.172566 | 0.246802 | +| 1 | float32 | [5, 1, 1] | [5, 128, 128] | 0.082833 | 3.594770 | 3.677603 | +| 2 | float32 | [32, 807, 1] | [32, 807, 807] | 0.427489 | 1.107112 | 1.532601 | +| 3 | float16 | [1785, 1] | [1785, 128] | 0.049622 | 0.147476 | 0.197098 | +| 4 | float16 | [5, 1, 1] | [5, 128, 128] | 0.051206 | 3.039735 | 3.090941 | +| 5 | float16 | [32, 807, 1] | [32, 807, 807] | 0.407556 | 0.980826 | 1.388382 | ## 1.2 业内方案调研 @@ -123,24 +126,27 @@ __global__ void ReduceTensorCUDAKernel( ## 1.3 对比分析 -除了Paddle框架以外,[OP Benchmark](https://github.com/PaddlePaddle/benchmark/tree/master/api/tests_v2)中还有针对Tensorflow的静态图测试脚本,下表给出的是Tensorflow框架下ExpandAs算子在各类case中的性能: +除了Paddle框架以外,[OP Benchmark](https://github.com/PaddlePaddle/benchmark/tree/master/api/tests_v2)中还有针对Tensorflow的静态图测试脚本,下表给出的是Tensorflow框架下ExpandAs算子在各类case中的性能(测试环境:Tesla V100-32G, CUDA 11.2): -| Case | Device | Data type | src_shape | dst_shape | Tensorflow forward (ms) | Tensorflow backward (ms) | -| ---- | -------- | --------- | ------------ | -------------- | ----------------------- | ------------------------ | -| 0 | V100 32G | Float32 | [1785, 1] | [1785, 128] | 0.150479 | 0.159827 | -| 1 | V100 32G | Float32 | [5, 1, 1] | [5, 128, 128] | 0.104476 | 0.108868 | -| 2 | V100 32G | Float32 | [32, 807, 1] | [32, 807, 807] | 9.223847 | 9.212913 | +| Case | Data type | src_shape | dst_shape | Tensorflow forward (ms) | Tensorflow backward (ms) | Total(ms) | +| ---- | -------- | --------- | ------------ | -------------- | ----------------------- | ------------------------ | +| 0 | float32 | [1785, 1] | [1785, 128] | 0.150479 | 0.159827 | 0.310306 | +| 1 | float32 | [5, 1, 1] | [5, 128, 128] | 0.104476 | 0.108868 | 0.213345 | +| 2 | float32 | [32, 807, 1] | [32, 807, 807] | 9.223847 | 9.212913 | 18.436761 | +| 3 | float16 | [1785, 1] | [1785, 128] | 0.042221 | 0.044698 | 0.086919 | +| 4 | float16 | [5, 1, 1] | [5, 128, 128] | 0.024973 | 0.031283 | 0.056257 | +| 5 | float16 | [32, 807, 1] | [32, 807, 807] | 5.511609 | 5.298775 | 10.810385 | -在3个op benchmark case中,Paddle现有的前向算子表现都要优于Tensorflow,并且在case 2中比Tensorflow快20倍以上; +在case 2和case 5当中,Paddle比Tensorflow快近10倍;而在case 1和case 4中,Tensorflow的性能又有显著优势。另外,当数据类型从`float32`变为`float16`后,Tensorflow算子的性能有明显的提升,而相比之下,数据类型对Paddle算子性能的影响不大。 -然而在后向算子中,除case 2外Paddle的性能都要弱于Tensorflow,特别是在case 1中,Tensorflow比Paddle快30倍以上。针对Paddle框架后向算子在case 1中的不佳表现,我们进行了进一步测试: +特别值得注意的是,在case 1中Tensorflow后向算子比Paddle快30倍以上,case 4则更是快了近100倍。针对Paddle框架后向算子在这两个case中的不佳表现,我们进行了进一步测试(测试环境:Tesla V100-32G, CUDA 11.2): -| Case | Device | Data type | src_shape | dst_shape | Paddle forward (ms) | Paddle backward (ms) | -| ---- | -------- | --------- | ------------ | -------------- | ----------------------- | ------------------------ | -| 3 | V100 32G | Float32 | [16, 1, 1] | [16, 807, 807] | 0.271686 | 254.208616 | -| 4 | V100 32G | Float32 | [32, 1, 1] | [32, 256, 256] | 0.097565 | 18.539683 | +| Case | Data type | src_shape | dst_shape | Paddle forward (ms) | Paddle backward (ms) | Total(ms) | +| ---- | --------- | ------------ | -------------- | --------------------| ---------------------| -----------------| +| 6 | float32 | [16, 1, 1] | [16, 807, 807] | 0.271686 | 254.208616 | 254.480303 | +| 7 | float32 | [32, 1, 1] | [32, 256, 256] | 0.097565 | 18.539683 | 18.637249 | -综上可见,在整体上Paddle的前向算子性能更优,后向算子的表现各有优劣。另外,Tensorflow中前向后向算子的性能差距不大,而在Paddle中,前向算子的性能要远好于后向算子,也就是说**后向算子有很大的优化空间**。而所降维数空间越大,进行约归求和的数据量也就越大,这应该是导致Paddle后向算子性能存在如此差异的主要原因。 +综上可见,无论前向还是后向算子,Paddle与Tensorflow相比较均各有优劣。但是,Tensorflow中前向后向算子的性能差距不大,而在Paddle中,前向算子的性能通常要明显好于后向算子,也就是说**Paddle的后向算子有很大的优化空间**。所降维数空间越大,进行约归求和的数据量也就越大,这应该是导致Paddle后向算子性能存在如此差异的主要原因。 # 2 设计方案与性能预期