PyTorch的使用经验都有哪些(pytorch功能)

用Pytorch做深度学习 第一部分

大家好,今天小编来为大家解答PyTorch的使用经验都有哪些这个问题,cuda不建议使用二维数组很多人还不知道,现在让我们一起来看看吧!

本文目录

  1. PyTorch的使用经验都有哪些
  2. 什么是Scikit-learn
  3. C语言如何利用数组批量处理数据

PyTorch的使用经验都有哪些

PyTorch的构建者表明,PyTorch的哲学是解决当务之急,也就是说即时构建和运行计算图。目前,PyTorch也已经借助这种即时运行的概念成为最受欢迎的框架之一,开发者能快速构建模型与验证想法,并通过神经网络交换格式ONNX在多个框架之间快速迁移。本文从基本概念开始介绍了PyTorch的使用方法、训练经验与技巧,并展示了可能出现的问题与解决方案。

项目地址:https://github.com/Kaixhin/grokking-pytorch

PyTorch是一种灵活的深度学习框架,它允许通过动态神经网络(例如利用动态控流——如if语句或while循环的网络)进行自动微分。它还支持GPU加速、分布式训练以及各类优化任务,同时还拥有许多更简洁的特性。以下是作者关于如何利用PyTorch的一些说明,里面虽然没有包含该库的所有细节或最优方法,但可能会对大家有所帮助。

神经网络是计算图的一个子类。计算图接收输入数据,数据被路由到对数据执行处理的节点,并可能被这些节点转换。在深度学习中,神经网络中的神经元(节点)通常利用参数或可微函数转换数据,这样可以优化参数以通过梯度下降将损失最小化。更广泛地说,函数是随机的,图结构可以是动态的。所以说,虽然神经网络可能非常适合数据流式编程,但PyTorch的API却更关注命令式编程——一种编程更常考虑的形式。这令读取代码和推断复杂程序变得简单,而无需损耗不必要的性能;PyTorch速度很快,且拥有大量优化,作为终端用户你毫无后顾之忧。

本文其余部分写的是关于grokkingPyTorch的内容,都是基于MINIST官网实例,应该要在学习完官网初学者教程后再查看。为便于阅读,代码以块状形式呈现,并带有注释,因此不会像纯模块化代码一样被分割成不同的函数或文件。

Pytorch基础

PyTorch使用一种称之为imperative/eager的范式,即每一行代码都要求构建一个图,以定义完整计算图的一个部分。即使完整的计算图还没有构建好,我们也可以独立地执行这些作为组件的小计算图,这种动态计算图被称为「define-by-run」方法。

PyTorch张量

正如PyTorch文档所说,如果我们熟悉NumPy的多维数组,那么Torch张量的很多操作我们能轻易地掌握。PyTorch提供了CPU张量和GPU张量,并且极大地加速了计算的速度。

从张量的构建与运行就能体会,相比TensorFLow,在PyTorch中声明张量、初始化张量要简洁地多。例如,使用torch.Tensor(5,3)语句就能随机初始化一个5×3的二维张量,因为PyTorch是一种动态图,所以它声明和真实赋值是同时进行的。

在PyTorch中,torch.Tensor是一种多维矩阵,其中每个元素都是单一的数据类型,且该构造函数默认为torch.FloatTensor。以下是具体的张量类型:

除了直接定义维度,一般我们还可以从Python列表或NumPy数组中创建张量。而且根据使用Python列表和元组等数据结构的习惯,我们可以使用相似的索引方式进行取值或赋值。PyTorch同样支持广播(Broadcasting)操作,一般它会隐式地把一个数组的异常维度调整到与另一个算子相匹配的维度,以实现维度兼容。

自动微分模块

TensorFlow、Caffe和CNTK等大多数框架都使用静态计算图,开发者必须建立或定义一个神经网络,并重复使用相同的结构来执行模型训练。改变网络的模式就意味着我们必须从头开始设计并定义相关的模块。

但PyTorch使用的技术为自动微分(automaticdifferentiation)。在这种机制下,系统会有一个Recorder来记录我们执行的运算,然后再反向计算对应的梯度。这种技术在构建神经网络的过程中十分强大,因为我们可以通过计算前向传播过程中参数的微分来节省时间。

