高性能计算(High performance computing, 缩写HPC)
指通常使用很多处理器(作为单个机器的一部分)
或者某一集群中组织的几台计算机(作为单个计 算资源操作)的计算系统和环境。
有许多类型的HPC 系统,其范围从标准计算机的大型集群,到高度专用的硬件。
大多数基于集群的HPC系统使用高性能网络互连,比如那些来自 InfiniBand 或 Myrinet 的网络互连。
基本的网络拓扑和组织可以使用一个简单的总线拓扑,
在性能很高的环境中,网状网络系统在主机之间提供较短的潜伏期,
所以可改善总体网络性能和传输速率。
0、小米 mace
Mobile AI Compute Engine (MACE) 是一个专为移动端异构计算平台优化的神经网络计算框架。
1、OpenVINO intel cpu 核显 优化加速
Intel推出OpenVINO工具包,将计算机视觉带到物联网终端
OpenVINO(开放的视觉推理和神经网络优化)工具包
使开发人员能够在云上(如TensorFlow,MXNet和Caffe等流行款框架)构建和训练人工智能模型,
并将其部署到各种产品中。
Windows*
Linux* (supports Ubuntu*, CentOS*, and Yocto Project*)
Linux for FPGA
2、腾讯NCNN框架入门到应用
3、FeatherCNN
4、Tengine 高性能神经网络推理引擎
5、百度MDL
6、九言科技 绝影(Prestissimo)
7、Google量化方法 r=S(q-Z) tflite TensorFlow Lite
8、英伟达 TensorRT , NVIDIA TensorRT是一种高性能神经网络推理(Inference)引擎
9、FaceBOOK caffe2 pytorch QNNPACK uint8量化
目前,卷积的计算大多采用间接计算的方式,主要有以下三种实现方式:
1、im2col + GEMM。
caffe等很多框架中都使用了这种计算方式,
原因是将问题转化为矩阵乘法后可以方便的使用很多矩阵运算库(如MKL、openblas、Eigen等)。
GEMM 普通矩阵乘法(General Matrix Multiplication)多种优化
2、FFT变换。
时域卷积等于频域相乘,因此可将问题转化为简单的乘法问题。
3、Winograd。
这种不太熟悉,据说在GPU上效率更高。
NNPACK就是FFT和Winograd方法的结合。
上面三种方法执行效率都还不错,但对内存占用比较高,因为需要存储中间结果或者临时辅助变量。
1、Strassen 算法:
分析 CNN 的线性代数特性,增加加法减少乘法,
这样降低了卷积运算的计算的复杂度(o(n^3) -> o(n^2.81)),
但是这种方法不适合在硬件里面使用,这里就不做详细的介绍了。
2、 MEC:
一种内存利用率高且速度较快的卷积计算方法
MEC: Memory-efficient Convolution for Deep Neural Network 论文
快速矩阵乘法 分块矩阵乘法 Strassen算法 Coppersmith-Winograd算法
BLAS是 Basic Linear Algebra Subprograms (基本线性代数子程序)的首字母缩写,主要用来做基础的矩阵计算,或者是向量计算。它分为三级:
BLAS 1级,主要做向量与向量间的dot或乘加运算,对应元素的计算;
BLAS 2级,主要做矩阵和向量,就类似PPT中蓝色部分所示,矩阵A*向量x, 得到一个向量y。除此之外,可能还会有对称的矩阵变形;
BLAS 3级,主要是矩阵和矩阵的计算,最典型的是A矩阵*B矩阵,得到一个C矩阵。由矩阵的宽、高,得到一个m*n的C矩阵。
最原始3个for循环 (矩阵比较小的时候,速度还能快一些,当矩阵大了的时候,一定会跌下去,cache缓存问题):
矩阵分块,块复用,减少仿存,相当于减少内存访问,提高Cache利用率:
核心汇编优化:
- 寄存器分块
- SIMD指令
- 指令流水线优化,循环展开,重排,预取
操作寄存器,不是操作内存:
我可以申请一堆C 00,01这样的寄存器变量,在C语言中是register double,还有矩阵A的部分,也用寄存器变量。
当然B还是之前的方式,最后再写回C里面。
只是我们引入了寄存器变量,让更多的数据保存到寄存器里,而不是放到cache缓存里,来减轻cache的压力.
B矩阵仿存,使用指针访问,
一开始先把对应的指针位置指好,每次计算的时候只要指针连续移动就好,而不是每次读一个位置重新算一遍,这样速度就会快一些。
最里层循环展开:
在最里层循环,是不是可以展开成4次,在做这个的时候,我们可以降低整个循环这部分的开销,而且让它流水的情况更好。
通过使用寄存器变量,使用了指针,在做了一定的底层循环展开之后,达到了红色线的性能:
之后可以使用更大的分块,在进行寄存器,指针,展开优化。