作者 | OneFlow社区

来源 | OneFlow

InsightFace模型里大量使用了PReLU激活函数,而PReLU的工作模式有两种:

1. PReLU(1),此时权重alpha的形状为(1, ),等价于一个Elementwise操作。

2. PReLU(channels),此时权重alpha的形状为(channels, ),和输入特征(N, C, H, W)中C的大小是对应的。此时PReLU等价于一个Binary Broadcast操作。

InsightFace模型里的PReLU工作模式是第二种,之前已经介绍过CUDA Elementwise操作优化,而在Broadcast情形下也存在一定的优化机会。

1

朴素实现

一个朴素实现的思想就是在循环内部,根据当前元素的索引,推算出该元素对应需要使用的alpha权重的索引。然后判断当前元素x是否大于0,若大于0则返回x,小于0则返回alpha*x。对应代码如下:

template<typename T>
__global__ void PReluForwardGpu(const int32_t elem_cnt, const int32_t alpha_size,const int32_t inner_size, const T* x, const T* alpha, T* y) {CUDA_1D_KERNEL_LOOP(i, elem_cnt) {const T x_i = x[i];const T alpha_i = alpha[(i / inner_size) % alpha_size];y[i] = x_i > 0 ? x_i : x_i * alpha_i;}
}

其中:

  • inner_size表示的是通道维后面维度乘积,以NCHW格式为例,inner_size=H*W

  • alpha_size表示通道维大小

