跳到主要内容

第一个神经网络:MNIST 与全部零件

这一章讲三件事: 照开发流程十步写出第一个完整的神经网络程序;把它身上每个零件 (层、激活函数、损失函数、优化器、指标)挨个拆开讲透;以及作者用十一个实验证明的一件事—— 换零件很容易,选零件没有理论,只有实验。 这是全书第一个「完整交付」的程序,后面章节都是换着零件重跑它。

1. 主走查:一个能用的手写数字辨识器

任务:输入一张 28×28 像素的手写数字图片,输出它是 0~9 的哪一个。数据集是 MNIST 机构收集的 60000 张训练图 + 10000 张测试图1

先看作者给的下限:TensorFlow 2.x 官网为回应 PyTorch 的竞争,在文档首页放了一个「炫技版」程序——去掉注释只有十多行,辨识准确率 97%~98%2。深度学习的门槛没有想象中高,但「能跑」和「懂」之间隔着本章剩下的全部内容。

照十步流程写完整版(第 01 章许诺的兑现),每一轮走查的数字都是书里跑出来的:

步骤1-3 加载 60000 张图;EDA:像素值 0~255(0 是白、255 是黑,与 RGB 相反!);
特征缩放:除以 255 归一到 (0,1)——缩放能提高准确度、加快收敛

步骤4 切分:MNIST 已自带训练/测试划分

步骤5 搭模型(四层,从下往上):
Flatten 28×28 的图压扁成 784 个数(模型的输入必须是平的)
Dense 128 输出 128 个神经元 = 128 条回归线,每条 784 个特征
Dropout 训练时随机丢掉 20% 神经元(防过拟合)
Dense 10 输出 10 个数 + Softmax → 变成「是 0~9 各自的概率」

步骤6 编译+训练:优化器 Adam,损失 sparse_categorical_crossentropy;
validation_split=0.2(留两成训练数据当「模拟考」),训练 5 轮

步骤7 evaluate 测试集:loss=0.0833,accuracy=0.9743

步骤8+ 看不懂的地方就调(本章后面 11 个实验),最后存盘部署

图说:十步流程在这里第一次完整落地;括号里的每个数都在后文有出处。

几个走查途中的关键站点:

  • 模型到底有多少参数? 手算:输出层 10 条回归线,每条 128 个权重加 1 个偏差,10×(128+1)=1290 个——与 model.summary() 的输出一致3。第 03 章说 Dense=y=wx+b,这里看见了它的规模:仅这一层就上千个待调的数;
  • 模型也会犹豫:第 9 张测试图,模型给出「5 和 6 的概率很相近」。书里的对策很实用:概率不超过门槛(如 0.8)就不算辨识成功——宁可说「不确定」,不硬给答案4;
  • 验证数据是什么? validation_split 从训练数据里切出 20%,每轮训练后用它在「模拟考」上测一次——它不参与训练,用来观察训练过程有没有跑偏5

2. 十一个问题的总答案:神经网络还是黑箱

作者把几年教学中学生最常问的问题列了 11 个,逐一做实验。实验之前,他先给了诚实的总答案:到目前为主,神经网络依然是黑箱科学——784 维空间里根本无法判断损失曲面是不是「凸」的(只有一个谷底),没人能从理论推出最优层数,「依旧需要经验与实验」6

带着这个前提看实测结果(全是书里的原始数字):

改动结果一句话解读
加一对 Dense/Dropout 层0.9743 → 0.9733,微降层数不是越多越好
第一层 128 → 256 神经元→ 0.9764,微升神经元翻倍只换来 0.002,训练时间还变长
ReLU 换 sigmoid→ 0.9762,略低激活函数有优劣,但差距不大
Dropout 0.2 → 0.1→ 0.9755,略升丢太多会伤模型
训练 5 轮 → 10 轮→ 0.9785,略升轮数过多会过拟合,反而下降

(前三行的数字分别见书中的实验 1~37。)规律:这些旋钮都在 0.97 附近微调,没有一个带来质变。 书里引另一本教材的实验:神经元数有极限,超过后准确率不升反降8

判断(我们的,不是书里的): 这张表其实是全书方法论的一个「元结论」——深度学习的进步常靠「大规模试错+挑最好的」,而不是「推导出最优」。后面第 05 章的自动调参工具、第 08 章「case by case 调出最佳模型」,都是这个元结论的工程化。 如果错,会错在: 如果某些结构创新(如第 07 章的 ResNet)其实有理论依据,那「只有实验」的说法就过强;更准确的说法是:有了方向后的微调靠实验,方向本身靠洞察。

