张量(Tensor)

张量(Tensor)


1. 张量是什么

1.1 本质

张量在数据本身上可以理解为数组:一个可以存在于任意维度(0 到 N 维)的数组。

如果只看"长得像什么",张量和数组很像;但在深度学习框架里,张量通常还带有更强的计算属性:

  • 可以在 GPU 等硬件上高效并行计算;
  • 可以记录计算图(computational graph) ,并支持自动微分(自动求梯度)。

可以把张量记成一个"超级数组":不仅能装数据,还能高效计算、并自动参与求导。

计算图 可先宏观理解为:把"张量是如何一步步算出来的"记录成一张有向依赖图,后续 backward() 可沿这张图自动反向求梯度。

1.2 PyTorch 与 NumPy 的关系

定位
NumPy 通用数值计算(主要在 CPU)
PyTorch 面向深度学习的张量框架(CPU/GPU + 自动求导)
  • NumPy 是数学计算器;PyTorch 是带 GPU 和自动求导的数学计算器。
  • 张量数据操作概念用 NumPy 同样可以练习;进入模型训练后建议统一使用 PyTorch,避免类型来回转换。
python 复制代码
import numpy as np
import torch

A_np = np.array([[1, 2], [3, 4]], dtype=np.float32)
B_t = torch.tensor([[5, 6], [7, 8]], dtype=torch.float32)

# A_np @ B_t   # TypeError: 类型不同,不能直接混算

C = torch.tensor(A_np) @ B_t   # 先统一类型
D = A_np @ B_t.numpy()

2. 维度与张量阶

2.1 维度(阶 / ndim)

这里说的"维度 "是指张量的ndim),即轴的数量,不是数学里"向量有几个分量"的那个维度。

名称 形状示例 典型场景
0 标量 () 损失值、单个数值
1 向量 (n,) 一条样本特征
2 矩阵 (m, n) 表格数据(样本×特征)、灰度图
3 三维张量 (c, h, w)(h, w, c) 单张 RGB 图
4 四维张量 (b, c, h, w)(b, h, w, c) 批次图像

补充说明:

  • 4 维图像:把多张 3 维图片沿 batch 轴堆叠后的结果。
  • 表格/结构化数据通常只用 2 维:[样本数, 特征数]
  • 常见约定:PyTorch 多用 [b, c, h, w]TensorFlow 多用 [b, h, w, c]
    • b = batch(批次大小)、c = channel(通道数)、h = height、w = width。
    • 例:32 张 RGB 图片、每张 224×224,在 PyTorch 中常写为 [32, 3, 224, 224]
    • 轴顺序弄错会导致卷积输入维度不匹配或结果错位。

2.2 轴、形状与常用属性

  • 轴(axis / dim) :描述数据延伸的方向,编号从 0 开始。
  • 张量维度(阶 / ndim):张量拥有的轴的总数。
  • 长度:某一个具体轴上元素的个数。
  • 形状(shape):将所有轴的长度按顺序组合成的元组。

shape=(3, 4) 为例:

  • 包含 2 个数字 → 2 维张量(有 2 个轴)
  • 第 0 个数字是 3 → 第 0 轴(行方向)长度为 3
  • 第 1 个数字是 4 → 第 1 轴(列方向)长度为 4
类型 ndim shape len() 行为
标量张量 0 torch.Size([]) 报错(无轴)
向量张量 1 torch.Size([n]) 返回 n
矩阵张量 2 torch.Size([m, n]) 返回 m(第 0 轴长度)

常用属性与方法:

属性/方法 含义
ndim / dim() / ndimension() 轴数(阶)
shape / size() 每个轴的长度
len() 第 0 轴的长度
numel() 元素总数(number of elements)

2.3 数学语境 vs 张量语境(易混淆)

