LLM系列:2.pytorch入门:2.PyTorch张量运算

PyTorch张量运算

在PyTorch中,能够作用于Tensor的数学运算被统一称作算子。根据官方的规范分类,PyTorch总共为Tensor设计了六大类数学运算:

  • 1. 逐点运算(Pointwise Ops):指的是针对Tensor中每个元素执行的相同运算操作;
  • 2. 规约运算(Reduction Ops):指的是对于某一张量进行操作得出某种总结值;
  • 3. 比较运算(Comparison Ops):指的是对多个张量进行比较运算的相关方法;
  • 4. 谱运算(Spectral Ops):指的是涉及信号处理傅里叶变换的操作;
  • 5. BLAS和LAPACK运算:指的是基础线性代数程序集(Basic Linear Algebra Subprograms)和线性代数包(Linear Algebra Package)中定义的、主要用于线性代数科学计算的函数和方法;
  • 6. 其他运算(Other Ops):其他未被归类的数学运算。

(注:由于谱运算涉及较深的信号处理基础,日常深度学习主要高频使用其余几类。在进行具体运算前,我们需要先掌握张量运算的核心规则------广播特性。)


一. 张量的广播(Broadcast)特性

张量的广播特性是指在不同形状的张量进行计算时,一个或多个张量通过隐式转化,转化成相同形状的两个张量,从而完成对应位置元素计算的机制。 这与 NumPy 中的广播机制完全一致。

1. 广播的核心依据与规则

并不是任意两个不同形状的张量都能进行广播。要触发广播,必须从两个张量的尾部维度(右侧)开始依次向前比较,且在每个维度上都必须满足以下三个规则之一:

  1. 维度大小相等( Tensor1.shape[i] == Tensor2.shape[i] ),即:在某一个对应维度上的长度(也就是元素个数)完全一样。

  2. 其中一个维度的取值为 1( Tensor1.shape[i] == 1Tensor2.shape[i] == 1 )。

  3. 其中一个张量在该维度不存在,即低维张量自动在前面补1升维。注意:PyTorch和NumPy的广播机制是极其死板的,它绝对不会去猜测你的意图,也绝对不会在形状的中间或者右边去补1。永远只能右对齐,在最左侧补1。

    ( 如: Tensor1.ndim != Tensor2.ndim,较少维度的张量其 shape 会隐式在左侧补 1,如 (2, 2) 会被当做 (1, 2, 2) 处理)。

总结:判断两个张量能否触发广播机制,需从尾部维度(右侧)起依次向前比对。只要在每一次维度判定中,满足"长度完全相等"、"其中一者为 1"或"该维度缺失"这三个条件中的任意一项,即可成功广播。

示例:

python 复制代码
# 1. 标量与张量计算 (标量被视为零维,可与任意形状广播)
t1 = torch.arange(3)       # tensor([0, 1, 2])
res1 = t1 + 1              # tensor([1, 2, 3])

# 2. 相同维度、不同形状广播
t2 = torch.zeros((3, 4))   # 形状 (3, 4)
t21 = torch.ones(1, 4)     # 形状 (1, 4),行维度为1,可广播
res2 = t2 + t21            # 形状拓展为 (3, 4) 后相加

# 3. 不同维度的张量广播 (低维自动前面补1升维)
t3 = torch.zeros(3, 2, 2)  # 形状 (3, 2, 2)
t_2d = torch.ones(2, 2)    # 形状 (2, 2)
res4 = t3 + t_2d           # t_2d 隐式转化为 (1, 2, 2) 后广播计算

二. 逐点运算 (Pointwise Ops)

逐点运算指的是针对 Tensor 中每个元素执行的相同运算操作,并且大多数科学运算只能作用于 Tensor 对象,不能与 Python 原生类型混合。

逐点运算主要包括数学基本运算、数值调整运算和数据科学运算三块。

1. 数学基本运算

(1). add & subtract & multiply & divide - 基础四则运算

作用:对张量执行按元素的加、减、乘、除运算。等效于 +, -, *, / 运算符。支持广播机制。

python 复制代码
torch.add(input, other, alpha=1)
torch.subtract(input, other, alpha=1)
torch.multiply(input, other)
torch.divide(input, other)

参数:

  • 输入张量 (input): 参与运算的左侧张量 (Tensor)。
  • 其他对象 (other): 参与运算的右侧对象,可以是形状匹配(或可广播)的张量,也可以是数值标量 (Tensor 或 Number)。
  • 乘子 (alpha): 仅 addsubtract 支持,在加减前对 other 乘以该值 (Number)。

返回值:

  • 成功: 返回执行基础四则运算后的结果张量 (Tensor)。

示例:

python 复制代码
t1 = torch.tensor([1, 2])
t2 = torch.tensor([3, 4])
res_add = torch.add(t1, t2)        # tensor([4, 6])
res_div = torch.divide(t1, t2)     # tensor([0.3333, 0.5000])

2. 数值调整运算

(1). abs & ceil & floor & round & neg - 数值调整

作用:对张量中的每个元素进行绝对值(abs)、向上取整(ceil)、向下取整(floor)、四舍五入(round)或取相反数(neg)操作。

注:这些函数均有以 _ 结尾的同名原地修改方法(如 t.abs_()),可直接修改原张量。许多科学计算都有这样的同名方法。

python 复制代码
torch.abs(input)      # 取绝对值
torch.ceil(input)     # 向上取整(向正无穷方向取整)
torch.floor(input)    # 向下取整(向负无穷方向取整)
torch.round(input)    # 四舍五入取整
torch.neg(input)      # 取相反数(乘以 -1)

参数:

  • 输入张量 (input): 需要进行数值调整的目标张量 (Tensor)。

返回值:

  • 成功: 返回数值调整后的新张量 (Tensor)。

示例:

python 复制代码
t = torch.randn(2)                 # tensor([-0.5184, 0.4910])
res_abs = torch.abs(t)             # tensor([0.5184, 0.4910])
res_round = torch.round(t)         # tensor([-1., 0.])

3. 数据科学运算

数学运算函数 数学公式 描述
幂运算
torch.exp(t) y_{i} = e\^{x_{i}} 返回以e为底、t中元素为幂的张量
torch.expm1(t) y_{i} = e\^{x_{i}} - 1 对张量中的所有元素计算exp(x) - 1
torch.exp2(t) y_{i} = 2\^{x_{i}} 逐个元素计算2的t次方。
torch.pow(t,n) \\text{out}_i = x_i \^ \\text{exponent} 返回t的n次幂
torch.sqrt(t) \\text{out}*{i} = \\sqrt{\\text{input}*{i}} 返回t的平方根
torch.square(t) \\text{out}_i = x_i \^ \\text{2} 返回输入的元素平方。
对数运算
torch.log10(t) y_{i} = \\log_{10} (x_{i}) 返回以10为底的t的对数
torch.log(t) y_{i} = \\log_{e} (x_{i}) 返回以e为底的t的对数
torch.log2(t) y_{i} = \\log_{2} (x_{i}) 返回以2为底的t的对数
torch.log1p(t) y_i = \\log_{e} (x_i + 1) 返回一个加自然对数的输入数组。
三角函数运算
torch.sin(t) 三角正弦。
torch.cos(t) 元素余弦。
torch.tan(t) 逐元素计算切线。

注:

  1. PyTorch 已支持标量自动提升 (Scalar Auto-Promotion) ,许多科学计算现在可以直接传入 Python 原生数值,不再强制必须是 Tensor 对象。

    python 复制代码
    torch.pow(2, 2) # 正确运行,返回 tensor(4)
  2. 绝大多数科学运算要求输入张量必须是浮点型 (Float)。

(1). exp & log 系 - 指数与对数运算

作用:对张量执行指数运算(如 exe^xex, 2x2^x2x)以及对数运算(如 ln⁡\lnln, log⁡2\log_2log2, log⁡10\log_{10}log10)。

python 复制代码
torch.exp(input)      # e的x次方
torch.expm1(input)    # e的x次方 - 1
torch.exp2(input)     # 2的x次方
torch.log(input)      # 自然对数 (底数为e)
torch.log1p(input)    # ln(1 + x) ------ 在x极小时具有更高的数值稳定性
torch.log2(input)     # 底数为2的对数
torch.log10(input)    # 底数为10的对数

参数:

  • 输入张量 (input): 参与指数或对数运算的浮点型目标张量 (Tensor)。

返回值:

  • 成功: 返回逐元素计算指数/对数后的结果张量 (Tensor)。

示例:

python 复制代码
t = torch.tensor([0.0, 1.0, 2.0])
res_exp = torch.exp(t)             # tensor([1.0000, 2.7183, 7.3891])
res_log = torch.log(res_exp)       # tensor([0.0000, 1.0000, 2.0000])
res_log1p = torch.log1p(t)         # tensor([0.0000, 0.6931, 1.0986]),即 ln(1+t)
(2). pow & sqrt & square - 幂与开方运算