从概念上来说,Autograd会维护一个图并记录对变量执行的所有运算。这会产生一个有向无环图,其中叶结点为输入向量,根结点为输出向量。通过从根结点到叶结点追踪图的路径,我们可以轻易地使用链式法则自动计算梯度。

在内部,Autograd将这个图表征为Function对象的图,并且可以应用apply()计算评估图的结果。在计算前向传播中,当Autograd在执行请求的计算时,它还会同时构建一个表征梯度计算的图,且每个Variable的.grad_fn属性就是这个图的输入单元。在前向传播完成后,我们可以在后向传播中根据这个动态图来计算梯度。

PyTorch还有很多基础的模块,例如控制学习过程的最优化器、搭建深度模型的神经网络模块和数据加载与处理等。这一节展示的张量与自动微分模块是PyTorch最为核心的概念之一,读者可查阅PyTorch文档了解更详细的内容。

下面作者以MNIST为例从数据加载到模型测试具体讨论了PyTorch的使用、思考技巧与陷阱。

PyTorch实用指南

导入

importargparseimporttorchfromtorchimportnn,optimfromtorch.nnimportfunctionalasFfromtorch.utils.dataimportDataLoaderfromtorchvisionimportdatasets,transforms

除了用于计算机视觉问题的torchvision模块外,这些都是标准化导入。

设置

parser=argparse.ArgumentParser(description='PyTorchMNISTExample')parser.add_argument('--batch-size',type=int,default=64,metavar='N',help='inputbatchsizefortraining(default:64)')parser.add_argument('--epochs',type=int,default=10,metavar='N',help='numberofepochstotrain(default:10)')parser.add_argument('--lr',type=float,default=0.01,metavar='LR',help='learningrate(default:0.01)')parser.add_argument('--momentum',type=float,default=0.5,metavar='M',help='SGDmomentum(default:0.5)')parser.add_argument('--no-cuda',action='store_true',default=False,help='disablesCUDAtraining')parser.add_argument('--seed',type=int,default=1,metavar='S',help='randomseed(default:1)')parser.add_argument('--save-interval',type=int,default=10,metavar='N',help='howmanybatchestowaitbeforecheckpointing')parser.add_argument('--resume',action='store_true',default=False,help='resumetrainingfromcheckpoint')args=parser.parse_args()use_cuda=torch.cuda.is_available()andnotargs.no_cudadevice=torch.device('cuda'ifuse_cudaelse'cpu')torch.manual_seed(args.seed)ifuse_cuda:torch.cuda.manual_seed(args.seed)

argparse是在Python中处理命令行参数的一种标准方式。

编写与设备无关的代码(可用时受益于GPU加速,不可用时会倒退回CPU)时,选择并保存适当的torch.device,不失为一种好方法,它可用于确定存储张量的位置。关于与设备无关代码的更多内容请参阅官网文件。PyTorch的方法是使用户能控制设备,这对简单示例来说有些麻烦,但是可以更容易地找出张量所在的位置——这对于a)调试很有用,并且b)可有效地使用手动化设备。

对于可重复实验,有必要为使用随机数生成的任何数据设置随机种子(如果也使用随机数,则包括随机或numpy)。要注意,cuDNN用的是非确定算法,可以通过语句torch.backends.cudnn.enabled=False将其禁用。

数据

train_data=datasets.MNIST('data',train=True,download=True,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,),(0.3081,))]))test_data=datasets.MNIST('data',train=False,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,),(0.3081,))]))train_loader=DataLoader(train_data,batch_size=args.batch_size,shuffle=True,num_workers=4,pin_memory=True)test_loader=DataLoader(test_data,batch_size=args.batch_size,num_workers=4,pin_memory=True)

torchvision.transforms对于单张图像有非常多便利的转换工具,例如裁剪和归一化等。

DataLoader包含非常多的参数,除了batch_size和shuffle,num_workers和pin_memory对于高效加载数据同样非常重要。例如配置num_workers>0将使用子进程异步加载数据,而不是使用一个主进程块加载数据。参数pin_memory使用固定RAM以加速RAM到GPU的转换,且在仅使用CPU时不会做任何运算。

