zoukankan      html  css  js  c++  java
  • 数据操作

    数据操作 - 基于 pytorch

    为了更好地完成我们需求的任务,我们需要一些方法来存储和操作数据。让我们自己动手来处理综合的数据,需要引入N维数组(n-dimensional array)的概念,它也被称为张量(tensor)

    如果你使用过 NumPy,就会发现这篇博客的内容何其相似。其实用什么框架无所谓,张量类型(tensor class)(其中还有 MXNet 的 ndarray 和 PyTorch 和 TensorFlow 中的 Tensor )都是和 NumPy 的 ndarray 有着非常类似的特征。

    首先,GPU 将会在对计算工作起到非常好的加速支持,然而 NumPy 仅支持 CPU 计算;其次, tensor 类型可以自动地支持这两者。这些属性让 tensor 类型更适合深度学习。

    首先我们引入库文件

    注意我们引入的是 torch 而不是 pytorch

    import torch
    

    张量代表了数值数组,对于一个轴,张量代表了数学中的向量(vector),对于两个轴,其代表了矩阵(matrix),对于二个轴以上的张量,没有特别的数学名称。

    我们可以先使用 arange 函数创建一个行向量,参数中传递了行向量的数值范围,它们默认是 int64 类型。每一个值被称为向量的元素。除非特别说明,新创建的张量将会存储在内存中并且是基于 CPU 计算。

    x = torch.arange(12)
    x
    

    我们可以通过 shape 属性来获得张量的形状,即每个轴上的长度

    x.shape
    

    如果我们只是想查看张量元素的数量,即 shape 元素的乘积,我们可以使用 numel 方法

    x.numel()
    
    12
    

    为了改变张量的形状而不修改其中的值,我们可以使用 reshape 函数,下面的例子中,我们将行向量 x 转换成了一个 (3 imes 4) 的矩阵,返回的新张量内包含的值是相同的;注意,原张量的大小是不变的

    X = x.reshape(3, 4)
    X
    
    tensor([[ 0,  1,  2,  3],
            [ 4,  5,  6,  7],
            [ 8,  9, 10, 11]])
    

    对于, reshape 的每个维度是可以不必须指定的,如果目标是一个矩阵,我们只需要知道宽度,高度将会被隐含地给出。可以在参数传递时将 -1 传递在维度的位置表示让张量自动地计算;上面的函数调用还可以写成 x.reshape(3, -1) 或者 x.reshape(-1, 4)

    通常我们想让我嫩的矩阵初始化为 0 或 1,其他的一些常数,或者服从某些指定分布的随机数。

    torch.zeros((2, 3, 4))
    
    tensor([[[0., 0., 0., 0.],
             [0., 0., 0., 0.],
             [0., 0., 0., 0.]],
    
            [[0., 0., 0., 0.],
             [0., 0., 0., 0.],
             [0., 0., 0., 0.]]])
    
    torch.ones((2, 3, 4))
    
    tensor([[[1., 1., 1., 1.],
             [1., 1., 1., 1.],
             [1., 1., 1., 1.]],
    
            [[1., 1., 1., 1.],
             [1., 1., 1., 1.],
             [1., 1., 1., 1.]]])
    

    通常我们需要使用随机值初始化神经网络,我们可以创建一个张量,其所有元素服从标准高斯(正态)分布,均值为 0,方差为 1

    torch.randn(3, 4)
    
    tensor([[ 0.0701, -0.5225, -1.0090,  0.3266],
            [-1.2237,  0.1912,  1.7305, -1.3328],
            [-1.0946, -0.3725,  0.2093, -0.2414]])
    

    我们还可以将 python 中的列表(list)的中的每一个值用来创建一个张量,下面的例子中,外部的 list 代表 0 轴,里面的 list 代表 1 轴

    torch.tensor([[1, 3, 5, 7], [11, 13, 17, 19], [2, 4, 6, 8]])
    
    tensor([[ 1,  3,  5,  7],
            [11, 13, 17, 19],
            [ 2,  4,  6,  8]])
    

    运算

    x = torch.tensor([1.0, 2, 4, 8])
    y = torch.tensor([2, 2, 2, 2])
    x + y, x - y, x * y, x / y, x ** y  # The ** operator is exponentiation
    
    (tensor([ 3.,  4.,  6., 10.]),
     tensor([-1.,  0.,  2.,  6.]),
     tensor([ 2.,  4.,  8., 16.]),
     tensor([0.5000, 1.0000, 2.0000, 4.0000]),
     tensor([ 1.,  4., 16., 64.]))
    
    torch.exp(x)
    
    tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])
    

    如果想要连结(concatenate)多个张量在一起,我们将张量放在列表中传入函数,并且指定按哪个轴连结,比如 axis 0 表示 shape 的第一个元素,axis 1 是第二个元素,以此类推;在下面的例子中,第一个返回值是一个 (6 imes 4) 的矩阵,因为是按照 axis 0 连结,两个张量的 shape 的第一个元素都是 3,所以合并后的 axis 0 的值是 6

    X = torch.arange(12, dtype=torch.float32).reshape((3, 4))
    Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
    torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)
    
    (tensor([[ 0.,  1.,  2.,  3.],
             [ 4.,  5.,  6.,  7.],
             [ 8.,  9., 10., 11.],
             [ 2.,  1.,  4.,  3.],
             [ 1.,  2.,  3.,  4.],
             [ 4.,  3.,  2.,  1.]]),
     tensor([[ 0.,  1.,  2.,  3.,  2.,  1.,  4.,  3.],
             [ 4.,  5.,  6.,  7.,  1.,  2.,  3.,  4.],
             [ 8.,  9., 10., 11.,  4.,  3.,  2.,  1.]]))
    

    有时候,我们需要通过逻辑语句构造一个二进制值的张量,例如 X == Y,返回的张量的每一个元素都是 0 或 1

    X == Y
    
    tensor([[False,  True, False,  True],
            [False, False, False, False],
            [False, False, False, False]])
    

    计算张量的总和,将返回一个只有一个元素的张量

    X.sum()
    
    tensor(66.)
    

    索引和切片

    就像其它的 Python 数组对象,张量中的元素可以使用索引访问。通常在 Python 数组中,第一个元素下标从 0 开始到数组长度减 1 的索引。作为标准的 Python 列表,也可以通过元素的相对位置,通过负索引访问最后的元素。

    X[-1], X[1:3]
    
    (tensor([ 8.,  9., 10., 11.]),
     tensor([[ 4.,  5.,  6.,  7.],
             [ 8.,  9., 10., 11.]]))
    

    也可以通过索引对元素进行修改

    X[1, 2] = 9
    X
    
    tensor([[ 0.,  1.,  2.,  3.],
            [ 4.,  5.,  9.,  7.],
            [ 8.,  9., 10., 11.]])
    

    如果想要对多个元素分配相同的值,可以简单地使用索引指派。[0:2, :] 表示第 1 行和第 2 行,: 表示 axis 1 (column) 的所有元素。同样地,索引的操作也可以用来向量和多于 2 维的张量上。

    X[0:2, :] = 12
    X
    
    tensor([[12., 12., 12., 12.],
            [12., 12., 12., 12.],
            [ 8.,  9., 10., 11.]])
    

    广播机制

    在上面的运算符部分,我们可以看到两个相同 shape 的张量可以按照元素对元素(elementwise)的运算符计算得到新的相同 shape 的张量;在某些条件下,即使我们张量的 shape 不同,我们仍然可以通过广播机制(broadcasting mechanism)对两个向量进行按元素对元素运算;它的工作过程如下:首先,将两个张量元素都复制到合适的相同大小,然后将转换后的有着相同 shape 的两个向量进行 elementwise 运算。

    a = torch.arange(3).reshape((3, 1))
    b = torch.arange(2).reshape((1, 2))
    a, b
    
    (tensor([[0],
             [1],
             [2]]),
     tensor([[0, 1]]))
    

    因为 ab 分别是 (3 imes 1)(1 imes 2) 的矩阵, 它们的 shape 并匹配,如果我们对其进行相加操作,我们将触发广播机制在这两个矩阵上,将其增大为 (3 imes 2) 的矩阵,将矩阵 a 将相应的列和 b 相应的行复制到合适的大小

    a + b
    
    tensor([[0, 1],
            [1, 2],
            [2, 3]])
    

    内存开销

    运行操作符将导致在内存中新开辟一部分空间存储新的运行结果,比如我们执行 Y = X + Y 语句,我们将开辟新内存空间,然后将 Y 重新指向这个内存地址。

    before = id(Y)
    Y = X + Y
    id(Y) == before
    
    False
    

    首先,我们不希望不断地在内存中申请非必需的空间,在机器学习中,我们可能有成千上百 M 的参数需要去更新,我们希望在原内存空间中更新这些参数,并且一般将会由多个变量指向相同的参数,如果将参数更新,其它的指针可能还指向原先参数的旧空间地址。

    我们可以简单地在内存原地址操作数据,我们可以使用切片符号对之前已经申请了的空间进行更新或使用,例如 Y[:] = <expression> 语句

    Z = torch.zeros_like(Y)
    print('id(Z): ', id(Z))
    Z[:] = X + Y
    print('id(Z): ', id(Z))
    
    id(Z):  2122309357184
    id(Z):  2122309357184
    

    如果 X 的值在之后无需使用,可以使用 X += Y 语句在内存上操作

    before = id(X)
    X += Y
    id(X) == before
    
    True
    

    转换为其它 Python 对象

    可将张量转换为 NumPy 的 ndarray 对象,转换之后的对象是不共享内存的,这使得我们在进行计算时,你不想停止运算,等待着查看 NumPy 包是否想要在相同的内存做其它操作。

    A = X.numpy()  # 将 tensor 转换为 NumPy 的 ndarray
    B = torch.tensor(A)  # 将 ndarray 转换为 Tensor
    type(A), type(B)
    
    (numpy.ndarray, torch.Tensor)
  • 相关阅读:
    Spring使用Cache
    Spring AOP之切入点指示符
    centos下 php未安装posix扩展 安装phpsh导致的问题fix
    Linus:利用二级指针删除单向链表
    AngularJS学习之 ui router
    AngularJS学习之 angular-file-upload控件使用方法
    AngularJS学习之 登录表单 清爽验证(边学边更新)
    AngularJS图片上传功能实践
    JavaScript基础知识之 每日一题(网上搜罗来滴)
    AngularJS学习之 ngTable 翻页 功能以及利用angular service准备测试数据
  • 原文地址:https://www.cnblogs.com/geekfx/p/13897761.html
Copyright © 2011-2022 走看看