作用:执行求指定次幂(pow)、求正平方根(sqrt)、求平方运算(square)。

python 复制代码
torch.pow(input, exponent)  # 幂运算:input 的 exponent 次方
torch.sqrt(input)           # 平方根(√x)
torch.square(input)         # 平方(x^2)

参数:

  • 输入张量 (input): 被进行幂/开方运算的目标底数张量 (Tensor)。
  • 指数 (exponent): pow 函数中指定的幂次,可以是张量或数值 (Tensor 或 Number)。

返回值:

  • 成功: 返回计算结果的新张量 (Tensor)。

示例:

python 复制代码
t = torch.tensor([1., 2., 3.])
res_pow = torch.pow(t, 2)          # tensor([1., 4., 9.])
res_sqrt = torch.sqrt(res_pow)     # tensor([1., 2., 3.])
(3). sin & cos & tan - 三角函数运算

作用:逐元素计算张量内数据的正弦、余弦和正切值。

python 复制代码
torch.sin(input)
torch.cos(input)
torch.tan(input)

参数:

  • 输入张量 (input): 输入的以弧度为单位的数值张量 (Tensor)。

返回值:

  • 成功: 返回计算后的三角函数值张量 (Tensor)。
(4). sort - 排序运算

作用:对张量沿指定维度进行排序,默认升序。注: 返回的是新张量(副本),不是视图(view)

python 复制代码
torch.sort(input, dim=-1, descending=False)

参数:

  • 输入张量 (input): 需要排序的目标张量 (Tensor)。
  • 操作轴 (dim): 指定沿哪一个维度进行排序。默认为 -1,即最后一个维度 (int)。
  • 降序标志 (descending): 控制排序方向。False 为升序,True 为降序 (bool)。

返回值:

  • 成功: 返回一个命名元组 (NamedTuple),包含两个张量:(values, indices)
    • values: 排序后的取值张量 (Tensor)。
    • indices: 排序后的元素在原张量中的索引张量 (Tensor[Long])。

示例:

python 复制代码
t = torch.arange(11,-1,-1).float().reshape(3, 4)
res_sort = torch.sort(t, dim=1)
# torch.return_types.sort(
# values=tensor([[ 8.,  9., 10., 11.],
#         [ 4.,  5.,  6.,  7.],
#         [ 0.,  1.,  2.,  3.]]),
# indices=tensor([[3, 2, 1, 0],
#         [3, 2, 1, 0],
#         [3, 2, 1, 0]]))

三. 规约运算 (Reduction Ops)

规约运算是指针对张量进行操作得出某种总结值(如均值、最大值、方差等)的函数。

函数 描述
torch.mean(t) 返回张量均值
torch.var(t) 返回张量方差
torch.std(t) 返回张量标准差
torch.var_mean(t) 返回张量方差和均值
torch.std_mean(t) 返回张量标准差和均值
torch.max(t) 返回张量最大值
torch.argmax(t) 返回张量最大值索引
torch.min(t) 返回张量最小值
torch.argmin(t) 返回张量最小值索引
torch.median(t) 返回张量中位数
torch.sum(t) 返回张量求和结果
torch.logsumexp(t) 计算 log(sum(exp(x))),适用于数据量较小的情况
torch.prod(t) 返回张量累乘结果
torch.dist(t1, t2) 计算两个张量的闵式距离,可使用不同范式
torch.topk(t) 返回t中最大的k个值对应的指标

注:indices是索引列表的意思

1. mean & sum & max & min & median & prod & logsumexp - 常见聚合函数

作用:对张量中的元素进行求均值(mean)、求和(sum)、求最大值(max)、求最小值(min)、求中位数(median)、累乘(prod)、对数-指数-求和(logsumexp)。

python 复制代码
torch.mean(input, dim=None, keepdim=False)
torch.sum(input, dim=None, keepdim=False)
torch.max(input, dim=None, keepdim=False)
torch.min(input, dim=None, keepdim=False)
torch.median(input, dim=None, keepdim=False)
torch.prod(input, dim=None, keepdim=False)
torch.logsumexp(input, dim, keepdim=False)  # 计算 log(sum(exp(x)))

参数:

  • 输入张量 (input): 需要计算的输入张量 (Tensor)。
  • 操作轴 (dim):沿哪个轴计算。如果不指定,默认全局计算压缩为标量 (int 或 None)。注:对于 logsumexpdim 参数通常是必须指定的。 (int 或 None)。
  • 保持维度 (keepdim): 若设为 True,则输出张量保留计算的维度(尺寸变为 1),便于后续广播 (bool)。

返回值:

  • 成功: 返回聚合计算的结果张量。若指定了 dim 计算极值(如 max/min/median),通常会返回命名元组 (values, indices) (Tensor 或 NamedTuple)。

补充:

任意张量:
sum(X,dim=d) \text{sum}(X, \text{dim}=d) sum(X,dim=d)
本质就是:
S[... ]=∑kX[...,k,... ] S[\dots] = \sum_{k} X[\dots, k, \dots] S[...]=k∑X[...,k,...]
其中:

  • k 放在第 d 个位置
  • 这一维被消掉,即sum后的shape为原shape去掉指定维度(如:torch.Size([2, 3, 4])对0,1,2维相加得到是shape分别是:torch.Size([3, 4]); torch.Size([2, 4]); torch.Size([2, 3]))。

示例:

python 复制代码
t1 = torch.arange(12).float().reshape(3, 4)
# tensor([[ 0.,  1.,  2.,  3.],
#         [ 4.,  5.,  6.,  7.],
#         [ 8.,  9., 10., 11.]])
res_sum = torch.sum(t1, dim=0)      # 沿行压缩,按列求和: tensor([12., 15., 18., 21.])
res_mean = torch.mean(t1)           # 全局均值: tensor(5.5000)
res_max = torch.max(t1, dim=0)
# torch.return_types.max(
# values=tensor([ 8.,  9., 10., 11.]),
# indices=tensor([2, 2, 2, 2]))  # 表示最大值来自第3行

t2 = torch.tensor([1., 2., 3.])
res_lse = torch.logsumexp(t2, dim=0) # 结果约为 3.4076 (即 log(e^1 + e^2 + e^3))

t3 = torch.arange(24).float().reshape(2, 3, 4)
# tensor([[[ 0.,  1.,  2.,  3.],
#          [ 4.,  5.,  6.,  7.],
#          [ 8.,  9., 10., 11.]],
# 
#         [[12., 13., 14., 15.],
#          [16., 17., 18., 19.],
#          [20., 21., 22., 23.]]])
torch.sum(t3, dim = 1)
# tensor([[12., 15., 18., 21.],
#         [48., 51., 54., 57.]])
torch.sum(t3, dim=2)
# tensor([[ 6., 22., 38.],
#         [54., 70., 86.]])

2. var & std - 方差与标准差

作用:计算张量的方差(var)和标准差(std),用于统计数据的离散程度。使用 var_meanstd_mean 时可以一步到位同时返回统计值及其对应的均值。

python 复制代码
torch.var(input, dim=None, keepdim=False)
torch.std(input, dim=None, keepdim=False)
torch.var_mean(input, dim=None, keepdim=False) # 返回 (方差, 均值)
torch.std_mean(input, dim=None, keepdim=False) # 返回 (标准差, 均值)

参数:

  • 输入张量 (input): 需要计算的浮点型输入张量 (Tensor)。
  • 操作轴 (dim): 沿哪个轴计算 (int 或 None)。
  • 保持维度 (keepdim): 是否在输出中保留原维度长度为1 (bool)。

返回值:

  • 成功:返回计算所得的结果:var/std 返回单张量(Tensor),var_mean/std_mean返回一个包含两个张量的元组 (Tensor, Tensor)。

3. argmax & argmin - 最值索引

作用:找出张量中最大值或最小值所在的索引位置。

python 复制代码
torch.argmax(input, dim=None, keepdim=False)
torch.argmin(input, dim=None, keepdim=False)

参数:

  • 输入张量 (input): 目标张量 (Tensor)。
  • 操作轴 (dim): 沿哪个轴计算索引 (int 或 None)。如果不指定,则将张量展平后返回一维索引。
  • 保持维度 (keepdim): 决定是否保持被缩减的维度 (bool)。

返回值:

  • 成功: 返回最大/最小值的整数索引张量 (Tensor[Long])。

4. topk - 提取前k个极值

作用:返回张量沿指定维度中最大的 k 个值及其对应的索引。

python 复制代码
torch.topk(input, k, dim=-1, largest=True, sorted=True)

参数:

  • 输入张量 (input): 目标张量 (Tensor)。
  • 提取数量 (k): 需要获取的前多少个极值 (int)。
  • 操作轴 (dim): 指定进行操作的维度,默认为 -1 最后一维 (int)。
  • 最大值标记 (largest): 控制是取最大值 (True) 还是取最小值 (False) (bool)。
  • 是否排序 (sorted): 控制返回的这 k 个元素是否需要按顺序排列 (bool)。

