PyTorch教程:Tensor的使用介绍

目录

创建Tensor

Tensor的shape

tensor数据类型

PyTorch tensor的数学和逻辑运算

Tensor Broadcasting广播

复制tensor

改变维数

和Numpy的转换

Tensor是PyTorch中心的数据抽象,本文深度详细介绍PyTorch的torch.Tensor类。包括创建Tensor的方法,Tensor的shape属性,tensor的数据类型和数学运算,tensor的广播机制,克隆tensor,改变tensor的维数,将tensor转换维Numpy的ndarray以及将ndarray转为为tensor。

创建Tensor

import torch
import math

x = torch.empty(3, 4)
print(type(x))
print(x)
  • 使用torch模块的工厂函数torch.empty()创建一个tensor,该tensor是2维,有3行4列。返回的对象类型是torch.Tensor,是torch.FloatTensor的别名。默认情况下PyTorch tensor是32bit的浮点数。你可能会看到打印的tensor是像随机数的值,这是因为torch.empty为tensor调用内存分配,但是并没有初始化其值,你看到的是在分配内存时的值。

  • 1维的tensor叫做向量vector,2维的tensor叫做矩阵matrix,高于两维一般称其为tensor

更多情况下,你想用一些值来初始化tensor,通常情况下将初始化为全0,全1或者随机值。torch模块为这些初始化提供了工厂函数:

zeros = torch.zeros(2, 3)
print(zeros)

ones = torch.ones(2, 3)
print(ones)

torch.manual_seed(1729)
random = torch.rand(2, 3)
print(random)

torch.manual_seed()用于手动设置随机数生成器的种子,保证使用torch模块随机数工厂函数torch.rand()的代码的可再现性

torch.manual_seed(1729)
random1 = torch.rand(2, 3)
print(random1)

random2 = torch.rand(2, 3)
print(random2)

torch.manual_seed(1729)
random3 = torch.rand(2, 3)
print(random3)

random4 = torch.rand(2, 3)
print(random4)

输出:

tensor([[0.3126, 0.3791, 0.3087],
        [0.0736, 0.4216, 0.0691]])
tensor([[0.2332, 0.4047, 0.2162],
        [0.9927, 0.4128, 0.5938]])
tensor([[0.3126, 0.3791, 0.3087],
        [0.0736, 0.4216, 0.0691]])
tensor([[0.2332, 0.4047, 0.2162],
        [0.9927, 0.4128, 0.5938]])

最后一种创建tensor的方法:

some_constants = torch.tensor([[3.1415926, 2.71828], [1.61803, 0.0072897]])
print(some_constants)

some_integers = torch.tensor((2, 3, 5, 7, 11, 13, 17, 19))
print(some_integers)

more_integers = torch.tensor(((2, 4, 6), [3, 6, 9]))
print(more_integers)

Tensor的shape

我们经常对两个或者多个tensor执行操作,这些tensor需要是相同的shape,也就是有相同的维数,并且在各个维度上的cells数目相同,我们可以使用torch.*_liek()方法,比如torch.empty_like(),torch.zeros_like(), torch.ones_like(),toch.rand_like()

x = torch.empty(2, 2, 3)
print(x.shape)
print(x)

empty_like_x = torch.empty_like(x)
print(empty_like_x.shape)
print(empty_like_x)

zeros_like_x = torch.zeros_like(x)
print(zeros_like_x.shape)
print(zeros_like_x)

ones_like_x = torch.ones_like(x)
print(ones_like_x.shape)
print(ones_like_x)

rand_like_x = torch.rand_like(x)
print(rand_like_x.shape)
print(rand_like_x)

tensor数据类型

通过在torch的工厂函数输入参数中指定dtype的值,给创建的tensor指定数据类型,默认的数据类型是torch.float(32位浮点),常见的数据类型如下 Available data types include:

  • torch.bool
  • torch.int8
  • torch.uint8
  • torch.int16
  • torch.int32
  • torch.int64
  • torch.half
  • torch.float
  • torch.double
  • torch.bfloat

PyTorch tensor的数学和逻辑运算

ones = torch.zeros(2, 2) + 1
twos = torch.ones(2, 2) * 2
threes = (torch.ones(2, 2) * 7 - 1) / 2
fours = twos ** 2
sqrt2s = twos ** 0.5

print(ones)
print(twos)
print(threes)
print(fours)
print(sqrt2s)

输出:

tensor([[1., 1.],
        [1., 1.]])
tensor([[2., 2.],
        [2., 2.]])