python 复制代码
v = torch.tensor([1, 2, 3])
  • 数学上:3 维向量(内部含有 3 个分量)
  • 张量上 :1 维张量(只有 1 个轴,shape=(3,)

1 维张量不区分"行/列"shape=(3,) 既不是行向量也不是列向量。只有升维为 2 维时,行列方向才明确:

  • 行向量:shape=(1, 3)(1 行 3 列)
  • 列向量:shape=(3, 1)(3 行 1 列)
python 复制代码
import torch

# 标量张量
s = torch.tensor(3)
print(s.ndim, s.shape, s.numel())   # 0, torch.Size([]), 1
# print(len(s))                     # TypeError: 0 维张量无轴

# 向量张量
a = torch.arange(12)
print(a.ndim, a.size(), len(a), a.numel())  # 1, [12], 12, 12

# 矩阵张量
x = torch.ones((3, 4))
print(x.ndim, x.shape, len(x), x.numel())   # 2, [3,4], 3, 12

3. 线性代数视角下的基本对象

PyTorch 中,标量、向量、矩阵通常都由 Tensor 类型承载:

数学对象 数学示例 张量示例
标量 3.0 torch.tensor(3.0) 0
向量 [1, 2, 3] torch.tensor([1., 2., 3.]) 1
矩阵 [[1,2],[3,4]] torch.tensor([[1.,2.],[3.,4.]]) 2
张量 更高维数组 3 维及以上 ≥3

记法速记:

  • 标量 变量:普通小写字母(如 xy
  • 向量 :粗体小写(如 x∈Rn\mathbf{x} \in \mathbb{R}^nx∈Rn)
  • 矩阵 :粗体大写(如 A∈Rm×n\mathbf{A} \in \mathbb{R}^{m \times n}A∈Rm×n)

4. 创建张量

4.1 常见创建方式

类别 API 说明
从数据 torch.tensor() 从列表/数组创建
顺序/区间 arange(start, end, step) 范围 [start, end),默认 int64
linspace(start, end, steps) 等间距,范围 [start, end],默认 float32
指定形状 zeros / ones / eye 全 0、全 1、单位矩阵
随机 randn 标准正态分布(参数初始化常用)
rand [0, 1) 均匀分布
randint(low, high, size) 整数均匀,范围 [low, high)
特殊 full(size, value) 全填充某值
empty(size) 未初始化(值不确定!)
复制 clone() 深拷贝

函数名速记:arange = array range · linspace = linear space · randn = random normal · reshape = re-shape

4.2 示例

python 复制代码
import torch

# 从数据创建
s = torch.tensor(3.0)                            # 标量
a = torch.tensor([1.0, 2.0, 3.0])                # 向量
m = torch.tensor([[1., 2., 3.], [4., 5., 6.]])   # 矩阵

# 顺序创建
torch.arange(6)                    # [0,1,2,3,4,5],int64
torch.arange(0, 1, 0.2)            # 不含 end=1.0,float32
torch.linspace(0, 1, 5)            # 含 end=1.0,共 5 个点

# 指定形状
torch.zeros(3, 3)
torch.ones(3, 3)
torch.eye(3)

# 随机
torch.randn(10)                    # 标准正态
torch.rand(10)                     # [0,1) 均匀
torch.randint(10, 20, (10,))       # [10,20) 整数

# 特殊初始化
f = torch.full((2, 3), 3.0)
e = torch.empty((2, 3))          # 值不确定
e.fill_(3.0)                     # 原地填充

# 复制
c = f.clone()
torch.allclose(f, c)               # True

默认设备通常是 CPU(除非显式放到 GPU)。


5. 形状变换

reshape 只改"看待方式",不改元素值与元素总数

  • 可以用 -1 自动推断某一维:x.reshape(-1, 4)x.reshape(3, -1)
  • 实战心法:改形状前先确认总元素数一致
python 复制代码
import torch

X = torch.arange(12)
X1 = X.reshape(3, 4)     # (3, 4)
X2 = X.reshape(-1, 4)    # 自动推断为 (3, 4)
X3 = X.reshape(3, -1)    # 自动推断为 (3, 4)

6. 按元素运算与聚合

6.1 按元素运算

同形状张量可直接做按元素运算:

运算 符号
加 / 减 / 乘 / 除 + - * /
求幂 **
逻辑比较 == >
python 复制代码
import torch

a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[10, 20], [30, 40]])

