31 深度学习硬件:CPU 和 GPU【动手学深度学习v2】

深度学习硬件
计算机
构成

- CPU(处理器):除了运行操作系统和其他许多功能外,还能执行程序;通常由 8 个或者更多个核心组成
- 内存(随机访问存储,RAM):用于存储和检索计算结果,如权重向量和激活参数,以及训练数据
- 以太网:一个或者多个,速度从 1 GB/s 到 100 GB/s 不等
- 高速扩展总线(PCle):用于系统连接一个或者多个 GPU;服务器最多有 8 个加速卡,通常以更高级的拓扑方式连接,而桌面系统则有 1 个或 2 个加速卡,具体取决于用户的预算和电源负载的大小。
- 持久性存储设备:为系统需要的训练数据和中间检查点需要的存储提供了足够的传输速度;如磁盘驱动器、固态驱动器,在许多情况下使用高速扩展总线连接
程序执行的原理
- 在计算机上运行代码的时候,需要将数据转移到处理器(GPU 或者 CPU)上执行计算
- 然后将结果从处理器转移回到随机访问存储和持久访问存储器中
内存
- 主要用于存储需要随时访问的数据
当想要从内存中读取一部分内容时,需要先将地址(信息的位置)发送到 RAM,然后可以选择只读取一条 64 位记录还是一长串记录(突发读取,burst read)
- 向内存发送地址并设置传输大约需要 100 ns(细节取决于所用内存芯片的特定定时系数),每个后续传输只需要 0.2 ns
- 第一次读取的成本是后续读取的 500 倍
- 每秒最多可以执行一千万次随机读取
- 应该尽可能地避免随机内存访问,而是使用突发模式读取和写入
当拥有多个存储体时,每个存储体大部分时候都可以独立地读取内存
- 如果随机操作均匀分布在内存中,有效的随机操作次数将高达 4 倍(突发读取的速度也快了 4 倍)
- 由于内存对齐是 64 位边界,因此最好将任何数据结构与相同的边界对齐(当设置了适当的标志时,编译器基本上就是自动地执行对齐操作)
因为 GPU 的处理单元比 CPU 多得多,因此它对内存带宽的需要也更高
- 一种解决办法是使内存总线变得更宽,这样可以同时传输更多的信息(首要方法)
- 另一种方法是在 GPU 中使用特定的高性能内存(GPU 虽然速度更快,但是它的内存通常比 CPU 的内存小得多,因为成本更高,价格昂贵,通常仅限于在高端服务器的芯片上使用)
存储器
- 随机访问存储的一些关键特性是带宽(bandwidth)和延迟(latency),存储设备也是如此,只是不同设备之间的特性差异可能更大
硬盘驱动器(hard disk drive,HDD)
- 它包含许多旋转的盘片,这些盘片的磁头可以放置在任何给定的磁道上进行读写
优点
- 相对便宜
缺点
1、典型的灾难性故障模式
2、相对较高的读取延迟
- 硬盘驱动器的转速大约为 7200 RPM(每分钟转速),如果速度再快一点,就会由于施加在碟片上的离心力而破碎
- 在访问磁盘上的特定扇区时,需要等待碟片旋转到位(可以移动磁头,但是无法对磁盘加速),因此可能需要 8 毫秒才能使用请求的数据
- 硬盘驱动器可以以大约 100 IOPs(每秒输入/输出操作)的速度工作,在过去二十年中这个数字基本上没变,带宽(大约为 100 - 200 MB/s)也很难增加(每个磁头读取一个磁道的比特,因此比特率只随信息密度的平方根缩放)
- 对于非常大的数据集,HDD 正迅速降级为归档存储和低级存储
固态驱动器(solid state drives,SSD)
- 固态驱动器使用闪存持久存储信息以更快地访问存储的记录
缺点
1、固态驱动器以块的方式( 256KB 或更大)存储信息
- 块只能作为一个整体写入(而且块必须被读取、擦除,然后再重新写入新的信息),需要耗费大量的时间,导致固态驱动器在按位随机写入时性能非常差
2、存储单元磨损比较快
- 通常在几千次写入之后就已经老化了
- 不建议将固态驱动器用于交换分区文件或大型日志文件
3、带宽的大幅增加迫使计算机设计者将固态驱动器与 PCIe 总线相连接,这种驱动器称为 NVMe(非易失性内存增强)
- 最多可以使用 4 个 PCIe 通道
- 在 PCIe4.0 上最高可达 8 GB/s
云存储
中央处理器(CPU)
组成
1、处理器核心(processor cores):用于执行机器代码
- 前端加载指令并尝试预测将采用哪条路径,然后将指令从汇编代码解码为微指令(汇编代码通常不是处理器执行的最低级别代码,复杂的微指令可以被解码成一组更低级的操作,然后由实际的执行核心处理,通常执行核心能够同时执行许多操作)
- 高效的程序可以在每个时钟周期内执行多条指令,前提是这些指令可以独立执行
- 为了提高吞吐量,处理器还可以在分支指令中同时执行多条代码路径,然后丢弃未选择分支的结果
2、总线(bus):连接不同组件。总线会因为处理器型号、各代产品和供应商之间的特定拓扑结构有明显不同
3、缓存(cache):相比主内存实现更高的读取带宽和更低的延迟内存访问
- 为了避免出现向 CPU 传输用于处理的数据不足的情况,应该尽量避免从内存中加载新数据,而是应该将数据放在 CPU 的缓存上