返回值:

  • 成功: 返回命名元组 (values, indices),分别存储提取的值及其索引 (NamedTuple)。

5. dist - 距离计算(更推荐使用 vector_norm)

作用:计算两个张量之间的闵可夫斯基距离。通过改变 p 值可以计算欧式距离、街道距离等。

注:在现代 PyTorch 中 torch.dist 较少使用,强烈推荐使用 torch.linalg.vector_norm(t1 - t2) 替代。

D(x,y) = (\\sum^{n}_{u=1}\|x_u-y_u\|^{p})\^{1/p}

python 复制代码
torch.dist(input, other, p=2)

参数:

  • 输入张量 1 (input): 第一个目标张量 (Tensor)。
  • 输入张量 2 (other): 第二个目标张量 (Tensor)。
  • 范数参数 §: 决定距离类型。p=2 为欧式距离,p=1 为街道(曼哈顿)距离 (Number)。

返回值:

  • 成功: 返回计算得出的距离标量张量 (Tensor)。

示例:

python 复制代码
t1 = torch.tensor([1.0, 2.0])
t2 = torch.tensor([3.0, 4.0])
res_dist = torch.dist(t1, t2, 2)   # tensor(2.8284)

6. vector_norm - 向量范数计算

作用:计算张量的向量范数(即 L-p 范数,可以理解为向量到空间原点的闵可夫斯基距离)。通过改变 ord 值可以计算 L2范数(欧式长度)、L1范数(街道长度)、最大范数等。

\|\|x\|\|_p = (\\sum^{n}_{i=1}\|x_i\|^{p})\^{1/p}

python 复制代码
torch.linalg.vector_norm(x, ord=2, dim=None, keepdim=False)

参数:

  • 输入张量 (x): 目标张量 (Tensor)。
  • 范数参数 (ord): 决定范数类型。ord=2 为 L2范数(欧几里得距离/模长),ord=1 为 L1范数(曼哈顿距离/绝对值之和),还可以指定为 float('inf') 计算最大绝对值 (Number/String)。
  • 维度参数 (dim): 指定在哪个或哪些维度上进行范数计算。如果为 None,则默认将整个张量展平后计算全局范数 (Int 或 Tuple)。
  • 保持维度 (keepdim): 决定输出张量是否保留原有的维度数。如果为 True,被计算的维度长度将变为 1 (Boolean,默认为 False)。

返回值:

  • 成功: 返回计算得出的范数张量 (Tensor)。

示例:

python 复制代码
t = torch.tensor([3.0, 4.0])
res_norm = torch.linalg.vector_norm(t, ord=2)   # tensor(5.0)

# 沿特定维度计算
t_2d = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
res_dim0 = torch.linalg.vector_norm(t_2d, ord=1, dim=0) # tensor([4., 6.]) 按列求L1范数

7. norm - 通用范数计算 (向量与矩阵)

作用:计算张量的向量范数或矩阵范数。这是 PyTorch 中最全能的范数函数。与专门计算向量范数的 vector_norm 不同,norm 会根据你传入的张量维度或指定的 dim 参数,智能判断是执行向量范数计算,还是复杂的矩阵范数计算(如 Frobenius 范数、核范数等)。

向量 L-p 范数公式: \|\|x\|\|_p = (\\sum^{n}_{i=1}\|x_i\|^{p})\^{1/p}

矩阵 Frobenius 范数公式: ∣∣A∣∣F=∑i,j∣aij∣2||A||F = \sqrt{\sum{i,j}|a_{ij}|^2}∣∣A∣∣F=∑i,j∣aij∣2

python 复制代码
torch.linalg.norm(A, ord=None, dim=None, keepdim=False)

参数:

  • 输入张量 (A): 目标张量 (Tensor)。
  • 范数参数 (ord): 决定范数类型。默认为 None(对于一维向量默认计算 L2 范数;对于二维矩阵默认计算 Frobenius 范数)。
    • 当计算向量范数时:与 vector_norm 一致,如 2, 1, float('inf') 等。
    • 当计算矩阵范数时:支持 'fro' (Frobenius 范数,等价于把矩阵展平求 L2 范数)、'nuc' (核范数,即矩阵的所有奇异值之和)、2 (谱范数,即最大的奇异值) 等 (Number/String)。
  • 维度参数 (dim): 指定在哪个或哪些维度上进行计算。避坑提醒:这个参数决定了它的计算模式! 如果指定一个整数(如 dim=0),它按向量范数计算;如果指定包含两个整数的元组(如 dim=(0, 1)),它按矩阵范数计算。如果为 None,它会将整个 1D 或 2D 张量作为整体进行默认范数计算 (Int, Tuple 或 None)。
  • 保持维度 (keepdim): 决定输出张量是否保留原有的维度数。如果为 True,被计算的维度长度将变为 1 (Boolean,默认为 False)。

返回值:

  • 成功: 返回计算得出的范数标量或张量 (Tensor)。

示例:

python 复制代码
# 1. 向量范数计算 (与 vector_norm 行为一致)
t_vec = torch.tensor([3.0, 4.0])
res_vec_norm = torch.linalg.norm(t_vec)         # tensor(5.0) 默认 L2 范数

# 2. 矩阵范数计算 (这是 norm 独有的能力)
t_mat = torch.tensor([[1.0, 2.0], 
                      [3.0, 4.0]])
# 默认计算 Frobenius 范数 (所有元素平方和开根号: sqrt(1+4+9+16))
res_fro = torch.linalg.norm(t_mat)              # tensor(5.4772) 

# 计算矩阵的核范数 (Nuclear Norm: 矩阵奇异值之和)
res_nuc = torch.linalg.norm(t_mat, ord='nuc')   # tensor(5.4650)

# 3. 指定维度的高维运算
t_3d = torch.randn(2, 3, 4) # Batch size=2, 3x4 矩阵
# 在后两个维度上求每个 3x4 矩阵的 Frobenius 范数
res_dim = torch.linalg.norm(t_3d, dim=(1, 2))   # 返回形状 (2,) 的张量

四. 比较运算 (Comparison Ops)

比较运算常用于不同张量之间的逻辑运算,最终返回布尔类型的逻辑张量。

1. eq & ne & gt & ge & lt & le - 逐元素比较

作用:比较两个张量中对应各元素是否满足相等、不相等、大于、大于等于、小于、小于等于条件。等效于原生运算符。

python 复制代码
torch.eq(input, other)   # 等效 ==
torch.ne(input, other)   # 等效 !=
torch.gt(input, other)   # 等效 >
torch.ge(input, other)   # 等效 >=
torch.lt(input, other)   # 等效 <
torch.le(input, other)   # 等效 <=

参数:

  • 输入张量 (input): 左侧参与比较的张量 (Tensor)。
  • 其他对象 (other): 右侧参与比较的张量或数值,支持广播 (Tensor 或 Number)。

返回值:

  • 成功: 返回与输入张量广播后形状相同的布尔类型张量 (Tensor[Bool])。

示例:

python 复制代码
t1 = torch.tensor([1.0, 3, 4])
t2 = torch.tensor([1.0, 2, 5])
res_eq = torch.eq(t1, t2)          # tensor([ True, False, False])
res_gt = torch.gt(t1, t2)          # tensor([False,  True, False])

2. equal - 张量整体比较

作用:判断两个张量是否在形状和元素取值上完全相同。这是一个强条件判断。

python 复制代码
torch.equal(input, other)

参数:

  • 输入张量 1 (input): 目标张量 (Tensor)。
  • 输入张量 2 (other): 用于对比的张量 (Tensor)。

返回值:

  • 成功: 仅当两个张量尺寸与内容绝对相同时返回 True,否则返回 False (bool)。

五. 线性代数运算 (BLAS & LAPACK)

PyTorch 中并没有单独的"矩阵"对象,二维张量即等价于矩阵。高维张量参与运算时(如三维),通常被视作包含多个矩阵的集合(Batch)。

BLAS (Basic Linear Algebra Subprograms) 和 LAPACK (Linear Algebra Package) 模块提供了完整的线性代数基本方法。所有现代写法强烈推荐统一迁移至 torch.linalg 下!由于涉及到函数种类较多,此处对其进行简单分类,具体包括:

  • 1. 矩阵的形变及特殊矩阵的构造方法: 包括矩阵的转置、对角矩阵的创建、单位矩阵的创建、上/下三角矩阵的创建等;
  • 2. 矩阵的基本运算: 包括矩阵乘法、向量内积、矩阵和向量的乘法等,当然,此处还包含了高维张量的基本运算,将着重探讨矩阵的基本运算拓展至三维张量中的基本方法;
  • 3. 矩阵的线性代数运算: 包括矩阵的迹、矩阵的秩、逆矩阵的求解、伴随矩阵和广义逆矩阵等;
  • 4. 矩阵分解运算: 特征分解、奇异值分解和SVD分解等。

1.数学概念补充

(1).点积 (Dot Product)

