pytorch笔记

南楼画角 提交于 2019-11-27 05:02:38

Tensor

tensor.size()返回torch.Size对象,它是tuple的子类,但其使用方式与tuple略有区别。

tensor.shape等价于tensor.size()

需要注意的是,t.Tensor(*sizes)创建时,系统不会马上分配空间,只会计算剩余的内存是否足够使用,使用到tensor时才会分配,而其他操作都是在创建完tensor后马上进行空间分配。

tensor.view:可以调整tensor的形状,但必须保证总数一致。不会修改自身的数据,共享内存,即更改其中一个,另外一个也会跟着改变。

squeeze和unsqueeze:添加或减少某一维度。

resize:也可用来调整size,但可修改尺寸,如b.resize_(1, 3)

CPU tensor与GPU tensor之间的互相转换通过tensor.cuda和tensor.cpu的方法实现。

pytorch的线性函数主要封装了Blas和Lapack,其用法和接口都与之类似。

当遇到Tensor不支持的操作时,可先转成Numpy数组,处理后再转回tensor,其转换开销很小。

tensor分为头信息区(Tensor)和存储区(Storage)

在科学计算中应当避免使用Python原生的for循环,尽量使用向量化的数值计算,有近10倍的速度差。

因此在平时写代码时,就应养成向量化的思维习惯。

Variable

torch.autograd:自动求导引擎,它能够根据输入和前向传播过程自动构建计算图,并执行反向传播。

其核心数据结构是Variable。它封装了tensor,并记录对tensor的操作记录用来构建计算图。主要包含三个属性:

  • data:保存variable所包含的tensor
  • grad:对应的梯度,grad也是variable,而非tensor
  • grad_fn:指向一个Function,记录variable的操作历史,用来构建计算图。如果某个变量是由用户创建的,则它为叶子节点,对应grad_fn等于None。

Variable的构造函数需要传入tensor,同时有两个可选参数。

  • requires_grad:是否需要对该variable进行求导。
  • volatile:为True时,构建在该variable之上的图都不会求导,专为推理阶段设计。

Variable支持大部分tensor支持的函数,但其不支持部分inplace函数,因为这些函数会修改tensor自身,而在反向传播中,variable需要缓存原来的tensor来计算梯度。

variable.backward(grad_variables=None, retain_graph=None, create_graph=None)主要有如下参数:

  • grad_variables:形状与variable一致,相对于链式法则Zx = Zy * Yz中的Zy
  • retain_graph:缓存中间结果
  • create_graph:对反向传播过程再次构建计算图

神经网络工具箱nn

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

import torch as t
from torch import nn
from torch.autograd import Variable as V

class Linear(nn.Module):
    def __init__(self, in_features, out_features):
        super(Linear, self).__init__() # 等价于nn.Module.__init__
        self.w = nn.Parameter(t.randn(in_features, out_features)) # 定义参数,为一种Variable
        self.b = nn.Parameter(t.randn(out_features))

    def forward(self, x):
        x = x.mm(self.w)
        return x + self.b.expand_as(x)

layer = Linear(4, 3)
input = V(t.randn(2, 4))
output = layer(input) # 会调用forward
print(output)

官方文档有图像相关层、激活函数、循环神经网络层、Embedding层、损失函数、

优化器:所有方法都继承基类optim.Optimizer,并实现了自己的优化步骤。

nn.functional:nn.Module实现的layers是一个特殊的类,都是由class Layer(n.Module)定义,会自动提取可学习的参数;而nn.functional中的函数更像是纯函数,由def function(input)定义。

如果模型有可学习的参数,最好用nn.Module,否则既可以使用nn.functional也可以使用nn.Module,二者在性能上没有太大差异,具体的使用方式取决于个人喜好。由于激活函数、池化等层没有可学习参数,可以使用对应的functional函数替代,而卷积、全连接等具有可学习参数的网络建议使用nn.Module。

from torch.nn import functional as F
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = F.pool(F.relu(self.conv1(x)), 2)
        x = F.pool(F.relu(self.conv2(x)), 2)
        x = x.view(-1, 16*5*5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

初始化策略

nn.Module的模块参数都采取了较合理的初始化 策略,因此一般不用我们考虑。当然,我们也可以用自定义初始化代替系统的默认初始化。当我们使用Parameter时,自定义初始化尤为重要。nn.init模块专门为初始化设计。

在PyTorch中保存模型十分简单,所有的Module对象都具有state_dict()函数,返回当前Module所有的状态数据。将这些状态数据保存后,下次使用模型时即可利用model.load_state_dict()函数将状态加载进来。优化器(optimizer)也有类似的机制,不过一般并不需要保存优化器的运行状态。

t.save(net.state_dict(), 'net.pth')
net2 = Net()
net2.load_state_dict(t.load('net.pth'))

将Module放在GPU上运行也十分简单,只需以下两步:

  • model = model.cuda():将模型的所有参数转存到GPU
  • input.cuda():将输入数据放置到GPU上

至于如何在多个GPU上并行计算,PyTorch也提供了两个函数,可实现简单高效的并行GPU计算。

# 方法 1
new_net = nn.DataParallel(net, device_ids=[0,1])
output = new_net(input)
# 方法 2
output = nn.parallel.data_parallel(net, input, device_ids=[0,1])

DataParallel并行的方式,是将输入一个batch的数据均分成多份,分布送到对应的GPU进行计算,然后将各个GPU得到的梯度相加。与Module相关的所有数据也会以浅复制的方式复制多份。

可视化工具

使用tensorboard_logger进行训练损失的可视化。

$ pip install tensorboard_logger

使用visdom,是facebook专门为PyTorch开发的一款可视化工具。

$ pip install visdom

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!