一、 它有名字
这个压缩函数叫 sigmoid
演示 ② 的灯泡显示 0.57,中间那步"压缩"用的是 sigmoid 函数(也叫 logistic 函数)。它把任何一个实数——不管是 −1000 还是 +1000——都映射到 0 与 1 之间:
把它接在加权求和后面,就得到一个神经元的完整公式。演示 ② 里的三个输入 x₁ x₂ x₃、三个权重 w₁ w₂ w₃、一个偏置 b,合起来是:
括号里那一坨,讲义里叫"加权总分",数学上通常记作 z。所以整件事就两步:先求 z,再套 σ。
二、 逐步代入
0.57 是怎么算出来的
用演示 ② 打开时的默认值:x₁=0.80、x₂=0.10、x₃=0.60,w₁=1.0、w₂=0.0、w₃=0.0,门槛 b=−0.5。
页面里对应的代码,恰好也是两行:
// 第一步:加权总分 const z = x[0]*w[0] + x[1]*w[1] + x[2]*w[2] + b; // 第二步:sigmoid 压缩 const a = 1 / (1 + Math.exp(-z));
三、 看图
sigmoid 长什么样
曲线的形状,比任何解释都能说明为什么选它。拖动滑块,看红点在曲线上滑动。
互动图:σ(z) 的全貌
横轴是加权总分 z(可以是任意实数),纵轴是压缩后的输出(永远落在 0 到 1 之间)。
四、 一个副作用
饱和为什么会拖慢学习
回想讲义第 7 节的"蒙眼下山":机器靠感觉脚下的坡度来决定往哪挪。坡度,就是曲线在那一点的陡峭程度。
把上面那个"显示此处的陡峭程度"勾上,拖到两端看看——数值会掉到接近 0。这意味着:当一个神经元的总分很大或很小时,微调它的权重几乎不会改变输出,机器也就感觉不出该往哪走。坡太平,人就在原地打转。层数一多,这个问题会一路向前累积,训练慢得让人绝望。
顺带一提,sigmoid 的陡峭程度有个漂亮的写法,用它自己就能表达:
五、 替代方案
所以今天大多改用 ReLU
为了绕开饱和,现代网络的隐藏层普遍改用一个简单到近乎粗暴的函数——ReLU,全称"修正线性单元"(Rectified Linear Unit)。名字唬人,干的事只有一句:
把上面互动图里的"叠加 ReLU 曲线"勾上,对比一下:ReLU 在正半轴是一条永不变平的直线,坡度恒为 1,机器随时都能感觉到方向。代价是它不再有 0 到 1 的上限——所以"灯泡"这个比喻在隐藏层里就不太贴切了,但网络并不在乎。
不过输出层通常还是要压缩的:认数字这类任务,最后一层常用 sigmoid 的多分类版本 softmax,好让十个输出加起来正好是 1,读作"概率"。
六、 从一个到一层
矩阵写法,与 13,002 的来历
一个神经元要写三项乘法。一层有 16 个神经元、上一层有 784 个,全写出来是 12544 项——没人这么干。把上一层所有亮度排成一列向量 a⁽⁰⁾,所有权重排成一个矩阵 W,所有偏置排成向量 b,整层的计算就浓缩成一行:
这也顺带解释了为什么显卡对深度学习这么关键:训练也好、推理也好,主体工作就是飞快地做矩阵乘法。
最后核一下讲义里"一万三千多个旋钮"这个数。网络结构是 784 → 16 → 16 → 10:
| 部位 | 算式 | 个数 |
|---|---|---|
| 输入层 → 隐藏层 1 的权重 | 784 × 16 | 12,544 |
| 隐藏层 1 → 隐藏层 2 的权重 | 16 × 16 | 256 |
| 隐藏层 2 → 输出层的权重 | 16 × 10 | 160 |
| 各层神经元的偏置 | 16 + 16 + 10 | 42 |
| 合计 | — | 13,002 |