- 添加缓存一方面能够确保处理器核心不缺乏数据,但同时也增加了芯片的尺寸,消耗了原本可以用来提高处理能力的面积
4、向量处理单元(vector processing unit):为高性能线性代数和卷积运算提供辅助
- CPU在一个时钟周期内执行许多操作,是通过向量处理单元实现的(这些处理单元有不同的名称:在 ARM 上叫做 NEON,在 x86 上被称为 AVX2)
- 常见的功能是能够执行单指令多数据操作(single instruction multiple data,SIMD)
如何提升cpu的利用率?(如何使运算在cpu上进行的更快,特别是数值运算:矩阵乘法、线性运算等)
1、提升空间和时间的内存本地性
如果要计算两个向量的和a+b
在计算之前需要准备数据,a 和b很有可能是放在主内存中的,如果想要将a和b进行相加,就需要将数据从主内存搬运到寄存器中(数据只有被搬运到寄存器中才能参与运算):主内存=>L3 cache(shared LLC)=>L2 cache=>L1 cache=>寄存器
- 这条路径中最快的是寄存器,寄存器可以认为是和主频一样快
- L1 访问延时:0.5ns (L1比寄存器要大,访问延迟比寄存器要高)
- L2 访问延时:7ns (14 *L1 ,访问一次L2相当于访问14次L1)
- 主内存访问延时:100ns (200 * L1 ,访问一次主内存相当于访问200次L1)
- 虽然cpu算的比较快、频率比较高,但是在实际测试的时候运算速度可能远低于理论值:这通常是由于内存访问速度过慢导致的
所以一般来说,加速的关键点就是提升空间和时间的内存本地性,来提升缓存的效率
- 提升时间上的本地性:重用数据使得保持在他们的缓存里(计算时需要将数据从主内存搬运到寄存器中,如果计算完的数据不再使用,cpu会将数据从寄存器一直回退到主内存中,因此,对于重复使用的数据,就希望能够将重复使用的数据一直保持在寄存器或者是L1中,以便于下一次使用)
- 提升空间上的本地性:按序读写数据使得可以预读取(cpu在读取内存的时候是一块一块地读,如果所要计算的数据如果在内存中是存储在一起的话,就希望下一次计算所使用到的数据和前一次计算所需要的数据是相邻的,这样能够提升cpu读取数据的效率)
例:

如果一个矩阵是按行存储的(在行上面的内存地址是连续的),访问一行会比访问一列要快
- cpu一次读取64字节(缓存线),一个Float是4个字节
- cpu会提前读取下一个(缓存线)
2、尽量使用多核并行计算
高端cpu有几十个核
并行来利用所有核
- 超线程不一定提升性能,因为它们共享寄存器
例:
使用以下两种方式来计算a + b

左边使用循环对元素进行逐个相加,右边是使用计算框架(numpy等)进行加法运算,最终在运算的时候左边会比右边慢很多:
1、左边调用了n次函数(n是a的长度),每次调用都是有开销的
2、右边很容易做并行(C++的并行实现如下所示)

- omp:C++中比较常用的并行方法
- 第一行omp的标记表示该循环可以被多个线程并行执行,可以很好地利用多核
网络和总线
- 当单个设备不足以进行优化时,需要使用网络和总线来回传输数据以实现同步处理
深度学习的互联方式:

cpu和gpu的对比

- 表中的“/”表示一般型号的参数/高端型号的参数
- GPU的核心数量远多于CPU,所以就导致了GPU每秒能计算的浮点数(TFLOPS,可以用核心数量和主频的乘积来做一个简单的近似)也远高于CPU
- 每一次计算都需要从内存中读取数据,因此内存带宽也很重要,通常来说,如果达不到计算峰值一般是由于内存带宽的限制
- 核心数量和内存带宽的优势使得GPU在运算速度上要远快于CPU,但是这也导致了GPU的内存大小不是很大,控制流很弱(CPU是做通用计算的,因此需要很强的控制流)
如何提升GPU的利用率?
1、并行
- 使用数千个线程
2、内存本地性
- 缓存更小,架构更简单(GPU为了节省面积将缓存做得比较小,这样做的好处是内存的带宽会更高一点)
3、少用控制语句
- 支持有限
- 同步开销很大
CPU/GPU带宽