概念: 点积又叫数量积标量积 。它接受两个长度相同的一维向量 ,并返回一个单一的数值(标量)。点积可以说是多维空间中向量"相似度"或"投影长度"的一种度量。

公式:

点积有两种等价的数学表达方式:

  • 代数定义(基于坐标计算):

    将两个向量对应位置的元素相乘,然后把所有的乘积加起来。

    设向量 a=[a1,a2,...,an]\mathbf{a} = [a_1, a_2, \dots, a_n]a=[a1,a2,...,an] 和 b=[b1,b2,...,bn]\mathbf{b} = [b_1, b_2, \dots, b_n]b=[b1,b2,...,bn],则:
    a⋅b=∑i=1naibi=a1b1+a2b2+⋯+anbn\mathbf{a} \cdot \mathbf{b} = \sum_{i=1}^n a_i b_i = a_1b_1 + a_2b_2 + \dots + a_nb_na⋅b=i=1∑naibi=a1b1+a2b2+⋯+anbn

  • 几何定义(基于夹角和长度):

    点积等于两个向量的模长(长度)相乘,再乘以它们夹角的余弦值。
    a⋅b=∥a∥∥b∥cos⁡(θ)\mathbf{a} \cdot \mathbf{b} = \|\mathbf{a}\| \|\mathbf{b}\| \cos(\theta)a⋅b=∥a∥∥b∥cos(θ)
    (注:当 θ=90∘\theta = 90^\circθ=90∘ 即两个向量垂直时,cos⁡(90∘)=0\cos(90^\circ) = 0cos(90∘)=0,点积为 0。)


(2).内积 (Inner Product)

概念:

内积是点积的高维抽象与推广 ,内积包含点积,但是在实际用的时候都差不多,特殊情况(不是实数的情况)遇不到。

**即:点积是内积在欧几里得空间(常见的实数空间)中的一种具体特例。 在一般的实数向量空间里,内积的计算方式和点积一模一样;**但内积的概念还可以推广到更抽象的数学空间(比如复数空间、函数空间等)。

公式:

内积通常用尖括号 ⟨x,y⟩\langle \mathbf{x}, \mathbf{y} \rangle⟨x,y⟩ 表示。对于实数向量,它的公式与点积完全相同:
⟨a,b⟩=a⋅b=∑i=1naibi\langle \mathbf{a}, \mathbf{b} \rangle = \mathbf{a} \cdot \mathbf{b} = \sum_{i=1}^n a_i b_i⟨a,b⟩=a⋅b=i=1∑naibi

补充:复数空间下的内积 (对应 PyTorch 的 vdot)

如果在复数空间中,为了保证向量自己跟自己的内积必须是非负实数,计算时需要对其中一个向量取复数共轭 (conjugate):
⟨a,b⟩=∑i=1naˉibi\langle \mathbf{a}, \mathbf{b} \rangle = \sum_{i=1}^n \bar{a}_i b_i⟨a,b⟩=i=1∑naˉibi


(3).矩阵乘法 (Matrix Multiplication)

概念:

矩阵乘法是针对二维张量(矩阵)的运算。它是点积的高阶组合 。当一个 m×nm \times nm×n 的矩阵 AAA 乘以一个 n×pn \times pn×p 的矩阵 BBB 时,本质上是 AAA 的每一行向量 与 BBB 的每一列向量 分别做点积

核心规则:

必须满足**"左矩阵的列数 = 右矩阵的行数"**,即 (m×n)×(n×p)→(m×p)(m \times n) \times (n \times p) \rightarrow (m \times p)(m×n)×(n×p)→(m×p)。

公式:

设矩阵 C=ABC = ABC=AB,则结果矩阵 CCC 中第 iii 行第 jjj 列的元素 cijc_{ij}cij 计算公式为:
cij=∑k=1naikbkjc_{ij} = \sum_{k=1}^n a_{ik} b_{kj}cij=k=1∑naikbkj
(通俗解释:cijc_{ij}cij 的值,就是矩阵 AAA 的第 iii 行向量,与矩阵 BBB 的第 jjj 列向量的点积。)


(4).总结

点积就是对应相乘再相加;内积是点积的学名;矩阵乘法就是批量做点积(行乘列)。

概念 数学符号 参与对象 输出结果 核心本质
点积 a⋅b\mathbf{a} \cdot \mathbf{b}a⋅b 两个一维向量 (1D ×\times× 1D) 一个数值 (标量) 对应元素相乘后求和
内积 ⟨a,b⟩\langle \mathbf{a}, \mathbf{b} \rangle⟨a,b⟩ 两个一维向量 一个数值 (标量) 点积的抽象统称(在实数域中即为点积)
矩阵乘法 ABABAB 两个二维矩阵 (2D ×\times× 2D) 一个二维矩阵 (2D) 行向量与列向量的批量点积

(5). 矩阵的迹 (Trace)

**概念: 迹是方阵特有的属性,但 PyTorch 中不是方阵也能计算,它等于矩阵主对角线上所有元素的总和。**在物理学和线性代数中,迹拥有非常好的性质(比如在坐标变换下保持不变)。

公式与性质:

设 AAA 为 n×nn \times nn×n 的方阵,其迹 Tr(A)\text{Tr}(A)Tr(A) 为:

Tr(A)=∑i=1naii=a11+a22+⋯+ann\text{Tr}(A) = \sum_{i=1}^n a_{ii} = a_{11} + a_{22} + \dots + a_{nn}Tr(A)=i=1∑naii=a11+a22+⋯+ann

(核心性质:矩阵的迹,在数值上严格等于该矩阵所有特征值之和。)


(6). 矩阵的秩 (Rank)

概念:

矩阵的秩(Rank)是指矩阵中行或列的极大线性无关数(即极大线性无关组中包含的向量个数)。任何矩阵的秩都是唯一值。

  • 极大线性无关组: 指的是从矩阵中挑出的一组向量,它们之间互相绝对独立(没有任何一个向量可以通过其他向量加减乘除组合出来),且矩阵中剩下的所有冗余向量都可以由这组向量线性表示。

通俗来说,秩衡量了矩阵里面含有多少真正有效且不重复的核心信息。如果把矩阵看作是对空间的一种变换,秩就代表了变换后空间的实际维度。

性质与核心应用:

  • 行列秩相等: 矩阵中行、列的极大无关数总是相同的,无论矩阵是宽是长。
  • 满秩 (Full Rank): 特指在方阵(行数和列数相同的矩阵)中,行数、列数和秩完全相同。这意味着全员独立、没有冗余。满秩矩阵具有线性唯一解等重要特性。
  • 降秩与降维: 如果矩阵的秩小于行/列数,说明存在可以被替代的"废话/冗余信息"。在空间变换中,降秩意味着原本的3D空间被压扁成了2D平面甚至1D的线。在数据科学中,正是利用了这一点,通过求解秩来对高维复杂数据进行降维。
  • 算法基石: 秩也是奇异值分解 (SVD)、主成分分析 (PCA) 等高级数学运算中不可或缺的核心指标。

(7). 行列式 (Determinant)

概念:

行列式是方阵的一个专属基本性质或属性,行列式永远是一个单一的数值(标量,Scalar)。

  1. 代数角度来看,通过行列式的计算,我们能够知道矩阵是否可逆,从而可以进一步求解矩阵所对应的线性方程组。不满秩的的方阵行列式就是0,行列式一旦是0就无法计算这个矩阵的逆矩阵。
  2. 几何角度来看,行列式实际上就是矩阵进行线性变换时,对空间体积(或面积)的伸缩因子(缩放比例)。

基础二阶方阵的计算公式:

对于最基础的 2×22 \times 22×2 方阵,它的行列式计算有一条固定公式,即"主对角线乘积 减去 副对角线乘积":
设 A=[abcd]A = \begin{bmatrix} a & b \\ c & d \end{bmatrix}A=[acbd],则其行列式为:
det⁡(A)=ad−bc\det(A) = ad - bcdet(A)=ad−bc

计算方法与代数余子式 (Cofactor):

对于 3×33 \times 33×3 及更高阶的方阵,其行列式的计算通常依赖于代数余子式展开(拉普拉斯展开),这是一种将高维行列式降维计算的核心方法。

  • 余子式 (MijM_{ij}Mij):在一个 nnn 阶方阵中,划去元素 aija_{ij}aij 所在的第 iii 行和第 jjj 列后,留下来的 n−1n-1n−1 阶方阵的行列式。
  • 代数余子式 (CijC_{ij}Cij):在余子式的基础上赋予正负号。符号的规则取决于行标与列标之和的奇偶性,公式为 Cij=(−1)i+jMijC_{ij} = (-1)^{i+j} M_{ij}Cij=(−1)i+jMij。
  • 展开定理:行列式的值等于它的任意一行(或一列)的各元素与其对应的代数余子式乘积之和。即 det⁡(A)=∑j=1naijCij\det(A) = \sum_{j=1}^n a_{ij} C_{ij}det(A)=∑j=1naijCij。

性质与几何意义:

