在PyTorch快速入门中我们大概知道了一个神经网络模型的构成模块以及如何从数据处理到模型训练。但是没有具体去了解每部分的细节,本章节我们来学习一些PyTorch必备的知识,为后续学习奠定基础。
深度学习能够超过传统的机器学习算法离不开神经网络,然而神经网络最基本的数据结构就是张量,神经网络的输入是张量,然后通过每个张量进行线性变换,再经过激活函数的非线性变换,通过层层计算最终使得损失函数的最小化,完成模型的训练。所以要想学好深度学习,对基础的数据结构还是要非常了解。
1、向量
向量(1维数组)定义为一行或者一列数,分别称之为行向量和列向量,如图1和图2所示(这里用T代表转置,意思是行列互换)。向量是最基本的一种数据排列方式,组成向量的每个数称为向量的分量,这里用来表示,其中的n代表向量分量的数目,即向量的大小。
向量与向量之间一个重要的运算是点积(Dot Product),或者称之为内积(Inner Product),表现为两个相同大小的向量按分量相乘并且求和.。如图3所示
内积的几何解释:两个向量的内积等于向量的模长乘以向量之间夹角的余弦,如图4所示。
我们把向量与自身内积的平方根称之为向量的长度(或模,即L2-norm)。
在神经网络中,向量往往不是某事物的特征。例如,房子的价格是受多种因素(是否为学区房、附近有无地铁、房子面积、房间数量、楼层等)来影响,那么我们将这多种因素来表示为房子的特征,这一组特征值就可以用向量表示。
2、矩阵
矩阵由一组向量组成的集合。矩阵也称为2维数组。
在神经网络中,在刚才的例子中,一套房子的特征可以用一个向量来表示。那么我们要建m套房子的数据集,那么就是m个向量的组合,也即是得到一个m行n列的矩阵。(n为一套房子的向量的长度)。
3、张量
张量是矩阵的推广,可以用来描述N维数据。其实在计算机领域内,大家叫法都不那么严格,一个矩阵,你可以叫它矩阵,也可以叫它二阶张量,也可以叫它二维数组。
在神经网络中,张量在图像领域用的是很普遍的。如一张彩色图像,有宽度和高度,同时又有R,G,B三个通道。所以一张彩色图像就是三阶张量(通道 * 宽度 *高度)。
再比如高一阶的四阶张量,可以理解为一个批次(批次简单理解为多张图片)的彩色图像。因为在做图像识别过程中,我们训练和推理过程中可以一次推理N张图像,这个N称为批次。即是 批次 * 通道 * 宽度 *高度 的四阶张量。在深度学习中,我们要处理不止一张图片或一篇文档——我们要处理一个集合。我们可能有10,000张郁金香的图片,这意味着,我们将用到4阶张量
4、向量、矩阵和张量比较
几何代数中定义的张量是基于向量和矩阵的推广,比如我们可以将标量视为零阶张量,矢量可以视为一阶张量,矩阵就是二阶张量。
张量维度 | 代表含义 |
0维张量 | 代表的是标量(数字) |
1维张量 | 代表的是向量 |
2维张量 | 代表的是矩阵 |
3维张量 | 时间序列数据 股价 文本数据 单张彩色图片(RGB) |
1. 标量,也称 Scalar,是一个只有大小,没有方向的量,比如 1.8、e、10 等。
2. 向量,也称 Vector,是一个有大小也有方向的量,比如 (1,2,3,4) 等。
3. 矩阵,也称 Matrix,是多个向量合并在一起得到的量,比如[(1,2,3),(4,5,6)]等。
不难发现,几种数据表示其实都是有着联系的,标量可以组合成向量,向量可以组合成矩 阵。那么,我们可否将它们看作是一种数据形式呢?
答案是可以的,这种统一的数据形式,在 PyTorch 中我们称之为张量 (Tensor)。从标 量、向量和矩阵的关系来看,大致可以认为它们就是不同“维度”的 Tensor。
张量是深度学习的基础。它的核心是一个数据容器,多数情况下,它包含数字,有时候它也包含字符串,但这种情况比较少。
1、向量:一个向量表示一组有序排列的数,通过次序中的索引我们能够找到每个单独的数,向量通常用粗体的小写字母表示,如x。
import numpy as np
#行向量
a = np.array([1,2,3,4])
2、矩阵:是一个二维数组,其中的每一个元素由两个索引来决定( ),矩阵通常用加粗斜体的大写字母表示,如X。
import numpy as np
#矩阵
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
3、张量:
张量是一种特殊的数据结构,与数组和矩阵非常相似。在 PyTorch 中,我们使用张量对模型的输入和输出以及模型的参数进行编码。
张量类似于NumPy 的ndarray,除了张量可以在 GPU 或其他硬件加速器上运行。事实上,张量和 NumPy 数组通常可以共享相同的底层内存,从而无需复制数据(请参阅Bridge with NumPy)。张量也针对自动微分进行了优化(我们将在稍后的Autograd 部分中看到更多相关内容)。如果您熟悉 ndarrays,那么您对 Tensor API 会很熟悉。如果没有,请跟随!
import·torch
import·numpy·as·np
3.1 初始化张量
张量可以以各种方式初始化。请看以下示例:
直接创建张量
首先来看直接创建的方法,这也是最简单创建的方法。我们可以通过torch.tensor()直接使用数据,构造一个张量。数据类型是自动推断的。
data = [[1, 2],[3, 4]]
x_data = torch.tensor(data)
x_data
tensor([[1, 2],
[3, 4]])
NumPy 数组创建张量
在实际应用中,我们在处理数据 的阶段多使用的是 NumPy,而数据处理好之后想要传入 PyTorch 的深度学习模型中,则 需要借助 Tensor,所以 PyTorch 提供了一个从 NumPy 转到 Tensor 的语句。并且可以从 NumPy 数组创建,反之亦然 。
np_array = np.array(data)
x_np = torch.from_numpy(np_array)
x_np
tensor([[1, 2],
[3, 4]])
随机初始化张量
我们可以通过torch.rand()的方法,构造一个随机初始化的矩阵(2阶张量):
import torch
x = torch.rand(6, 4)
print(x)
注意:
全0矩阵的构建
我们可以通过torch.zeros()构造一个矩阵全为 0,并且通过dtype设置数据类型为 long。
import torch
x = torch.zeros(5 3, dtype=torch.long)
print(x)
根据一个张量构建形状相同的张量:
新张量保留参数张量的属性(形状、数据类型),除非显式覆盖。
x = torch.ones(2, 2, dtype=torch.double)
print(x)
x1 = torch.randn_like(x, dtype=torch.float)
print(x1)
# 结果会有一样的size
# 获取它的维度信息
print(x.size())
print(x1.shape)
tensor([[1, 1],
[1, 1]])
tensor([[0.0809, 0.7885],
[0.0739, 0.3876]])
使用随机值和定值:
shape是张量维度的元组。在下面的函数中,它决定了输出张量的维度。
shape = (2,3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)
print(f"Random Tensor:
{rand_tensor}
")
print(f"Ones Tensor:
{ones_tensor}
")
print(f"Zeros Tensor:
{zeros_tensor}")
Random Tensor:
tensor([[0.0312, 0.8956, 0.5396],
[0.0653, 0.3294, 0.7575]])
Ones Tensor:
tensor([[1., 1., 1.],
[1., 1., 1.]])
Zeros Tensor:
tensor([[0., 0., 0.],
[0., 0., 0.]])
Tensor 的转换
在实际项目中,我们接触到的数据类型有很多,比如 Int、list、NumPy 等。为了让数据在 各个阶段畅通无阻,不同数据类型与 Tensor 之间的转换就非常重要了。接下来我们一起来看看 int、list、NumPy 是如何与 Tensor 互相转换的。
Int 与 Tensor 的转换:
a = torch.Tensor(1)
b = a.item()
我们通过 torch.Tensor 将一个数字(或者标量)转换为 Tensor,又通过 item() 函数,将 Tensor 转换为数字(标量),item() 函数的作用就是将 Tensor 转换为一个 python number。
list 与 tensor 的转换:
a = [1, 2, 3]
b = torch.Tensor(a)
c = b.numpy().tolist()
在这里对于一个 list a,我们仍旧直接使用 torch.Tensor,就可以将其转换为 Tensor 了。 而还原回来的过程要多一步,需要我们先将 Tensor 转为 NumPy 结构,之后再使用 tolist() 函数得到 list。
张量到 NumPy 数组
背后原理:CPU 中张量和 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 数组中。
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 数组到张量
n = np.ones(5)
t = torch.from_numpy(n)
print(n)
print(t)
[1. 1. 1. 1. 1.]
tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
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.]
常见的构造张量(Tensor)的方法总结
函数 | 功能 |
Tensor(sizes) | 基础构造函数 |
tensor(data) | 类似于np.array |
ones(sizes) | 全1 |
zeros(sizes) | 全0 |
eye(sizes) | 对角为1,其余为0 |
arange(s,e,step) | 从s到e,步长为step |
linspace(s,e,steps) | 从s到e,均匀分成step份 |
rand/randn(sizes) | rand是[0,1)均匀分布;randn是服从N(0,1)的正态分布 |
normal(mean,std) | 正态分布(均值为mean,标准差是std) |
randperm(m) | 随机排列 |
3.2 张量的属性
张量属性描述了它们的形状、数据类型和存储它们的设备
tensor = torch.rand(3,4)
# Get cpu or gpu device for training.
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Using {device} device")
print(f"Shape of tensor: {tensor.shape}")
print(f"Datatype of tensor: {tensor.dtype}")
print(f"Device tensor is stored on: {tensor.device}")
Using cuda device
Shape of tensor: torch.Size([3, 4])
Datatype of tensor: torch.float32
Device tensor is stored on: cpu
3.3 张量运算
在PyTorch中有超过 100 种张量运算,包括算术、线性代数、矩阵操作(转置、索引、切片)、采样等。
这些操作中的每一个都可以在 GPU 上运行(通常以比 CPU 更高的速度)。如果您使用的是 Colab,请转到运行时 > 更改运行时类型 > GPU 来分配 GPU。
默认情况下,张量是在 CPU 上创建的。我们需要使用 .to方法明确地将张量移动到 GPU(在检查 GPU 可用性之后)。请记住,跨设备复制大张量在时间和内存方面可能会很昂贵!
标准的类似 numpy 的索引和切片:
tensor = torch.ones(4, 4)
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.]])
拼接张量
您可以用来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.]])
t2 = torch.cat([tensor, tensor, tensor], dim=0)
print(t2)
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.]])
t2 = torch.stack([tensor, tensor, tensor], dim=2)
print(t2.shape)
torch.Size([4, 4, 3])
算术运算:加法、减法、乘法
import torch
# 方式1
x = torch.rand(4, 3)
y = torch.rand(4, 3)
print(x + y)
# 方式2
print(torch.add(x, y))
# 方式3 in-place,原值修改
y.add_(x)
print(y)
2.减法操作
import torch
x = torch.rand(4, 3)
y = torch.rand(4, 3)
print(x - y)
3.乘法操作
# 相同位置的元素之间相乘.,计算出来的张量形状不变。如z1, z2, z3 将是相同值。
tensor = torch.ones(4, 4)
z1 = tensor * tensor
print(z1)
z2 = tensor.mul(tensor)
print(z2)
z3 = torch.rand_like(tensor)
print(z2)
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.]])
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
1、认识了向量、矩阵和张量之间的区别和联系
2、向量、矩阵和张量在PyTorch如何实现
3、张量的基本操作,如算术运行、Numpy转Tensor等
谈谈 torch.Tensor() 和 torch.tensor() 两种函数区别??
页面更新:2024-04-07
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号