- CPU和GPU并不是独立的,所有的任务都是运行在CPU上的,如果要在GPU上做运算,就会存在带宽的问题
- CPU和内存之间的带宽,可以认为CPU每个针脚会传输一定的数据,分配给内存的针脚越多,带宽就越大
- CPU和GPU之间的带宽:带宽不是很高,特别是在多个GPU的情况下,可能需要共享带宽
- 因此不要频繁地在CPU和GPU之间传递数据:带宽限制,同步开销(这里的同步是由驱动决定的)
如何在CPU上进行高性能计算编程?
C++或者任何高性能语言
- 编译器成熟
如何在GPU上进行高性能计算编程?
Nvidia上用CUDA
- 编译器和驱动成熟
其他使用OpenCL(CUDA也支持OpenCL)
- 质量取决于硬件厂商(编译器和驱动是根据硬件厂商决定)
总结
- CPU:可以处理通用计算。性能优化考虑数据读写效率和多线程(多核)
- GPU:使用更多的小核和更好的内存带宽,适合能大规模并行的计算任务
- 设备有运行开销,数据传输时要争取量大次少而不是量少次多
- 在训练过程中数据类型过小可能会导致数值的溢出(在推断过程中影响不大)
Q&A
- 1、如果要提高泛化性,就有可能增加数据?调参的意思是不是最大了?QA P2 - 00:10
- 2、我之前用alexnet先做的实验,我发现resnet18比alexnet的模型文件要小很多,可是您之前的课程里里面有一张图,好像是resnet的运算量比alexnet大,怎么解释这个问题?QA P2 - 02:08
- 3、我看resnet和gbdt很像,就是树模型换神经网络?QA P2 - 03:50
- 4、昨天用torch做梯度下降,根据课程书上描述的优化不会出现梯度消失报错w=lr*w.grad,但是换种写法w=w-lr*w.grad就会消失,这是为什么呢?都在torch.nograd下执行的。接前面补充下,不是梯度消失,是梯度那个参数变为falseQA P2 - 04:30
- 5、请问老师,训练集准确率不断增加,但是验证集的准确率大幅震荡,是过拟合的原因吗,还是有其他原因导致的?QA P2 - 05:35
- 6、请问增加的层数也是超参数吗?如何去加层呢?哪些层可以加?哪些参数不能动?我现在不知道如何改,有技巧吗?比如加ResNet-24?QA P2 - 06:36
- 7、请问如何理解yolo v4输出层(根据输出层获取预测框坐标等信息)?linux环境C++部署yolo v4推荐darknet,tensorflow还是其他框架C++ API(以部署简易性为标准)?QA P2 - 08:04
- 8、llc(last level cache)是显存还是缓存?llc是L1还是L2,L3?QA P2 - 08:17
- 9、请问加的层数也是超参数吗?可以加哪些网络层?加多少层合适?我现在不知道如何修改已有的网络。例如可以加入多个网络ResNet,然后加权取结果吗?谢谢QA P2 - 09:10QA P2 - 08:49
- 10、既然CPU这么垃圾,为啥现在生产的电脑不把GPU作为出厂设置和核心?QA P2 - 09:23
- 11、按行存储需要怎么改代码?QA P2 - 10:36
- 12、只能看到有文章预测未来计算设备都会专业化,而不是都在同样的“计算机”上,比如医疗专用计算设备、物理专用计算设备,请问您对这件事情怎么看?QA P2 - 11:45
- 13、C++有omp,python不也有multiprocessing吗?还是不行?QA P2 - 20:00
- 14、multiprocessing是会把计算分布到各个核上?QA P2 - 20:30
- 15、做计算时把for-loops运算尽可能通过向量化?QA P2 - 21:03
- 16、可视化时,常常需要把数据在CPU和GPU之间切换,如何不要频繁在CPU和GPU之间传输数据?常见的这样的错误操作有哪些?有命令能看到吗?怎么排查这种错误?QA P2 - 21:27
- 17、老师,go怎么样?未来有可能用于高性能CPU或者GPU计算编程语言吗?QA P2 - 24:34
- 18、rust语言做底层怎么样呢?QA P2 - 26:09
- 19、FORTRAN现在做底层开发的多吗?感觉一般都是用来做数值计算的?QA P2 - 26:38
- 20、研一刚进入科研,是一直看论文吗,代码要怎么练习才能复现论文呢?QA P2 - 27:04
- 21、我做了一个东西,现在想跟别人的算法去比,但是他原始的code是tf写的,我现在把他改写成torch版的,这样去比较会不会有争议?QA P2 - 29:30
- 22、还能再比较一下GPU、TPU、NPU吗?QA P2 - 30:49
- 23、paddlepaddle比pytorch有更多什么优势吗?QA P2 - 31:00
- 24、请问老师有没有推荐的适合做DL的笔记本,或者性价比高的云服务?QA P2 - 31:19
- 25、您怎么看矿机asic,这个转到深度学习芯片难度很大吗?QA P2 - 31:30
- 26、gpt3或者悟道2.0,也是按照咱们现在学的卷积网络这样构造的么?QA P2 - 31:41
- 27、请问下国内外有比较好的讨论这些硬件架构的技术网站吗?QA P2 - 31:56
- 28、pytorch的data loader有哪些常用的加速方法?QA P2 - 32:16
- 29、老师,分布式和高性能的区别是什么?为什么分布式做的好,高性能不行?QA P2 - 32:21
- 30、分布式追求的高性能应该是高并发,深度学习里面的高性能是大数据量计算,是这意思吗?QA P2 - 32:53
- 31、老师,请问未来对抗样本方向的发展前景如何呢?目前比较流行的几种对抗样本算法(白盒、黑盒)是什么呢?QA P2 - 33:51
- 32、这个QA是什么脚本写的?QA P2 - 35:16
- 33、深度学习可以做测量吗?目前是不是还是用传统算法做的多?比如测量一个物体的宽度?QA P2 - 36:01
- 34、go语言可以做分布式很好,但为什么高性能不行?老师刚才说hpc和分布式一回事QA P2 - 36:35
- 35、框架调用Cppapi和pyapi差距大多少?QA P2 - 38:03
- 36、yolo常用的除了darknet还有什么框架吗,想在自己的数据集上做迁移学习,但是darknet不好编译?QA P2 - 39:26
- 37、对国内出的AI芯片(比如:寒武纪、平头哥)怎么看?QA P2 - 39:53
- 38、做统计+神经网络的算法提升模型的鲁棒性以及可解释性,这个方向有做的吗,怎么入手啊?QA P2 - 40:53
- 39、矿机asic厂家转深度学习芯片,为什么您认为不行?哪方面难度比较大?QA P2 - 41:54
- 40、resnet只能用在图像领域吗?文本可以用吗?QA P2 - 43:59
- 41、老师说的julia用于机器学习和深度学习吗?QA P2 - 44:08
- 42、咱们课程会讲分布式推荐系统吗?国内现在有很多做推荐学习的QA P2 - 44:21
- 43、tf/mxnet的底层都是c++,但是有些模型为什么在infer的时候还是c++调用更快呢?QA P2 - 45:13
- 44、为啥v2版本的课程教的是pytorch而不是mxnet呢,是因为现在pytorchQA P2 - 45:41
- 45、arm被nvidia收购了,对移动端深度学习的影响?QA P2 - 47:15
- 46、rust高性能计算前景如何?QA P2 - 47:18
- 47、Xavier初始化可以和BN一起用吗?效果会更好吗?QA P2 - 47:30
- 48、老师能帮忙比较一下,做DL,打算投资一个WmaiGPU,一块3080ti和两块3060ti如何选择?QA P2 - 47:38
- 49、老师,我看了很多目标检测的paper,但是现在打比赛就是会用一些简单集成,数据增强,感觉没有什么模型原创性,怎样才能有更多的模型改造和优化能力?有系统的成长方法吗?QA P2 - 48:16
- 50、老师,GoogLeNet中的Inception如果使用ResNet的跳转连接,是否有意义?QA P2 - 48:51
- 51、我觉得huggingface做的很好,现在如果要在ai方向创业,做一个平台类型的东西,老师有什么想法吗?比如做一个平台让大家更加方便fine tuning(比sageMake更方便简单)QA P2 - 48:59
- 52、现在是不是公司用spark比用mapreduce多很多啊?QA P2 - 50:01
- 53、老师您认为自动驾驶也是烧钱,但是短时间很难看到落地和未来的是吗?就相当于您不看好nas一样?QA P2 - 50:21
- 54、老师,用现有的网络如ResNet在一幅大图像上做物体检测,是需要先把大图像切块,再分块输入网络进行检测吗?那切块的大小一般怎么确定?QA P2 - 51:01
----end----
其他参考:
1、《动手学深度学习》,课程安排,https://courses.d2l.ai/zh-v2/assets/pdfs/part-2_1.pdf
2、《动手学深度学习》,https://zh-v2.d2l.ai/chapter_computational-performance/hardware.html