用 det⁡(A)\det(A)det(A) 或 ∣A∣|A|∣A∣ 表示。

  • det⁡(A)>0\det(A) > 0det(A)>0: 空间体积被放大了 det⁡(A)\det(A)det(A) 倍,且空间方向保持不变。
  • det⁡(A)<0\det(A) < 0det(A)<0: 空间体积被缩放,同时空间发生了翻转(类似于照镜子)。
  • det⁡(A)=0\det(A) = 0det(A)=0: 绝对的核心考点!说明空间被压扁了(体积变成0,伸缩因子为0)。此时矩阵必定降秩,且必定没有逆矩阵(不可逆)。

(8). 逆矩阵 (Inverse Matrix)

概念:

相当于矩阵乘法中的倒数。如果矩阵 AAA 是一种线性变换(比如把空间顺时针旋转90度),那么它的逆矩阵 A−1A^{-1}A−1 就是把这个操作完美撤销的动作(逆时针转回90度)。

公式与前提:

AA−1=A−1A=IA A^{-1} = A^{-1} A = IAA−1=A−1A=I

(注:III 是单位阵,相当于数字里的 111。前提条件是方阵 AAA 必须满秩,即行列式 det⁡(A)≠0\det(A) \neq 0det(A)=0。如果空间已经被压扁成了0维,就再也无法还原回去了。)

在正式进入到更进一步矩阵运算的讨论之前,我们需要对矩阵建立一个更加形象化的理解。通常来说,我们会把高维空间中的一个个数看成是向量,而由这些向量组成的数组看成是一个矩阵。例如:(1,2),(3,4)是二维空间中的两个点,矩阵A就代表这两个点所组成的矩阵。

如果更进一步,我们希望在二维空间中找到一条直线,来拟合这两个点,也就是所谓的构建一个线性回归模型,我们可以设置线性回归方程:y=ax+by = ax + by=ax+b

带入(1,2)和(3,4)两个点之后,我们还可以进一步将表达式改写成矩阵表示形式,改写过程如下

而用矩阵表示线性方程组,则是矩阵的另一种常用用途,接下来,我们就可以通过上述矩阵方程组来求解系数向量x。

首先一个基本思路是,如果有个和A矩阵相关的另一个矩阵,假设为A−1A^{-1}A−1,可以使得二者相乘之后等于1,也就是A∗A−1=1A * A^{-1} = 1A∗A−1=1,那么在方程组左右两边同时左乘该矩阵,等式右边的计算结果A−1∗BA^{-1} * BA−1∗B就将是x系数向量的取值。而此处的A−1A^{-1}A−1就是所谓的AAA的逆矩阵。(并非所有矩阵都有逆矩阵,对于一个矩阵来说,首先必须是方正,其次矩阵的秩不能为零,满足两个条件才能求解逆矩阵。)

然后在方程组左右两边同时左乘A−1A^{-1}A−1,求解x

A\^{-1} \* A \* x= A\^{-1} \* B

E \* x = A\^{-1} \* B

x=A−1∗Bx = A^{-1} * Bx=A−1∗B

最终得到线性方程为: y = x + 1


(9). 特征分解 (Eigenvalue Decomposition)

引言:

矩阵分解有非常多门派,常见的如 QR 分解、LU 分解、特征分解、SVD 分解等。虽然在形式上,它们都是将一个复杂的矩阵拆分成几个特殊矩阵(如正交阵、对角阵)的乘积,但本质上,矩阵分解是为了剥离表象,去探索矩阵更深层次的几何属性和物理规律。 下面主要围绕深度学习中最核心的特征分解SVD分解展开讲解。

核心概念:

特征分解旨在拆解一个**方阵**的核心 DNA。当一个矩阵作用于空间中的一组向量时,绝大多数向量都会被改变方向;但有一类极其特殊的向量,它们在变换后方向完全不变(或完全反向),仅仅是长度被拉伸或压缩了

  1. 一个矩阵作用于空间中的一组向量"在高等数学的视角里,矩阵不仅仅是一堆死板的数字,它是一个"动作",一种对空间的"变换"。当你用一个矩阵 AAA 去乘一个向量 x\mathbf{x}x(即 AxA\mathbf{x}Ax),这就相当于你抓住这个空间,对它进行拉伸、挤压、或者旋转。空间里的向量就像是画在橡皮筋上的箭头,随着空间的扭曲,它们也会跟着变换位置。
  2. "绝大多数向量都会被改变方向"想象你在纸上画了一个指向右上角的箭头。现在我把这张纸横向拉伸两倍,再纵向斜切一下(这就是矩阵变换)。你会发现,原本指向右上角的箭头,可能被扯得偏向了右下角。对于空间中 99% 的普通向量来说,经历矩阵变换后,它们不仅长度变了,连指向的方向也偏离了原来的轨道。
  3. 但有一类极其特殊的向量...方向完全不变,仅长度被拉伸或压缩"在这一片混乱的扭曲空间中,有几根极其"倔强"的箭头。不管你怎么用这个特定的矩阵去拉伸、挤压空间,这几根箭头就像是被钉在了自己原本的直线上。它们绝对不会发生旋转或偏移,唯一发生改变的,只是它们变长了、变短了,或者反向了(乘了个负数)。这些"倔强、不偏离方向"的特殊箭头,就叫作矩阵的 特征向量 (Eigenvector)。它们被拉伸或压缩的"倍数",就叫作对应的 特征值 (Eigenvalue)。
  • 特征向量 (Eigenvector):
    • 直观理解: 它代表了矩阵这个空间变换操作中的**"独立方向"或"主轴"**。
    • 物理意义: 不管矩阵怎么扭曲空间,这些方向就像是空间的"骨架",岿然不动。特征向量之间通常是线性无关的(在对称矩阵中甚至相互垂直正交)。
  • 特征值 (Eigenvalue):
    • 直观理解: 它代表了矩阵在对应特征向量那个方向上的**"拉伸/压缩倍数"**。
    • 物理/信息意义: 它是特征向量的"权重"。特征值的绝对值越大,说明矩阵在这个方向上施加的能量(或包含的信息量、方差)越大。
    • 与秩的关系: 极其重要!一个方阵中非零特征值的个数,严格等于这个矩阵的秩 (Rank)。如果某个特征值为 0,说明矩阵在那个方向上把空间彻底"压扁"了。

公式与拆解:
将方阵 AAA 分解为三个矩阵的乘积:
A=QΛQ−1A = Q \Lambda Q^{-1}A=QΛQ−1

参数详解:

  • QQQ (特征向量矩阵): 它是由矩阵 AAA 的所有特征向量按列拼成的一个方阵。
  • Q−1Q^{-1}Q−1 (逆矩阵): 是 QQQ 的逆矩阵。(注:如果 AAA 是一个实对称矩阵,那么 QQQ 会是一个正交矩阵,此时 Q−1=QTQ^{-1} = Q^TQ−1=QT,公式可以直接简写为 A=QΛQTA = Q \Lambda Q^TA=QΛQT,计算极其高效!)
  • Λ\LambdaΛ (特征值对角阵): 是一个除了主对角线以外其他元素全为 0 的矩阵。主对角线上的元素就是矩阵 AAA 的特征值
    • 避坑提醒: 在未经人工排序的情况下,Λ\LambdaΛ 中的特征值排列是无序的(并非默认降序)。对角线上的第 iii 个特征值,严格对应着矩阵 QQQ 中的第 iii 列特征向量。

总结:
A=QΛQ−1A = Q \Lambda Q^{-1}A=QΛQ−1 其实是在描述一个三步走的过程:

  1. Q−1Q^{-1}Q−1:把原本杂乱的坐标系,旋转对齐到矩阵的"骨架(特征向量)"上。
  2. Λ\LambdaΛ:在骨架方向上,按照"特征值"的大小,进行简单的、独立的拉伸或缩放。
  3. QQQ:把缩放完的空间,再旋转回原来的坐标系中。

(10). 奇异值分解 (SVD - Singular Value Decomposition)

引言:

对于一个方阵来说,我们可以利用特征分解 A = Q\\Lambda Q\^{-1} 来提取矩阵的核心信息。这里,QQQ 是由特征向量组成的矩阵,而 Λ\LambdaΛ 是由特征值构成的对角矩阵。特征值的绝对值大小,直接代表了对应特征向量方向上蕴含的信息量(方差/能量)。

在很多情况下,最大的一小部分特征值的和,就已经约等于所有特征值的总和。因此,我们可以通过在 QQQ 和 Λ\LambdaΛ 中删去那些极小的特征值及其对应的特征向量,仅使用少量的核心数据来近似描述整个矩阵,从而达到数据压缩与降维的效果。

然而,特征分解有一个致命的局限性:它只能作用于方阵 。在实际问题中绝大多数矩阵都是 m×nm \times nm×n 的非方阵(矩形矩阵)。此时,就需要请出特征分解的终极推广形态------奇异值分解(SVD)。

