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=<CloneBackward0>)
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()函数。

### 回答1: PyTorchtensor切片是指从一个tensor选择特定的元素或子集。切片操作可以通过索引或范围来指定。下面是关于PyTorch tensor切片的一些重要信息: 1.基本切片操作:您可以使用索引操作符[]来对tensor进行切片。例如,如果有一个3x3的tensor,可以使用`tensor[1:3, 0:2]`来获得第二行和第三行的前两列。 2.索引规则:切片操作的索引是从0开始的。在切片时,起始索引是包含在切片的,而结束索引是不包含在切片的。例如,`tensor[1:3]`将返回索引为1和2的元素,但不包括索引为3的元素。 3.负数索引:您可以使用负数索引来从后面开始对tensor进行切片。例如,`tensor[-1]`将返回最后一个元素。 4.步长操作:您可以使用步长操作来跳过某些元素进行切片。例如,`tensor[0:3:2]`将返回索引为0和2的元素。 5.高维tensor切片:对于高维tensor,您可以在多个维度上进行切片。例如,`tensor[:, 1]`将返回所有行的第二列。 6.更改切片:切片的结果是原始tensor的视图,并且共享相同的内存。因此,对切片的更改将反映在原始tensor上。 7.使用切片进行赋值:您可以使用切片操作来对tensor的某些元素进行赋值。例如,`tensor[1:3, 0:2] = 0`将第二行和第三行的前两列设置为0。 请注意,这只是关于PyTorch tensor切片的一些基本信息,更复杂的操作如高级索引和掩码索引等也是可行的。 ### 回答2: PyTorchtensor切片是指从一个tensor选择部分元素的操作。通过切片操作,我们可以访问或修改tensor的特定元素,或者创建一个新的tensor来存储所选元素。 切片操作的基本语法是t[start:stop:step],其start表示起始位置,stop表示结束位置(但不包括该位置上的元素),step表示步长。 例如,如果有一个1维tensor t = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],我们可以使用切片操作来选择其的一部分元素。 - t[2:6]将返回一个新的tensor,包含元素2, 3, 4, 5; - t[:5]将返回一个新的tensor,包含元素0, 1, 2, 3, 4; - t[5:]将返回一个新的tensor,包含元素5, 6, 7, 8, 9; - t[1:8:2]将返回一个新的tensor,包含元素1, 3, 5, 7。 对于多维tensor,我们可以使用相同的切片操作来选择各个维度上的元素。 例如,如果有一个2维tensor t = [[0, 1, 2], [3, 4, 5], [6, 7, 8]],我们可以使用切片操作来选择其的一部分元素。 - t[1:3, :2]将返回一个新的tensor,包含元素[[3, 4], [6, 7]],表示选择第1行和第2行的前2列; - t[:, 1]将返回一个新的tensor,包含元素[1, 4, 7],表示选择所有行的第1列。 需要注意的是,切片操作返回的是原始tensor的一个视图,而不是创建一个新的tensor。这意味着对切片后的tensor进行修改,将会影响到原始tensor。如果需要创建一个新的tensor对象,可以使用切片操作的clone()方法来复制原始tensor的数据。 ### 回答3: PyTorch是一个常用的深度学习框架,TensorPyTorch用于处理数据的基本数据结构。在PyTorch,我们可以使用Tensor进行切片操作来选择或修改我们需要的元素。 通过索引操作,我们可以对Tensor进行切片。在切片操作,可以使用逗号分隔的索引列表来选择多个维度的元素。例如,使用tensor[a:b, c:d]的切片操作,可以选择Tensor从第a行到第b行(不包括b)以及第c列到第d列(不包括d)的元素。 在切片操作,索引的开始和结束位置都是可选的,如果不指定,则默认为从开头到末尾。此外,还可以使用负数索引来表示从末尾开始的位置。 除了使用切片进行选择之外,我们还可以使用切片进行修改。通过将切片操作放在赋值语句的左侧,我们可以将新的值赋予切片所选择的元素。 值得注意的是,切片操作返回的是原始Tensor的视图,而不是复制。这意味着对切片的修改也会反映在原始Tensor上。 需要注意的是,在PyTorch进行切片操作不会对Tensor进行内存复制,这样可以减少内存消耗并提高代码的执行效率。 总而言之,PyTorchTensor切片操作允许我们根据需要选择或修改Tensor的元素。通过索引和切片操作,我们可以根据具体需求灵活操作Tensor的数据。这为我们在深度学习任务提供了丰富的选择和便利性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值