线性映射保留 AI 模型所需的组合
检验变换是否保留求和与缩放,说明输入空间和输出空间,并区分神经网络层与其激活函数。
神经网络会反复把一种表示转换成另一种表示。要理解一层做了什么,可以先问两个问题:哪些向量可以作为输入,哪些向量可以作为输出?线性映射回答这两个问题,同时保留向量彼此组合的方式。这样,我们就能把矩阵权重看作不同空间之间的变换,并准确辨认网络在哪一步引入了非线性行为。
学完本课后,你将能够检验一个映射是否线性,说明它的输入空间和输出空间,并区分神经网络层中的矩阵变换与激活函数。
**学习目标:**检验线性,并描述映射的输入空间和输出空间。
本课建立在第 027 课介绍的向量空间规则之上。Mathematics for Machine Learning第 2.7 节在向量组合开始连接坐标与矩阵之处引入线性映射。这里的计算、神经网络层示例、图示和练习均为原创。
变换应尊重输入的组合方式
向量可以相加,也可以缩放。对于两个实向量空间 和 ,当映射 同时保留这两种运算时,它就是线性的:
这里 ,且 。结果属于 ,右侧的系数分别缩放对应的输出。
可以直接检验这个组合规则,也可以拆成两项检查:
第一项表示:先把两个输入相加再变换,结果应与分别变换后再相加相同。第二项表示:先缩放输入再变换,结果应与用相同倍数缩放输出相同。两项都必须对每个有效输入和每个实数标量成立,包括负数。
输入空间 ℝ²
- e₁ = (1, 0)
- e₂ = (0, 1)
- e₁ + e₂ = (1, 1)
输出空间 ℝ²
- T(e₁) = (2, −1)
- T(e₂) = (1, 1)
- T(e₁ + e₂) = (3, 0)
组合检验:T(e₁ + e₂) = T(e₁) + T(e₂)
这三支箭头展示了一次具体的加法检验。这里,,而 。图示提供了几何直观;公式所表达的一般要求必须对所有向量和标量成立,而不仅仅是这两个基向量。
矩阵说明映射连接哪些空间
设 是一个 矩阵,也就是有 行和 列。它与一个含 个坐标的列向量相乘,得到一个含 个坐标的列向量:
定义域是映射允许的输入集合;陪域是它承诺输出所在的空间。对这个矩阵规则,输入属于 ,输出属于 。两边维数不必相同:映射可以把向量扩展为更多坐标,也可以压缩为更少坐标。
矩阵乘法是线性的,因为它对加法和标量乘法都满足分配律。对于任意长度为 的向量 以及标量 ,
来看一个小型数值例子:
偏置会平移原点;激活函数会改变规则
在机器学习代码中,“线性层”是常见的简写。从数学角度看,具体细节决定了运算是否线性。对于按行组织的批次,PyTorch 的 torch.nn.Linear 计算 ,并且默认包含偏置 。当偏置非零时,这个规则是仿射的:它保留系数和为一的组合,但通常不保留任意缩放或求和。PyTorch 文档将其称为仿射变换,也允许通过 bias=False 禁用偏置(torch.nn.Linear 文档)。当权重之和为一时,它仍会保留加权配对:
最后一个等式成立,是因为 。普通向量加法使用的系数是 和 ,它们的和不是一,因此在 中偏置不会抵消。
零向量是一个快速诊断方法。每个线性映射都必须把零映射到零,因为 。对于仿射规则 ,
如果 ,那么 就不是线性的。偏置并不会让这一层变得错误;它让模型即使在输入为零时也能平移输出。
神经网络还会在权重变换之后执行另一种运算。常见形式是 ,其中 ReLU 将每个负坐标替换为零。它是非线性的。例如,令 。那么 ,但 。加法检验失败了。PyTorch 文档将 torch.nn.ReLU 定义为这个逐元素取最大值的运算(ReLU 文档)。
这个差异解释了网络为何要组合这些步骤。如果两层都只是线性映射,它们的复合仍然是一个线性映射:。增加层数会改变矩阵,但不会产生非线性的输入输出规则。激活函数会阻止这种合并,使网络能够表示更多样的关系。权重矩阵混合输入特征;激活函数改变作用于结果坐标的规则。
用代码检查变换
可以使用 NumPy 检查同样的计算。列向量使“矩阵在左侧”的约定与上面的推导一致:
import numpy as np
A = np.array([[2, 1],
[-1, 1]])
u = np.array([1, 0])
v = np.array([0, 1])
def T(x):
return A @ x
print(T(u + v)) # [3 0]
print(T(u) + T(v)) # [3 0]
print(T(-2 * u)) # [-4 2]
print(-2 * T(u)) # [-4 2]
在 PyTorch 中处理批次时,向量通常按行存储,所以库中的权重矩阵会以显示公式中的转置形式出现。批次维度保持不变,最后的特征维度则从 in_features 变为 out_features:
import torch
from torch import nn
x = torch.tensor([[1.0, 0.0], [0.0, 1.0]]) # shape: (2 examples, 2 features)
linear_part = nn.Linear(2, 3, bias=False)
activation = nn.ReLU()
pre_activation = linear_part(x) # shape: (2, 3); a linear map
hidden = activation(pre_activation) # shape: (2, 3); nonlinear elementwise step
这里的线性映射把每个 特征向量映射到 中的向量。这个实例省略了偏置,所以第一个运算确实是线性的。若使用默认偏置,PyTorch 将其描述为仿射运算。激活函数保留输出形状,却无法通过向量组合检验。形状相同并不能说明一个运算是否线性;决定因素是代数规则。
线性映射仍可能丢失信息
线性并不意味着映射可逆、保长度,甚至不意味着它对所有下游任务都有用。零矩阵会把每个输入映射为零向量,但仍满足线性的两项规则。从 到 的线性映射不可能是一一映射:至少有一个输入方向的信息会消失。要判断信息是否得到保留,还需要线性无关、秩和可逆性等其他概念。
检查神经网络模块时,应写出每项运算前后的空间,并检验每项运算采用的规则。矩阵乘法以可预测的方式变换组合;偏置会平移原点;激活函数会改变组合的行为。记住这一区分,下一课将进一步介绍线性映射的具体矩阵表示。
检查理解
问题 1
映射要成为线性的,必须满足哪两项性质?只检验向量加法还遗漏了什么?
显示分步解答
线性映射必须保留加法和标量乘法:对每个有效的 和每个实数标量 ,都有 和 。应用这两项性质即可得到组合规则:。加法检验只覆盖输入的求和;要直接确立定义,还需检验每个实数缩放。
问题 2
对于 T(x₁, x₂) = (2x₁ + x₂, −x₁ + x₂),计算 T(3, 2)。写出两个输出坐标,并说明输入空间和输出空间。
显示分步解答
矩阵有两列,因此接受来自 的向量。矩阵有两行,因此输出属于 。用输入分别乘以每一行:
所以这是映射 ,输出为 。
问题 3
使用本课的矩阵,验证 T((1, 0) + (0, 1)) = T(1, 0) + T(0, 1)。
显示分步解答
令 ,。例题给出 ,,因此二者之和为 。输入之和为 ,矩阵乘法得出 。两边相等,因此这次具体的加法检验成立。这个例子支持该规则,但不能证明它对每个向量都成立;矩阵乘法的分配律才给出一般证明。
问题 4
对于同一个矩阵,取 u = (1, 0),计算 T(−2u),并与 −2T(u) 比较。这个检验考查什么?
显示分步解答
首先,,所以 。另外,,并且
两项结果一致。这检验了负标量下的缩放保持性;这很重要,因为线性要求对每个实数标量都成立。
问题 5
某个候选层定义为 F(x) = Ax + (0, 2)。F 能是线性映射吗?使用零向量检验,并说明所加向量的作用。
显示分步解答
对于线性映射, 必须等于零:任何输入乘以 ,其输出也必须乘以 。这里,。因此 不是线性的。所加的向量会把每个输出平移 ,使它成为仿射映射。
问题 6
PyTorch 模块先执行 <code>nn.Linear(4, 8)</code>,再执行 <code>nn.ReLU()</code>。请给出输入和输出特征空间,并判断每项运算的类型。
显示分步解答
每个输入样本有四个特征,因此是 中的向量。线性层生成八个坐标,属于 。PyTorch 默认启用偏置,所以 nn.Linear(4, 8) 通常是仿射映射,而不是数学意义上的线性映射。nn.ReLU() 保留八维形状,但对每个坐标应用 ,因此是非线性运算。设置 bias=False 时,第一个运算才是 的线性映射。
问题 7
用输入 −1 和 1 说明 ReLU 不保留加法。它的失败会改变输出维数吗?
显示分步解答
ReLU 把 映射为 。如果它保留加法,那么先对输入求和再应用它,应与分别变换后再相加相同。但是,,而 。两项结果不同,因此 ReLU 是非线性的。它仍对每个输入数值返回一个数值,所以输出形状与输入形状相同,尽管规则是非线性的。
问题 8
每个线性映射都可逆或保长度吗?请为其中一项说法给出线性反例。
显示分步解答
不是。零映射 是线性的,因为 且 ;但它把每个输入都映射成同一输出,因而无法逆转。保长度也不是线性的必然性质: 是线性映射,但 的长度为 ,而不是 。线性描述的是组合如何变化,并不表示长度或信息保持不变。