核心基础补充:正交矩阵 (Orthogonal Matrix)

  • 定义: 如果一个方阵 QQQ 满足 QTQ=QQT=IQ^T Q = Q Q^T = IQTQ=QQT=I(即它的转置就等于它的逆矩阵 QT=Q−1Q^T = Q^{-1}QT=Q−1),那么它就是正交矩阵。
  • 向量视角: 正交矩阵内部的每一行(或每一列)都是长度为1的单位向量,并且它们两两之间互相垂直(点积为 0)。
  • 极其重要的几何意义: 用正交矩阵去乘以一个向量,相当于在空间中做了一次纯粹的"旋转"或"镜像翻转"。它绝对不会拉伸或压缩向量的长度,也不会改变向量之间的夹角。

例子:

假设我们有一个正交矩阵 QQQ:
Q=[0.8−0.60.60.8]Q = \begin{bmatrix} 0.8 & -0.6 \\ 0.6 & 0.8 \end{bmatrix}Q=[0.80.6−0.60.8]

我们把它按劈开,看作是空间里的两个向量(两根箭头):

  • 第 1 列(向量 u\mathbf{u}u) :[0.80.6]\begin{bmatrix} 0.8 \\ 0.6 \end{bmatrix}[0.80.6]
  • 第 2 列(向量 v\mathbf{v}v) :[−0.60.8]\begin{bmatrix} -0.6 \\ 0.8 \end{bmatrix}[−0.60.8]

现在,我们来验证它是不是符合你摘抄的那两句话:

  1. 验证:长度都是 1 吗?

    根据勾股定理,向量的长度等于各个元素的平方和再开根号。

    • 向量 u\mathbf{u}u 的长度 :0.82+0.62=0.64+0.36=1=1\sqrt{0.8^2 + 0.6^2} = \sqrt{0.64 + 0.36} = \sqrt{1} = 10.82+0.62 =0.64+0.36 =1 =1
    • 向量 v\mathbf{v}v 的长度 :(−0.6)2+0.82=0.36+0.64=1=1\sqrt{(-0.6)^2 + 0.8^2} = \sqrt{0.36 + 0.64} = \sqrt{1} = 1(−0.6)2+0.82 =0.36+0.64 =1 =1

    结论: 它们的长度完美等于 1(它们是单位向量)。

  2. 验证:它们互相垂直吗(点积为0)?

    我们把你之前学过的点积公式(对应位置相乘再相加)拿出来算一下:

    • u⋅v\mathbf{u} \cdot \mathbf{v}u⋅v** = (0.8×−0.6)+(0.6×0.8)(0.8 \times -0.6) + (0.6 \times 0.8)(0.8×−0.6)+(0.6×0.8)
    • u⋅v\mathbf{u} \cdot \mathbf{v}u⋅v** = −0.48+0.48=0-0.48 + 0.48 = 0−0.48+0.48=0

    结论: 点积为 0!这就意味着这两个向量在空间中的夹角是绝对的 90 度。

(注:正交矩阵还有一个像魔法一样的对称性,如果你把矩阵按劈开算,结论依然完全一样!)

SVD 概念与公式:

SVD 适用于世界上任意形状大小的矩阵! 它能提取出任何矩阵中最重要的主成分。

将任意大小为 m×nm \times nm×n 的矩阵 AAA 分解为三个特殊矩阵的乘积:

Am×n=Um×mΣm×nVn×nTA_{m \times n} = U_{m \times m} \Sigma_{m \times n} V^T_{n \times n}Am×n=Um×mΣm×nVn×nT

参数详解与几何意义:

  • VTV^TVT (右奇异矩阵的转置): 这是一个 n×nn \times nn×n 的正交矩阵 。它负责在输入空间中进行第一次纯旋转操作。它的行向量被称为右奇异向量。
  • Σ\SigmaΣ (奇异值矩阵): 这是一个 m×nm \times nm×n 的对角矩阵(非对角线元素全为0)。它负责在各个独立的方向上进行纯拉伸或压缩 。对角线上的数值被称为奇异值(Singular Values) ,PyTorch 会自动将它们从大到小降序排列。奇异值越大,代表这部分信息越重要。
  • UUU (左奇异矩阵): 这是一个 m×mm \times mm×m 的正交矩阵 。它负责在输出空间中进行最后一次纯旋转操作。它的列向量被称为左奇异向量。

SVD 的几何动作总结: 任何一个极其复杂的 m×nm \times nm×n 矩阵变换,都可以被 SVD 拆解为三个极其简单的标准化动作:旋转 (VTV^TVT) →\rightarrow→ 沿坐标轴拉伸/压扁 (Σ\SigmaΣ) →\rightarrow→ 再旋转 (UUU)

截断 SVD 与降维应用:

与特征分解类似,由于 Σ\SigmaΣ 中的奇异值是按降序排列的,且往往前 kkk 个奇异值占据了绝大部分的比重(比如占了 99% 的信息量)。

通常情况下,我们不需要存储完整的矩阵,只需要保留前 kkk 个最大的奇异值,以及 UUU 和 VTV^TVT 中对应的前 kkk 列/行即可。

这就是截断 SVD (Truncated SVD) ,公式近似表达为:
Am×n≈Um×kΣk×kVk×nTA_{m \times n} \approx U_{m \times k} \Sigma_{k \times k} V^T_{k \times n}Am×n≈Um×kΣk×kVk×nT

通过这种方式,原本需要存储 m×nm \times nm×n 个数字的庞大矩阵,被极大地减少了存储空间,这也是主成分分析(PCA)、图像压缩、自然语言处理(LSA)等高级算法的核心基石。


2. 矩阵的形变及特殊矩阵的构造方法

(1). t/T/transpose & eye & diag & triu & tril - 形变与特殊矩阵构造

作用:提供矩阵的转置(t / transpose / .T)、单位阵构造(eye)、对角阵(diag)及上下三角矩阵的提取(triu, tril)。

  • 转置就是行变列,列变行。转置就是行变列,列变行。(注意:torch.t()仅限2D矩阵,现代写法更推荐 .T.transpose())
  • 单位矩阵对角线是1,其他都是0。
  • 上三角矩阵:对角线右上方保留,左下方为0;下三角矩阵:对角线左下方保留,右上方为0;
python 复制代码
torch.t(input)                         # 仅限二维张量转置
input.T                                # 推荐:更现代的转置写法
input.transpose(dim0, dim1)            # 推荐:支持高维张量指定维度转置
torch.eye(n, m=None)
torch.diag(input, diagonal=0)
torch.triu(input, diagonal=0)
torch.tril(input, diagonal=0)

参数:

  • 输入张量 (input): 操作的目标张量 (Tensor)。
  • 行列数 (n, m): eye 中生成的行数 n 和列数 m。不填 m 默认为方阵 (int)。
  • 对角线偏移 (diagonal): 指定以哪条对角线为基准,0为主对角线,正数为向上偏移,负数为向下偏移 (int)。

返回值:

  • 成功: 返回构造或截取后的新二维张量 (Tensor)。

示例:

python 复制代码
# 1. 矩阵转置 (t / .T)
mat = torch.tensor([[1, 2, 3], 
                    [4, 5, 6]])
res_t = mat.T                      # 推荐使用 .T 属性
# 结果形状变为 (3, 2): 
# tensor([[1, 4],
#         [2, 5],
#         [3, 6]])

# 2. 构造单位阵 (eye)
res_eye = torch.eye(3)             
# 3x3 的方阵,主对角线为1,其余为0
# tensor([[1., 0., 0.],
#         [0., 1., 0.],
#         [0., 0., 1.]])

# 3. 构造或提取对角阵 (diag)
vec = torch.tensor([1, 2, 3])
res_diag = torch.diag(vec)         
# 用一维张量生成对角阵:
# tensor([[1, 0, 0],
#         [0, 2, 0],
#         [0, 0, 3]])

# 4. 提取上下三角矩阵 (triu, tril)
mat2 = torch.ones(3, 3)
res_triu = torch.triu(mat2)        # 默认 diagonal=0,提取包含主对角线的上三角
# tensor([[1., 1., 1.],
#         [0., 1., 1.],
#         [0., 0., 1.]])

res_tril = torch.tril(mat2, diagonal=-1) # 向下偏移1,提取不包含主对角线的下三角
# tensor([[0., 0., 0.],
#         [1., 0., 0.],
#         [1., 1., 0.]])

3. 矩阵的基本运算

函数 描述
torch.dot(t1, t2) 计算t1、t2张量内积
torch.vdot(t1, t2) 计算两个一维张量的点积 (支持处理复数共轭)
torch.mm(t1, t2) 矩阵乘法
torch.mv(t1, t2) 矩阵乘向量
torch.bmm(t1, t2) 批量矩阵乘法
torch.addmm(t, t1, t2) 矩阵相乘后相加
torch.addbmm(t, t1, t2) 批量矩阵相乘后相加
(1). dot & vdot & mm & mv & bmm & addmm & addbmm - 矩阵乘法家族