print(a + b)       # 按元素加法
print(a ** 2)      # 按元素幂
print(a == b)      # 按元素比较
print(a.sum())     # 聚合为标量 tensor(10)

6.2 张量连结(cat)

torch.cat(concatenate 简写)沿指定轴拼接多个张量:

参数 效果 例:两个 (2, 3)
dim=0 按行方向拼接(样本数增加) (4, 3)
dim=1 按列方向拼接(特征数增加) (2, 6)
python 复制代码
c0 = torch.cat([a, b], dim=0)   # (4, 2)
c1 = torch.cat([a, b], dim=1)   # (2, 4)

7. 广播机制(Broadcasting)

当张量形状不同但"可对齐"时,框架会自动扩展维度为 1 的轴,再做按元素运算。

对齐规则 :从最后一维往前看,每一维要么相等,要么其中一个为 1

  • 1 维向量 (n,) 在与矩阵 (m, n) 运算时,自动视为行向量 (1, n)
  • 广播是"虚拟扩展",不一定真实拷贝内存。

经典例子

  • a 形状 (3, 1)b 形状 (1, 2)a + b 结果 (3, 2)

快检口诀:从右往左看,维度要么相等,要么有 1;否则报错。

python 复制代码
import torch

a = torch.arange(3).reshape(3, 1)   # (3, 1)
b = torch.arange(2).reshape(1, 2)   # (1, 2)
c = a + b                           # (3, 2)
# tensor([[0,1],[1,2],[2,3]])

反例(会报错):

python 复制代码
x = torch.ones((3, 2))    # 3 行 2 列
# y = torch.ones((3,))  # 1 维 3 元素,末维 2 vs 3 不匹配 → RuntimeError

m = torch.ones((2,))      # 可视为 (1, 2),可以与 x 相加
n = x + m

8. 索引、切片与赋值

