首页 > 其他 > 详细

数据操作 - 基于 pytorch

时间:2020-10-29 19:56:26      阅读:35      评论:0      收藏:0      [点我收藏+]

数据操作 - 基于 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\times 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\times 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\times 1\)\(1\times 2\) 的矩阵, 它们的 shape 并匹配,如果我们对其进行相加操作,我们将触发广播机制在这两个矩阵上,将其增大为 \(3\times 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)

数据操作 - 基于 pytorch

原文:https://www.cnblogs.com/geekfx/p/13897761.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!