作用:执行向量和矩阵层面的各种乘法运算。避坑警告:PyTorch 针对不同维度的乘法有着严格的方法分类,不能像 NumPy 一样混用!

现代写法强烈推荐:
在现代 PyTorch 开发中,对于常规的矩阵乘法,强烈推荐统一使用 torch.matmul(input, other)@ 运算符。它能自动适配 1D、2D 以及高维 Batch 场景,更加接近 NumPy 的使用习惯。

python 复制代码
torch.dot(input, other)            # 仅限 1D × 1D (内积)
torch.vdot(input, other)           # 仅限 1D × 1D (复数点积,实数张量下等效于 dot)
torch.mm(input, mat2)              # 仅限 2D × 2D (矩阵乘法)
torch.mv(input, vec)               # 仅限 2D × 1D (矩阵乘向量)
torch.bmm(input, mat2)             # 仅限 3D × 3D (批量矩阵乘法)
torch.addmm(input, mat1, mat2, beta=1, alpha=1)      # 矩阵相乘后相加
torch.addbmm(input, batch1, batch2, beta=1, alpha=1) # 批量矩阵相乘并按批次求和后相加
  • 参数及严格Shape要求:

    参与运算的张量: 根据不同函数有极其严格的维度和形状匹配要求。

    • dot / vdot: - 要求:必须全是一维张量,且长度相同。

      Shape:(n)(n)(n) 与 (n)(n)(n) 结合 →\rightarrow→ 输出标量(零维)。

      注:若是复数类型,vdot 会对 input 取复数共轭,而 dot 不会。

    • mm: - 要求:必须全是二维矩阵,满足行列乘法规则(左列数=右行数)。

      Shape:(n,m)×(m,p)→(n, m) \times (m, p) \rightarrow(n,m)×(m,p)→ 输出 (n,p)(n, p)(n,p)。

    • mv: - 要求input为二维,vec 为一维。input的列数必须等于vec的长度。内部将其作为列向量 (m,1)(m, 1)(m,1) 处理进行矩阵乘法。

      Shape:(n,m)×(m,)→(n, m) \times (m,) \rightarrow(n,m)×(m,)→ 输出 (n,)(n,)(n,)。

    • bmm: - 要求:必须全是三维批量矩阵。第一维(Batch数)必须完全相等,且后两维满足矩阵乘法规则。

      Shape:(b,n,m)×(b,m,p)→(b, n, m) \times (b, m, p) \rightarrow(b,n,m)×(b,m,p)→ 输出 (b,n,p)(b, n, p)(b,n,p)。

      本质就是做了 b 次互相独立、互不干扰的二维矩阵乘法。

      input 的形状是 (b, n, m),意思是里面装着 b 个大小为 (n, m) 的矩阵。

      mat2 的形状是 (b, m, p),意思是里面装着 b 个大小为 (m, p) 的矩阵。

      在执行bmm 时,PyTorch会严格按照批次索引 i 一一对应地去计算:

      第一维的第 iii 个矩阵,只跟第二维的第 iii 个矩阵相乘(Ci=Ai×BiC_i = A_i \times B_iCi=Ai×Bi)。

    • addmm: - 要求:mat1mat2 为二维矩阵乘法,input 是可通过广播机制与乘法结果 (n,p)(n, p)(n,p) 相加的张量。

      Shape:input+[(n,m)×(m,p)]→input + [(n, m) \times (m, p)] \rightarrowinput+[(n,m)×(m,p)]→ 输出 (n,p)(n, p)(n,p)。

    • addbmm: - 要求:batch1batch2 必须是三维批量矩阵。批次乘法完成后,在内部沿着Batch维进行求和降维,结果加上二维张量 input

      Shape:input+∑[(b,n,m)×(b,m,p)]→input + \sum [(b, n, m) \times (b, m, p)] \rightarrowinput+∑[(b,n,m)×(b,m,p)]→ 降维并输出 (n,p)(n, p)(n,p)。

    • 乘子 (beta, alpha): addmmaddbmm 中的标量权重。

      • addmm 内部逻辑:Out=β⋅input+α⋅(mat1×mat2)Out = \beta \cdot input + \alpha \cdot (mat1 \times mat2)Out=β⋅input+α⋅(mat1×mat2) (Number)。
      • addbmm 内部逻辑:Out=β⋅input+α⋅∑i=0b−1(batch1i×batch2i)Out = \beta \cdot input + \alpha \cdot \sum_{i=0}^{b-1} (batch1_i \times batch2_i)Out=β⋅input+α⋅i=0∑b−1(batch1i×batch2i) (Number)。

    返回值:

    • 成功: 返回内积标量、矩阵乘法结果张量,或相加后的二维/三维张量 (Tensor)。

示例:

python 复制代码
# 1. 矩阵乘向量 (mv)
met = torch.arange(1, 7).reshape(2, 3) # 2x3矩阵
vec = torch.arange(1, 4)               # 长度3的向量
res_mv = torch.mv(met, vec)            # 结果形状(2,): tensor([14, 32])

# 2. 批量矩阵相乘后相加 (addbmm)
t = torch.zeros(2, 3)                  # (2, 3) 基础矩阵
b1 = torch.randn(4, 2, 2)              # 包含 4 个 2x2 矩阵的 Batch
b2 = torch.randn(4, 2, 3)              # 包含 4 个 2x3 矩阵的 Batch
# b1 和 b2 批量相乘得到 4 个 2x3 的矩阵,将其按批次累加成 1 个 2x3 的矩阵,再加到 t 上
res_addbmm = torch.addbmm(t, b1, b2)   # 结果形状: (2, 3)

(2). matmul - 大一统矩阵乘法

作用:执行泛型的矩阵乘法(支持广播机制)。它可以根据输入张量的维度自动推导并执行点积、矩阵乘向量、矩阵乘法或批量矩阵乘法。避坑警告:它极其强大且方便,但也正因其支持复杂的隐式广播和维度增减,在网络结构搭建时,如果把形状写错,它可能会默默地帮你"算"出一个错误维度的结果而掩盖 Bug!在需要严格维度约束的场景下,建议换回 mmbmm

python 复制代码
torch.matmul(input, other)
# 完全等价于 Python 的 @ 运算符: input @ other
  • 参数及自动推理 Shape 规则:

    参与运算的张量: 根据 inputother 的维度 (dim) 数量,matmul 会在内部应用以下五种不同的计算逻辑:

    • 1D ×\times× 1D: - 逻辑:执行内积(点积),等效于 torch.dot

      Shape:(n)(n)(n) 与 (n)(n)(n) 结合 →\rightarrow→ 输出标量(零维)。

    • 2D ×\times× 2D: - 逻辑:执行标准矩阵乘法,等效于 torch.mm

      Shape:(n,m)×(m,p)→(n, m) \times (m, p) \rightarrow(n,m)×(m,p)→ 输出 (n,p)(n, p)(n,p)。

    • 2D ×\times× 1D: - 逻辑:执行矩阵乘向量,等效于 torch.mv

      Shape:(n,m)×(m,)→(n, m) \times (m,) \rightarrow(n,m)×(m,)→ 输出 (n,)(n,)(n,)。

    • 1D ×\times× 2D: - 逻辑:向量扩维乘法。

      内部处理:会在一维张量前面隐式增加一个维度使其变成矩阵(即长度为 nnn 的向量被视为 (1,n)(1, n)(1,n))。完成二维矩阵乘法 (1,n)×(n,p)→(1,p)(1, n) \times (n, p) \rightarrow (1, p)(1,n)×(n,p)→(1,p) 后,再将前置的临时维度去掉。

      Shape:(n,)×(n,p)→(n,) \times (n, p) \rightarrow(n,)×(n,p)→ 输出 (p,)(p,)(p,)。

    • 包含 3D 及更高维度的计算: - 逻辑:带有广播机制的批量矩阵乘法 (Batched Matrix Multiplication)。它会将最内侧的两个维度视为矩阵维度,将其余所有靠外的维度统统视为 Batch 维度。

      Shape 示例 1 (严格匹配):(b,n,m)×(b,m,p)→(b, n, m) \times (b, m, p) \rightarrow(b,n,m)×(b,m,p)→ 输出 (b,n,p)(b, n, p)(b,n,p)。

      Shape 示例 2 (触发广播):(b,n,m)×(m,p)→(b, n, m) \times (m, p) \rightarrow(b,n,m)×(m,p)→ 内部将后者广播升维为 (b,m,p)(b, m, p)(b,m,p),输出 (b,n,p)(b, n, p)(b,n,p)。

      本质上,它超越了原生的 bmm,因为它允许 Batch 维度在不完全一致的情况下通过 Broadcasting(广播)机制对齐。

      例如:input 的形状是 (j,1,n,m)(j, 1, n, m)(j,1,n,m),other 的形状是 (k,m,p)(k, m, p)(k,m,p)。

      在执行 matmul 时,PyTorch 会先将 Batch 维度广播对齐到 (j,k)(j, k)(j,k),然后再对最内侧的 (n,m)(n, m)(n,m) 和 (m,p)(m, p)(m,p) 执行批量矩阵乘法。最终输出结果的形状为 (j,k,n,p)(j, k, n, p)(j,k,n,p)。

    返回值:

    • 成功: 返回计算得出的标量、一维向量或多维张量 (Tensor)。

