上一篇请移步【动手学深度学习PyTorch版】22续 ResNet为什么能训练出1000层的模型_水w的博客-CSDN博客

目录

一、深度学习硬件CPU 和 GPU

1.1 深度学习硬件

◼ 计算机构成

◼ 程序执行的原理

◼ 内存

◼ 存储器

◼ 中央处理器(CPU)

1.2 如何提升cpu的利用率?(如何使运算在cpu上进行的更快,特别是数值运算:矩阵乘法、线性运算等)

◼ 提升空间和时间的内存本地性

◼ 尽量使用多核并行计算

1.3 GPU

◼ GPU

◼ cpu和gpu的对比

◼ 如何提升GPU的利用率?

◼ CPU/GPU带宽

◼ 如何在CPU上进行高性能计算编程?

1.4 总结


一、深度学习硬件CPU 和 GPU

1.1 深度学习硬件

◼ 计算机构成

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

(1)CPU(处理器):除了运行操作系统和其他许多功能外,还能执行程序;通常由 8 个或者更多个核心组成。

(2)内存(随机访问存储,RAM):用于存储和检索计算结果,如权重向量和激活参数,以及训练数据。

(3)以太网:一个或者多个,速度从 1 GB/s 到 100 GB/s 不等。

(4)高速扩展总线(PCle):用于系统连接一个或者多个 GPU;服务器最多有 8 个加速卡,通常以更高级的拓扑方式连接,而桌面系统则有 1 个或 2 个加速卡,具体取决于用户的预算和电源负载的大小。

(5)持久性存储设备:为系统需要的训练数据和中间检查点需要的存储提供了足够的传输速度;如磁盘驱动器、固态驱动器,在许多情况下使用高速扩展总线连接。

◼ 程序执行的原理

程序执行的原理:在计算机上运行代码的时候,需要将数据转移到处理器(GPU 或者 CPU)上执行计算,然后将结果从处理器转移回到随机访问存储和持久访问存储器中。

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

CPU(处理器):除了运行操作系统和其他许多功能外,还能执行程序;通常由 8 个或者更多个核心组成。

CPU的芯片图:

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

◼ 内存

主要用于存储需要随时访问的数据

当想要从内存中读取一部分内容时,需要先将地址(信息的位置)发送到 RAM,然后可以选择只读取一条 64 位记录还是一长串记录(突发读取,burst read),

当拥有多个存储体时,每个存储体大部分时候都可以独立地读取内存,

因为 GPU 的处理单元比 CPU 多得多,因此它对内存带宽的需要也更高,

◼ 存储器

随机访问存储的一些关键特性是带宽(bandwidth)和延迟(latency),存储设备也是如此,只是不同设备之间的特性差异可能更大。

(1)硬盘驱动器(hard disk drive,HDD)

它包含许多旋转的盘片,这些盘片的磁头可以放置在任何给定的磁道上进行读写,

优点是相对便宜,:缺点:

(2)固态驱动器(solid state drives,SSD)

固态驱动器使用闪存持久存储信息以更快地访问存储的记录,

缺点是:

◼ 中央处理器(CPU)

(1)组成:

前端加载指令并尝试预测将采用哪条路径,然后将指令从汇编代码解码为微指令(汇编代码通常不是处理器执行的最低级别代码,复杂的微指令可以被解码成一组更低级的操作,然后由实际的执行核心处理,通常执行核心能够同时执行许多操作)。

高效的程序可以在每个时钟周期内执行多条指令,前提是这些指令可以独立执行。

为了提高吞吐量,处理器还可以在分支指令中同时执行多条代码路径,然后丢弃未选择分支的结果。

总线会因为处理器型号、各代产品和供应商之间的特定拓扑结构有明显不同。

为了避免出现向 CPU 传输用于处理的数据不足的情况,应该尽量避免从内存中加载新数据,而是应该将数据放在 CPU 的缓存上。

添加缓存一方面能够确保处理器核心不缺乏数据,但同时也增加了芯片的尺寸,消耗了原本可以用来提高处理能力的面积。

    CPU在一个时钟周期内执行许多操作,是通过向量处理单元实现的(这些处理单元有不同的名称:在 ARM 上叫做 NEON,在 x86 上被称为 AVX2),常见的功能是能够执行单指令多数据操作(single instruction multiple data,SIMD)。

1.2 如何提升cpu的利用率?(如何使运算在cpu上进行的更快,特别是数值运算:矩阵乘法、线性运算等)

◼ 提升空间和时间的内存本地性

从图中我们可以看到,一个数据要参与计算,需要走很长的一条路。

