zoukankan      html  css  js  c++  java
  • Pytorch学习笔记(二)——Tensor

    一、对Tensor的操作

    从接口的角度讲,对Tensor的操作可以分为两类:

    (1)torch.function (2)tensor.function

    比如torch.sum(a, b)实际上和a.sum(b)功能等价。

    从存储的角度讲,对Tensor的操作也可以分为两类:

    (1)不修改自身数据,如a.add(b),加法结果返回一个新的tensor;

    (2)修改自身数据,如a.add_(b),加法结果仍存在a中,a被改变。

    函数名以_结尾的称为inplace方式。

    二、Tensor的创建

    常见的新建tensor的方法:

    Tensor(*sizes) 基础构造函数,不分配空间,未初始化

    ones(*sizes) 全1的tensor

    zeros(*sizes) 全0的tensor

    eye(*sizes) 对角线为1,其余为0,不要求行列数相同

    arange(s, e, step) 从s到e,步长为step

    linspace(s, e, steps) 从s到e,均匀切分成steps份

    rand/randn(*sizes) 均匀/标准分布

    normal(mean, std)/uniform(from, to) 正态分布/均匀分布

    randperm(m) 随机排列

     

    range(start, end, step),返回一个list对象也就是range.object,起始值为start,终止值为end,但不含终止值,步长为step。只能创建int型list。range的step不能是浮点型。

    arange(start, end, step),与range()类似,也不含终止值。但是返回一个array对象。需要导入numpy模块(import numpy as np或者from numpy import*),arange可以使用浮点型数据。

     

    Tensor既可以接收一个list,也可以根据指定形状新建tensor,还可以传入其他的tensor。

    tensor.size()等价于tensor.shape()。

    a = t.Tensor(2, 3)
    b = t.Tensor([[1, 2, 3], [4, 5, 6]])
    print(b.tolist()) # 把tensor转为list
    print(b.size()) # 形状
    print(b.numel()) # 元素总个数
    c = t.Tensor(b.size())

    通过tensor.view方法可以调整tensor的形状,但要保证调整前后元素总数一致。view不会更改自身数据,但是新的tensor与原tensor共享内存。也就是说更改其中一个,另一个也会跟着改变。

    如果要添加或减少某一维度,就需要通过squeeze和unsqueeze函数。

    a = t.arange(0, 6)
    print(a.view(2, 3))
    b = a.view(-1, 3) # 当某一维为-1时,系统自动计算大小
    print(b)
    print(b.unsqueeze(1)) # 在第一维度上增加一维
    print(b.unsqueeze(-2)) # 在倒数第二维上增加一维

    运行结果:

    tensor([[0, 1, 2],
            [3, 4, 5]])
    tensor([[0, 1, 2],
            [3, 4, 5]])
    tensor([[[0, 1, 2]],
    
            [[3, 4, 5]]])
    tensor([[[0, 1, 2]],
    
            [[3, 4, 5]]])
    a = t.arange(0, 6)
    print(a.view(2, 3))
    b = a.view(-1, 3) # 当某一维为-1时,系统自动计算大小
    c = b.view(1, 1, 1, 2, 3)
    print(c.squeeze(0).size())
    print(c.squeeze().size()) # 将所有维度为1的压缩

    运行结果:

    tensor([[0, 1, 2],
            [3, 4, 5]])
    torch.Size([1, 1, 2, 3])
    torch.Size([2, 3])

    resize也可以用来调整tensor的大小。如果新尺寸超过了原始尺寸,那么会自动分配新的内存空间;而如果新尺寸小于原尺寸,则之前的数据依旧会保留。

    a = t.arange(0, 6)
    b = a.view(-1, 3) # 当某一维为-1时,系统自动计算大小
    a[1] = 100 # 由于a与b共享内存,所以a改变时b也会改变
    b.resize_(1, 3)
    print(b)
    print(b.resize_(3, 3)) # 之前的数据并没有因为上一步的resize操作丢失

    运行结果:

    tensor([[  0, 100,   2]])
    tensor([[                  0,                 100,                   2],
            [                  3,                   4,                   5],
            [  31244186271350784, 3775491366621020160, 5936959698761888869]])

    Tensor支持与numpy.ndarray相似的索引操作。索引结果与原tensor共享内存。注意以下两种索引的区别:

    a = t.randn(3, 4)
    print(a[0 : 1, : 2].size())
    print(a[0, : 2].size())

    运行结果:

    torch.Size([1, 2])
    torch.Size([2])

    选择产生的结果与原tensor不共享内存空间。

    torch.FloatTensor(2,3) 构建一个2*3 Float类型的张量

    torch.DoubleTensor(2,3) 构建一个2*3 Double类型的张量

    torch.ByteTensor(2,3) 构建一个2*3 Byte类型的张量

    torch.CharTensor(2,3) 构建一个2*3 Char类型的张量

    torch.ShortTensor(2,3) 构建一个2*3 Short类型的张量

    torch.IntTensor(2,3) 构建一个2*3 Int类型的张量

    torch.LongTensor(2,3) 构建一个2*3 Long类型的张量

    torch.Tensor是默认的tensor类型(torch.FlaotTensor)的简称。

    三、tensor数据类型转换

    torch.long() 将tensor转换为long类型

    torch.half() 将tensor转换为半精度浮点类型

    torch.int() 将该tensor转换为int类型

    torch.double() 将该tensor转换为double类型

    torch.float() 将该tensor转换为float类型

    torch.char() 将该tensor转换为char类型

    torch.byte() 将该tensor转换为byte类型

    torch.short() 将该tensor转换为short类型

    几种数据类型转换的方式如下:

    a = t.Tensor(2, 3)
    b = a.float()
    c = a.type_as(b)
    d = a.new(2, 3)

    四、选择

     

    gather操作

    对于一个二维tensor,输出的每个元素如下:

    out[i][j] = input[index[i][j]][j] # dim = 0
    out[i][j] = input[i][index[i][j]] # dim = 1
    a = t.arange(0, 16).view(4, 4)
    index = t.LongTensor([[0, 1, 2, 3]])
    print(a.gather(0, index)) # 提取对角线元素
    index = t.LongTensor([[3, 2, 1, 0]]).t() # 针对2D tensor转置
    print(a.gather(1, index)) # 提取反对角线元素
    index = t.LongTensor([[3, 2, 1, 0]])
    print(a.gather(0, index)) # 提取反对角线元素

    运行结果:

    tensor([[ 0,  5, 10, 15]])
    tensor([[ 3],
            [ 6],
            [ 9],
            [12]])
    tensor([[12,  9,  6,  3]])

    gather的逆操作是scatter_,gather是把数据从input中按照index取出,而scatter_是把取出的数据再放回去。

    高级索引

    x[[1, 2], [1, 2], [2, 0]] # x[1, 1, 2]和x[2, 2, 0]
    x[[2, 1, 0], [0], [1]] # x[2, 0, 1], x[1, 0, 1], x[0, 0, 1]
    x[[0, 2], ...] # x[0]和x[2]

    五、逐元素操作

     

    其中clamp实现的功能如下:

     

    六、归并操作

    使输出形状小于输入形状,并沿着某一维度进行指定操作。比如加法sum,既可以计算整个tensor的和,也可以计算tensor中每一行或者每一列的和。常用的归并操作如下:

     

    以上函数几乎都有一个dim参数,类似于numpy的axis,用于指定这些操作在哪个维度上执行。简单来说,假设输入形状为(m, n, k):

    如果dim=0,则输出形状为(1, n, k)或(n, k);

    如果dim=1,则输出形状为(m, 1, k)或(m, k);

    如果dim=2,则输出形状为(m, n, 1)或(m, n)。

    size中是否有“1”,取决于参数keepdim,如果keepdim=True会保留维度1。其中keepdim默认值为False。

    七、比较操作

     

    t.max(tensor) 返回tensor中最大的一个数

    t.max(tensor, dim) 指定维度上的最大的数,返回tensor和下标

    t.max(tensor1, tensor2) 比较两个tensor相比较大的元素

    如果要比较一个tensor和一个数字,可以使用clamp函数。

    a = t.linspace(0, 15, 6).view(2, 3)
    b = t.linspace(15, 0, 6).view(2, 3)
    print('a=', a)
    print('b=', b)
    print('a[a > b]=', a[a > b])
    print('t.max(a)=', t.max(a))
    print('t.max(b, dim = 1)=', t.max(b, dim = 1))
    print('t.max(a, b)=', t.max(a, b))

    运行结果:

    a= tensor([[ 0.,  3.,  6.],
            [ 9., 12., 15.]])
    b= tensor([[15., 12.,  9.],
            [ 6.,  3.,  0.]])
    a[a > b]= tensor([ 9., 12., 15.])
    t.max(a)= tensor(15.)
    t.max(b, dim = 1)= (tensor([15.,  6.]), tensor([0, 0]))
    t.max(a, b)= tensor([[15., 12.,  9.],
            [ 9., 12., 15.]])

    八、线性代数

    pytorch的线性函数主要封装了Blas和Lapack。常用的线性代数函数如下:

     

    矩阵的转置会导致存储空间不连续,需要调用它的.contiguous方法将其转为连续。

    九、Tensor和Numpy

    numpy和tensor共享内存。当输入数组的某个维度的长度为1时,计算时沿此维度复制扩充成一样的形状。

    广播的手动实现:

    (1)unsqueeze或view:为数据某一维的形状补1;

    (2)expand或expand_as:重复数组。不会占用额外的空间(repeat会复制多份数据,所以会占用额外空间)。

    Numpy的广播法则:

    (1)所有输入数组都向shape最长的数组看齐,shape中不足的部分通过在前面加1维补齐;

    (2)两个数组要么在某一个维度上的长度一致,要么其中一个为1,否则不能计算。

    尽量使用向量化计算,少用for循环。

    大多数t.function都有一个参数out,产生的结果可以保存在out指定的tensor中。

    t.set_printoptions可以用来设置打印tensor时的数值精度和格式。

    十、练习:线性回归

    代码:

    import torch.nn as nn
    import torch as t
    from torch.autograd import Variable
    import torch.nn.functional as F
    import torch.optim as optim
    import torchvision as tv
    import torchvision.transforms as transforms
    from torchvision.transforms import ToPILImage
    from matplotlib import pyplot as plt
    
    # 设置随机数种子,保证在不同的计算机上运行时产生的输出一致
    t.manual_seed(1000)
    
    def get_fake_data(batch_size = 8):
        # 产生随机数据,加入噪声
        x = t.rand(batch_size, 1) * 20
        y = x * 2 + (1 + t.randn(batch_size, 1)) * 3
        return x, y
    
    x, y = get_fake_data()
    
    # 随机初始化参数
    w = t.rand(1, 1)
    b = t.zeros(1, 1)
    
    lr = 0.001
    
    for ii in range(20000):
        # forward
        y_pred = x.mm(w) + b.expand_as(y)
        loss = 0.5 * (y_pred - y) ** 2
        loss = loss.sum()
    
        # backward
        dloss = 1
        dy_pred = dloss * (y_pred - y)
    
        dw = x.t().mm(dy_pred)
        db = dy_pred.sum()
    
        # update parameters
        w.sub_(lr * dw)
        b.sub_(lr * db)
    
    x2 = t.arange(0, 20, 1.0).view(-1, 1)
    y2 = x2.mm(w) + b
    
    plt.plot(x2.numpy(), y2.numpy())
    plt.scatter(x.squeeze().numpy(), y.squeeze().numpy())
    plt.show()

    运行结果:

  • 相关阅读:
    Evidence on the impact of sustained exposure to air pollution on life expectancy
    International Immunopharmacology/ Perinatal and early childhood environmental factors influencing allergic asthma immunopathogenesis
    Projections of the effects of climate change on allergic asthma: the contribution of aerobiology
    Word List 2
    GRE : TC21
    Grammar Mistake: What is a faulty tense sequence?
    Biology 02: Respiration
    127 super()方法详解
    128 类的多态和多态性
    126 菱形继承问题
  • 原文地址:https://www.cnblogs.com/cieusy/p/10565726.html
Copyright © 2011-2022 走看看