CPU 与 GPU | 计算机视觉的两种实现方式

444 阅读6分钟

概述

如今组装电脑很难选 CPU 了,因为 CPU 的更新换代速度比 CPU 的运算速度都要快,可谓是一年更新一代,并且每更新一代,其性能就得到进一步的优化。不知不觉中,intel 处理器已经发展到第 12 代技术了。结果实测与分析得出,10 代到 11 代与 11 代到 12 代 CPU 之间,CPU 性能只能用优化来形容,其实根本谈不上提高,CPU 的 “性能代差” 根本没有老型号那么显著,可以说,技术越 “新” 的 CPU 越没有性价比。简单的说,CPU 可以连接到主机内存,也可以连接到 GPU 。

提升 CPU 利用率

简单的说,如何更快速的在 CPU 上完成一个运算。对于计算机视觉领域的问题,更多的是进行矩阵运算,比如矩阵乘法等各种线性运算,这里以 矩阵 a + 矩阵 b 为例来说明。

在计算 a + b 之前,需要先准备数据,将原来在主内存里面的 ab 的数组搬到 L3 cache,然后搬到 L2 cache,再搬到 L1 cache,最后搬到寄存器上参与运算,且三层 cache 性能互不相同:

  • 寄存器访问延时逼近主频,最快;
  • L1 cache 访问延时:0.5 ns 且存储空间大于寄存器;
  • L2 cache 访问延时:7 ns 且存储空间大于 L1 cache;
  • 主内存访问延时:100 ns 且存储空间大于 L3 cache;

可以看到,即使 CPU 运算频率很高,但是每一次运算都无法达到 CPU 所应有的速度,这是因为内存访问过慢,解决方法是 提升空间和时间的内存本地性,即使缓存的效率更高,有如下两种实现方式:

  • 时间:重用数据使得保持它们在缓存里。即如果一个数据从主存一路搬到寄存器上参与运算,且后面运算中还会被用到,则不需要一路搬回去主存,而是放在靠近寄存器的存储空间内(寄存器、 L1 cache 等),从时间上提升的运算速度。
  • 空间:按序读写数据使得可以预读取。如果一个矩阵是按行存储,则访问一行会比访问一列要快,且 CPU 会聪明的提前读取下一个数据到缓存线中。

另外一个角度提升 CPU 利用率的方法是并行。鉴于摩尔定律,CPU 与 GPU 的频率在过去这些年的提升幅度有限,但是可以通过增加内核数量来变相提高频率。其中,intel 公司会通过超线程技术,将原来的 n 个物理核超线程成 2n 个运算单元,并在系统中告知你有 2n 个核。值得一提的是,超线程技术对于计算密集型的领域来说不一定提升性能,因为它们共享寄存器。

GPU

下面是 Nvidia Titan X(Pascal)的架构图。其中大核数量取决于显卡,档次越高的显卡,大核数量越多,档次越低的显卡,大核数量越少。大核内的每一个绿点可以看做是一个小核,即一个运算单元,可以运行一个线程,执行单独的运算,也就是说 GPU 可以并行执行上千个线程。即使 GPU 每一个小核的运算能力比 CPU 的核要弱,但是 GPU 拥有上千的小核,正所谓众人拾柴火焰高,从这方面上 GPU 的运算速度相比于 CPU 要快很多。

Nvidia Titan X(Pascal).png

提升 GPU 利用率

GPU 的核数量相对较多,可以考虑从一下几个方面去提升 GPU 的利用率:

  • 并行:使用数千个线程。这种情况一般适用于需要运算的向量较为庞大,如达到千维数量级。故如果神经网络较小,则在 GPU 上计算时,并行效率不高。
  • 内存本地性:缓存更小,架构更加简单。对 GPU 而言,相同的芯片面积,更多的给运算单元占用,故用于缓存的内存空间有限,且内存带宽更高。
  • 少用控制语句:支持有限且同步开销大。如果执行控制语句,则 GPU 上几乎所有的核都将停止工作一段时间,即几十个或者几百个线程同步执行,增大执行开销。

CPU vs GPU

CPU VS GPU.png

上表给出了 一般/高端 的 CPU 与 GPU 在不同指标上的比较。其中,由于 GPU 的核数量多,所以 GPU 在 TFLOPS(每秒钟浮点数运算次数) 指标上远远高于 CPU。这是理论情况下的表现,实际上由于内存带宽跟不上,所以 CPU 与 GPU 的实际运算速度可能受到内存带宽的限制而无法达到理论速度值。所以相比于 CPU 而言,GPU 通过自身的内存带宽与庞大的核数量,实现更高速的运算。但是 GPU 的瓶颈是内存大小受限。

由于 CPU 的功能不但是计算矩阵,还有很多其他的工作需要完成,如渲染 html 等,所以 CPU 内有很多 if - else 指令来处理控制流,实现跳转,故 CPU 的控制流较 GPU 强。故可以理解为, GPU 是为了并行计算而生的。

此外,CPU 与 GPU 并非独立开来的,因为计算机任务都是跑在 CPU 上的。其中,CPU 通过通道 Memory IO与计算机内存相连接,CPU 也与 GPU 直接相连,且 CPU 到内存的带宽要高于 CPU 到 GPU 的带宽,若有多个 GPU 则共享 CPU 到 GPU 的带宽,故不要频繁在 CPU 和 GPU 之间传数据,原因就是带宽限制,同步开销。

CPU / GPU 高性能计算编程

  • CPU:C++ 或者任何高性能语言。在 CPU 上做开发,一般都使用 C++ 进行编程,很少用 Python,也就是说,很多框架的底层都是使用 C++ 进行编写,原因就是说 C++ 的编译器较为成熟。
  • GPU:Nvidia 上用 CUDA,其他用 OpenCL。其中,Nvidia 用几千人 花了十几年在做 CUDA,所以驱动等方面都已经很成熟,且性能也很不错。OpenCL 是与 CUDA 很相像的一门语言,且是业界的一个标准,当然 CUDA 也支持 OpenCL。

总结

  • CPU:可以处理通用计算,性能优化考虑数据读写效率和多线程。
  • GPU:使用更多的小核和更好的内存带宽,适合能大规模并行的计算任务。目前主流使用 GPU 做深度学习的开发。