tensor([[3., 3.],
        [3., 3.]])
tensor([[4., 4.],
        [4., 4.]])
tensor([[1.4142, 1.4142],
        [1.4142, 1.4142]])

Tensor Broadcasting广播

一般情况下进行算术运算的tensor的shape必须相同,但是有一种例外情况是tensor的广播。

rand = torch.rand(2, 4)
doubled = rand * (torch.ones(1, 4) * 2)

print(rand)
print(doubled)

输出:

tensor([[0.6146, 0.5999, 0.5013, 0.9397],
        [0.8656, 0.5207, 0.6865, 0.3614]])
tensor([[1.2291, 1.1998, 1.0026, 1.8793],
        [1.7312, 1.0413, 1.3730, 0.7228]])
a =     torch.ones(4, 3, 2)

b = a * torch.rand(   3, 2) # 3rd & 2nd dims identical to a, dim 1 absent
print(b)

c = a * torch.rand(   3, 1) # 3rd dim = 1, 2nd dim identical to a
print(c)

d = a * torch.rand(   1, 2) # 3rd dim identical to a, 2nd dim = 1
print(d)

输出:

tensor([[[0.6493, 0.2633],
         [0.4762, 0.0548],
         [0.2024, 0.5731]],

        [[0.6493, 0.2633],
         [0.4762, 0.0548],
         [0.2024, 0.5731]],

        [[0.6493, 0.2633],
         [0.4762, 0.0548],
         [0.2024, 0.5731]],

        [[0.6493, 0.2633],
         [0.4762, 0.0548],
         [0.2024, 0.5731]]])
tensor([[[0.7191, 0.7191],
         [0.4067, 0.4067],
         [0.7301, 0.7301]],

        [[0.7191, 0.7191],
         [0.4067, 0.4067],
         [0.7301, 0.7301]],

        [[0.7191, 0.7191],
         [0.4067, 0.4067],
         [0.7301, 0.7301]],

        [[0.7191, 0.7191],
         [0.4067, 0.4067],
         [0.7301, 0.7301]]])
tensor([[[0.6276, 0.7357],
         [0.6276, 0.7357],
         [0.6276, 0.7357]],

        [[0.6276, 0.7357],
         [0.6276, 0.7357],
         [0.6276, 0.7357]],

        [[0.6276, 0.7357],
         [0.6276, 0.7357],
         [0.6276, 0.7357]],

        [[0.6276, 0.7357],
         [0.6276, 0.7357],
         [0.6276, 0.7357]]])

tensor的大多数二元操作将返回第三个新的tensor,例如,c = a * b,a和b是两个tensor,新的tensor c将占据不同与a和b的内存区域。 有时候,当你做元素操作时希望丢弃中间结果,可以使用单下划线_的函数版本,可就地改变tensor。

a = torch.ones(2, 2)
b = torch.rand(2, 2)

print('Before:')
print(a)
print(b)
print('\nAfter adding:')
print(a.add_(b))
print(a)
print(b)
print('\nAfter multiplying')
print(b.mul_(b))
print(b)

输出:

Before:
tensor([[1., 1.],
        [1., 1.]])
tensor([[0.0905, 0.4485],
        [0.8740, 0.2526]])

After adding:
tensor([[1.0905, 1.4485],
        [1.8740, 1.2526]])
tensor([[1.0905, 1.4485],
        [1.8740, 1.2526]])
tensor([[0.0905, 0.4485],
        [0.8740, 0.2526]])

After multiplying
tensor([[0.0082, 0.2012],
        [0.7638, 0.0638]])
tensor([[0.0082, 0.2012],
        [0.7638, 0.0638]])

需要注意的是in-place算术函数是torch.Tensor对象的方法,而不是想许多其他函数一样附加在torch模块。

复制tensor

与Python中的任何对象一样,将tensor赋值给变量,会使变量是tensor的标签,而不是拷贝它。
当需要分开拷贝数据时,可以使用clone()方法。

a = torch.ones(2, 2)
b = a.clone()

assert b is not a      # 在内存中是不同的对象
print(torch.eq(a, b))  # 但是所存储的内容相同

a[0][1] = 561          # a 改变了
print(b)               # 但b仍然是1

