本节摘要:一个神经元只会画一条直线,把它们堆起来,你就能画出任何形状。1969 年 Minsky 与 Papert 证明了单层网络在数学上无法学会异或——这几乎让神经网络资金断流了十年。事后看,解法显而易见:别只用一层。把神经元堆成层,让第一层把输入空间雕刻成新特征,第二层再把这些特征组合成单条直线做不出的决策。这个堆叠就是多层网络,它是当今所有生产级深度学习模型的根基。而前向传播(Forward Pass)——数据从输入流经隐藏层抵达输出——是你让网络动起来之前必须先搭好的第一件事。本节将用纯 Python(不用 numpy)从零实现
Layer与Network类,跑通完整的前向传播,追踪矩阵维度,讲透万能逼近定理,并用一个 2-2-1 网络配合手工调好的 sigmoid 权重破解异或。
阅读完本节,你应当能够:
Layer 与 Network 类的多层网络,跑通完整的前向传播。单个神经元是一台画线机,仅此而已——在你数据上画一条直线。AI 里的一切真实任务——图像识别、语言理解、下围棋——都需要曲线。把神经元堆成层,你才能得到曲线。
1969 年,Minsky 与 Papert 证明了这个限制是致命的:单层网络学不会 XOR。不是「学得很吃力」,而是数学上不可能。XOR 真值表把 [0,1] 与 [1,0] 放一边、[0,0] 与 [1,1] 放另一边,没有任何一条直线能把它们分开。
这砍掉了神经网络十多年的研究经费。事后看,解法太简单:别再用一层。把神经元堆成层,让第一层把输入空间雕刻成新特征,第二层再把这些特征组合成单条直线做不出的决策。
这个堆叠就是多层网络,它是当今所有生产级深度学习模型的根基。前向传播——数据从输入经隐藏层流向输出——是你让其它一切都跑起来之前必须先搭好的第一块。
多层网络有三类层:
这是一个 2-3-1 网络:两个输入、三个隐藏神经元、一个输出。每条连线带一个权重,每个神经元(除输入外)带一个偏置。
每一层产出一个向量,叫隐藏状态。对文本,隐藏状态会升维——把一个词编码成 768 个数以捕捉语义;对图像,它会降维——把数百万像素压成可控的表示。学习就住在隐藏状态里。
每个神经元做三件事:
本节的激活函数是 sigmoid:
sigmoid(z) = 1 / (1 + e^(-z))
sigmoid 把任意实数压到 (0, 1) 区间:大正数挤向 1,大负数挤向 0,0 落在 0.5。这条光滑曲线正是让学习成为可能的关键——不像感知机的硬阶跃,sigmoid 处处都有梯度。
前向传播把输入数据逐层推过网络,直到输出。前向传播期间不发生任何学习,它是纯计算:乘、加、激活、重复。
每一层按顺序做两件事:
z = W * input + b (线性变换) a = sigmoid(z) (激活)
上一层的输出变成下一层的输入。这就是前向传播的全部。
追踪维度是深度学习里最重要的调试技能。看这个 2-3-1 网络:
| 步骤 | 运算 | 维度 | 结果形状 |
|---|---|---|---|
| 输入 | x | -- | (2,) |
| 隐藏层线性 | W1 * x + b1 | W1: (3, 2), b1: (3,) | (3,) |
| 隐藏层激活 | sigmoid(z1) | -- | (3,) |
| 输出层线性 | W2 * h + b2 | W2: (1, 3), b2: (1,) | (1,) |
| 输出层激活 | sigmoid(z2) | -- | (1,) |
规则:第 k 层的权重矩阵 W 形状是(第 k 层神经元数, 第 k−1 层神经元数)。行对应当前层,列对应上一层。形状对不上,就是有 bug。
1989 年,George Cybenko 证明了一件惊人的事:只要隐藏神经元足够多,单隐藏层网络就能以任意精度逼近任意连续函数。
但这不代表单隐藏层永远最优——它只说明架构理论上可行。实践中,更深网络(更多层、每层更少神经元)用远少于「浅而宽」网络的总参数量,就能学会同样的函数。这正是深度学习行得通的原因。
直觉:隐藏层里每个神经元学会一个「凸起」或一种特征,把足够多的凸起摆在合适位置,就能逼近任何光滑曲线。神经元越多,凸起越多,逼近越好。
神经网络是可组合的——你可以堆叠、串联、并行。Whisper 模型用一个编码网络处理音频、另一个解码网络生成文本;现代 LLM 多为 decoder-only;BERT 是 encoder-only;T5 是 encoder-decoder。架构选型决定了模型能做什么。
纯 Python,不用 numpy,所有矩阵运算都从零写。完整代码见原课程 phases/03-deep-learning-core/02-multi-layer-networks/code/ 相应文件。
import math def sigmoid(x): x = max(-500.0, min(500.0, x)) return 1.0 / (1.0 + math.exp(-x))
那个截断到 [-500, 500] 是为了防止溢出:math.exp(500) 很大但有限,math.exp(1000) 就是无穷了。
深度学习里最重要的运算就是矩阵乘法。每一层、每个注意力头、每一次前向传播——底层都是 matmul。线性层接收输入向量,乘以权重矩阵,加上偏置向量:y = Wx + b。神经网络里 90% 的计算量就是这一个公式。
层持有一个权重矩阵和一个偏置向量,其 forward 方法接收输入向量、返回激活后的输出。权重矩阵形状是 (n_neurons, n_inputs):每一行是一个神经元跨全部输入的权重。forward 遍历神经元,算加权求和加偏置,套 sigmoid,收集结果。
网络就是一列层。前向传播把它们串起来:第 k 层输出喂进第 k+1 层。逻辑就四行:数据进去,逐层流过,从另一头出来。
在第 01 节里我们用 OR、NAND、AND 感知机组成了 XOR。现在用我们的 Layer 与 Network 类做同样的事,采用 2-2-1 架构:两个输入、两个隐藏神经元、一个输出。
隐藏层权重设成 [[20, 20], [-20, -20]]、偏置 [-10, 30],输出层权重 [[20, 20]]、偏置 [-30]。这些大权重(20、-20)让 sigmoid 表现得近乎阶跃函数:第一个隐藏神经元近似 OR,第二个近似 NAND,输出神经元把它们合成 AND,也就是 XOR。
再上一个更难的任务:判定二维点是否落在以原点为圆心、半径 0.5 的圆内。这需要弯曲的决策边界——单个感知机无能为力。生成 200 个点,搭一个 2-8-1 网络,跑前向传播。
用随机权重,网络几乎判不准。但前向传播照样跑得通——这就是要点:前向传播只是计算,学会正确的权重是第 03 节反向传播的事。
PyTorch 四行就能把上面的事做完:
import torch import torch.nn as nn model = nn.Sequential( nn.Linear(2, 8), nn.Sigmoid(), nn.Linear(8, 1), nn.Sigmoid(), ) x = torch.tensor([[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]]) output = model(x) print(output)
nn.Linear(2, 8) 就是你的 Layer 类:权重矩阵形状 (8, 2)、偏置向量形状 (8,)。nn.Sigmoid() 是你逐元素的 sigmoid。nn.Sequential 就是你的 Network 类:按顺序串层。
差距在速度与规模:PyTorch 跑在 GPU 上、处理百万级样本的 batch、自动算反向传播的梯度。但前向传播的逻辑和你从零写的完全一致。
本节产出(位于原课程 outputs/):
prompt-network-architect.md:一个可复用提示,在你需要决定「该用几层、每层几个神经元、用哪种激活函数」时给出建议。Network 类上实现一个 count_parameters 方法,返回可训练权重和偏置的总数。在 784-256-128-10 网络(经典 MNIST 架构)上测试,它有多少参数?下一节,我们正式推导反向传播——前向传播把数据推过去,反向传播把梯度推回来,亲手实现一遍,你就真正懂了「学习」在做什么。