模型

classNet(nn.Module):def__init__(self):super(Net,self).__init__()self.conv1=nn.Conv2d(1,10,kernel_size=5)self.conv2=nn.Conv2d(10,20,kernel_size=5)self.conv2_drop=nn.Dropout2d()self.fc1=nn.Linear(320,50)self.fc2=nn.Linear(50,10)defforward(self,x):x=F.relu(F.max_pool2d(self.conv1(x),2))x=F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)),2))x=x.view(-1,320)x=F.relu(self.fc1(x))x=self.fc2(x)returnF.log_softmax(x,dim=1)model=Net().to(device)optimiser=optim.SGD(model.parameters(),lr=args.lr,momentum=args.momentum)ifargs.resume:model.load_state_dict(torch.load('model.pth'))optimiser.load_state_dict(torch.load('optimiser.pth'))

神经网络初始化一般包括变量、包含可训练参数的层级、可能独立的可训练参数和不可训练的缓存器。随后前向传播将这些初始化参数与F中的函数结合,其中该函数为不包含参数的纯函数。有些开发者喜欢使用完全函数化的网络(如保持所有参数独立,使用F.conv2d而不是nn.Conv2d),或者完全由layers函数构成的网络(如使用nn.ReLU而不是F.relu)。

在将device设置为GPU时,.to(device)是一种将设备参数(和缓存器)发送到GPU的便捷方式,且在将device设置为CPU时不会做任何处理。在将网络参数传递给优化器之前,把它们传递给适当的设备非常重要,不然的话优化器不能正确地追踪参数。

神经网络(nn.Module)和优化器(optim.Optimizer)都能保存和加载它们的内部状态,而.load_state_dict(state_dict)是完成这一操作的推荐方法,我们可以从以前保存的状态字典中加载两者的状态并恢复训练。此外,保存整个对象可能会出错。

这里没讨论的一些注意事项即前向传播可以使用控制流,例如一个成员变量或数据本身能决定if语句的执行。此外,在前向传播的过程中打印张量也是可行的,这令debug更加简单。最后,前向传播可以使用多个参数。以下使用间断的代码块展示这一点:

defforward(self,x,hx,drop=False):

hx2=self.rnn(x,hx)

print(hx.mean().item(),hx.var().item())

ifhx.max.item()>10orself.can_dropanddrop:

returnhx

else:

returnhx2

训练

model.train()train_losses=[]fori,(data,target)inenumerate(train_loader):data,target=data.to(device),target.to(device)optimiser.zero_grad()output=model(data)loss=F.nll_loss(output,target)loss.backward()train_losses.append(loss.item())optimiser.step()ifi%10==0:print(i,loss.item())torch.save(model.state_dict(),'model.pth')torch.save(optimiser.state_dict(),'optimiser.pth')torch.save(train_losses,'train_losses.pth')

网络模块默认设置为训练模式,这影响了某些模块的工作方式,最明显的是dropout和批归一化。最好用.train()对其进行手动设置,这样可以把训练标记向下传播到所有子模块。

在使用loss.backward()收集一系列新的梯度以及用optimiser.step()做反向传播之前,有必要手动地将由optimiser.zero_grad()优化的参数梯度归零。默认情况下,PyTorch会累加梯度,在单次迭代中没有足够资源来计算所有需要的梯度时,这种做法非常便利。

PyTorch使用一种基于tape的自动化梯度(autograd)系统,它收集按顺序在张量上执行的运算,然后反向重放它们来执行反向模式微分。这正是为什么PyTorch如此灵活并允许执行任意计算图的原因。如果没有张量需要做梯度更新(当你需要为该过程构建一个张量时,你必须设置requires_grad=True),则不需要保存任何图。然而,网络倾向于包含需要梯度更新的参数,因此任何网络输出过程中执行的计算都将保存在图中。因此如果想保存在该过程中得到的数据,你将需要手动禁止梯度更新,或者,更常见的做法是将其保存为一个Python数(通过一个Python标量上的.item())或者NumPy数组。更多关于autograd的细节详见官网文件。

