这一页用训练好的真实权重,把某一个样本从输入到输出完整拆开。 不是示意图,每一个数字都是模型实际算出来的。
模型看到的不是日期,是 12 个数字。下面是原始值和标准化(z-score,减均值除标准差)之后的值。
均值和标准差来自训练集:μ = 617.32,σ = 570.95。 标准化后的值才是模型真正看到的输入。
这就是隐藏层的全部内容。16 个神经元,每个神经元对 12 个输入各有一个权重,共 192 个数字。行是输入时刻,列是神经元编号,颜色深浅表示权重绝对值。 鼠标悬停可以看到精确数值。
加上 16 个偏置 b₁,隐藏层一共 192 + 16 = 208 个参数。输出层再有 16 个权重加 1 个偏置,总共 225 个。
每个神经元先对自己那一列的 12 个权重和输入做加权求和,得到 z₁;
再过 ReLU(修正线性单元,max(0, z₁))得到 h₁。
z₁ 为负的神经元输出被压成 0,等于这个样本上它没有参与决策。
16 个神经元里只有 4 个被激活(n3、n6、n10、n12)。 其余 12 个的 z₁ 全为负,被 ReLU 压成了 0。
这就是 ReLU 的稀疏性:同一个样本只走其中一小部分通路,不同样本激活不同的神经元。
n10 是这一样本里输出绝对值最大的神经元。它的算法就是「12 个乘积求和,再加偏置」, 和线性模型一模一样——区别只在于最后过了一道 ReLU。
| 时刻 | 输入 x | 权重 w | 乘积 | 累加 |
|---|---|---|---|---|
| 06:00 | -0.797 | -0.297 | +0.237 | +0.237 |
| 07:00 | +0.050 | -0.105 | -0.005 | +0.231 |
| 08:00 | +1.045 | +0.175 | +0.183 | +0.414 |
| 09:00 | +2.054 | +0.456 | +0.937 | +1.351 |
| 10:00 | +1.297 | +0.163 | +0.212 | +1.563 |
| 11:00 | +1.614 | +0.163 | +0.262 | +1.825 |
| 12:00 | +1.697 | -0.015 | -0.026 | +1.799 |
| 13:00 | +1.553 | +0.078 | +0.122 | +1.921 |
| 14:00 | +1.204 | +0.358 | +0.432 | +2.353 |
| 15:00 | +0.900 | -0.032 | -0.029 | +2.324 |
| 16:00 | +1.108 | -0.270 | -0.300 | +2.024 |
| 17:00 | +0.076 | +0.688 | +0.053 | +2.077 |
| 累加和 | +2.077 | |||
| 加偏置 b₁ = +0.136 | z₁ = +2.213 | |||
| 过 ReLU | h₁ = 2.213 | |||
09:00(1790 辆/小时)和 17:00(661 辆/小时)对它的贡献较大。 这些权重是训练过程中自己学出来的,没有人指定它应该关注哪个时刻。
只有激活的神经元有输出,其余是 0。所以实际参与最后的加权的只有这 4 个。
| 神经元 | h₁ | W₂ | 贡献 h₁·W₂ |
|---|---|---|---|
| n3 | 1.538 | -0.426 | -0.656 |
| n6 | 1.168 | +0.412 | +0.482 |
| n10 | 2.213 | -0.373 | -0.825 |
| n12 | 3.710 | +0.141 | +0.522 |
| 加偏置 b₂ = -0.1011 | -0.5786 | ||
真实值是 242 辆/小时,预测 287, 差 45 辆。
同一组 z₁,过 ReLU 前后对比。上半部分是 z₁,下半部分是 h₁:
负值全部归零,正数原样通过。 这一步是整个网络唯一的非线性来源——如果去掉它, 两层矩阵乘法会合并成一个矩阵,模型立刻退化成实验 01 的线性模型。
副作用是「死神经元」:某个神经元如果长期只输出负值, 梯度恒为 0,它就再也学不动了。这个样本里 12 个神经元处于这种状态。
手写版(numpy):
# 前向:12 维 → 16 维 → 1 维 z1 = X @ W1 + b1 # (m, 16) 这张表就是上面那个热力图 h1 = np.maximum(0.0, z1) # (m, 16) ReLU pred = h1 @ W2 + b2 # (m, 1) 合成输出
框架版(PyTorch)等价写法:
self.fc1 = nn.Linear(12, 16) # 对应 W1, b1 self.act = nn.ReLU() # 对应 np.maximum(0, z1) self.fc2 = nn.Linear(16, 1) # 对应 W2, b2
所以「隐藏层」不是一个抽象概念:它就是一张 12×16 的权重表、一个 16 维偏置向量, 加一道 max(0, ·)。这个样本走完一遍,就是 12×16 = 192 次乘法加 16 次比较。