还有一个问题值得单独抄下来:「准确率能达到 100% 吗?」作者的回答:很少——神经网络是近似解,而且测试数据若与训练数据分布不同,准确率没有保证9

最锋利的一问是第 9 问:换成辨识别的东西要改多少? 答案:只改一行加载数据的代码(换成 FashionMnist——10 种服饰配件),其余照旧。书里由此点破本质:模型并不真的「认识」数字或鞋子,它只是统计出这些图的像素大概分布在哪些位置——从数据中挖出知识(KDD)而已10。这句话是理解第 06 章「卷积」和第 12 章「词向量」的钥匙:模型学到的永远是「统计规律」,不是「概念」。

3. 零件表(一):模型结构与激活函数

模型两种搭法:Sequential(顺序型,一层接一层,像叠盘子,除第一层外都不用声明输入维度(特征的个数))够用全书大部分场景;Functional API 允许分叉/合并、多输入多输出——书里的演示把三个输出 128+32+12 合并成 17211。后面 GAN 章(Pix2Pix)会用到 Functional。

激活函数(Activation Function):第 02 章说过,没有它神经网络只是一堆直线叠直线,永远弯不了。常用的四个,书里逐个测过12:

函数输出范围用在哪备注
  • ReLU(输出:负数归零)——隐藏层标配。三个旋钮:threshold(阈值,即判真判假的分界线)、max_value(上限)、alpha(负半轴斜率;0.01 时叫 Leaky ReLU)。

  • sigmoid(输出 0~1)——S 形平滑曲线,降低预测变异,适合二分类(只分两类的任务)的输出层。

  • tanh(输出 −1 到 1)——与 sigmoid 同形但更陡,旧式隐藏层用过。

  • softmax(把一组数变成总和为 1 的概率)——多分类输出层标配:把 10 个数变成「0~9 各自的概率」。

书里给 ReLU 的比喻很省笔墨:负的输入被直接无视,「就像轻轻碰一下皮肤,大脑可能不做出反应」。本章主走查模型里的「Dense 128 + ReLU」「Dense 10 + Softmax」,用的正是这张表的两端。

Dropout:训练时随机丢弃一定比例(本例 0.2)的神经元,预测时不丢13。直觉:每次训练都在「阉割版」网络上进行,最后等于平均了一大堆略有不同的模型,极端错误被稀释。书里的经验:神经网络里用 Dropout 通常比用正则函数(L1/L2)有效14

4. 零件表(二):损失函数——模型怎么定义「错」

损失函数回答「错得有多离谱」,是梯度下降的起点(第 02 章)。选错损失函数,模型就朝错误的方向优化。书里的分类15:

  • 回归用 MSE(均方误差):预测值与真实值差的平方的平均。书里的手算示例:两笔数据 ((1−1)²+(0−1)²)/2=0.5;
  • 分类用交叉熵(Entropy):直觉是「对正确答案的惩罚随置信度陡增」——书里给出二元形式:真实为 1 时损失=−log(p),预测概率 p 越低惩罚越大。作者用两笔数据算了 BinaryCrossentropy=0.8149,再用公式手工验算,结果一致16。这不是普通的两道计算:框架算的和公式算的对上了,说明损失函数不是黑盒,是能自己验算的数学;
  • Sparse 版吃整数标签(3),普通版吃 One-Hot 向量(0001000000)——效果一样,Sparse 省一步预处理;
  • Hinge Loss:SVM 用的「单边损失」,只惩罚错得离谱的,0/1 标签会自动转成 −1/117;
  • 自定义损失:写个函数,输入(真实值,预测值),输出一个数即可。——书里在此埋下伏笔:第 09 章风格转换、第 10 章 GAN 都靠自定义损失实现「意想不到的功能」。

在本章的主走查里,交叉熵出场的方式是 compile 参数 sparse_categorical_crossentropy:10 个输出概率里,真实答案那一项的概率越低,损失越高——梯度就朝「抬高正确答案的概率」的方向调参数。

5. 零件表(三):优化器

优化器管「怎么更新权重」,是第 02 章梯度下降的工程化。书里给它派了两大任务:设定学习率的变化以加速收敛,以及避开马鞍点等局部最小值、尽量找到全局最小——第 01 章「困在局部」的隐患,由它专职看管18。按「攒多少数据再更新一次」分三档:

  • 批量(BGD):全部样本算一次梯度才更新——稳但慢;
  • 随机(SGD):一个样本就更新——快但路线曲折;
  • 小批量(Mini-batch):折中,深度学习默认。