截取计算图的一种方式是使用.detach(),当通过沿时间的截断反向传播训练RNN时,数据流传递到一个隐藏状态可能会应用这个函数。当对损失函数求微分(其中一个成分是另一个网络的输出)时,也会很方便。但另一个网络不应该用「loss-examples」的模式进行优化,包括在GAN训练中从生成器的输出训练判别器,或使用价值函数作为基线(例如A2C)训练actor-critic算法的策略。另一种在GAN训练(从判别器训练生成器)中能高效阻止梯度计算的方法是在整个网络参数上建立循环,并设置param.requires_grad=False,这在微调中也很常用。

除了在控制台/日志文件里记录结果以外,检查模型参数(以及优化器状态)也是很重要的。你还可以使用torch.save()来保存一般的Python对象,但其它标准选择还包括内建的pickle。

测试

model.train()train_losses=[]fori,(data,target)inenumerate(train_loader):data,target=data.to(device),target.to(device)optimiser.zero_grad()output=model(data)loss=F.nll_loss(output,target)loss.backward()train_losses.append(loss.item())optimiser.step()ifi%10==0:print(i,loss.item())torch.save(model.state_dict(),'model.pth')torch.save(optimiser.state_dict(),'optimiser.pth')torch.save(train_losses,'train_losses.pth')

为了早点响应.train(),应利用.eval()将网络明确地设置为评估模式。

正如前文所述,计算图通常会在使用网络时生成。通过withtorch.no_grad()使用no_grad上下文管理器,可以防止这种情况发生。

其它

内存有问题?可以查看官网文件获取帮助。

CUDA出错?它们很难调试,而且通常是一个逻辑问题,会在CPU上产生更易理解的错误信息。如果你计划使用GPU,那最好能够在CPU和GPU之间轻松切换。更普遍的开发技巧是设置代码,以便在启动合适的项目(例如准备一个较小/合成的数据集、运行一个train+testepoch等)之前快速运行所有逻辑来检查它。如果这是一个CUDA错误,或者你没法切换到CPU,设置CUDA_LAUNCH_BLOCKING=1将使CUDA内核同步启动,从而提供更详细的错误信息。

torch.multiprocessing,甚至只是一次运行多个PyTorch脚本的注意事项。因为PyTorch使用多线程BLAS库来加速CPU上的线性代数计算,所以它通常需要使用多个内核。如果你想一次运行多个任务,在具有多进程或多个脚本的情况下,通过将环境变量OMP_NUM_THREADS设置为1或另一个较小的数字来手动减少线程,这样做减少了CPUthrashing的可能性。官网文件还有一些其它注意事项,尤其是关于多进程。

什么是Scikit-learn

作为一个适用于Python编程语言的机器学习(ML)库,Scikit-learn拥有大量算法,可供程序员和数据科学家在机器学习模型中轻松部署。

什么是Scikit-learn?

Scikit-learn是一个热门且可靠的机器学习库,拥有各种算法,同时也是用于ML可视化、预处理、模型拟合、选择和评估的工具。

Scikit-learn基于NumPy、SciPy和matplotlib构建,并具有大量用于分类、回归和集群的高效算法。其中包括支持向量机、随机森林、梯度提升、k-means和DBSCAN。

Scikit-learn拥有一致且设计高效的API、适用于大多数算法的丰富文档以及大量在线教程,因此相对易于开发。

当前版本可用于Linux、MacOS和Windows等热门平台。

为何选择Scikit-learn?

得益于其相对易于使用、且设计周到又充满热情的社区,Scikit-learnAPI已成为机器学习实施的实际标准。

Scikit-learn为ML模型构建、拟合及评估提供了以下模块:

