深度学习的算法是高度结构化的,主要组成部分是线性变换、激活函数、反向传播和梯度优化等模块,实际应用中,为了方便算法的实现,常会将算法模型抽象成对张量的一系列计算,并将计算设计的一些算法抽象层应用程序接口API供用户调用,从而实现各种各样的深度学习算法
深度学习的框架层出不穷,不同的框架的功能也是千差万别的,但本质上,所有的深度学习框架都支持一些基本的功能,并通过组合这些功能,构建复杂的神经网络模型
深度学习框架的计算图
为了计算权重梯度和数据梯度,神经网络还应当记录运算的过程,并构建计算图
构建计算图的方法
- 静态图:在计算之前预先构建一个计算图,图中的节点是运算操作,包括矩阵的乘法和加减等,图中的边则是参与运算的张量
- 动态图:在计算过程中逐渐构建计算图,最后得到神经网络的输出结果,如果要进行反向传播的九三,传播的路径只有在计算图构建完成之后才能获得
支持静态计算图的框架包括TensorFlow、Caffe,使用框架的时候,一般使用配置文件或者不同语言的接口函数先构建出深度学习模型对应的静态图,然后在静态图中输入张量,框架的执行引擎会根据输入的张量进行计算,最后输出深度学习的结果
静态图的前向和反向传播路径在计算之前就已经被构建了,所以是已知的,由于计算图在实际发生计算之前就已经存在,所以执行引擎可以在计算之前对静态图进行优化;同时由于计算图是固定的,所以不必每次都重新构建,有效的减少了计算图的构建时间,相对来说效率较高,但是静态图为了效率牺牲了灵活性,构建完成之后无法修改,故自爱静态图中使用条件控制会不大方便
因为在计算图中需要有对应条件的控制语句,增加了控制语句之后,需要计算条件的所有的不同的分支,也会给计算图增加一定的消耗;其次在框架的易用性上,静态图只能检查一些静态参数的合理性——在执行时暴露的一些问题可能无法在计算图的构建阶段预先排查,只能在引擎执行的时候被发现,在代码调试阶段,静态图也比较低效,使得基于静态图的深度学习框架上手比较困难
使用动态计算图的框架有Pytorch和Chainer等,对动态图来说,条件控制语句非常简单,可以使用python等现成的条件控制语句。动态计算图的另一个特点是方便使用,可以实时输出深度学习模型的中间张量——调试非常方便而且很容易得到出错的原因,动态图的构建也是深度学习框架的主流发展方向
深度学习的自动求导和反向传播
除了计算图的构建,深度学习框架的另一个特性就是能够自动求导
一般深度学习模型在训练的时候,需要构建计算图,计算图的最后就是输出一个损失函数的标量值。从标量值反推计算图权重张量的梯度的过程称为自动求导
在静态图的计算中,构建前向的计算操作的同时也会构建一个反向传播的梯度计算,这样前向的计算图构建完毕伴随着反向计算图的构建完毕,有了损失函数之后,就可以从损失函数所在的张量的边开始逐渐沿着反向计算图获取对应的梯度
与静态图的构建相比,动态图在构建前向计算图的时候则是给每个输出张量绑定一个反向传播的梯度计算函数,当计算图达到最终的损失函数的张量的时候,直接调用该张量对应的反向传播函数,并不大根据前向计算图进行递归的反向传播函数的调用,最后到达输入张量,即可求得每个权重张量对应的梯度张量
在损失函数优化部分,基于静态计算图的深度学习框架直接在计算图中集成了优化器,在求出权重张量梯度之后直接执行优化器的计算图,更新权重张量的值。与静态计算图相比,动态计算图则是将优化器绑定在了对应的梯度张量,优化器的工作是根据绑定的梯度张量来更新权重张量,同样,动态图在损失函数的优化方面,可以更加灵活的进行设计——比如可以指定一些权重使用一个学习率,另一些权重使用另外一个学习率
Pytorch框架
Pytorch使用了动态计算图,方面初学者上手,在保持API简单性的同时,提供了强大的可扩展性,包括自由定制张量计算操作、CPU/GPU上的易购操作以及并行训练环境等
Pytorch的安装过程
2023最新pytorch快速安装指南(超详细版)_python_脚本之家
Python安装Pytorch教程(图文详解)-CSDN博客
Pytorch包的结构
Pytorch主要包括下面16个模块
1、torch模块
torch模块包含了一些Pytorch常用的激活函数以及对张量的一些操作,比如矩阵的乘法、张量元素的选择。需要注意的是:这些操作的对象大多都是张量,传参类型错误的话会报错;另外还有一些函数增产生特殊形状的张量:torch.zeros 产生元素全为0的张量, torch.randn产生元素服从正态分布的张量
2、torch.Tensor模块
此模块定义了张量的不同类型,其中的张量有不同的类型,如单精度,双精度浮点、整数类型等,而且张量还具有一定的维数和形状
同时张量的类中还包含一系列的方法,返回新的张量或者更改当前的张量,torch.Storage负责torch.Tensor底层的数据存储,即前面提到的为一个张量分配恋雪的一维内存地址(用于存储相同类型的一些列元素,数目则为张量的总元素数量)
如果张量的某个方法会返回张量,按照Pytorch中的命名规则,如果张量方法后缀带下划线,则该方法会修改张量本身的数据,反之则会返回新的张量,如 Tensor.add 方法会让当前的张量和输入参数张量做加法,返回新的张量,而 Tensor.add_ 方法会修改当前张量的值,新的值为旧的值和输入参数之和
3、torch.sparse模块
torch.sparse模块定义了稀疏张量,其中构造的稀疏张量采用的是 COO(Coordinate)格式,主要方法是用一个长整型定义非零元素的位置,用浮点数张量定义对应非零元素的值
稀疏张量之间可以做元素的加减乘除运算和矩阵乘法
4、torch.cuda模块
torch.cuda模块定义了与CUDA运算相关的一系列函数,包括但不限于检查系统的CUDA能否使用,当前进程对应的GPU序号(在多GPU的情况下),消除GPU上的缓存,设置GPU的计算流(Stream),同步GPU上执行的所有核函数(Kernel)等
5、torch.nn模块
torch.nn模块是Pytorch神经网络模块化的核心,这个模块定义了一系列模块,包括卷积层 nn.ConvNd(N=1,2,3)和线性层(全连接层)nn.Linear 等
构建深度学习模型的时候,可以通过继承 nn.Module 类并重写forward方法来实现一个新的神经网络,另外 torch.nn 中也定义了一系列的损失函数,包括平方损失函数、交叉熵损失函数等,一般来说,torch.nn 里定义的神经网络模块都有参数,可以使用优化其对这些参数进行训练
6、torch.nn.functional 函数
torch.nn.functional 函数模块是Pytorch函数模块,定义了一些和神经网络相关的函数,包括卷积函数和池化函数,这些也是深度学习模型构建的基础,torch.nn 模块中定义的模块一般会用 torch.nn.functional 函数模块里的函数,如 nn.ConvNd 模块会调用 torch.nn.functional.convNd 函数;另外 torch.nn.functional 还定义了一些不常用的激活函数,如 torch.nn.functional .relu6 和 torch.nn.functional.elu 等
7、torch.nn.init模块
torch.nn.init模块定义了神经网络权重的初始化,如果权重取值不合适,会导致后面的优化过程很慢,甚至不熟练——这个模块就是为了解决神经网络权重的初始化问题,其中使用了很多的初始化方法,包括均匀初始化 torch.nn.init.uniform_ 和 torch.nn.init.normal_ 等,这些方法会直接改变传入张量的值,同时返回改变后的张量
8、torch.optim模块
torch.optim模块定义了一系列的优化器,包括但不限于随机梯度下降算法、AdaGrad算法、RMSProp算法和Adam算法等。此模块还包含了学习率衰减的算法的子模块,即 torch.optim.Ir_scheduler,这个子模块中包含了如学习率阶梯下降算法 torch.opt.Ir_scheduler.StepLR 和预先退火算法 torch.opt.Ir_scheduler.CosineAnnealingLR 算法
9、torch.autograd模块
torch.autograd模块是Pytorch的自动微分算法模块,定义了一系列的自动微分函数,包括 torch.autograd.backward 函数,主要用于在求得损失函数之后进行反向梯度传播,torch.autograd.grad 函数用于一个标量张量(即只有一个分量的张量)对另一个张量求导,以及在代码中设置不参与求导的部分
另外这个模块还内置了数值梯度功能和检查自动微分引擎是否输出正确结果的功能
10、torch.distrubuted模块
torch.distrubuted模块是Pytorch的分布式计算模块,主要功能是提供pytorch并行运算环境,其主要之后的后端有MPI、GIoo、NCCL三种,Pytorch的分布式工作原理主要是启动多个并行的进程,每个进程都拥有一个模型的备份,然后输入密码不同的训练数据到多个并行的进程,计算损失函数,每个进程独立地做反向传播,最后所有进程权重张量的梯度做归约
用到后端的部分主要是数据的广播和数据的收集,其中,前者是把数据从一个节点传播到另一个节点(进程),比如归约后的梯度张量的传播,后者则是把数据从其他节点转移到当前的节点(进程),比如把梯度张量从其他节点转移到某个特定的节点,然后对所有的张量求平均,Pytorch的分布式计算模块不但提供了一个后端的包装,还提供了一些启动方式来启动多个进程,包括但不限于通过网络(TCP)、通过环境变量、通过共享文件等
11、torch.distributions模块
torch.distributions模块提供了一系列类,使得pytorch能够对不同的分布进行采样,并且生成概率采样过程的计算图
在强化学习中,经常会采用一个深度学习模型来模拟在不同环境条件下采取的策略,需要根据概率对策略进行采样来模拟当前的策略概率分布,最后用梯度下降方法来让最优策略的概率最大
实际上由于采样的输出结果是离散的,无法直接求导,所以不可能使用反向传播算法来优化网络,torch.distributions模块存在的目的就是为了解决这个问题,我们可以结合torch.distributions.Categorical 进行采样,然后使用对数求导技巧来规避这个问题
12、torch.hub模块
torch.hub模块提供了一系列的模型供用户使用,可以通过torch.hub.list函数来获取某个模型镜像站点的模型信息,通过torch.hub.load来载入预训练的模型,载入后的模型可以保存到本地,并且可以看到这些模型对应类支持的方法
13、torch.jit模块
torch.jit模块是Pytorch模块的即时编译器,这个模块存在的意义就是把Pytorch的动态图转换为可以优化和序列化的静态图,其主要工作的原理是通过预先定义好的张量,追踪整个动态图的构建过程,得到最终构建出来的动态图,然后转化为静态图
通过JIT得到的静态图可以被保存,并且被Pytorch其他的前端支持
另外JIT也可用于生成其他格式的神经网络描述文件,如ONNX,需要注意的是,torch.jit 支持两种模式,即脚本模式和追踪模式,两者都能构建静态图,区别在于前者支持控制流,后者不支持,但是前者支持的神经网络模块比后者少,如脚本模式不支持torch.nn.GRU
14、torch.multiprocessing模块
torch.multiprocessing模块定义了pytorch中的多进程API,通过这个模块,可以启动不同的进程,每个进程运行在不同的深度学习模型上,并且能够在进程间共享张量,共享的张量可以在CPU上,也可以在GPU上,多进程API还提供了与Python原生的多进程API相同的一系列函数,包括锁(Lock)和队列(Queue)等
15、torch.random模块
torch.random模块提供了一系列的方法来保存和设置随机数生成器的状态,包括使用get_rng_state函数获取当前随机数生成器的状态,set_rng_state函数设置当前随机数生成器的状态,并且可以使用 manual_seed 函数来设置随机种子,也可使用 initial_seed 函数来得到程序初始的随机种子,因为神经网络的训练是一个随机的过程,包括数据的输入、权重的初始化都具有一定的随机性,设置一个统一的随机种子可以帮我们有效的测试不同神经网络结构的表现,有助于调试神经网络的结构
16、torch.onnx模块
torch.onnx模块定义了Pytorch导出和载入ONNX格式的深度学习模型描述文件,此格式的文件方便了不同深度学习模型框架直接交换模型
Pytorch的辅助工具模块
torch.utils 提供了一系列的工具来帮助神经网络的训练、测试和优化,主要有以下6个子模块
1、torch.utils.bottleneck模块
torch.utils.bottleneck模块用于检查深度学习模型中模块的运行时间,从而找到导致性能瓶颈的那些模块,通过优化那些模块的运行时间,优化整个深度学习模型的性能
2、torch.utils.checkpoint模块
torch.utils.checkpoint 可以用来节约深度学习使用的内存,因为进行梯度反向传播的时候,构架计算图要保存中间的数据,这些数据大大增加了深度学习的内存消耗,为了减少内存消耗,让迷你批次的大小得到提高,从而提升深度学习模型的性能和优化时的稳定性,可以使用这个模块记录中间数据的计算过程,然后丢弃这些数据,等到需要用的时候再重新计算这些数据
这个模块主要是以计算时间换内存空间,使用得当的话,就可以大大提升模型的性能
3、torch.utils.cpp_extension模块
torch.utils.cpp_extension模块定义了pytorch的C++扩展,主要包含:CPPExtension定义了使用C++编写的扩展模块的源代码信息,CUDAExtension则定义了C++/CUDA编写的扩展模块的源代码信息
底层上,这个扩展模块使用了pybind11,保持了接口的轻量性并使得pytorch易于扩展
4、torch.utils.data模块
torch.utils.data模块引入了数据集(Dataset)和数据载入器(DataLoader)的概念,前者代表了所有数据的数据集,通过索引能够得到某一条特定的数据,后者通过对数据的包装,可以对数据集进行随机排列和采样,得到一系列打乱排序的迷你批次
5、torch.utils.dlpacl模块
torch.utils.dlpacl模块定义了Pytorch张量和DLPack张量存储格式之间的转换,用于不同框架之间张量数据的交换
6、torch.utils.tensorboard模块
torch.utils.tensorboard模块是Pytorch对TensorBoard数据可视化工具的支持,TensorBoard原来是TensorFlow自带的数据可视化工具,能够显示深度学习模型在训练过程中的损失函数、张量权重的直方图,以及模型训练过程中输出的文本、退选哪个和视频等
TensorBoard的功能非常强大,而且是基于可交互的动态网页设计的,使用者可以通过预先提供一系列的功能来输出特定的训练过程的细节(如神经网络的权重的直方图或者训练过程中某一段时间的损失函数)可视化之后,在pytorch的训练中,可以方便的观察中间输出的张量,也可以方便地调试深度学习模型