Pytorch学习笔记【整理】

Pytorch学习笔记【整理】

1.Tensor/numpy:

     (1)Tensor是pytorch中的重要数据结构,可以被认为是一个高维数组。它可以是一个数(标量)/一维数组(向量)/二维数组(矩阵)或更高维度的数组;

     (2)Tensor分为头信息区(Tensor)和存储区(Storage),信息区主要保存着Tensor的形状(Size)/步长(stride)/数据类型(type)等信息,而真正的数据则保存成连续数组;

     (3)绝大多数操作并不修改Tensor的数据,只修改Tensor的头信息,这种做法更节省内存,同时提升了处理速度。此外,有些操作会导致Tensor不连续,这时需调用tensor.contiguous方法将它们变成连续的数据,该方法复制数据到新的内存,不再与原来的数据共享storage;

     (4)可以使用t.save()和t. load()完成Tensor的保存和加载;

     (5)Tensor和Numpy的ndarrays类似,区别在于Tensor可以使用GPU加速,而Numpy只能在CPU上计算;

     (6)Tensor和Numpy对象共享内存,所以它们之间相互转换速度快并且几乎不消耗资源,这也意味着其中一个改变,另外一个也会随之改变;

     (7)tensor.size()返回torch.Size对象, 除tensor.size ()外还可以利用tensor.shape查看Tensor的形状,tensor.shape()等价于tensor.size();

     (8)tensor.view()方法可以调整Tensor的形状,但必须保证调整前后元素总数—致。view()不会修改自身数据,返回的新Tensor与原Tensor共享内存;

     (9)resize()方法也可用来可以调整Tensor的形状,但与view()不同,它可以修改Tensor的尺寸,如果新尺寸超过了 原尺寸,会自动分配新的内存空间,而如果新尺寸小于原尺寸,则之前的数据依旧会被保存;

     (10)squeeze()和 unsqueeze()两个函数用来添加或减少Tensor的某—维度;

     (11)Tensor有不同的数据类型,每种类型分别对应有CPU(torch.FloatTensor)和GPU(torch.cuda.FloatTensor)版本,默认的Tensor是FloatTensor,可通过t.set default tensor type修改默认Tensor类型。CPU Tensor与GPU Tensor之间的互相转换通过tensor.cuda()和tensor.cpu()的方法实现;

     (12)Pytorch中的Tensor支持自动广播机制,在快速执行向量化的同时不会占用额外的内存/显存,但建议通过以下两个函数的组合手动实现广播法则:
                 1) unsqueeze/view:

                     为数据某—维的形状补1。让所有输入数组都向其中shape最长的数组看齐,shape中不足的部分通过在前面加1补齐;

                 2) expand/expand as:

                     当输入数组的某个维度的长度为1时,计算时沿此维度复制扩充成一样的形状,该操作不会复制数组,所以不会占用额外的空间。

 

2.自动微分机制:

     (1)PyTorch的Autograd模块实现了自动微分功能,在Tensor上的所有操作Autograd都能为它们自动提供微分,避免手动计算导数的复杂过程;

     (2)在PyTorch0.4版本以下autograd.Variable是Autograd 中的核心类,它简单封装了Tensor并支持几乎所有Tensor的操作,在低版本PyTorch中forward()函数的输入和输出都是Variable, 只有Variable才具有自动求导功能,所以在输入时可将Tensor封装为Variable,在此之后可以调用它的.backward()实现反向传播,自动计算所有梯度。

               在PyTorch0.4版本以上将Tensor类和Variable类进行合并(0.3版本和0.4.x版本的最大的区别),不再需要进行转换就可以执行操作;

     (3)计算图(Computation Graph)是Pytorch的核心,计算图是—种特殊的有向无环图,用于记录算子与变量之间的关系,它为自动求导算法--反向传播(Back Propagation)提供了理论支持。Pytorch在autograd模块中实现了计算图的相关功能;

     (4)Pytorch使用的是动态图,它的计算图在每次前向传播时都是从头开始构建的,所以它能够使用Python控制语句(如for、if等)根据需求创建计算图,这意味着不需要事先构建所有可能用到的图的路径,图在运行时才构建。

 

