打开网易新闻 查看精彩图片

张量

上期文章我们介绍了pytorch的基础知识,本期我们将开始我们的pytorch之旅的第一个技术知识点--张量

Numpy 提供了一个 n 维数组对象,以及许多用于操作这些数组的函数。Numpy 是科学计算的通用框架;它对计算图、深度学习或梯度一无所知。但是,我们可以通过使用 numpy 操作手动实现网络的前向和后向传递。

Numpy 是一个很棒的框架,但它不能利用 GPU 来加速其数值计算。对于现代深度神经网络,GPU 通常提供50 倍或更高的加速,因此不幸的是 numpy 不足以用于现代深度学习。

这里我们介绍最基本的PyTorch 概念:张量。PyTorch Tensor 在概念上与 numpy 数组相同:Tensor 是一个 n 维数组,PyTorch 提供了许多操作Tensor 的函数。在幕后,张量可以跟踪计算图和梯度,但它们也可用作科学计算的通用工具。

同样与 numpy 不同的是,PyTorch Tensors 可以利用 GPU 来加速其数值计算。要在 GPU 上运行 PyTorch Tensor,只需指定正确的设备。

在开始本文章前,我们需要安装pytorch第三方库软件,直接在cmd命令框中输入

pip install pytorch torchvision
#torch-1.9.0 torchvision-0.10.0 本篇文章的环境版本
张量

张量是一种特殊的数据结构,与数组和矩阵非常相似。在 PyTorch 中,我们使用张量对模型的输入和输出以及模型的参数进行编码。

张量类似于NumPy 的ndarray,不同之处在于张量可以在 GPU 或其他硬件加速器上运行。事实上,张量和 NumPy 数组通常可以共享相同的底层内存,从而无需复制数据。张量也针对自动微分进行了优化(我们将在后面的Autograd 部分分享相关信息)

打开网易新闻 查看精彩图片

张量

张量的定义
import torch
a = torch.ones(5)
print(a)
# tensor([1., 1., 1., 1., 1.])

b = torch.zeros(5)
print(b)
# tensor([0., 0., 0., 0., 0.])

c = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0])
print(c)
#tensor([1., 2., 3., 4., 5.])

使用以上方法我们定义了一维的数据张量,其中torch.tensor中接受一个numpy的数组

当然我们也可以定义一个2维数据或者多维数据,并可以使用shape属性查看张量的属性

data = [[1, 2],[3, 4]]
x_data = torch.tensor(data)
print(x_data)
tensor([[1, 2],
[3, 4]])
np_array = np.array(data)
x_np = torch.from_numpy(np_array)
print(x_np)
tensor([[1, 2],
[3, 4]], dtype=torch.int32)
g = torch.tensor([[[1., 2.], [3., 4.]], [[5., 6.], [7., 8.]]])
print(g)
print(g.shape)
tensor([[[1., 2.],
[3., 4.]],

[[5., 6.],
[7., 8.]]])
torch.Size([2, 2, 2])

当然通过以上的方式定义一个张量外,我们还可以使用另外一个张量来定义新的张量

这里需要说明除非明确覆盖,否则新张量保留原始张量的属性(形状、数据类型)。

data = [[1, 2],[3, 4]]
x_data = torch.tensor(data)
print(x_data)

x_ones = torch.ones_like(x_data) # 保持原始张量属性
print(f"Ones Tensor: \n {x_ones} \n")

x_rand = torch.rand_like(x_data, dtype=torch.float) # 重新定义张量为float类型
print(f"Random Tensor: \n {x_rand} \n")

################
tensor([[1, 2],
[3, 4]])
Ones Tensor:
tensor([[1, 1],
[1, 1]])

Random Tensor:
tensor([[0.6791, 0.0938],
[0.8537, 0.9403]])

同样的我们还可以使用张量的shape的属性定义一个张量,shape是张量维度的元组,除了shape属性外,张量还有tensor.dtype与tensor.device属性

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}")

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}")

############################
Random Tensor:
tensor([[0.2010, 0.4683, 0.1847],
[0.8443, 0.3900, 0.8123]])

Ones Tensor:
tensor([[1., 1., 1.],
[1., 1., 1.]])

Zeros Tensor:
tensor([[0., 0., 0.],
[0., 0., 0.]])
Shape of tensor: torch.Size([3, 4])
Datatype of tensor: torch.float32
Device tensor is stored on: cpu

张量运算

张量运算与普通的数据运算类似,包括算术、线性代数、矩阵操作(转置、索引、切片)、采样等。这些操作中的每一个都可以在 GPU 上运行(速度通常比在 CPU 上更高)。默认情况下,张量是在 CPU 上创建的。我们需要使用.to方法明确地将张量移动到 GPU

if torch.cuda.is_available():
tensor = tensor.to('cuda')
##张量的数学操作可以参考##pytorch.org/docs/stable/torch.html
tensor1 = torch.tensor([[1,2,3],[4,5,6]])
tensor2 = torch.tensor([[-1,2,-3],[4,-5,6]])
print(tensor1+tensor2)
print(torch.add(tensor1,tensor2))
# tensor([[ 0, 4, 0],
# [ 8, 0, 12]])

print(tensor1-tensor2)
print(torch.sub(tensor1,tensor2))
# tensor([[ 2, 0, 6],
# [ 0, 10, 0]])

print(tensor1 * 2)
# tensor([[ 2, 4, 6],
# [ 8, 10, 12]])

print(tensor1 * tensor2)
# tensor([[ -1, 4, -9],
# [ 16, -25, 36]])

tensor3 = torch.tensor([[1,2],[3,4],[5,6]])
print(torch.mm(tensor1,tensor3))
# tensor([[22, 28],
# [49, 64]])

# Tensor with scalar
print(tensor1/2)
# tensor([[0, 1, 1],
# [2, 2, 3]])
##张量除法
print(tensor1/tensor2)
# tensor([[-1, 1, -1],
# [ 1, -1, 1]])
##连接张量
t1 = torch.cat([tensor1, tensor2], dim=1)
print(t1)
tensor([[ 1, 2, 3, -1, 2, -3],
[ 4, 5, 6, 4, -5, 6]])

numpy数组到张量的互相转换张量到 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.]
张量的变化反映在 NumPy 数组中。这是由于CPU 和 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 数组到张量,同样的由于CPU 和 NumPy
数组上的张量可以共享它们的底层内存位置,改变一个将改变另一个
n = np.ones(5)
t = torch.from_numpy(n)
t: tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
n: [1. 1. 1. 1. 1.]
t: tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
n: [2. 2. 2. 2. 2.]