在许多情况下,如果你的模型在forward()方法中有多种计算路径。并且原始的tensor和克隆的tensor都对模型的输出有贡献,为了使能模型学习,你希望autograd在这两种tensor上开启。如果原始tensor的autograd开启了,你将得到你所希望的结果。 另一方面,如果在做计算时,原始tensor和克隆的tensor都不需要跟踪梯度,只要原始tensor的autograd没有开启,你将得到你所希望的结果。 第三种情况是,设想你在模型的forward()函数中执行计算,梯度是默认开启的,你想拉一些中间值去生成新的特性,这种情况下,你不想克原始tensor的克隆拷贝跟踪梯度--当autograd的历史跟踪关闭时性能将提高。这种情况下,可以在原始tensor上使用.detech()方法

a = torch.rand(2, 2, requires_grad=True) # 开启autograd
print(a)

b = a.clone()
print(b)

c = a.detach().clone()
print(c)

print(a)

输出:

tensor([[0.6545, 0.4144],
        [0.0696, 0.4648]], requires_grad=True)
tensor([[0.6545, 0.4144],
        [0.0696, 0.4648]], grad_fn=)
tensor([[0.6545, 0.4144],
        [0.0696, 0.4648]])
tensor([[0.6545, 0.4144],
        [0.0696, 0.4648]], requires_grad=True)

改变维数

有时候我们需要改变维数,例如传递单个输入实例到模型。Pytorch模型通常期望是batch的输入。假设你的模型处理3x226x226的图像(3个颜色通道,226x226的尺寸),输入的tensor的shape是(3,226,226),但是模型期望的输入是(N,3,226,226),N表示一个batch的图像数目,如果将输入转换为包含一个图像的batch呢?

a = torch.rand(3, 226, 226)
b = a.unsqueeze(0)

print(a.shape)
print(b.shape)

输出:

torch.Size([3, 226, 226])
torch.Size([1, 3, 226, 226])

还可以使用squeeze()将batch转换为non-batch计算

a = torch.rand(1, 20)
print(a.shape)
print(a)

b = a.squeeze(0)
print(b.shape)
print(b)

c = torch.rand(2, 2)
print(c.shape)

d = c.squeeze(0)
print(d.shape)
d = c.squeeze(1)
print(d.shape)

输出:

torch.Size([1, 20])
tensor([[0.3118, 0.9180, 0.7293, 0.5351, 0.5078, 0.8012, 0.5088, 0.3142, 0.8068,
         0.6503, 0.4621, 0.6882, 0.7282, 0.9156, 0.4836, 0.1451, 0.7946, 0.4126,
         0.1625, 0.9214]])
torch.Size([20])
tensor([0.3118, 0.9180, 0.7293, 0.5351, 0.5078, 0.8012, 0.5088, 0.3142, 0.8068,
        0.6503, 0.4621, 0.6882, 0.7282, 0.9156, 0.4836, 0.1451, 0.7946, 0.4126,
        0.1625, 0.9214])
torch.Size([2, 2])
torch.Size([2, 2])
torch.Size([2, 2])

可以看到使用squeeze()后,2维的tensor变成了1维的tensor,a的外层比b多一个方括号[]

squeeze()只能是改变宽度为1的维,当在c中尺寸是2的维上使用squeeze()时,并不会有任何改变。

有时候希望彻底改变tensor的形状,但保留其元素和内容不变。 出现这种需求的一种情况是在卷积层和线性层的接口,通常发生在图像分类模型。一个卷积核产生的tensor的形状是特征图的个数宽度高度,但是紧接着的线性层希望一维的输入。reshape()将为你做这一工作。

output3d = torch.rand(6, 20, 20)
print(output3d.shape)

input1d = output3d.reshape(6 * 20 * 20)
print(input1d.shape)

# can also call it as a method on the torch module:
print(torch.reshape(output3d, (6 * 20 * 20,)).shape)

输出:

torch.Size([6, 20, 20])
torch.Size([2400])
torch.Size([2400])

reshape()执行成功以后会返回tensor的一个改变的视图view,但底层的内存区域保持不变。这意味着对原来tensor的任何改变都会反映在这个tensor的视图上,除非使用clone()方法。

和Numpy的转换

当你有已经存在使用Numpy的ndarray存储的数据的机器学习或者科学的代码,你希望将这些数据表示成PyTorch tensor,利用PyTorch的GPU加速或者它用于构建机器学习模型的高效抽象能力。可以很容的在ndarray和PyTorch tensor直接切换。使用torch.from_numpy()可以将numpy ndarray转换为tensor,使用torch.numpy()可以将tensor转换为numpy ndarray。但是tensor和numpy ndarray使用同样的内存,除非使用clone()函数。

你可能感兴趣的:(Pytorch教程,pytorch,深度学习,python,tensor,pytorch教程)