Pytorch官方引导02-TENSORS
目录
张量(Tensor),是一种特殊化的数据结构,与数组和矩阵非常相似。在Pytorch中,我们使用张量来编码一个模型的输入输出,以及模型参数。
import torch
import numpy as np
初始化张量
初始化张量的方式有多种,示例如下:
直接来源于数据
张量能够直接从数据创建,其数据类型是自动推断的:
data = [[1, 2], [3, 4]]
x_data = torch.tensor(data)
来源于numpy数组
张量也能够从numpy矩阵创建:
来源于另一个张量
新的张量将保持原先的特征(形状,数据类型),除非被重载(如下第5行)。
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.1385, 0.3441],
[0.5776, 0.6181]])
使用随机值或常值
shape是一个描述张量不同维度的元组。如下的函数中,它决定了生成张量的维度性质。
shape = (2, 3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)
print(f"Random Tensor; \n{rand_tensor} \n")
print(f"Ones Tensor:\n{ones_tensor}\n")
print(f"Zeros Tensor:\n{zeros_tensor}\n")
Random Tensor;
tensor([[0.5773, 0.8621, 0.5393],
[0.0931, 0.3914, 0.0294]])
Ones Tensor:
tensor([[1., 1., 1.],
[1., 1., 1.]])
Zeros Tensor:
tensor([[0., 0., 0.],
[0., 0., 0.]])
张量的属性
张量的属性包括相互其形状(shape)、数据类型(datatype)以及他们所处的设备(device):
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
对张量的操作
张量操作有超过100种,包括算数、线性代数、矩阵操作
(转置、编号、切片)、采样和其他更复杂的操作。
每一个操作都可以在GPU上跑,速度远高于CPU上。如果你正在使用Colab,可以使用Runtime > Change runtime type分配一个GPU。
默认地,张量是在CPU上创建的,我们需要使用.to方法显式地将其移动到GPU上(应先检查GPU可用性)。需要注意的是,跨设备复制大型张量可能是机器耗费时间和内存资源的。
.to本身应该不对原张量进行变动,此处应当赋一次值保存更改:
# We move our tensor to the GPU if available
if torch.cuda.is_available():
tensor = tensor.to("cuda")
尝试一些如上列出的操作。如果你对numpy API比较熟悉,
Tensor API用起来应该相当简单。
标准numpy风格的索引和切片操作
tensor = torch.ones(4, 4)
print('First row: ', tensor[0])
print('First column:', tensor[:, 0])
print('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.]])
连接张量
可以使用torch.cat函数来沿某一维度连结一个张量序列,也可以使用torch.stack(与torch仅有细微差异)。
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.]])
算数操作
# This computes the matrix multiplication between two tensors. y1, y2, y3 will have the same value
y1 = tensor @ tensor.T
y2 = tensor.matmul(tensor.T)
y3 = torch.rand_like(tensor)
torch.matmul(tensor, tensor.T, out=y3)
# This computes the element-wise product. z1, z2, z3 will have the same value
z1 = tensor * tensor
z2 = tensor.mul(tensor)
z3 = torch.rand_like(tensor)
torch.mul(tensor, tensor, out=z3)
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
print("y1:\n", y1, "\n")
print("y2:\n", y2, "\n")
print("y3:\n", y3, "\n")
print("z1:\n", z1, "\n")
print("z2:\n", z2, "\n")
print("z3:\n", z3, "\n")
y1:
tensor([[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.]])
y2:
tensor([[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.]])
y3:
tensor([[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.]])
z1:
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
z2:
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
z3:
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
上例中,@、matmul是矩阵乘法(matrix multiply),而*、mul是点乘(multiply),这两个函数都能够:
- 直接赋值输出;
- 通过out参数输出。
单元素张量
如果你有一个仅含一个元素的张量,比如累加一个张量的所有值到一个值上所获得的张量,那么你通过item()方法就能够将其转换成一个python数值(简单数据类型)。
agg = tensor.sum()
agg_item = agg.item()
print(agg_item, type(agg_item))
12.0 <class 'float'>
就地操作
将返回值存入原变量的操作被称为就地操作(in-place operations),通常通过下标"_"与一般的方法区分开来。比如x.copy_(y), x.t()_,都将直接改变x本身:
print(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.]])
注:in-place操作能够节约内存,但是可能由于立即失去历史而在计算导数时出现问题,因此不推荐使用。
与NumPy联合使用
CPU上的张量以及NumPy数组能够攻下他们的内存地址,修改其中一个将会同时改变另一个。
张量 to 数组
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.]
对张量的改变也会反映到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.]
数组 to 张量
n = np.ones(5)
t = torch.from_numpy(n)
对numpy数组的改变也会反映到张量上,如下所示:
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.]
总结:
- 张量到数组直接使用self.numpy()方法;
- 数组到张量使用torch.from_numpy()函数。