在CUDA中,整数除法的计算代价是比较昂贵的(https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#maximize-instruction-throughput)关于计算指令耗时这一章中有提到:

Integer division and modulo operation are costly as they compile to up to 20 instructions.

整数除法,取余操作会被编译成多达20条指令。而我们这里计算alpha的索引的时候,分别用到一次除法,一次取余,占整个Kernel的主要计算量,下面我们将用向量化的思路来提高读写带宽的同时,减少整数除法,取余的计算次数。

2

Pack向量化优化

我们考虑一个比较简单的例子,输入为(1, 2, 4, 4),对应PReLU(2)

显然,输入在hw维上是连续的,在 inner_size 满足被pack整除的条件下,一个pack内的元素应用到的是同一个alpha权重**。参见下图:

这样我们就能以向量化形式去处理元素,以提升读写带宽。并且每一个pack内部只需要计算一次,向量化处理相比逐元素计算能节省不小计算量。对应代码如下:

template<typename T, typename IndexType, int pack_size>
__global__ void PReluForwardMultiAlphaGpu(const IndexType elem_cnt, const IndexType alpha_size,const IndexType inner_size, const T* x, const T* alpha, T* y) {
int32_t global_thread_id = blockIdx.x * blockDim.x + threadIdx.x;using LoadType = cuda::elementwise::PackType<T, pack_size>;using LoadPack = cuda::elementwise::Pack<T, pack_size>;T zero_val = static_cast<T>(0);for (int64_t linear_index = global_thread_id * pack_size; linear_index < elem_cnt;linear_index += gridDim.x * blockDim.x * pack_size) {// 计算当前Pack所使用到Alpha的索引IndexType alpha_idx = (linear_index/inner_size%alpha_size);const LoadType* x_load = reinterpret_cast<const LoadType*>(x + linear_index);// 以向量化的形式加载输入xLoadPack x_vec;x_vec.storage = *x_load;LoadPack y_vec;// 循环展开,逐个处理Pack内的元素
#pragma unrollfor (int i = 0; i < pack_size; i++) {y_vec.elem[i] = x_vec.elem[i] > zero_val ? x_vec.elem[i] : x_vec.elem[i] * alpha[alpha_idx];}// 以向量化的形式存储输出y*(reinterpret_cast<LoadType*>(y + linear_index)) = y_vec.storage;}
}

我们在Nsight Compute内简单比较下优化前后的结果,测试数据为(96, 64, 112, 112),机器为A100-40GB。蓝色一栏是使用向量化优化过的kernel,而绿色一栏是朴素实现的kernel。可以看到,经过优化后,我们计算占比降低20%-30%,吞吐提升了30+%。优化后的kernel带宽能达到1350GB/s,已经很接近A100上的理论带宽1555GB/s。

当然也不是所有形状都支持向量化操作,当inner_size无法被对应的pack_size 整除时,只能退回到朴素实现上。

3

基准测试

在A100-40GB测试机器上,我们对Insightface涉及到的Tensor形状,与PyTorch实现进行比较,测试数据如下:

经过优化PReLU的OneFlow,在大部分情况下均有比PyTorch接近2倍的领先优势,在最后一种情况由于形状较为特殊,无法应用向量化的优化,所以表现与PyTorch持平。

往期回顾

AI卷到艺术界了,DALL·E将战胜人类?

Pandas 与 SQL 的超强结合,爆赞!

云上风景虽好,但不要盲目跟风!

Python 字符串深度总结

分享
点收藏
点点赞
点在看

CUDA 优化之 PReLU 性能调优相关推荐

  1. 第七篇:双管齐下,JVM内部优化与JVM性能调优

    文章目录 一.前言 二.编译时优化 2.1 Javac编译器 2.2 Java语法糖 2.2.1 泛型和泛型擦除 2.2.2 自动装箱.自动拆箱.遍历循环 2.2.3 条件编译 三.运行时优化(核心: ...

  2. webpack打包优化_前端性能优化:webpack性能调优与Gzip原理

    链接:https://juejin.im/book/5b936540f265da0a9624b04b 从输入 URL 到显示页面这个过程中,涉及到网络层面的,有三个主要过程: DNS 解析 TCP 连 ...

  3. C++优化系列之性能调优工具篇

    大家好,我是程序喵,虽然假期都快过去了,有很多朋友问程序喵怎么没更文呢?是不是偷懒了!其实我这几天没闲着,一直在整理学习资料,昨晚终于完成了,估计这两天会跟大家见面. 好了,我们CPP优化系列正式开始 ...

  4. db2和mysql性能优化_DB2数据库性能调优的十个办法

    这篇文章主要是针对e-business OLTP的10个性能方面的Tips. 10. Monitor Switches 打开Monitor Switch,才能获得性能方面的信息,命令如下 db2 &q ...

  5. 如何合理的规划一次jvm性能调优

    这是jvm优化系列第三篇: jvm优化--垃圾回收 jvm优化--监控工具 JVM性能调优涉及到方方面面的取舍,往往是牵一发而动全身,需要全盘考虑各方面的影响.但也有一些基础的理论和原则,理解这些理论 ...

  6. 深聊性能测试,从入门到放弃之:如何对IO进行性能调优

    1.引言 2. 硬盘知识 2.1 磁盘原理 2.2 磁盘接口 2.3 磁盘读写 2.4 磁盘KPI 2.5 计算 2.5.1 IOPS计算 2.5.2 传输速率/吞吐率计算 2.6 IO延时 2.6. ...

  7. 从蚂蚁金服裸辞,京东三面遭调优猛击,闭关俩月啃完653页性能调优实战手册,拿到京东offer

    性能优化是很多 Java 程序员希望彻底掌握的一门技能.很多人都想学好性能优化,希望能够在自己的工作中灵活运用提高性能,从而为用户提供良好的用户体验.然而,很多人在设计技术方案或者编码时缺乏系统地.方 ...

  8. 上线半天下载量破100W!美团大佬的Java性能调优实战手册,超详细

    随着互联网的发展,高可靠.高并发以及降本增效,已成为各大公司面临的现实挑战,性能优化需求愈发迫切,大到分布式系统,小到代码块的算法优化,都已经成为你日常工作中必须要面对的事情.对于开发者而言,性能优化 ...

  9. CUDA程序性能调优

    目录 1.kernel function parameters 2. local variables 3.shared memory with __syncthreads__ call 4.devic ...

  10. 性能调优之Java系统级性能监控及优化

    性能调优之Java系统级性能监控及优化 对于性能调优而言,通常我们需要经过以下三个步骤:1,性能监控:2,性能剖析:3,性能调优 性能调优:通过分析影响Application性能问题根源,进行优化Ap ...

最新文章

  1. oracle 体系结构及内存管理 13_事务
  2. JavaScript:prototype属性使用说明
  3. python 彩票分析_294期钱哥福彩3D预测奖号:杀号分析
  4. typora绑定github博客_博客生产线:WordPress(平台)+Typora(编辑器)+GitHub(图床)
  5. 从petshop中一实例谈using 的三种用法
  6. 华为内部狂转好文:有关大数据,看这一篇就够了
  7. python图像切面numpy_NumPy做图像处理不香吗?我用Python把秋日里最美的景色做成了这种效果~...
  8. owa outlook使用中的一些问题-陆续添加
  9. 渗透测试各种扫描工具集合(好用)
  10. 关注手机病毒:重点手机安全事件盘点
  11. HBuilderX格式化css
  12. 【WLAN】【基础知识】WIFI那些事儿之Beamforming
  13. picpick尺子像素大小精度不够准确_picpick尺子像素大小精度不够准确_相机的像素精度,物理定位精度,亚像素定位之间的关系和进行像素的固定误差累积......
  14. I.MX8M mini物联网开发板框架及屏幕接口详解
  15. 计算机语言zuv,我们的拼语_大家的语言_新浪博客
  16. idea创建SSM项目(Spring+SpringMVC+MyBatis)
  17. MySQL数据库锁表,如何释放锁
  18. kylin v10系统_Kylin10正式版 银河麒麟桌面操作系统(Kylin) V10 x86/兆芯版/海光版下载-520下载...
  19. SafeSignCertReg.exe导致系统工作异常
  20. Arduino uno 驱动安装问题解决(win10)

热门文章

  1. 光环PMP下午茶做题时间
  2. MySql数据恢复方法个人总结
  3. 三菱伺服驱动器示例_三菱伺服电机伺服驱动器
  4. ROS 机器人操作系统:概述
  5. java snmp walk,snmpwalk命令常用方法总结(转)
  6. ADS史密斯圆阻抗匹配
  7. Python日期时间格式转换
  8. linux格式化分区error,linux格式化磁盘出错
  9. (二)安装redies,配置,启动
  10. 2017马哥python高级实战班培训推荐