Tensor
Tensor¶
📐 张量 (Tensor) 讲解¶
张量 (Tensor) 是 PyTorch、TensorFlow 等深度学习框架中的核心数据结构,它在数学上是标量、向量和矩阵概念的泛化。
简单来说,张量就是深度学习中的数据容器。
1. 张量的数学概念:维度 (Rank)¶
张量可以被看作是一个多维数组,它的“维度”或“阶”(在数学和物理中称为 Rank)决定了它能表示的数据复杂程度。
- 维数 (Rank) 和形状 (Shape)¶
- 维数 (Rank): 指的是张量中 轴 (Axes) 的数量,也就是张量形状 (Shape) 元组中元素的个数。
- 例如,形状为
(1, 3, 7)的张量,其维数是 3。
- 例如,形状为
- 形状 (Shape): 一个元组,描述了张量在每个维度上的大小。
- 形状
(D0, D1, D2, ...)中的 $D_i$ 就是第 $i$ 维的大小。
- 形状
- 默认维度顺序¶
PyTorch 张量默认的维度顺序采用 从左到右、从外到内 的索引规则:
| 维度名称 | 索引值 (在 dim 参数中) |
默认含义 (在深度学习中) | 形状元组中的位置 |
|---|---|---|---|
| 第 0 维 | dim=0 |
Batch Size(批量大小) | 最左边第一个 |
| 第 1 维 | dim=1 |
Channels(通道数,如图像 $R, G, B$) | 第二个 |
| 第 2 维 | dim=2 |
Height(高度) | 第三个 |
| 第 3 维 | `dim=3$ | Width(宽度) | 第四个 |
| ... | $dim=k$ | $k$ 维 | $k+1$ 个 |
- 维度 (Dim) 的理解和应用¶
当您在 PyTorch 中使用涉及 dim 参数的函数时,这个参数告诉函数您希望沿着哪个轴进行操作。
| PyTorch 函数 | dim 的意义 |
示例 |
|---|---|---|
torch.sum(tensor, dim=1) |
沿着 dim=1 的方向 对数据进行求和,然后这个维度会被压缩或移除。 |
如果张量形状是 (1, 3, 7),沿着 dim=1 求和后,新张量形状会变为 (1, 7)。 |
torch.cat((t1, t2), dim=0) |
沿着 dim=0 的方向 将张量进行拼接。 |
如果 $t1$ 是 (1, 3, 7),$t2$ 也是 (1, 3, 7),沿着 dim=0 拼接后,新张量形状变为 (2, 3, 7)。 |
torch.unsqueeze(tensor, dim=1) |
在 dim=1 的位置 插入一个新的、大小为 1 的维度。 |
如果张量形状是 (1, 7),在 dim=1 插入后,新张量形状变为 (1, 1, 7)。 |
简记法则: dim=k 始终指向形状元组中第 $k+1$ 个数字所代表的轴。
| 阶/维度 (Rank) | 形状 (Shape) | 描述 | 示例数据 |
|---|---|---|---|
| 0 阶 | () |
标量 (Scalar):一个纯量。 | 5, $\pi$, 损失函数值 loss |
| 1 阶 | (n,) |
向量 (Vector):一维数组。 | 词嵌入 (Word Embedding),$\begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix}$ |
| 2 阶 | (n, m) |
矩阵 (Matrix):二维数组。 | 图像的灰度值,线性层权重 $\mathbf{W}$ |
| 3 阶 | (n, m, k) |
三阶张量:三维数组。 | 彩色图像 (高 x 宽 x 颜色通道),视频帧 |
| 4 阶 | (n, m, k, l) |
四阶张量:四维数组。 | 批量 (Batch) 的彩色图像 (批量大小 x 颜色通道 x 高 x 宽) |
2. 张量的主要属性¶
在 PyTorch 等框架中,一个张量对象主要包含以下几个关键属性:
| 属性 | 描述 | 示例 |
|---|---|---|
| Data (数据) | 存储在张量中的实际数值。 | [[1, 2], [3, 4]] |
| Shape (形状) | 定义了张量在每个维度上的大小。 | 2x2 矩阵的形状是 (2, 2) |
| Dtype (数据类型) | 存储的元素的数据类型。 | torch.float32, torch.int64 等。 |
| Device (设备) | 张量存储的位置,可以是 CPU 或 GPU。 | cpu 或 cuda:0 |
requires_grad |
一个布尔值,表示是否需要计算该张量的梯度(用于反向传播)。 | True 或 False |
3. 张量在深度学习中的应用¶
张量是表示所有数据的通用语言:
| 数据类型 | 对应的张量形状 (常见) | 描述 |
|---|---|---|
| 图像 | (C, H, W) 或 (H, W, C) |
通道数 (C)、高 (H)、宽 (W)。 |
| 文本 (批量) | (Batch_size, Seq_len, Embedding_dim) |
批量大小、序列长度、词嵌入维度。 |
| 训练批量 (Batch) | (Batch_size, C, H, W) |
深度学习中处理数据的主流形式,一次处理多张图片。 |
| 模型参数 | 各种形状 | 模型的权重 $\mathbf{W}$ 和偏置 $\mathbf{b}$ 都是张量。 |
4. PyTorch 张量的特点:自动微分¶
PyTorch 的张量 (torch.Tensor) 最强大的特性是它集成了自动微分 (Autograd) 系统。
- 当你创建一个张量并设置
requires_grad=True时,PyTorch 会开始跟踪所有作用在这个张量上的操作。 - 这使得模型在训练时可以轻松地通过
.backward()方法自动计算所有参数的梯度,这是实现反向传播和优化模型的基础。
import torch
# 创建一个需要计算梯度的 2 阶张量 (矩阵)
x = torch.tensor([[1., 2.], [3., 4.]], requires_grad=True)
print(f"张量的形状: {x.shape}")
print(f"是否需要计算梯度: {x.requires_grad}")
# 进行一些操作
y = x + 2
z = y * y * 3
out = z.mean()
# out.backward() # 调用 backward 会自动计算所有 require_grad=True 的张量的梯度
总结: 张量是深度学习中数据的载体,它不仅能存储多维数据,还集成了自动微分能力,是构建和训练神经网络的基石。
PyTorch 张量常见功能映射表¶
| 功能类别 | 数学/NumPy 概念 | PyTorch 对应函数/方法 | 常见用途和说明 |
|---|---|---|---|
| I. 创建与初始化 | 零矩阵 | torch.zeros(shape) |
创建一个所有元素都为 0 的张量。 |
| '1'矩阵 | torch.ones(n, m) |
创建一个 $n \times m$ 的全'1'矩阵。 | |
| 单位矩阵 | torch.eye(n, m) |
创建一个 $n \times m$ 的单位矩阵。 | |
| 随机数 | torch.rand(shape) |
创建服从 $[0, 1)$ 均匀分布的张量。 | |
| 正态分布随机数 | torch.randn(shape) |
创建服从标准正态分布 ($\mu=0, \sigma=1$) 的张量。 | |
| 基于现有张量创建 | torch.ones_like(tensor) |
根据另一个张量的形状创建新张量。 | |
| 从 Python/NumPy 创建 | torch.tensor(data), torch.from_numpy(ndarray) |
将 Python 列表、数组或 NumPy 转换成张量。 | |
| II. 形状和维度操作 | 形状查询 | tensor.shape 或 tensor.size() |
返回张量的形状(元组)。 |
维度重塑 (NumPy: reshape) |
tensor.view(new_shape) 或 tensor.reshape(new_shape) |
改变张量的形状。view 要求内存连续,reshape 更灵活。 |
|
| 增加/减少维度 | torch.squeeze(), torch.unsqueeze(dim) |
移除(维度为 1)或增加维度(如将向量转为 Batch )。 | |
维度转置 (NumPy: T) |
tensor.permute(dims), tensor.transpose(dim0, dim1) |
交换张量的维度位置(常用于 $HWC \to CWH$)。 | |
张量拼接 (NumPy: concatenate) |
torch.cat((t1, t2), dim=0) |
沿指定维度将多个张量拼接起来(维度增加)。 | |
张量堆叠 (NumPy: stack) |
torch.stack((t1, t2), dim=0) |
沿一个新的维度将多个张量堆叠起来(维度数量增加)。 | |
| 基于索引的元素分散操作 | target.scatter_(dim, index, src,value (optional)) |
将一个 src 张量(源数据)中的值,根据一个 index 张量(索引)的指示,分散写入(覆盖或累加)到调用该方法的 目标张量(self,即 target)的指定位置;如果不使用 src 张量,可以传入一个标量值,所有写入操作都使用这个固定值。 | |
| III. 数学运算 | 元素级加减乘除 | t1 + t2, t1 * t2, torch.add(t1, t2, out=t3) |
对应元素进行运算。 |
矩阵乘法 (NumPy: @ 或 dot) |
torch.matmul(t1, t2) 或 t1 @ t2 |
适用于矩阵、向量乘法,也支持 Batch 矩阵乘法。 | |
向量内积 (NumPy: dot) |
torch.dot(vec1, vec2) |
仅用于一维张量(向量)。 | |
求和 (NumPy: sum) |
torch.sum(tensor, dim=None) |
对所有元素或指定维度求和。 | |
| 平均值 | torch.mean(tensor, dim=None) |
对所有元素或指定维度求平均值。 | |
| IV. 梯度控制与设备管理 | 设备查询 | tensor.device |
返回张量所在的设备(如 cpu 或 cuda:0)。 |
| 设备移动 | tensor.to('cuda'), tensor.cpu() |
将张量在 CPU 和 GPU 之间移动。 | |
| 梯度追踪 | tensor.requires_grad |
布尔值,指示是否需要计算梯度(默认为 False)。 |
|
| 停止梯度追踪 | with torch.no_grad(): 或 tensor.detach() |
在不需要计算梯度时(如评估阶段)使用,节省计算和内存。 | |
| V. 索引和切片 | 标量值 | tensor.item() |
从只包含一个元素的张量中获取 Python 标量值。 |
| 标准索引/切片 | tensor[0], tensor[:, 2:5] |
与 NumPy 索引规则相同。 | |
| 掩码索引 | tensor[tensor > 5] |
使用布尔张量作为索引(获取满足条件的元素)。 |
PyTorch 与 NumPy 的关键区别¶
- 设备支持: PyTorch Tensors 默认在 CPU 上创建,但可以使用
.cuda()或.to('cuda')轻松移动到 GPU 上进行高性能计算。NumPy $ndarray$ 只能在 CPU 上运行。 - 梯度追踪: PyTorch Tensors 可以使用
requires_grad=True启用 自动求导 (Autograd),这是构建神经网络的核心功能,而 NumPy 不具备此功能。 - 原地操作 (In-place Operations): PyTorch 提供了许多以
_结尾的方法(例如add_()),这些是原地操作,会直接修改张量本身的值。在涉及 Autograd 时使用原地操作需要小心,可能会破坏计算图。
import torch import numpy as np
In [8]:
one = torch.ones((3,4))
print(one)
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])
In [15]:
one = torch.ones(3,4) #no difference
print(one)
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])
In [16]:
# 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.]
In [17]:
t.add_(1)
print(f"t: {t}")
print(f"n: {n}")
t: tensor([2., 2., 2., 2., 2.]) n: [2. 2. 2. 2. 2.]