书里给的更新公式仍然是老朋友:w = w − 学习率 × 梯度;在这个基础上加动能(momentum):velocity = momentum × velocity − 学习率 × 梯度,w = w + velocity——像球下坡带惯性,远离谷底时迈大步,接近谷底时收步,既快又不冲过头18

Adam 是动能思路的集大成者(自适应调学习率),书里引 2014 年 Kingma 的原始论文评价它「计算效率高、内存耗费少,适合大数据集及参数个数很多的模型」;同一道测试题,SGD 要走 50 步,Adam 10 步收敛19。作者的结论也很实在:「大多数状况下,Adam 优化器都有不错的表现」——它是默认安全牌20

6. 零件表(四):效果衡量指标

效果衡量指标管「怎么算分」,远不止准确率一个数。一切的起点是混淆矩阵:

预测为真 预测为假
实际为真 TP FN(漏报)
实际为假 FP(误报) TN

四个指标都从这四格里算21:

准确率=(TP+TN)/总数,即「预测正确数/总数」。

精确率,即 TP/(TP+FP)——报出来的阳性里,有多少是真的。

召回率,即 TP/(TP+FN)——真货里捞回来了多少,漏掉的代价由它盯着。

F1,即精确率与召回率的调和平均数22

为什么准确率不够用? 书里的例子是全书最生动的反面教材之一:某病染病率 1%,一台故障设备对所有人一律报「阴性」——它算出来的准确率是 99%(100 个人里只「错」1 个)。样本比例悬殊(不平衡)时,准确率是骗人的,必须看精确率/召回率23。还有一个无法两全的取舍:放宽阳性标准,漏报(FN)少了但误报(FP)多了——书里拿新冠检测举例:放宽能多找确诊者,却可能压垮整个医疗体系,所以政策要随疫情反复调整24。此外还有 ROC/AUC:不固定 0.5 这个判决门槛,而是把各种门槛下的表现连成曲线,算覆盖面积,面积越大模型在不同严格程度下都越可靠25

拿主走查的模型实际算一遍:8 笔数据,真实 [0,0,0,1,1,1,1,1]、预测 [0,1,0,1,0,1,0,1],得 TP=3、FP=1、TN=2、FN=2,于是准确率 0.625、精确率 0.75、召回率 0.626。同一个模型,三个数讲三个故事:整体六成四猜对;「报真」的里头四分三是真的;真货里捞回六成。

7. 可带走的

  1. 十多行代码就能到 97%,但读懂每个零件才能从 97% 走向「知道自己为什么对/错」;
  2. 十步流程第一次落地:EDA→缩放→切分→搭模型→compile→fit→evaluate,任何深度学习项目都是这条流水线;
  3. 参数手算:输出层 10×(128+1)=1290——模型大小不是玄学,是乘法;
  4. 11 个实验的总答案:加层微降、加神经元微升、换激活微动——都在 0.97 附近,结构没有理论最优,只有实验比较;神经网络至今是黑箱;
  5. 模型不「认识」数字:它只是统计了像素分布——换数据集只改一行代码,这个「不认识」同时也是「万能」的原因;
  6. 激活函数选址:隐藏层 ReLU,二分类 sigmoid,多分类 softmax(输出一组概率、总和为 1);Leaky ReLU=负半轴留一点斜率;
  7. 损失函数选错,优化方向就错:回归 MSE、分类交叉熵(0.8149 可手验)、SVM 用 Hinge;自定义损失是后面生成类算法的种子;
  8. 优化器:w −= 学习率×梯度 是本体,动能让它又快又稳;Adam 是默认安全牌(50 步 vs 10 步);
  9. 准确率会撒谎:染病率 1% 时「全部判阴性」的故障设备准确率 99%——不平衡数据看精确率/召回率/F1;门槛可调(0.8 拒绝模糊答案);
  10. 模型会犹豫,要给它「不确定」的出口:概率不满门槛就不算数。

8. 原文地图

