本文通过一个简单的案例说明引入了非线性变换之后,向量特征(Feature)及特征的维度的本质。
案例内容
想象一个由两个变量(x, y)构成的二维空间,x和y是该空间的两个“根本特征”,意思是空间中的任何向量都由这两个特征唯一确定。
如下图所示,现在空间中有两个三角形围成的区域,两区域存在交集。由解析几何知识可知,两个三角形区域可以分别表示为f1(x, y) > 0且f2(x, y) > 0且f3(x, y) > 0和g1(x, y) > 0且g2(x, y) > 0且g3(x, y) > 0。

也就是说,对于空间内的任意向量(x, y),我可以通过非线性变换(全连接层 + ReLU)计算得到以下 6 个特征:
feature_f1 = bool(f1(x, y) > 0)
feature_f2 = bool(f2(x, y) > 0)
feature_f3 = bool(f3(x, y) > 0)
feature_g1 = bool(g1(x, y) > 0)
feature_g2 = bool(g2(x, y) > 0)
feature_g3 = bool(g3(x, y) > 0)
然后,同样使用一些其他的非线性变换,我可以实现对这 6 个特征的逻辑运算,从而得到最终的两个特征,来分别表示向量(x, y)是否在这两个三角形内:
feature_in_triangle_f = feature_f1 and feature_f2 and feature_f3 # 是否在三角形 f 中
feature_in_triangle_g = feature_g1 and feature_g2 and feature_g3 # 是否在三角形 g 中
至此,二维空间中两个根本特征x和y经过一系列线性和非线性的变换已经变成了另外两个含义十分鲜明和形象的特征feature_in_triangle_f和feature_in_triangle_g了。
思考
首先思考一个问题,案例中最初向量(x, y)拥有两个特征,经过变换后最终得到的也是两个特征。特征的数量不变,但是特征feature_in_triangle_f和feature_in_triangle_g却显然无法再反推回x和y了。这表明:对向量进行非线性变换时,即使不减少向量的特征数量,也会丢失信息。
然后我们思考一下,这个变换过程中计算了 6 个中间特征,这等于是将二维向量映射到六维空间中了,这 6 个维度肯定不是相互独立的,那这种扩维是必须的吗?按理说只通过 2 个维度就能完整表达二维向量的所有信息才对啊?
经过分析后不难发现,这是不可能的,一个三角形区域的 3 个边界必须通过 3 个对应的特征来表示。造成这种现象的原因在于,x和y虽然可以通过 2 个特征就精确表示一个向量,但是这 2 个特征都太综合、太笼统了,相当于通过两个坐标轴把整个向量空间简单分成了 4 份,这种表达能力是很弱的。而这种数量更多、但是职责更加明确的简单特征(比如每个特征只表示三角形的一条边),不仅可以大大增强特征的非线性表达能力,还可以弥补由于非线性变换导致的信息丢失。你也可以理解为:每个特征的信息变少了,但是特征的数量变多了,加在一起的总信息还是和最初的两个特征差不多,但是特征数量的增多给特征的表达能力带来了质的飞跃,也给单个特征赋予了更加明确的具体含义。
回到问题本身:这种扩维是必须的吗?现在我们可以回答:增加特征数量不仅不是信息的冗余,反而是增加网络表达能力、维护信息完整性的关键。非线性神经网络的这种反直觉的性质需要重点关注!
再做一个小小的拓展。案例中的区域形状是三角形,三角形只需要 3 个特征就可以描述,那如果我增加特征数量,不是就可以描述六边形、八边形乃至任意复杂的空间分布了吗?这再次揭示了:
- 特征的本质作用是描述向量,而不是定义向量。
- 增加特征数量可以显著增强模型的非线性表达能力。
再思考一个问题,案例中只有 2 个三角形,因此最终得到的是 2 个特征。那如果案例中有更多三角形,或者只有 1 个三角形呢?所以,在使用神经网络对向量进行非线性变换时,输出向量的维度和输入向量的维度并没有必然联系,而是取决于空间中向量分布的复杂程度,而向量分布又依赖于业务从哪个角度对向量进行分类,或者说更关注向量的哪些特征。
逐位置前馈网络
以上内容是我在学习 Transformer 架构中的逐位置前馈网络(Position-wise Feed-Forward Network, FFN)时引发的思考。FFN 的网络结构和上文的案例几乎一致,网络的思想上文也分析了,本节仅对 FFN 本身做简单介绍。
FFN 的计算表达式如下:

其核心思想就是:先把输入向量通过全连接层映射到一个高维空间中(通常将维度扩展 4 倍),经过 ReLU 激活后再通过另一个全连接层映射回原来的维度。这种“先扩大再缩小”的模式,被认为有助于模型学习更丰富的特征表示。
FFN 的 pytorch 实现如下:
import torch.nn as nn
class PositionwiseFeedForward(nn.Module):
def __init__(self, d_model, d_ff, dropout=0.1):
super(PositionwiseFeedForward, self).__init__()
self.linear1 = nn.Linear(d_model, d_ff) # 第一个线性层,扩展维度
self.relu = nn.ReLU() # 非线性激活函数
self.dropout = nn.Dropout(dropout) # Dropout用于防止过拟合
self.linear2 = nn.Linear(d_ff, d_model) # 第二个线性层,压缩回原始维度
def forward(self, x):
# x 的形状通常为 (batch_size, seq_len, d_model)
x = self.linear1(x)
x = self.relu(x)
x = self.dropout(x)
x = self.linear2(x)
return x
浙公网安备 33010602011771号