Halide应用开发
Halide应用开发
1. 基本原理
1.1、介绍
随着人工智能的普及,深度学习网络的不断涌现,为了让各硬件(CPU, GPU, NPU,...)能够支持深度学习应用,各硬件芯片需要软件库去支持高性能的深度学习张量运算。目前,这些高性能计算库主要由资深HPC工程师(高性能计算优化工程师)进行开发,为了加快开发进程,缩短深度学习应用落地周期,自动化算子优化是一个趋势。
AutoKernel是由OPEN AI LAB提出的高性能算子自动优化工具,可以自动优化调度策略、生成底层优化代码,大幅减少各硬件芯片算子开发成本,提升算子优化效率,让工程师更快实现深度学习算法在各硬件芯片上的高性能部署。
1.2、 AutoKernel架构
AutoKernel分为3个模块:
算子生成器
该模块使用了开源项目Halide;Halide是业界广泛使用的自动代码生成项目,它首次提出将计算和调度分离。该模块的输入是和硬件无关的算子计算描述,输出是相应后端的优化汇编代码/目标文件;
自动搜索模块
该模块可以通过最优化算法/搜索算法/机器学习/强化学习搜索出相应后端的最优算子的调度策略参数(该模块仍在开发中);
算子部署插件(AutoKernel Plugin)
Tengine是OPEN AILAB开源的深度学习推理框架,实现了AI算法在不同硬件的快速高效部署。该模块实现了将自动生成的优化算子代码以plugin的形式一键集成到Tengine中,实现自动优化算子的一键部署;
1.3、 AutoKernel特点
低门槛: 无需底层优化汇编的知识门槛
简单易用: 提供docker环境,无需安装环境,plugin一键集成到推理框架Tengine
高效率: 无需手写优化汇编,一键生成优化代码,一键部署
2 AutoKernel优化GEMM实践
本部分将带领大家一步步优化矩阵乘法GEMM。无需手工撸代码,编写繁杂冗长的底层汇编代码,只需十几行简洁的调度代码。
2.1、优化的本质
在详细讲解优化步骤前,先谈谈优化的本质。在谈”优化“的时候:
计算机底层做了什么?
优化的”瓶颈“是什么?
为什么通过一波"优化操作",性能就能提升呢?
AutoKernel使用的Halide是如何实现自动优化的呢?
上图是典型的存储理器层次结构:主存容量大,访问速度慢,寄存器和缓存读取速度快,但容量有限。在寄存器的层级上,CPU可以在一个时钟周期内访问它们,如果CPU去访问外部的DDR的话,延迟是非常大的,大概是200个时钟周期左右。如果CPU去访问cache的话,一般需要6到12个cycle就够了。所以,第1个优化宗旨是:优化内存访问,充分利用寄存器和高速缓存去存数据。
第2个优化宗旨则是提高并行性:充分利用SIMD进行指令向量化和多核心并行。大部分现代CPU支持SIMD(Single Instruction Multiple Data,单指令流多数据流)。在同一个CPU循环中,SIMD可在多个值上同时执行相同的运算/指令。如果在4个数据点上进行向量化,一次计算四个数据,理论上就可以实现4倍的加速。
2.2、运行环境搭建
AutoKernel提供了docker镜像,docker里已经配置好运行环境,进入docker即可直接运行demo代码:
# 拉取镜像
docker pull openailab/autokernel
# 启动容器,进入开发环境
docker run -it openailab/autokernel /bin/bash
# 获取代码
git clone https://github.com/OAID/AutoKernel.git
cd AutoKernel/doc/tutorials/data/
目录下的build.sh是demo的执行脚本,运行需要指定优化步骤step,可选的step是从1 到7,其中step=1是默认不优化的,step=7是最极致优化的。
执行指令:
# 执行demo
./build.sh 1 ==> 默认不优化
./build.sh 7 ==> 最极致优化
下图展示了在Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz的电脑上的优化效果,无需手工撸代码,无需编写繁杂冗长的底层汇编代码,只需十几行简洁的调度代码, 就能性能优化200+倍~
2.3、详细的优化步骤:
STEP-1
第1个步骤是不带任何优化的。用Halide语言直接描述GEMM的计算过程。
Var x,y;
RDom k(0, K);
Func gemm("gemm");
gemm(x, y) += A(k, y) * B(x, k);
计算M=N=K=640的矩阵乘法。运行脚本第一个参数指定step=1。耗时结果如下:
root@xxxxxxxxxx
:/AutoKernel/doc/tutorials/data# ./06_build.sh 1
step = 1
M N K = 640 640 640 err 0.00 [rep 50] autokernel | blas 240.8523 ms 1.1376 ms
STEP-2
这一步采用分块tile。分块的目的是为了充分利用缓存。如果原来的循环较大,tile分块改成小块数据去计算,可以使得每次计算的数据都比较舒适地呆在缓存里,不用经历重复的驱逐(在缓存中重复的添加和删除数据)。分块后进行reorder操作,交换两个嵌套循环的顺序,目的是最内层的内存访问友好。按照x,y维度划分成16x8的小分块去计算:
gemm.update()
.tile
(x, y, xo, yo, xi, yi,
16,
8)
.reorder
(xi, yi, k, xo, yo);
执行结果如下:
root@xxxxxxxxxx
:/AutoKernel/doc/tutorials/data#./06_build.sh 2
step = 2
M N K = 640 640 640 err 0.00 [rep 50] halide | blas 81.8148 ms 1.1281 ms
性能从240ms优化到82ms,提升了近3倍。
STEP-3
在上一步的基础上增加向量化vectorize。向量化是把几个标量计算(scale)转换为一个向量计算(vector),充分利用SIMD向量指令。大部分现代CPU支持SIMD(Single Instruction Multiple Data,单指令流多数据流)。在同一个CPU循环中,SIMD可在多个值上同时执行相同的运算/指令。
gemm.update()
.tile
(x, y, xo, yo, xi, yi,
16,
8)
.reorder
(xi, yi, k, xo, yo)
.vectorize
(xi,
8);
执行结果
root@xxxxxxxxxx
:/AutoKernel/doc/tutorials/data# ./06_build.sh 3
step = 3
M N K = 640 640 640 err 0.00 [rep 50] autokernel | blas 27.5433 ms 1.1445 ms
性能从82ms优化到27ms,又加速了接近3倍。可以看到,围绕前面提到的两条优化宗旨:优化内存访问和提高并行性,从step1到step3,性能已经提升了近9倍。
STEP-4
调度策略在step3的基础上增加并行化parallel。对一个循环并行化是把循环的每次迭代分给多个线程或者处理器去同时处理,每个线程处理通过代码段(loop body),但是处理不同的数据。
增加并行化后,build.sh默认指定四线程,性能直接翻了近4倍,从27ms到7.3ms.
STEP-5
调度策略在上一步的基础上增加unroll展开。如果循环体内的语句没有数据相关依赖,循环展开可以增加并发执行的机会,使得更充分利用寄存器,减少循环时每个操作内存加载和保存的次数。
unroll展开后,性能从7.3ms优化到4.8ms.
STEP-6
前面的分块成 16 x 8的小kernel,
这一步先划分成 16 x 32的分块,然后把每个分块再分成
16 x 8的子分块。把最外层的两层循环合并到一层,并对这一层进行并行化。这一步计算描述多了一个prod函数来定义子分块的计算,prod函数的计算公式和总的gemm是一样的,通过 compute_at指定在 yi维度之下计算prod,则prod计算的是 16x8的小kernel, 大致逻辑如下:
这一步距离STEP1性能已经优化了近80倍了,性能越来越接近OpenBlas了。
STEP-7
这一步添加的操作是对矩阵B进行数据重排,使得在计算小kernel 16x8时,内存读取更顺畅。因为小kernel的x维度是按照16划分的,因此重排数据B的x维度也是按照16重排。
至此,的每一步调优策略始终都围绕两条优化宗旨“优化内存访问”,“提高并行性”展开优化,到最后性能已经与OpenBlAS差不多了,距离STEP1已经加速了200+倍了。
Halide应用开发的更多相关文章
- TVM:一个端到端的用于开发深度学习负载以适应多种硬件平台的IR栈
TVM:一个端到端的用于开发深度学习负载以适应多种硬件平台的IR栈 本文对TVM的论文进行了翻译整理 深度学习如今无处不在且必不可少.这次创新部分得益于可扩展的深度学习系统,比如 TensorFlo ...
- 避免重复造轮子的UI自动化测试框架开发
一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...
- App开发:模拟服务器数据接口 - MockApi
为了方便app开发过程中,不受服务器接口的限制,便于客户端功能的快速测试,可以在客户端实现一个模拟服务器数据接口的MockApi模块.本篇文章就尝试为使用gradle的android项目设计实现Moc ...
- 使用HTML5开发Kinect体感游戏
一.简介 我们要做的是怎样一款游戏? 在前不久成都TGC2016展会上,我们开发了一款<火影忍者手游>的体感游戏,主要模拟手游章节<九尾袭来 >,用户化身四代,与九尾进行对决, ...
- Android SwipeRefreshLayout 下拉刷新——Hi_博客 Android App 开发笔记
以前写下拉刷新 感觉好费劲,要判断ListView是否滚到顶部,还要加载头布局,还要控制 头布局的状态,等等一大堆.感觉麻烦死了.今天学习了SwipeRefreshLayout 的用法,来分享一下,有 ...
- Android Studio配置 AndroidAnnotations——Hi_博客 Android App 开发笔记
以前用Eclicps 用习惯了现在 想学学 用Android Studio 两天的钻研终于 在我电脑上装了一个Android Studio 并完成了AndroidAnnotations 的配置. An ...
- Android请求网络共通类——Hi_博客 Android App 开发笔记
今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...
- Angular2入门系列教程1-使用Angular-cli搭建Angular2开发环境
一直在学Angular2,百忙之中抽点时间来写个简单的教程. 2016年是前端飞速发展的一年,前端越来越形成了(web component)组件化的编程模式:以前Jquery通吃一切的田园时代一去不复 ...
- 构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)
通过前面几节的准备工作,对于 npm / node / gulp 应该已经有了基本的认识,本节主要介绍如何构建一个基本的前端自动化开发环境. 下面将逐步构建一个可以自动编译 sass 文件.压缩 ja ...
随机推荐
- Rsync多模块复制、排除指定文件及目录以及数据无差异复制的应用实例
在我的博客<Rsync 数据复制软件应用>中,拉取数据访问的都是服务器端的/backup 目录,当然我们在其他目录下拉取数据.而实现这种操作就是指多模块复制. 要实现多模块复制首先需要修改 ...
- 【JDK8】Java8 LocalDate操作时间和日期的API
时间项目中的涉及到的时间处理非常多,犹豫SimpleDateFormat的不安全性以及Calendar等类在计算时比较复杂, 往往我们都会使用工具类来封装较多的日期处理函数, 但是JDK8中新增了操作 ...
- hdu2433 spfa+mark[x][u][v]优化
题意: 删除每一条边求最短路的和,每删除一个就输出一个和. 思路: 直接暴力可定TLE了,自己SB的尝试过,就要剪纸,当每次输出一个答案的时候我们没有必要再从 ...
- hdu 1044 BFS(压缩图)+DFS
题意: 给你起点,终点,图上有墙有路还有宝物,问你在规定时间内能否能到终点,如果能问最多能捡到多少宝物. 思路: 看完这个题目果断 BFS+三维的mark ...
- Linux系统应急响应
目录 排查用户相关的信息 排查进程端口相关的信息 查找恶意程序并杀掉 斩草除根 判断入侵方式,修复漏洞 当我们被告知一台Linux服务器被黑客入侵,黑客利用该服务器进行挖矿,并且在该服务器上放置了木马 ...
- Windows核心编程 第七章 线程的调度、优先级和亲缘性(下)
7.6 运用结构环境 现在应该懂得环境结构在线程调度中所起的重要作用了.环境结构使得系统能够记住线程的状态,这样,当下次线程拥有可以运行的C P U时,它就能够找到它上次中断运行的地方. 知道这样低层 ...
- Portswigger web security academy:Cross-site request forgery (CSRF)
Portswigger web security academy:Cross-site request forgery (CSRF) 目录 Portswigger web security acade ...
- layui的loading加载中
var load = layer.load(1, { content: '数据加载中', shade: [0.4, '#393D49'], // time: 10 * 1000, success: f ...
- 【mybatis】mybaits generator 逆向工程的使用
mybatis逆向工程官方网站:http://www.mybatis.org/generator/quickstart.html 准备xml文件.如下generator.xml全部内容 <?xm ...
- python中的的异步IO
asyncio 是干什么的? 异步网络操作 并发 协程 python3.0 时代,标准库里的异步网络模块:select(非常底层) python3.0时代,第三方异步网络库:Tornado pytho ...