8.1 规则

  • 索引从 0 开始,负索引从末尾反向计数(-1 表示最后一个)。
  • 切片语法:start:end:step
    • start:起始下标(包含
    • end:结束下标(不包含
    • step:步长(默认 1
  • : 表示该轴"全选"。

8.2 常用模板

写法 含义
X[r, c] 取单个元素
X[r1:r2, c1:c2] 取子矩阵
X[:, c] 取某一列
X[r, :]X[r] 取某一行
X[::2, :] 每隔一行取一次

赋值规则:左侧切片选中的区域形状,需要与右侧值可对齐(相同形状或可广播)。

python 复制代码
import torch

X = torch.arange(12).reshape(3, 4)
# [[ 0,  1,  2,  3],
#  [ 4,  5,  6,  7],
#  [ 8,  9, 10, 11]]

print(X[-1])          # 最后一行
print(X[1:3])         # 第 2~3 行
print(X[:, 1])        # 所有行的第 2 列
print(X[0:3:2, :])    # 第 1 行和第 3 行

X[1, 2] = 9           # 单点赋值
X[0:2, :] = 12        # 区域赋值

9. 维度坍塌:求和与均值

维度坍塌(Dimensionality Collapse):通过聚合运算(求和、求平均等)减少张量维度数量的过程。沿某些轴运算时,这些轴会被"压缩"掉。

类型 说明 示例
完全坍塌 所有维度压缩为 0 维标量 A.sum()A.mean()
部分坍塌 只压缩指定轴(按轴降维) A.sum(dim=0)
防止坍塌 保留被压缩轴(长度为 1) A.sum(dim=0, keepdim=True)
python 复制代码
import torch

# shape: (2, 3)
A = torch.arange(6, dtype=torch.float32).reshape(2, 3)

# 完全坍塌
print(A.sum())    # tensor(15.),标量
print(A.mean())   # tensor(2.5000)

# 部分坍塌
print(A.sum(dim=0), A.sum(dim=0).shape)   # [3., 5., 7.]  → (3,)
print(A.sum(dim=1), A.sum(dim=1).shape)   # [3., 12.]     → (2,)

# 防止坍塌
print(A.sum(dim=0, keepdim=True).shape)   # (1, 3)
print(A.sum(dim=1, keepdim=True).shape)   # (2, 1)

三维示例(shape: [学生, 科目, 考试次数]):

python 复制代码
scores = torch.tensor([
    [[70, 75, 80, 85], [80, 82, 84, 86]],   # 学生 0
    [[60, 65, 70, 75], [90, 91, 92, 93]],   # 学生 1
    [[85, 87, 89, 91], [75, 78, 81, 84]]    # 学生 2
], dtype=torch.float32)

print(scores.sum(dim=0).shape)    # 按学生轴降维 → (2, 4)
print(scores.mean(dim=0).shape)   # 同上

sum(dim=...) 后维度消失,可能导致后续广播失败------可用 keepdim=True 保留轴。


10. 内存与类型转换

10.1 原地操作(高频坑点)

写法 行为
Y = Y + X 通常新分配内存(对象地址变了)
Y[:] = Y + XY += X 原地更新(更省内存,训练中更常见)
python 复制代码
import torch

X = torch.ones((2, 2))
Y = torch.ones((2, 2))
before = id(Y)

Y += X
print(id(Y) == before)   # True(原地更新)

# Y = Y + X
# print(id(Y) == before) # False(新对象)

10.2 与 NumPy / Python 标量互转

python 复制代码
import torch

X = torch.tensor([1.0, 2.0, 3.0])
A = X.numpy()              # Tensor → NumPy
B = torch.tensor(A)        # NumPy → Tensor
s = X[0].item()            # 单元素张量 → Python float

注意:PyTorch 与 NumPy 在部分场景下共享底层内存,原地改动可能连带修改另一个对象。


11. 易错点速查

易错点 正确理解
混淆"向量长度"与"张量阶数" [1,2,3] 数学上是 3 维向量,张量上是 1 维张量
1 维向量当行/列向量 reshape(1,n)reshape(n,1) 明确方向
广播末维不匹配 (3,2)(3,) 不能直接按元素运算
sum(dim=...) 后广播失败 使用 keepdim=True
Y = Y + X 频繁新分配 训练中优先 Y += XY[:] = ...
NumPy 与 PyTorch 混算 torch.tensor().numpy() 统一类型
图像轴顺序 PyTorch [b,c,h,w] vs TensorFlow [b,h,w,c]

12. 小结

张量 = 能装数据、能在 GPU 上算、能自动求导的 N 维数组。

看懂 shape、会用 reshape 和切片、理解广播与维度坍塌,是后续模型训练的基本功。

相关推荐
chsmiao3 小时前
深度学习之线性代数
人工智能·深度学习·线性代数
霸道流氓气质3 小时前
完全本地、免费、离线的AI编程助手:Ollama + Continue 完全指南
ai编程
超哥--3 小时前
B站视频内容智能分析系统(二):Docker Compose 一键部署
ai编程
HyperAI超神经4 小时前
MiniCPM5-1B采用RL+OPD训练,多项复杂任务达SOTA;面向复杂医疗业务自动化:医疗智能体评测数据集 CHI-Bench
人工智能·深度学习·ai·计算化学
一个王同学4 小时前
从零到一 | CV转多模态大模型 | week12 | 整理 MiniLLaVA 工程与文档
人工智能·深度学习·算法·机器学习·计算机视觉
chsmiao5 小时前
深度学习之微积分
人工智能·深度学习
阳明山水5 小时前
LightGBM为何胜过Prophet做销量预测
人工智能·深度学习·机器学习·微信公众平台·微信开放平台
JeJe同学5 小时前
LabelImg报错:IndexError: list index out of range 解决方法
深度学习·目标检测
winlife_5 小时前
全程用 AI 做一款商业级手游 · EP1 地基:先搭框架层,不急着写玩法
unity·ai编程·游戏架构·mcp·框架设计·funplay