3.torch.nn模块:

     (1)torch.nn:

                 1) torch.nn是专门为神经网络设计的模块化接口,torch.nn构建在Autograd之上,可用来定义和运行神经网络;

                 2) torch.nn只支持mini-batches,不支持一次只输入一个样本,即—次必须是一个batch。如果只想输入一个样本,需要调用input. unsqueeze (0) 将batch_size设为 1 ;

                 3) torch.nn实现了神经网络中大多数的损失函数,例如nn.MSELoss/nn.CrossEntropyLoss等。当调用loss.backward() 时,计算图会动态生成并自动微分,也会自动计算计算图中参数Parameter() 的导数。

     (2)nn.Module:

                 1) torch.nn的核心数据结构是Module, 它是一个抽象的概念,既可以表示神经网络中的某个层 (Layer),也可以表示一个包含很多层的神经网络。在实际使用中,最常见的做法是继承nn.Module来撰写自己的网络层;

                 2)PyTorch实现了神经网络中绝大多数的layer,这些layer 都继承于nn.Module, 封装了可学习参数parameter,并实现了forward函数。只要在nn.Module的子类中定义了forward()函数,backward函数就会被自动实现(利用Autograd);

                 3) 可以把nn.Module看作一个网络的封装,其中包含网络各层的定义及forward()方法,调用forward ()方法可返回前向传播的结果。 定义网络结构时,需要继承nn.Module,并实现它的forward方法,把网络中具有可学习参数的层放在构造函数中;

                 4) 在深度学习中参数的初始化十分重要,nn.Module的模块参数都采取了较合理的初始化策略,因此使用时一般不用考虑参数初始化问题;

                 5)nn.Module在实际使用中可能层层嵌套,一个module包含若干个子module,每一个子module又包含了更多的子module。为方便用户访问各个子module,nn.Module实现了很多方法,如函数children()可以查看直接子module;函数modules()可以查看所有的子module (包括当前module) ;以及函数named_childen()和 named_modules()能够在返回module列表的同时返回它们的名字;

                 6) forward()函数的简化:

                      对于前馈传播网络的forward()函数的实现有两种简化方式:Sequential和ModuleList。

                      Sequential是一个特殊的Module,它包含几个子module,前向传播时会将输入一层接—层地传递下去;              

                      ModulelList也是一个特殊的Module,可以包含几个子module, 可以像用list—样使用它,但不能直接把输入传给Modulelist。 Modulelist是Module的子类,当在Module中使用它时,就能自动识别为子module;

     (3)nn.functional:

                 1)nn.Module中的实现的大多数layer在nn.functional中都有一个与之对应的函数,二者的主要区别在于:由nn.Module实现的layer是一个由class Layer(nn.Module)定义的特殊的类,会自动提取可学习的参数;而nn.functional的函数更像是纯函数,由def function(input)定义;

                 2)如果模型有可学习的参数,建议使用nn.Module,否则既可以使用nn.functional也可以使用nn.Module,二者在性能上没有太大差异。

                       如激活函数(ReLU 、sigmoid 、 tanh) 、池化 (MaxPool)等无可学习参数的层可以使用对应的nn.functional函数代替,不具备可学习参数的层将它们用函数代替的好处是不需要放置在构造函数init()中;而卷积、全连接等具有可学习参数的网络建议使用nn.Module,事实上也可以用functional代替,但实现起来比较烦琐;

 