如果要计算两个向量的和a+b,在计算之前需要准备数据,a 和b很有可能是放在主内存中的,如果想要将a和b进行相加,就需要将数据从主内存搬运到寄存器中(数据只有被搬运到寄存器中才能参与运算):主内存=>L3 cache(shared LLC)=>L2 cache=>L1 cache=>寄存器。

这条路里面,每一个地方的能其实是不一样的。这条路径中最快的是寄存器,寄存器可以认为是和主频一样快,

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

虽然cpu算的比较快、频率比较高,但实际上,实测下来,在实际测试的时候会发现远远没有达到CPU理论的算的速度,运算速度可能远低于理论值,这通常是由于内存访问速度过慢导致的。

内存访问太慢了,所以一般来说,我们所谓的加速一个比较大的关键点就是提升空间和时间的内存本地性,来使得我的缓存的效率更高。

具体来说,有两种办法:

提升时间上的本地性:重用数据使得保持在他们的缓存里(计算时需要将数据从主内存搬运到寄存器中,如果计算完的数据不再使用,cpu会将数据从寄存器一直回退到主内存中,因此,对于重复使用的数据,就希望能够将重复使用的数据一直保持在寄存器或者是L1中,以便于下一次使用)。

提升空间上的本地性:按序读写数据使得可以预读取(cpu在读取内存的时候是一块一块地读,如果所要计算的数据如果在内存中是存储在一起的话,就希望下一次计算所使用到的数据和前一次计算所需要的数据是相邻的,这样能够提升cpu读取数据的效率)。

比如,例:

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

如果一个矩阵是按行存储的(在行上面的内存地址是连续的),访问一行会比访问一列要快,特别是当矩阵比较大的情况下。这是因为,

◼ 尽量使用多核并行计算

高端cpu有几十个核,比如:

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

加起来一共是64个核。

但是Intel比较有意思的是,假设从芯片上来说有4个物理核,但是从系统上你看到的核可能是有8个,因为它使用了超线程。把一个CPU超线程了两个核。

但是超线程对于计算密集型没有太多的用处,并行来利用所有核,超线程不一定提升性能,因为这2个超线程共享的是一个寄存器。

例:使用以下两种方式来计算a + b ,

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

左边使用循环对元素进行逐个相加,同样的道理,图的右边是使用计算框架(numpy等)进行加法运算,最终在运算的时候左边会比右边慢很多,慢个几百倍。

那是因为有2个原因:

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

1.3 GPU

◼ GPU

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

这个是Ncidia Titan X的一个架构图, 我们可以认为一小块就是一个核。其实3080,3070,3090等等没什么区别,唯一区别就是放了不同的大核而已。

大核里面有很多小核,每个小核的每一个绿点,它其实我们可以认为是一个计算单元,可以在每一个绿点上开一个线程。所以GPU来说,每次可以上千次计算。

就算每一个绿点的计算能力比cpu弱,速度慢上4,5倍,但是计算单元数量多,最终还是快的。

◼ cpu和gpu的对比

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

表中的“/”表示一般型号的参数/高端型号的参数。CPU的核心数量一般来说是6核,好一点的是64。而显卡的核心数量一般来说是2K核,好一点的是4K个。

GPU的核心数量远多于CPU,所以就导致了GPU每秒能计算的浮点数(TFLOPS,可以用核心数量和主频的乘积来做一个简单的近似)就要远高于CPU。

每一次计算都需要从内存中读取数据,因此内存带宽也很重要,通常来说,如果达不到计算峰值一般是由于内存带宽的限制。

也就是说,GPU通过高的内核带宽,多核,来换取它的计算更快。核心数量和内存带宽的优势使得GPU在运算速度上要远快于CPU。但是另外付出的代价是,这也导致了GPU的内存大小不是很大,GPU的控制流很弱(CPU是做通用计算的,因此需要很强的控制流)。

◼ 如何提升GPU的利用率?

本质上与cpu一样,

(1)并行:使用数千个线程;

(2)内存本地性:

缓存更小,架构更简单(GPU为了节省面积将缓存做得比较小,这样做的好处是内存的带宽会更高一点);

(3)少用控制语句:支持有限,同步开销很大;

◼ CPU/GPU带宽

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

CPU和GPU并不是独立的,所有的任务都是运行在CPU上的,如果要在GPU上做运算,就会存在带宽的问题。

因此不要频繁地在CPU和GPU之间传递数据:带宽限制,同步开销(这里的同步是由驱动决定的)。

【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

◼ 如何在CPU上进行高性能计算编程?

(1)C++或者任何高性能语言:编译器成熟;
(2)Nvidia上用CUDA:编译器和驱动成熟;

(3)其他使用OpenCL(CUDA也支持OpenCL):质量取决于硬件厂商(编译器和驱动是根据硬件厂商决定);

1.4 总结

发表回复