美文网首页
Pytorch的基本使用

Pytorch的基本使用

作者: Zimix | 来源:发表于2018-11-30 18:30 被阅读0次

    本篇内容参考官方文档自己总结而来仅供自学自查,详细需求请查阅官方文档。

    数据类型

    • 张量(Tnsor

    什么是张量?简单来说就可以看成是向量。一阶张量,就是一维向量,如此如此。

    1. torch自己的方法构造的数据都是默认为Tensor的张量,比如:
    • 定值构造
      定值构造方法还有很多,如下:
    import torch
    torch.Tensor(list/ndarray)#---->将列表转为,数组转为tensor
    torch.eye(3)#---->生成3行3列的值为1的对角矩阵
    torch.linspace(start, end, steps=100, out=None)#---->等差数列矩阵
    torch.logspace(start, end, steps=100, out=None)#---->对数等差数列矩阵
    

    torch.zeros()、ones()、等等方法和numpy类似,不一一举例。

    • 随机构造
      这类构造方法也不少,如下:
    import torch
    torch.rand(2,2)# ----->生成2X2的矩阵,数值再0-1之间
    torch.randn(2,2)# ---->生服从标准正态分布的2X2
    torch.arange(1,20,2)# ---->序列数组
    
    2. numpy的array或者list数组转换而来。

    这里介绍一下numpy的array和torch的tensor的区别,numpy的array是不支持GPU的,只支持CPU。而torch的tensor是两个都支持的。

    • array转tensor-----orch.from_numpy()
    >>> a = numpy.array([1, 2, 3])
    >>> t = torch.from_numpy(a)
    >>> t
    torch.LongTensor([1, 2, 3])
    >>> t[0] = -1
    >>> a
    array([-1,  2,  3])
    

    这个方法有一个缺点也是优点,生成的tensor和array指向同一个内存地址,一个变了都会变。

    • tensor转array
      tensor转成其他的数据的方法有很多,如下:
    import torch
    a = torch.rand(2,2)
    # to numpy.ndarray
    a.numpy()
    # 转换成支持CPU
    a.cpu()
    # 转换成支持GPU
    a.cuda()
    
    3. tensor的属性
    • 数据类型
      32位浮点型:torch.FloatTensor。也是pyorch.Tensor()的默认类型。
      64位整型:torch.LongTensor。
      32位整型:torch.IntTensor。
      16位整型:torch.ShortTensor。
      64位浮点型:torch.DoubleTensor。
    • 张量的大小
      tensor.size()
      tensor.shape
    >>> tt1
    tensor([[0.1372, 0.6473, 0.6765],
            [0.3346, 0.1886, 0.4174]])
    >>> tt1.shape
    torch.Size([2, 3])
    >>> tt1.size()
    torch.Size([2, 3])
    
    • 张量的元素个数
      torch.numel(input)
    >>> tt1.numel()
    6
    >>> torch.numel(tt1)
    6
    

    基本上张量的简介就差不多了,更多内容参考pytorch中文文档

    • 变量(Variable

    Variable类型数据是张量的升级版,给tensor加了装备:前向传播反向传播自动求导等功能,在计算图的构建中起的很重要的作用。有一个图能很形象的说明:


    其中最重要的两个属性是:data和grad。.data表示该变量保存的实际数据,通过该属性可以访问到它所保存的原始张量类型,而关于该 variable(变量)的梯度会被累计到.grad 上去。与tensor不同,Variable在另一个模块内----torch.autograd。不过,pytorch 0.4之后的版本,好像把Tensor和Variabel合并了。requires_grad变成了Tensor本来的一个属性了。这里给一片博客可以参考
    import torch
    from torch.autograd import Variable 
    # 定义三个Variable变量
    # requires_grad 是设置是否需要计算梯度
    x = Variable(torch.Tensor([1, 2, 3]), requires_grad=True)
    w = Variable(torch.Tensor([2, 3, 4]), requires_grad=True)
    b = Variable(torch.Tensor([3, 4, 5]), requires_grad=True)
    # 构建计算图,公式为:y = w * x^2 + b
    y = w * x * x + b 
    # 自动求导,计算梯度
    # 这里传入的torch.Tensor([1,1,1])是用来表示每个梯度的权重的
    y.backward(torch.Tensor([1, 1, 1])) 
    print(x.grad)# 2*w*x
    print(w.grad)# x*x
    print(b.grad)# 常量的导数为1
    

    数据操作

    - 索引 ---- 和numpy的索引相同
    >>> tt1
    tensor([[0.1372, 0.6473, 0.6765],
            [0.3346, 0.1886, 0.4174]])
    >>> tt1[1,1]
    tensor(0.1886)
    >>> tt1[:,2]
    tensor([0.6765, 0.4174])
    
    - 切片---- 和numpy的切片相同
    >>> tt1
    tensor([[-0.3623, -0.6115,  0.7283],
            [ 0.4699,  2.3261,  0.1599]])
    >>> tt1[:,1:2]
    tensor([[-0.6115],
            [ 2.3261]])
    >>> tt1[:,:]
    tensor([[-0.3623, -0.6115,  0.7283],
            [ 0.4699,  2.3261,  0.1599]])
    
    - 连接 ---- torch.cat()
    >>> tt1 = torch.rand(2,3)
    >>> tt2 = torch.rand(2,3)
    >>> torch.cat((tt1,tt2),0)
    tensor([[0.1372, 0.6473, 0.6765],
            [0.3346, 0.1886, 0.4174],
            [0.8388, 0.7322, 0.7819],
            [0.4745, 0.2260, 0.7371]])
    >>> torch.cat((tt1,tt2),1)
    tensor([[0.1372, 0.6473, 0.6765, 0.8388, 0.7322, 0.7819],
            [0.3346, 0.1886, 0.4174, 0.4745, 0.2260, 0.7371]])
    
    - reshape ---- torch.view()、torch.reshape()
    # view()
    >>> tt1
    tensor([[-0.3623, -0.6115,  0.7283],
            [ 0.4699,  2.3261,  0.1599]])
    >>> tt1.view(-1)
    tensor([-0.3623, -0.6115,  0.7283,  0.4699,  2.3261,  0.1599])
    >>> tt1.view(3,2)
    tensor([[-0.3623, -0.6115],
            [ 0.7283,  0.4699],
            [ 2.3261,  0.1599]])
    # reshape()
    >>> tt1
    tensor([[-0.7242,  0.6419, -1.2202],
            [-0.7509, -0.9206,  0.9566]])
    >>> tt1.reshape(3,2)
    tensor([[-0.7242,  0.6419],
            [-1.2202, -0.7509],
            [-0.9206,  0.9566]])
    
    • 最后补充一个增加和去除无用维度的操作
      • 去除-----torch.squeeze(input, dim=None, out=None)
      • 增加-----torch.unsqueeze(input, dim=None, out=None)
    >>> tt1
    tensor([[-0.7242,  0.6419, -1.2202],
            [-0.7509, -0.9206,  0.9566]])
    >>> tt = tt1.view(2,1,3)
    >>> tt
    tensor([[[-0.7242,  0.6419, -1.2202]],
    
            [[-0.7509, -0.9206,  0.9566]]])
    >>> tt.shape
    torch.Size([2, 1, 3])
    >>> ttt = tt.squeeze()
    >>> ttt
    tensor([[-0.7242,  0.6419, -1.2202],
            [-0.7509, -0.9206,  0.9566]])
    >>> ttt.shape
    torch.Size([2, 3])
    

    二者用法类似,返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。

    数学运算

    • 基本四则运算-----python自带的四则运算符 " +、-、*、/ "
      都是对应位置的操作。
    >>> tt1 = torch.randn(2,3)
    >>> tt2 = torch.randn(2,3)
    >>> tt1
    tensor([[-0.7242,  0.6419, -1.2202],
            [-0.7509, -0.9206,  0.9566]])
    >>> tt2
    tensor([[-0.7343, -2.0070,  1.1552],
            [ 0.1351, -0.5211,  0.7543]])
    >>> tt1+tt2
    tensor([[-1.4585, -1.3651, -0.0649],
            [-0.6158, -1.4417,  1.7109]])
    >>> tt1-tt2
    tensor([[ 0.0100,  2.6489, -2.3754],
            [-0.8859, -0.3995,  0.2023]])
    >>> tt1*tt2
    tensor([[ 0.5318, -1.2883, -1.4096],
            [-0.1014,  0.4797,  0.7215]])
    >>> tt1/tt2
    tensor([[ 0.9863, -0.3198, -1.0562],
            [-5.5598,  1.7666,  1.2683]])
    

    torch的:
    加法torch.add(input, value, out=None)
    乘法-----torch.mul(input, value, out=None)
    除法-----torch.div(input, value, out=None)

    # input是"被操作数",必须是tensor,value是"操作数"。
    # 两个张量相加,对应位置相加
    >>> torch.add(tt1,tt2)
    tensor([[-1.4585, -1.3651, -0.0649],
            [-0.6158, -1.4417,  1.7109]])
    # tensor+标量,为每个位置加上这个标量
    >>> torch.add(tt1,1)
    tensor([[ 0.2758,  1.6419, -0.2202],
            [ 0.2491,  0.0794,  1.9566]])
    

    这三个方法类似,不一一举例。

    • 高级运算
      • 求对数(e为底)-----torch.log(input, out=None)
      • 求指数(e为底)-----torch.exp(tensor, out=None)
      • 其他2、10为低的指数-----torch.log2(),torch.log10()
      • 求次幂-----torch.pow(input, exponent, out=None)
      • 求绝对值-----torch.abs(input, out=None)
      • 三角函数-----torch.cos()、torch.sin()、torch.tan()
      • 反三角函数-----torch.acos()、torch.asin()、torch.atan()
      • 均值、求和、方差、标准差-----torch.mean()、torch.sum()、torch.var()、torch.std()
    # 以tt1为底,0为指数
    >>> torch.pow(tt1,0)
    tensor([[1., 1., 1.],
            [1., 1., 1.]])
    # 以2.7为底,tt1为指数
    >>> torch.pow(2.7,tt1)
    tensor([[0.4871, 1.8919, 0.2976],
            [0.4743, 0.4008, 2.5861]])
    # e为底
    >>> torch.exp(tt1)
    tensor([[0.4847, 1.9001, 0.2952],
            [0.4720, 0.3983, 2.6029]])
    

    基本上够用了,方法不熟悉就边查遍用。
    最后补充一点矩阵方面的东西:

    • torch.dot(tensor1, tensor2) -> float
      计算两个一阶张量的点积
    • torch.eig(input, eigenvectors=False, out=None) -> (Tensor, Tensor)
      • 计算input(方阵:n行n列)的特征值和特征向量。
      • eigenvectors=True,同时计算特征值和特征微量,否则只计算特征值。
    • torch.inverse(input, out=None) -> Tensor
      对方阵input求逆
    • torch.mm(mat1, mat2, out=None) -> Tensor
      对矩阵mat1和mat2进行相乘。
    • torch.mv(mat, vec, out=None) -> Tensor
      对矩阵mat和向量vec进行相乘。
    • torch.t(input, out=None)
      输入一个矩阵(2维张量),并转置0,1维,可以被视为torch.transpose(input, 0, 1)的简写函数。torch.transpose()可以多维转置。

    流程结构

    这里主要介绍模型的搭建流程。

    1. 构建网络
    • class Net(torch.nn.Module)方式:
    import torch
    import torch.nn.functional as F
    
    
    class Net(torch.nn.Module):
        def __init__(self, n_feature, n_hidden, n_output):
            super(Net, self).__init__()
            self.hidden = torch.nn.Linear(n_feature, n_hidden)
            self.predict = torch.nn.Linear(n_hidden, n_output)
    
        def forward(self, x):
            x = F.relu(self.hidden(x))
            x = self.predict(x)
            return x
    # 实例化
    net = Net(10,3,2)
    
    • torch.nn.Sequential()
    # 直接在Sequential类中初始化
    net = torch.nn.Sequential(
        torch.nn.Linear(1, 10),
        torch.nn.ReLU(),
        torch.nn.Linear(10, 1)
    )
    

    这里有一篇文档做了更详细的举例

    2. 定义优化器、损失函数

    反向传播的流程是借助损失函数,优化器来实现的(更多函数请参考loss functionoptim)。

    # 定义损失函数
    loss_func = torch.nn.CrossEntropyLoss()
    
    # 定义优化器
    optimizer = torch.optim.SGD(net.parameters(), lr=0.02)
    
    3. 前向传播

    上面两个方法的前向传播都是如此

    predict = net(input)
    
    4. 更新参数

    使用优化器通过优化损失函数,得到梯度,反向更新模型参数。

    # 1. 计算loss
    loss = loss_func(predict,y_true)
    # 2. 计算梯度
    optimizer.zero_grad()   # 梯度清空
    loss.backward()         # 反向传播-->给优化器
    optimizer.step()        # 单步更新-->给参数
    

    如此一个网络搭建和一次训练就完成了!

    - 最后补充一点如何决定使用CPU还是GPU

    在训练网络之前,我们可以决定是通过CPU还是GPU来进行训练。

    • 默认的方式是CPU,无需任何操作。
    • 选择GPU
      第一种、实例化的时候使用.cuda()
      第二种、使用类似tensorflow的方式指定CUDA_VISIBLE_DEVICES
    net = Net(10,3,2).cuda()
    loss_func = torch.nn.CrossEntropyLoss().cuda()
    #================================================
    import os
    os.environ["CUDA_VISIBLE_DEVICES"] = "0"
    
    • 智能选择,可以用以下代码来决定:
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    

    对应的我们在实例化网络和损失函数的时候都需要.to(device)。即:

    net = Net(10,3,2).to(device)
    
    loss_func = torch.nn.CrossEntropyLoss().to(device)
    
    

    最后补充一篇解决模型超GPU显存的博客

    相关文章

      网友评论

          本文标题:Pytorch的基本使用

          本文链接:https://www.haomeiwen.com/subject/fnybqqtx.html