发布时间:2023-04-17 08:00
一、CPU和GPU
1、CPU:中央处理器
作为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元
运算特点:
1)需要少量的运算单元,具有强大的逻辑运算能力
2)需要足够的控制单元实现复杂的数据控制和数据转发
3)需要足够的缓存单元去存放一些已经计算完成的结果,或者是后面马上要用到的数据
2、GPU:显卡/图像处理单元,用于渲染计算机图形
1)大量的运算单元:负责处理大量简单的计算
2)少量的控制单元和缓存单元:主要是负责合并和转发数据,对这两块的需求较小,所以占据GPU较小的空间
对于深度学习领域,GPU擅长的高度并行且简单的运算任务意义重大,以最常见的矩阵乘法为例,GPU可将矩阵乘法拆解成大量元素点积并行运算,因此运算速度极快,而CPU擅长复杂的逻辑或计算任务,由于核数远小于GPU因此并不擅长此类高度并行的计算。
对痴迷显卡的设备党来说,AMD与NVIDIA之争是大家喜闻乐见的话题。
但在深度学习领域,NVDIA的GPU更适合处理深度学习任务,大力推动深度学习领域也是NVIDIA厂商战略的一大重点。
3、GPU编程:
CUDA:是一种由NVIDIA推出的通用并行计算架构,该架构使GPU能够解决复杂的计算问题,目前支持C语言、C++和FORTRAN
cuBLAS—矩阵乘法;
cuDNN—卷积、前向和反向传播、BN、递归神经网络(常用的库)
数据读取造成的训练瓶颈:模型储存在GPU上,而数据集储存在硬盘上,可能使得读取数据成为训练速度的瓶颈——在CPU上使用多线程预读数据到内存上,从而将缓存数据比较高效地传递给GPU。
二、深度学习引擎框架
1、常见的深度学习框架
Caffe2\PyTorch—Facebook
TensorFlow—Google
Paddle—百度
CNTK—微软
MXNet—亚马逊
MindSpore—华为
2、符号式编程与命令式编程
symbolic-stype program中,需要先给出一个函数的定义(可能十分复杂)。当我们定义这个函数时,并不会做真正的数值计算。这类函数的定义中使用数值占位符,当给定真正的输入后,才会对这个函数进行编译计算。上述代码中,语句 C = B ∗ A C=B∗A C=B∗A 并不会触发真正的数值计算,但会生成一个计算图(也称symbolic graph)描述这个计算。大部分symbolic-style program都显性或隐性的包含一个编译的步骤,把计算转换成可以调用的函数。上面的例子中,数值计算仅仅在代码最后一行进行,symbolic program一个重要特点是其明确有构建计算图和生成可执行代码两个步骤。
3、计算图:用于描述运算的有向无环图,采用计算图的好处是不仅让运算流的表达更加简洁清晰,更重要的是方便求导计算梯度
计算图的链式法则静态图与动态图:
动态图意味着计算图的构建和计算同时发生(define by run)。这种机制由于能够实时得到中间结果的值,使得调试更加容易,同时我们将大脑中的想法转化为代码方案也变得更加容易,对于编程实现来说更友好。Pytorch使用的就是动态图机制,因此它更易上手,风格更加pythonic,大受科研人员的喜爱。
静态图则意味着计算图的构建和实际计算是分开(define and run)的。在静态图中,会事先了解和定义好整个运算流,这样之后再次运行的时候就不再需要重新构建计算图了(可理解为编译),因此速度会比动态图更快,从性能上来说更加高效,但这也意味着你所期望的程序与编译器实际执行之间存在着更多的代沟,代码中的错误将难以发现,无法像动态图一样随时拿到中间计算结果。Tensorflow默认使用的是静态图机制,这也是其名称的由来,先定义好整个计算流(flow),然后再对数据(tensor)进行计算。
一个例子比较静态图/符号式编程/TensorFlow与动态图/命令式编程/PyTorch:
Tensorflow在静态图的模式下,每次运算使用的计算图都是同一个,因此不能直接使用 Python 的 while 循环语句,而是要使用其内置的辅助函数 tf.while_loop,而且还要tf.Session().run()之类的乱七八糟..
而Pytorch是动态图的模式,每次运算会构建新的计算图,在编程实现上不需要额外的学习成本(当然首先你得会Python)
TensorFlow:
编写计算大致分为两个部分:定义计算图+执行计算
创建tf.placeholder(占位符)对象作为计算图输入节点
tf.gradients()方法计算梯度
调用tf.Session()运行计算图,session.run()执行运算
使用字典储存数据初始化方法
将权重矩阵作为变量加入到计算图中以解决数据在CPU与GPU之间来回流动造成训练性能下降,但是需明确在session中需更新权重矩阵操作的技巧:在计算途中加入不占内存的仿制节点,使仿制节点的更新依赖于权重矩阵的更新,此类操作封装在TF的优化器中,如tf.train.GradientDescentOptimizer()函数
PyTorch
三层抽象:张量对象Tensor(可以在GPU上运行的Numpy);变量对象—计算图中的节点;模组对象(Module)——神经网络层
抽象层次很高,更多的关注模型的架构而非底层计算图的实现
变量带有二值标记relquires_grad = True/False来决定是否需要计算该变量的梯度
需要定义前向计算forward,后向运算通常由.backward()方法自动计算梯度
nn包封装了大多数常见的层及一些损失函数等
每次前向传播都建立了一张新的计算图
torch.optim封装了常见的优化器,optimizer.step()用于更新模型中所有需要更新的参数
DataLoader小批量多线程读取数据并打包
比较:
1、PT采用命令式编程,符合初学者编程习惯,易于理解但效率较低;TS采用符号式编程,先定义好静态图再调用session运行,实现复杂但效率较高
2、PT计算图为动态图,模型灵活方便调试;TS采用静态图,计算图一旦定义不可随意更改,对于控制流或循环命令需要采用特殊方法实现
综合来看,TS效率更高,更适于产业化,更倾向于针对所有问题的架构;PT更加灵活,更具有创新性和创造力,更适于科研
PS:本文主要对斯坦福李飞飞cs231n计算机视觉课程P18进行简要总结,笔者额外查阅了一些资料作为知识补充,部分内容参考来源:
深度学习框架 の 动态图 vs 静态图
深度学习框架:动态图 vs 静态图
神经网络——动态图和静态图