地址:https://pytorch.org/tutorials/beginner/basics/tensorqs_tutorial.html
Tensors are a specialized data structure that are very similar to arrays and matrices. In PyTorch, we use tensors to encode the inputs and outputs of a model, as well as the model’s parameters.
Tensors are similar to NumPy’s ndarrays, except that tensors can run on GPUs or other hardware accelerators. In fact, tensors and NumPy arrays can often share the same underlying memory, eliminating the need to copy data (see Bridge with NumPy). Tensors are also optimized for automatic differentiation (we’ll see more about that later in the Autograd section). If you’re familiar with ndarrays, you’ll be right at home with the Tensor API. If not, follow along!
简单翻译:
Tensor是一种特殊的数据类型,这种数据类型非常类似于数组和矩阵。在Pytorch中,我们使用tensors去对模型的输入和输出,以及模型的参数进行编码。
Tensors 是非类似于NumPy的ndarrays,除了tensor能偶运行在GPU和其他硬件计算器上以外。事实上,tensors和NumPy数组通常能够共享相同潜在的内存,从而消除复制数据的需要。Tensors也对自动微分进行了优化。如果你熟悉ndarrays,那么你使用Tensor API的时候就像回到家一般亲切。如果不熟悉,那么跟紧(以下教程)就对了。
import numpy as np
import torch
Tensor的初始化
Tensor可以以多种方式初始化,下面是一些例子。
直接由数据初始化
使用矩阵创建一个tensor。程序会自动推断出数据的类型。
data = [[1, 2], [3, 4]]
x_data = torch.tensor(data)
从numpy中获得tensor
np_array = np.array(data)
x_np = torch.from_numpy(np_array)
从其他的tensor中获得tensor:
新的tensor会保留原有tensor的维度和数据类型,除非显式的进行声明
x_ones = torch.ones_like(x_data) # retains the properties of x_data
print(f"Ones Tensor: \n {x_ones} \n")
x_rand = torch.rand_like(x_data, dtype=torch.float) # overrides the datatype of x_data
print(f"Random Tensor: \n {x_rand} \n")
Ones Tensor:
tensor([[1, 1],
[1, 1]])
Random Tensor:
tensor([[0.8823, 0.9150],
[0.3829, 0.9593]])
从随机或固定的值
shape是一个tensor维度的tuple,在下面的函数中,其决定了输出tensor的维度。
shape = (2, 3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape, dtype=torch.float)
print(rand_tensor)
print(ones_tensor)
print(zeros_tensor)
Random Tensor:
tensor([[0.3904, 0.6009, 0.2566],
[0.7936, 0.9408, 0.1332]])
Ones Tensor:
tensor([[1., 1., 1.],
[1., 1., 1.]])
Zeros Tensor:
tensor([[0., 0., 0.],
[0., 0., 0.]])
tensor的属性
tensor拥有三个属性,分别是形状,数据类型和其被存储的位置
tensor = torch.rand(3, 4,)
print(f"Shape of tensor: {tensor.shape}")
print(f"datatype of tensor: {tensor.dtype}")
print(f"Device tensor is stored on: {tensor.device}")
Shape of tensor: torch.Size([3, 4])
Datatype of tensor: torch.float32
Device tensor is stored on: cpu
对tensors的操作
有超过100种tensor的操作,包括运算,线性代数,矩阵操作(变换,索引,切片), 示例和更多信息被全面的描述在此:https://pytorch.org/docs/stable/torch.html
每一个操作都能运行在GPU上(通常速度会高于CPU)。如果你使用Colab,使用GPU的方法是前往Runtime > Change runtime type > GPU。
通常来说, Tensors会被创建于CPU,我们需要显式的将tensors移动到GPU,这会使用".to"方法(在检查GPU可用之后)。必须清楚的是,在时间和内存上而言,将巨大的tensors复制并移动设备会有巨大的花费!
if torch.cuda.is_available():
tensor = tensor.to("cuda")
请尝试一些列表中的list。如果你熟悉NumPy API,你会发现Tensor API是是非容易使用的。
像numpy一般标准的索引和切片
tensor = torch.ones(4, 4)
print(tensor)
print(f"First row(行): {tensor[0]}")
print(f"First column: {tensor[:, 0]}")
print(f"Last column: {tensor[..., -1]}")
tensor[:, 1] = 0
print(tensor)
First row: tensor([1., 1., 1., 1.])
First column: tensor([1., 1., 1., 1.])
Last column: tensor([1., 1., 1., 1.])
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
tensors的拼接 你可以使用torch.cat去以你所给的维度按照顺序凭借一系列的tensors。另见torch.stack——另外一种拼接tensors的方法。这种方法与torch.cat有细微的区别。
t1 = torch.cat([tensor, tensor, tensor], dim=1)
print(t1)
tensor([[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.]])
运算操作
# 以下将计算两个矩阵的乘法。y1,y2,y3都拥有相同的value
# tensor.T将返回一个tensor的转置
print(tensor)
y1 = tensor @ tensor.T
y2 = tensor.matmul(tensor.T)
print(y2)
y3 = torch.rand_like(y1)
torch.matmul(tensor, tensor.T, out=y3)
# 此处计算了元素相乘的乘法。其中z1,z2,z3将会拥有相同的value
z1 = tensor * tensor
z3 = torch.rand_like(tensor)
torch.mul(tensor, tensor, out=z3)
print(z3)
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
单元素tensors。 如果你有一个只有一个元素的tensor,比如说将一个tensor的值都聚合成为了一个值,你可以使用item()方法将其转化为Python的数值
agg = tensor.sum()
agg_item = agg.item()
print(agg_item, type(agg_item))
12.0 <class 'float'>
就地操作将结果存储在操作数的操作被称做就地操作。其被表示为添加“”后缀。举例而言:x.copy(y),x.t_(),都会改变x。
print(f"{tensor} \n")
tensor.add_(5)
print(tensor)
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
tensor([[6., 5., 6., 6.],
[6., 5., 6., 6.],
[6., 5., 6., 6.],
[6., 5., 6., 6.]])
注意:
就地操作会节约一些内存,但是在计算倒数的时候也有可能会出现问题,这是因为历史的信息会立即消失。因此,并不推荐使用就地操作。
NumPy的桥梁
在CPU上的Tensors和NumPy数组可以共享他们潜在的内存地址,并且改变其中一个将会改变另一个,即在tensor中的改变也会影响在NumPy中的数组。
Tensor对NumPy数组(的影响)
t = torch.ones(5)
print(f"t: {t}")
n = t.numpy()
print(f"n: {n}")
t: tensor([1., 1., 1., 1., 1.])
n: [1. 1. 1. 1. 1.]
在tensor中的改变会反映在NumPy数组中。
t.add_(1)
print(f"t: {t}")
print(f"n: {n}")
t: tensor([2., 2., 2., 2., 2.])
n: [2. 2. 2. 2. 2.]
NumPy数组对Tensor(的影响)
n = np.ones(5)
t = torch.from_numpy(n)
在NumPys数组中的改变会反映在tensor中。
np.add(n, 1, out=n)
print(f"t: {t}")
print(f"n: {n}")
t: tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
n: [2. 2. 2. 2. 2.]