4.模型的保存/载入/运行:

     (1)通过torch.save来保存模型的结构和参数有两种保存方式:

                 1)保存整个模型的结构信息和参数信息, 保存的对象是模型model;

                       torch.save(model, "./model.pth")

                 2)保存模型的参数, 保存的对象是模型的状态model.state_dict(),可以这样保存,save的第一个参数 是保存对象,第二参数是保存路径及名称。
                       torch.save(model.state_dict(), "./model_state.pth")

     (2)与上对应的模型加载也有两种方式:

                 1)加载完整的模型结构和参数信息,在网络较大的时候加载的时间比较长,同时存储空间也比较大;

                      load_model=torch.load("model.pth")

                 2)加载模型的参数信息,需要先导入模型的结构,再导入模型参数;

                      model.load_state_dict(torch.load("model_state.pth"))

     (3)利用save()+load()保存和载入模型严重依赖模型定义方式及文件路径结构等,所以很容易出问题,因而不建议使用;通常使用state_dict ()函数返回当前Module所有的状态数据,保存这些状态数据后,使用模型时利用model.load_state_diet ()函数将状态加载进来的方式;

     (4)将Module放在GPU上运行只需调用model=model.cuda () ,将模型的所有参数转存到GPU ,然后input.cuda(),将输入数据放置到GPU上。

 

5.Dataset/Dataloader:

     (1)Dataset对象是一个数据集,实现自定义的数据里需要继承Dataset,并实现两个Python魔法方法:

                 1)getitem():返回—条数据或一个样本,obj[index]等价于obj.getitem(index);

                 2)len():返回样本的数量,len(obj)等价于obj.len()。

     (2)Dataloader是一个可迭代的对象,它将dataset返回的每—条数据样本拼接成一个batch,并提供多线程加速优化和数据打乱等操作。当程序对Dataset的所有数据遍历完—遍之后,对Dataloader也完成了—次迭代操作;

     (3)Dataloader的相关参数解释:

                 1)dataset:加载的数据集 (Dataset对象);

                 2)batch_ size:batch_size (批大小);

                 3)shuffle:是否将数据打乱;

                 4)sampler:样本抽样,后续会详细研究;5、num_workers:使用多进程加载的进程数,0代表不使用多进程;

                 5)collate_ fn:如何将多个样本数据拼接成一个batch,一般使用默认的拼接方式即可;

                 6)pin_memory:是否将数据保存在pin_memory区,pin_memory中的数据转到GPU会快—些;

                 7)drop_last:dataset中的数据个数可能不是batch_size的整数倍,drop_last为True会将多出来不足 一个batch的数据丢弃。

     (4)在Dataset和DataLoader的使用方面有以下建议:

                 1)高负载的操作放在getitem()中,例如将文件读取等费时操作放在此函数中利用多进程加速,因为多进程会并行地调用getitem()函数,将负载高的放在getitem()函数中能够实现并行加速;

                 2)Dataset中应尽量只包含只读对象,避免修改任何可变对象。因为Dataloader使用多进程加载,如果在Dataset中使用了可变对象,可能会有意想不到的冲突。

 

6.torchvision:

     (1)torchvision主要包含以下三部分:
                 1)models:提供深度学习中各种经典网络的网络结构及预训练好的模型,包括 Alex-Net/VGG系列/ResNet系列/Inception系列等;

                 2)datasets:提供常用的数据集加载,设计上都是继承torch.utils.data.Dataset,主要包括MNIST/CIFAR10/100/
lmageNet/COCO等;
                 3)transforms:提供常用的数据预处理操作,主要包括对Tensor/PIL Image/Tensor对象的操作;

     (2)torchvision还提供了两个常用的函数:

                 1)make_grid():功能为将多张图片拼接在—个网格中;

                 2)save_img():功能为将Tensor保存成图片。

7.GPU加速:

     (1)在PyTorch中以下数据结构分为CPU和GPU 两个版本:

1、Tensor(0.3版本以下还包括Variable);2、nn.Module(包括常用的layer、loss function以及容器Sequential等),他们都自带一个.cuda()方法,调用此方法即可将其转为对应的GPU对象。

     (2)关于使用GPU 的—些建议:
                 1)GPU 运算很快,但运算量小时,并不能体现出它的优势,因此—些简单的操作可直接利用CPU完成;

                 2)数据在CPU和GPU之间的传递会比较耗时,应当尽量避免;

                 3)在进行低精度的计算时可以考虑HalfTensor,相比之下FloatTensor能节省一半的显存,但需注意数值溢出的情况。 

 

你可能感兴趣的:(pytorch)