示例:

python 复制代码
# 1. 自动处理 2D x 1D (等效于 mv)
mat = torch.randn(3, 4)        # (3, 4) 矩阵
vec = torch.randn(4)           # (4,) 向量
res_1 = torch.matmul(mat, vec) # 结果形状: (3,)

# 2. 强大的广播批量乘法 (传统的 bmm 无法做到)
b_mat1 = torch.randn(10, 3, 4) # (10, 3, 4) 包含 10 个 3x4 矩阵的 Batch
mat2 = torch.randn(4, 5)       # (4, 5) 单个二维基础矩阵
# mat2 会被自动广播到 10 个批次中分别参与计算
res_2 = torch.matmul(b_mat1, mat2) # 结果形状: (10, 3, 5)

# 3. 使用 @ 语法糖 (日常开发最推荐)
res_3 = b_mat1 @ mat2          # 计算结果与 torch.matmul 完全一致

4. 矩阵的线性代数运算

(1). trace & matrix_rank & det & inv - 线性代数特征分析

作用:求矩阵的迹(trace)、秩(matrix_rank)、行列式(det)和逆矩阵(inv)。注:涉及求秩与求逆时,强烈推荐使用新版 torch.linalg 下的 API,旧版已被弃用或不推荐。

python 复制代码
torch.linalg.trace(input)			   # 新版:求矩阵的迹
torch.linalg.matrix_rank(input)        # 新版:求矩阵的秩
torch.linalg.det(input)                # 新版:求行列式
torch.linalg.inv(input)                # 新版:求逆矩阵

参数:

  • 输入张量 (input): 必须是符合要求的矩阵 (Tensor)。
    • 计算 detinv 必须是方阵,且需为浮点型。

返回值:

  • 成功:
    • tracelinalg.det 返回计算的数值标量 (Tensor)。
    • linalg.matrix_rank 返回整数张量 (Tensor)。
    • linalg.inv 返回计算后的逆矩阵张量 (Tensor)。

5. 矩阵分解运算

(1). linalg.eig & linalg.svd - 矩阵分解 (新版规范)

作用:

  1. 特征分解 (linalg.eig) 将方阵分解为特征值与特征向量。
  2. 奇异值分解 (linalg.svd) 将任意形状的矩阵分解为 UΣVTU\Sigma V^TUΣVT。

版本大坑提醒:

  • 原有的 torch.eig 已经被移除。新版 linalg.eig 会强制返回复数类型 (Complex),因为即使是实数矩阵也可能产生复数特征值。
  • 如果你非常确定你的矩阵是实对称矩阵 (比如协方差矩阵),请务必使用 torch.linalg.eigh,它不仅计算速度快得多,而且保证返回的都是实数!
python 复制代码
# 特征分解
torch.linalg.eig(input)
torch.linalg.eigh(input) # 强烈推荐:专用于实对称/复共轭对称矩阵

# 奇异值分解
torch.linalg.svd(input, full_matrices=True)

参数:

  • 输入张量 (input): 目标分解矩阵。eig 要求必须是方阵,svd 不限形状 (Tensor)。
  • 完全分解/经济分解 (full_matrices): svd 的参数,默认为 True 计算完整的 UUU 和 VVV 矩阵;设为 False 则计算截断(经济型)SVD,可以大幅节省内存 (bool)。
  • (注:新版 eig 函数默认同时计算特征值和特征向量,不再需要老版的 eigenvectors=True 参数)

返回值:

  • 成功: 返回命名元组 (NamedTuple)。

    • linalg.eig / eigh:返回 (eigenvalues, eigenvectors)

      eigenvalues (特征值):一维张量。包含了矩阵分解出的所有特征值。(eig 返回复数张量,eigh 返回纯实数张量)。

      eigenvectors (特征向量):二维张量。避坑提醒:它的每一列才是一个独立的特征向量! 也就是说,eigenvectors[:, i] 这个列向量,对应的是 eigenvalues[i] 这个特征值。

      A = Q\\Lambda Q\^{-1}
      eigenvalues表示 AAA 矩阵分解后的 Λ\LambdaΛ 矩阵的对角线元素值。;
      eigenvectors 表示 AAA 矩阵分解后的 QQQ 矩阵。此处需要正确理解特征值与特征向量:特征向量代表了矩阵变换中的独立方向(主轴),而特征值则代表了在该方向上的信息权重/拉伸程度。 特征值的绝对值越大,说明矩阵在这个独立方向上包含的信息量(变异度)越大。特征值与矩阵的秩关系紧密:矩阵中非零特征值的个数,恰好等于该矩阵的秩。。

    • linalg.svd:返回 (U, S, Vh)。注:这里的 Vh 代表的是 VTV^TVT (转置后的V),而在老版 torch.svd 中返回的是未转置的 VVV

      U (左奇异矩阵):二维正交张量。它的每一列是一个左奇异向量,通常用于刻画输出空间(或行空间)的基底特征。

      S (奇异值向量):一维张量。包含了矩阵的奇异值(对应公式中的 Σ\SigmaΣ 的对角线元素)。PyTorch 会自动将它们按从大到小降序排列,且全为非负实数。值越大,代表对应的奇异向量包含的"信息量/重要性"越高。

      Vh (右奇异矩阵的转置):二维正交张量。代表公式中的 VTV^TVT(或复数下的共轭转置 VHV^HVH)。避坑提醒:因为它是转置后的结果,所以它的每一行才是一个右奇异向量!(注:老版 torch.svd 返回的是未转置的 VVV,新版直接返回了 VTV^TVT,更方便直接参与矩阵乘法计算)。

      Am×n=Um×mΣm×nVn×nTA_{m \times n} = U_{m \times m} \Sigma_{m \times n} V^T_{n \times n}Am×n=Um×mΣm×nVn×nT

示例:

python 复制代码
# 1. 特征分解 (eig & eigh)
A = torch.tensor([[1., 2.], 
                  [2., 4.]]) # 这是一个对称矩阵
# 推荐写法:使用 eigh 处理对称矩阵,直接得到纯实数结果
torch.linalg.eigh(A)
# torch.return_types.linalg_eigh(
# eigenvalues=tensor([0., 5.]),
# eigenvectors=tensor([[-0.8944,  0.4472],
#         [ 0.4472,  0.8944]]))

# 2. 奇异值分解 (svd)
C = torch.tensor([[1., 2., 3.], 
                  [2., 4., 6.], 
                  [3., 6., 9.]])
torch.linalg.svd(C)
# torch.return_types.linalg_svd(
# U=tensor([[-2.6726e-01,  9.6362e-01, -3.7767e-08],
#         [-5.3452e-01, -1.4825e-01, -8.3205e-01],
#         [-8.0178e-01, -2.2237e-01,  5.5470e-01]]),
# S=tensor([1.4000e+01, 4.2751e-08, 1.6397e-15]),
# Vh=tensor([[-0.2673, -0.5345, -0.8018],
#         [-0.9636,  0.1482,  0.2224],
#         [ 0.0000, -0.8321,  0.5547]]))
# S 中为按降序排列的奇异值向量:tensor([1.4000e+01, 2.9463e-16, 2.0734e-16])

# 注意:若要还原原矩阵,公式为 U @ torch.diag(S) @ Vh (新版直接乘Vh即可)
U, S, Vh = torch.linalg.svd(C)
U @ torch.diag(S) @ Vh
# tensor([[1.0000, 2.0000, 3.0000],
#         [2.0000, 4.0000, 6.0000],
#         [3.0000, 6.0000, 9.0000]])
相关推荐
给自己做减法2 小时前
RAG调参实践一
python·ai编程·rag
LeeeX!2 小时前
【OpenClaw最新版本】 命令行备忘录:高频操作与实战技巧
笔记·aigc·openclaw
djjdjdjdjjdj2 小时前
Golang如何做本地缓存加速_Golang本地缓存教程【核心】
jvm·数据库·python
2301_764150562 小时前
如何在 WordPress AMP 网站中为特定模板禁用 AMP 渲染
jvm·数据库·python
2301_773553622 小时前
bootstrap怎么给div添加背景图片
jvm·数据库·python
2301_773553622 小时前
CSS如何通过CSS变量实现组件颜色隔离_提升组件样式独立性
jvm·数据库·python
2401_871696522 小时前
如何让按钮悬停时阴影位置保持固定,仅按钮自身位移?
jvm·数据库·python
吕源林2 小时前
CSS如何使用Bootstrap网格嵌套布局_在栅格内创建内部行
jvm·数据库·python
Polar__Star2 小时前
php怎么调用OPPO AI图像超分_php如何将低分辨率图放大不失真
jvm·数据库·python