主题原书章原文位置
MNIST 数据集、官网十行程序4-1 撰写第一个神经网络程序text/25-ch04-4-1.txt:7(搜「60000个训练数据」) · text/25-ch04-4-1.txt:25(搜「97%~98%」)
像素 0~255 与 RGB 相反4-1 撰写第一个神经网络程序text/25-ch04-4-1.txt:47(搜「255为最深的黑色」)
模型结构 128/Dropout 0.24-1 撰写第一个神经网络程序text/25-ch04-4-1.txt:73(搜「128个神经元」) · text/25-ch04-4-1.txt:75(搜「随机丢弃一定比例」)
compile 与 validation_split4-1 撰写第一个神经网络程序text/25-ch04-4-1.txt:83(搜「sparse_categorical_crossentropy」) · text/25-ch04-4-1.txt:87(搜「validation_split」)
测试成绩与第 9 张的犹豫4-1 撰写第一个神经网络程序text/25-ch04-4-1.txt:107(搜「loss为0.0833」) · text/25-ch04-4-1.txt:115(搜「5及6的概率很相近」)
参数 1290 手算4-1 撰写第一个神经网络程序text/25-ch04-4-1.txt:129(搜「1290」)
黑箱总答案、11 个实验4-1 撰写第一个神经网络程序text/25-ch04-4-1.txt:177(搜「黑箱(Black Box」) · text/25-ch04-4-1.txt:185(搜「准确率未见提升」) · text/25-ch04-4-1.txt:201(搜「0.9764」) · text/25-ch04-4-1.txt:225(搜「sigmoid准确率确实略低」)
神经元数的极限4-1 撰写第一个神经网络程序text/25-ch04-4-1.txt:179(搜「不升反降」)
准确率不可能 100%4-1 撰写第一个神经网络程序text/25-ch04-4-1.txt:163(搜「100%」)
模型不认识数字(FashionMnist)4-1 撰写第一个神经网络程序text/25-ch04-4-1.txt:293(搜「像素大部分分布在那些位置」)
Sequential 与 Functional4-2 Keras模型种类text/26-ch04-4-2-keras.txt:7(搜「Sequential model」) · text/26-ch04-4-2-keras.txt:59(搜「128+32+12=172」)
Dropout 只在训练时运作4-3 神经层text/27-ch04-4-3.txt:81(搜「只在训练时运作」) · text/27-ch04-4-3.txt:67(搜「glorot_uniform」)
激活函数四件套4-4 激活函数text/28-ch04-4-4.txt:41(搜「Leaky」) · text/28-ch04-4-4.txt:59(搜「总和为1」)
交叉熵手验 0.8149、Hinge4-5 损失函数text/29-ch04-4-5.txt:53(搜「0.8149」) · text/29-ch04-4-5.txt:87(搜「Hinge Loss会自动将其转成」)
动量公式、Adam 50 步 vs 10 步4-6 优化器text/30-ch04-4-6.txt:57(搜「velocity = momentum」) · text/30-ch04-4-6.txt:97(搜「50步」) · text/30-ch04-4-6.txt:101(搜「Adagrad(Adaptive Gradient-based」)
混淆矩阵、故障设备 99%4-7 效果衡量指标text/31-ch04-4-7.txt:15(搜「TP(真阳性)」) · text/31-ch04-4-7.txt:37(搜「故障的检验设备」)
四指标定义、8 笔数据实测4-7 效果衡量指标text/31-ch04-4-7.txt:25(搜「准确率(Accuracy)」) · text/31-ch04-4-7.txt:31(搜「F1=精确率与召回率的调和平均数」) · text/31-ch04-4-7.txt:67(搜「TP=3」) · text/31-ch04-4-7.txt:79(搜「0.625」)
ROC/AUC4-7 效果衡量指标text/31-ch04-4-7.txt:43(搜「ROC/AUC曲线」)
CategoricalAccuracy 陷阱4-1 撰写第一个神经网络程序text/25-ch04-4-1.txt:241(搜「CategoricalAccuracy」)

Footnotes

  1. 出处:「4-1 撰写第一个神经网络程序」第 7 段(text/25-ch04-4-1.txt:7,搜「60000个训练数据」)。

  2. 出处:「4-1 撰写第一个神经网络程序」第 25 段(text/25-ch04-4-1.txt:25,搜「97%~98%」)。背景:官网此程序是为回击 PyTorch 而展示,见同节第 21 段(搜「回击对手」)。

  3. 出处:「4-1 撰写第一个神经网络程序」第 129 段(text/25-ch04-4-1.txt:129,搜「1290」)。

  4. 出处:「4-1 撰写第一个神经网络程序」第 115 段(text/25-ch04-4-1.txt:115,搜「5及6的概率很相近」)。

  5. 出处:「4-1 撰写第一个神经网络程序」第 87 段(text/25-ch04-4-1.txt:87,搜「validation_split」)。

  6. 出处:「4-1 撰写第一个神经网络程序」第 177 段(text/25-ch04-4-1.txt:177,搜「黑箱(Black Box」)。原文还解释了「凸集合才有全局最优、784 维无从判断」。

  7. 出处:「4-1 撰写第一个神经网络程序」第 185 段(text/25-ch04-4-1.txt:185,搜「准确率未见提升」)、第 201 段(text/25-ch04-4-1.txt:201,搜「0.9764」)、第 225 段(text/25-ch04-4-1.txt:225,搜「sigmoid准确率确实略低」)。Dropout 与 epochs 的实验数字在第 253、269 段。

  8. 出处:「4-1 撰写第一个神经网络程序」第 179 段(text/25-ch04-4-1.txt:179,搜「不升反降」)。出处注明来自《Deep Learning with TensorFlow 2.0 and Keras》一书的测试。

  9. 出处:「4-1 撰写第一个神经网络程序」第 163 段(text/25-ch04-4-1.txt:163,搜「100%」)。原文:「很少模型准确率能够达到100%」。

  10. 出处:「4-1 撰写第一个神经网络程序」第 293 段(text/25-ch04-4-1.txt:293,搜「像素大部分分布在那些位置」)。

  11. 出处:「4-2 Keras模型种类」第 7 段(text/26-ch04-4-2-keras.txt:7,搜「Sequential model」)、第 9 段(text/26-ch04-4-2-keras.txt:9,搜「允许非直线型的结构」)与第 59 段(text/26-ch04-4-2-keras.txt:59,搜「128+32+12=172」)。

  12. 出处:「4-4 激活函数」第 41 段(text/28-ch04-4-4.txt:41,搜「Leaky」)与第 59 段(text/28-ch04-4-4.txt:59,搜「总和为1」)。「轻碰皮肤」的比喻在第 13 段(搜「轻轻碰一下皮肤」)。

  13. 出处:「4-1 撰写第一个神经网络程序」第 75 段(text/25-ch04-4-1.txt:75,搜「随机丢弃一定比例」)与「4-3 神经层」第 81 段(text/27-ch04-4-3.txt:81,搜「只在训练时运作」)。

  14. 出处:「4-3 神经层」第 87 段(text/27-ch04-4-3.txt:87,搜「比Regularizer效果好」)。

  15. 出处:「4-5 损失函数」第 11 段(text/29-ch04-4-5.txt:11,搜「概率相关的损失函数」)。

  16. 出处:「4-5 损失函数」第 53 段(text/29-ch04-4-5.txt:53,搜「0.8149」)与第 57 段(text/29-ch04-4-5.txt:57,搜「与BinaryCrossentropy()计算结果一致」)。MSE 手算 0.5 在第 73 段(搜「0.5」)。

  17. 出处:「4-5 损失函数」第 87 段(text/29-ch04-4-5.txt:87,搜「Hinge Loss会自动将其转成」)。

  18. 出处:「4-6 优化器」第 57 段(text/30-ch04-4-6.txt:57,搜「velocity = momentum」)。「远处迈大步近处收步」的解释在同段前后。优化器的两大作用(加速收敛、避开马鞍点找全局最小)见第 7、9 段(text/30-ch04-4-6.txt:9,搜「避开马鞍点」)。 2

  19. 出处:「4-6 优化器」第 97 段(text/30-ch04-4-6.txt:97,搜「50步」)。Adam 论文的评价引自第 77 段(搜「计算效率高」)。

  20. 出处:「4-1 撰写第一个神经网络程序」第 235 段(text/25-ch04-4-1.txt:235,搜「Adam优化器都有不错的表现」)。

  21. 出处:「4-7 效果衡量指标」第 15 段(text/31-ch04-4-7.txt:15,搜「TP(真阳性」)。

  22. 出处:「4-7 效果衡量指标」第 25 段(text/31-ch04-4-7.txt:25,搜「准确率(Accuracy)」)与第 31 段(text/31-ch04-4-7.txt:31,搜「F1=精确率与召回率的调和平均数」)。

  23. 出处:「4-7 效果衡量指标」第 37 段(text/31-ch04-4-7.txt:37,搜「故障的检验设备」)。

  24. 出处:「4-7 效果衡量指标」第 33 段(text/31-ch04-4-7.txt:33,搜「Covid-19检测」)。原文讲阳性认定值的取舍与「政府机构随时调整」。

  25. 出处:「4-7 效果衡量指标」第 43 段(text/31-ch04-4-7.txt:43,搜「ROC/AUC曲线」)。

  26. 出处:「4-7 效果衡量指标」第 67 段(text/31-ch04-4-7.txt:67,搜「TP=3」)与第 79 段(text/31-ch04-4-7.txt:79,搜「0.625」)。精确率 0.75、召回率 0.6 见第 87、93 段。