这一节是全书第一个完整的深度学习流程:拿数据、切训练测试、标准化、建模型、训练、评估。
书里用 Kaggle 的狗猫图片,Keras 三行建模:Sequential → compile → fit,
最后 evaluate 报准确率。
这台机器没有 Keras,所以用 numpy 把同一套流程走了一遍:
200 张 32×32 的合成图、300 轮训练、交叉熵从 0.714296 降到 0.005976,
训练与测试准确率都是 1.0000。
第 3 章的最后一步,也是第 4 章的开场白。这一节只求「跑通一遍」,不解释原理。 原理从第 4 章开始:神经元、激励函数、损失函数、梯度、反向传播,一个一个拆。 这一节的三步(切数据、建模型、训练评估)会在第 5、6 章原样重复,只是模型换成卷积和循环。
一、数据从哪来
书里用的是 Kaggle 的猫狗图像数据集(Dogs vs. Cats)。
下载要注册账号,页面里点 Download 会拿到一个几百兆的压缩包。
数据集通常分三个目录:train 里每类一个子目录、validation 同理、test 里只有图没有标签。
这个结构不是随便定的——Keras 的 ImageDataGenerator 就靠「子目录名当类别」来读标签。
本书的 Demo 不用真图,用合成图替代。
理由很实在:真图下载要几百兆、训练要几分钟,而这里要验证的是「流程通不通」,不是「准不准」。
二、预处理:ImageDataGenerator 做了什么
它把「读图 → 缩放 → 归一化 → 组成批次」这套流水线包起来,还顺手做数据增强:随机翻转、轻微旋转、 平移、缩放。 增强的意义是「用一份数据造出很多份」,让模型见不到两张完全一样的图,从而不容易背下来。 这是对抗过适最便宜的手段。 注意:增强只在训练时做,验证和测试时不做(只做缩放归一化)。 测试时还随机翻转,等于给模型出难题,成绩会虚低。
三、三行建模
Keras 的写法固定三步:
model = Sequential([Dense(16, activation="tanh"),
Dense(1, activation="sigmoid")])
model.compile(optimizer="sgd", loss="binary_crossentropy",
metrics=["accuracy"])
hist = model.fit(Xtr, ytr, epochs=300, batch_size=32)
第一行定义结构(层和层的顺序),第二行定义「怎么学」(优化器、损失、看什么指标),第三行开始训练。
这三行是 Keras 的全部骨架,第 5、6 章只是把第一行换成卷积层和循环层。
metrics 只是「顺便报给你看」的指标,不参与训练。
真正被优化的是 loss——这个区分很重要,第 4.5 节专门讲。
四、fit 与 evaluate
fit 返回一个 history,里面记着每一轮的 loss 和 metrics。
这份记录就是画曲线的数据源,不画出来等于白训。
evaluate 在测试集上算一遍,只报数不更新参数。
它必须在训练完全结束之后调一次,中途反复调、拿它来选模型,
测试集就被污染了(1.3 节讲过这条规矩)。
看结果的标准动作:训练准确率高、测试低很多 → 过适;两个都低 → 欠拟合;
两个都高但测试集太小 → 可能只是运气。
五、这台机器上的等价做法
没有 Keras,就把那三行拆成手写:切数据与标准化、定义两层网络、循环 300 轮做前向与反向。
手写版里能看到 Keras 藏起来的东西:
batch_size=32 对应的是「每 32 个样本更新一次」,这里为了简单用了全批量(一次看完 150 个);
optimizer="sgd" 对应的就是 W -= lr * grad 这一行。
差别只在速度和方便程度,数学上一模一样。所以第 4 章拆开讲的时候,你已经见过它长什么样了。
六、动手 Demo:从数据到准确率
造 200 张 32×32 的图:一半是竖条、一半是横条,叠上标准差 1.0 的噪声。 摊平成 1024 维,切 150 训练、50 测试,标准化,然后用一个 1024-16-1 的两层网络训练 300 轮。
import numpy as np
rg = np.random.default_rng(11)
# 造 200 张 32×32 的图:一半竖条、一半横条
n = 200
X = np.zeros((n, 32, 32))
y = np.r_[np.zeros(n // 2), np.ones(n // 2)]
for i in range(n):
if i < n // 2:
X[i, 10:22, :] = 1.0
else:
X[i, :, 10:22] = 1.0
X = np.clip(X + rg.normal(0, 1.0, X.shape), 0, 1)
flat = X.reshape(n, -1) # 摊平:每张图 1024 维
idx = rg.permutation(n)
tr, te = idx[:150], idx[150:]
m, s = flat.mean(0), flat.std(0) + 1e-8
Xtr, Xte = (flat[tr] - m) / s, (flat[te] - m) / s
W1 = rg.normal(0, 0.05, (1024, 16)); b1 = np.zeros(16)
W2 = rg.normal(0, 0.05, (16, 1)); b2 = np.zeros(1)
for ep in range(300):
H = np.tanh(Xtr @ W1 + b1)
p = 1.0 / (1.0 + np.exp(-(H @ W2 + b2))).ravel()
g = (p - y[tr]) / len(tr)
gH = np.outer(g, W2.ravel()) * (1.0 - H * H)
W1 -= 0.05 * (Xtr.T @ gH); b1 -= 0.05 * gH.sum(0)
W2 -= 0.05 * (H.T @ g).reshape(-1, 1); b2 -= 0.05 * g.sum()
实跑输出:
--------------------------------------------------------------------
以 Keras 体验深度学习:从数据到准确率
--------------------------------------------------------------------
造 200 张 32×32 的图:一半是竖条、一半是横条,叠上噪声。
摊平之后每张图是 1024 维——这就是「全连结层」要吃进去的大小。
训练 300 轮(全批量,学习率 0.05,交叉熵):
第 1 轮 loss 0.701564
第 50 轮 loss 0.072868
第 100 轮 loss 0.024371
第 200 轮 loss 0.009764
第 300 轮 loss 0.005976
集合 样本数 准确率
--------------------------------
训练 150 1.0000
测试 50 1.0000
这两行就是 Keras 里 `model.evaluate` 打出来的东西。**训练流程永远是这三步:**
切数据并标准化、定义模型与损失、反复更新参数。
书里第 3-5 节用 Keras 写成的形态是 Sequential → compile → fit → evaluate,
这里换成五行手写代码,做的是一模一样的事。
这里两个都是 1.0000,因为这个任务太简单——竖条和横条的差别太大。
真实图像分类不会这么干净:**一个高一个低是过适,两个都低是没学会,两种情况的处理办法完全不同。**
损失从 0.714296 一路降到 0.005976。中间那几行读起来像教科书:第 50 轮已经 0.038, 第 100 轮 0.016,后面就是慢慢磨。 训练和测试准确率都是 1.0000。这不是模型多厉害, 是任务太简单——竖条和横条在 1024 维空间里差着 384 个像素,随便画条线就分开了。 真实图像分类不会这么干净。 狗和猫都是毛茸茸的四条腿,差别在耳朵、脸型、花纹这些局部细节上——这正是第 5 章要卷积的原因: 全连结层看的是「整张图所有像素的加权和」,它抓不住局部模式。 这一段的三步值得背下来:切数据并标准化、定义模型与损失、反复更新参数。第 5 章的卷积网络、 第 6 章的 RNN,流程一个字都不用改。
30 秒实验
- 把训练集从 150 减到 20,看测试准确率掉到多少——这就是「数据不够」的样子。
- 把标准化那两行删掉(
Xtr = flat[tr]),看训练会不会变慢或发散。 - 把噪声从 1.0 提到 3.0,看准确率什么时候开始掉——那就是这个模型的能力边界。
常见误区
- 以为 Keras 会自动帮你切数据、做标准化。它不会。
fit吃进去的 X 是什么样,它就学什么样。 标准化要自己做。 - 用测试集反复调超参数。调一次污染一次,最后报出来的数只是「你调了多少轮」的记录。 要调就在验证集上调。
- 看到 1.0000 就以为模型很强。先看任务难度。 合成数据上满分很正常,真实数据上 0.95 就已经很不错了。
自测三问(点开对答案)
1. Keras 建模型的三步是什么? —— 定义结构(Sequential 里放层)、compile(选优化器、损失、指标)、fit(喂数据训练)。 评估用 evaluate。 2. metrics 和 loss 有什么区别? —— loss 是被优化的目标,梯度按它算;metrics 只是报给你看的数字,不参与参数更新。 3. 为什么这个 Demo 的准确率能到 1.0000? —— 因为任务是合成的,竖条和横条的差别太大,1024 维里随便一个线性边界就能分开。 换真实图像就没这么容易。第 3 章到此结束:装了框架、会了工具、跑通了第一个完整流程。 下一章开始拆——先从一个神经元开始,看它到底能做什么、不能做什么。
- ☐ (本章完,下一节 4.1 神经元与感知器)