预处理是指Scikit-learn工具,这些工具可用于数据分析期间的特征提取和归一化。分类是指一组工具,这组工具可识别机器学习模型中与数据相关的类别。例如,这些工具还可用于将电子邮件分类为有效邮件或垃圾邮件。实际上,分类可确定目标所属的类别。回归是指ML模型的创建,该模型试图理解输入和输出数据(例如行为或股票价格)之间的关系。回归可预测与目标关联的连续值属性。Scikit-learn中的聚类工具自动将具有相似特征的数据以集的形式进行分组,例如根据物理位置排列成集的客户数据。降维可减少用于分析的随机变量数量。例如,为了提升可视化的效率,可能会将离散数据排除在外。模型选择是指算法及其提供相应工具的能力,并且这些工具能够比较、验证和选择最佳参数,以将其用于数据科学机器学习项目。流程是指用于构建模型工作流程的实用程序。机器学习可视化可支持快速绘图和视觉调整。

Scikit-learn的工作原理

Scikit-learn主要采用Python编写,并使用NumPy进行高性能线性代数以及数组运算。一些核心Scikit-learn算法则采用Cython编写,以提升整体性能。

作为更高级别的库,它包含各种机器学习算法的几种实施,Scikit-learn让用户仅使用几行代码即可构建、训练和评估模型。

Scikit-learn还提供一套统一的高级别API,以供构建ML流程或工作流程使用。

在Scikit-learnML流程中,您可以通过转换器传递数据并提取特征,使用估测器生成模型,并使用评估器测量模型的准确性。

Transformer:这是一种转换或输入数据,以进行预处理的算法。Estimator:这是一种机器学习算法,用于训练或拟合数据,以构建可用于预测的模型。流程:流程将多个转换器和估测器相连接,从而指定ML工作流程。

GPU加速的Scikit-learnAPI和端到端数据科学

在架构方面,CPU仅由几个具有大缓存内存的核心组成,一次只可以处理几个软件线程。相比之下,GPU由数百个核心组成,可以同时处理数千个线程。

基于CUDA-XAI?创建的NVIDIARAPIDS?开源软件库套件使您完全能够在GPU上执行端到端数据科学和分析流程。此套件依靠NVIDIA?CUDA?基元进行低级别计算优化,但通过用户友好型Python接口能够实现GPU并行化和高带宽显存速度。

RAPIDScuML的机器学习算法和数学基元遵循熟悉的类似于scikit-learn的API。单块GPU和大型数据中心部署均支持XGBoost、随机森林等主流算法。针对大型数据集,相较于同等功效的CPU,这些基于GPU的实施方案能够以10到50倍的速度更快地完成任务。

借助RAPIDSGPUDataFrame,数据可以通过一个类似Pandas的接口加载到GPU上,然后用于各种连接的机器学习和图形分析算法,而无需离开GPU。这种级别的互操作性可通过ApacheArrow等库实现,并且可加速端到端流程(从数据准备到机器学习,再到深度学习)。

RAPIDS支持在许多热门数据科学库之间共享设备内存。这样可将数据保留在GPU上,并省去了来回复制主机内存的高昂成本。

*本文转自NVIDIA英伟达

C语言如何利用数组批量处理数据

C语言数组无非就是一组连续的元素,在内存中连续存储。

最简单想到的办法自然就是挨个处理。这个就是一个简单循环结构。

但在图形图像处理像素数组时,一些核心代码会使用SIMD,比如一条指令加载4个像素到寄存器,再若干条指令直接处理这4个像素(加减乘除,逻辑,位移等),最后一条指令把4个像素处理的结果存回内存。SIMD大量用于图像处理,多媒体等。具有像素数组这样的应用。

人工智能的向量叉积运算,也可以用SIMD来运算叉积的结果。

SIMD的结构就像循环中,每次循环处理4个数据。

最后还有多线程或者OpenMP。类似把一个明确长度的数组分段,然后让每个段在一个核上跑。并行处理各自数据段。

也有把OpenMP和SIMD结合使用获取最佳效果的。

这些东西大学一般是不教的,也没几个老师会去研究这个。中国的教育真是失败。

文章分享结束,PyTorch的使用经验都有哪些和cuda不建议使用二维数组的答案你都知道了吗?欢迎再次光临本站哦!

用Pytorch做深度学习 第一部分

本文内容来自互联网,若需转载请注明:https://bk.jguuu.com//12/119558.html