Skip to content

MIT深度学习课程第三讲:Keras训练实践与图像分类入门 ​

本节课分为两部分:

  1. 使用 Keras 和 Colab 实际训练一个心脏病预测模型。
  2. 转入计算机视觉,介绍图像如何表示,并开始搭建图像分类模型。

老师强调,本节课会真正进入 Colab 实操。前半部分承接上一节神经网络训练的理论,后半部分为后续图像分类和彩色图像处理做准备。

一、本节课安排 ​

本节课计划做两个 Colab:

  • 第一个 Colab:训练一个用于心脏病预测的 Keras 模型。
  • 第二个 Colab:开始处理图像分类问题。

心脏病预测问题来自前面课程已经介绍过的数据集。图像分类部分会从数字图像的表示讲起,再进入 Fashion-MNIST 数据集。

二、神经网络训练流程回顾 ​

老师先回顾上一节课的核心思想:训练神经网络,本质上和训练其他机器学习模型没有根本区别。

神经网络中有一组参数:

  • weights
  • biases

训练的目标是使用数据找到一组好的参数。

这里的“好”通常指:

模型预测值与真实答案之间的差异尽可能小。

这个差异由 loss function 衡量。

整体训练流程可以概括为:

  1. 定义一个网络结构。
  2. 输入数据经过多层网络。
  3. 网络输出预测值。
  4. 将预测值与真实值一起送入 loss function。
  5. 得到一个 loss score。
  6. optimizer 计算 loss 对所有参数的梯度。
  7. 使用梯度更新 weights 和 biases。
  8. 重复这个过程。

因此,训练循环中的核心对象是:

  • network
  • prediction
  • ground truth
  • loss function
  • optimizer
  • gradient
  • parameter update

三、Gradient Descent 与 Stochastic Gradient Descent ​

上一节课介绍过 gradient descent。

在普通 gradient descent 中,每次迭代会使用所有训练样本:

  1. 所有数据点都通过网络。
  2. 对所有数据点计算预测值。
  3. 计算整体 loss。
  4. 计算 loss 对参数的梯度。
  5. 用梯度更新参数。

老师指出,实际训练中更常使用 stochastic gradient descent,简称 SGD。

SGD 的思路是:

不一次使用全部数据,而是随机选择一小部分样本,把它们暂时当成当前拥有的全部数据,基于这部分样本计算预测、loss、gradient,并更新参数。

这种小批量样本在技术上叫 minibatch。老师说明,后面会直接把它称为 batch,这也是文献和实践中常见的简化说法。

四、Epoch 的定义 ​

epoch 指的是:

对整个训练集完成一次完整遍历。

也就是说,所有训练样本都至少被送入网络一次。

在普通 gradient descent 中:

  • 一个 epoch 使用所有训练样本。
  • 在这个 epoch 结束时计算一次梯度。
  • 参数只更新一次。

老师提到,梯度可以写成:

text
d loss / dW

也可以用 nabla 符号表示。这些都是表示 loss 关于参数的梯度。

如果数据集有 10 billion 个样本,普通 gradient descent 会让所有样本都通过网络,得到所有输出后,再在 epoch 末尾进行一次参数更新。

五、SGD 中的 Batch 与 Epoch ​

在 SGD 中,训练数据会被分成多个 batches。

一个 epoch 的过程是:

  1. 将训练集分成 batch 1、batch 2,直到最后一个 batch。
  2. 对 batch 1 做一次前向传播,得到预测值。
  3. 计算 loss 和 gradient。
  4. 更新参数。
  5. 用更新后的参数处理 batch 2。
  6. 持续处理所有 batches。
  7. 所有训练数据都被处理一遍后,一个 epoch 结束。

因此,在 SGD 中:

一个 epoch 内会发生多次参数更新,更新次数等于 batch 数量。

老师举例:

  • 如果一个 batch 有 32 个样本。
  • 处理完第一个 batch 后,网络参数已经更新。
  • 第二个 batch 使用的已经是更新后的参数。

这也是 SGD 的重要优势:不必等所有数据都处理完才更新,而是边看数据边更新。

六、Batch 数量如何计算 ​

在一个 epoch 中,batch 数量由训练集大小和 batch size 决定。

公式可以理解为:

text
number_of_batches = ceil(training_set_size / batch_size)

老师强调,batch size 是建模者选择的。

常见默认值包括:

  • 32
  • 64

这些值常用的原因之一是它们与并行硬件的计算方式比较匹配。

Keras 会自动计算实际 batch 数量,建模者不需要手动管理每个 batch。但老师强调,仍然应该理解细节,因为只有概念足够清楚,后续遇到新问题时才能真正操作这些概念,而不是只会运行默认代码。

课堂示例:

  • 训练集大约有 194 个患者。
  • batch size = 32
  • 194 / 32 约等于 6.x
  • 向上取整后得到 7 个 batches。

于是:

  • 前 6 个 batch 各有 32 个样本。
  • 最后一个 batch 只剩下少量样本,例如 2 个。

老师指出,最后一个 batch 不需要和前面的 batch 一样大。

七、关于 Batch 与 Epoch 的课堂问答 ​

7.1 Batch 是取部分变量还是部分数据 ​

学生问:SGD 中只取一部分,是取部分变量,还是取部分数据?

老师回答:

取的是部分 rows,也就是部分 data points。

例如:

  • 1000 个患者样本中取 32 个患者。
  • 1000 张图片中取 32 张图片。

这 32 个样本构成一个 batch。

不是只取部分特征列,也不是只取网络的一部分。

7.2 每个 Batch 是否都会更新权重 ​

学生问:每次处理 batch 时,是否都会更新当前权重?

老师回答:会。

处理每个 batch 后,都会根据该 batch 计算出的 gradient 更新参数。

因此,训练过程是在不断“边走边修正”。

7.3 Epoch 不是 Loss Function ​

学生把 epoch 理解成正在求的 loss function。

老师纠正:

epoch 不是 loss function,而是对训练数据完成一次完整遍历。

在 SGD 中,一个 epoch 内有多个 batches,也就有多次参数更新。

7.4 每个 Batch 是否经过整个网络 ​

学生问:一个 batch 是经过整个网络,还是只经过某一层?

老师回答:

每个 batch 都要经过整个网络。

原因是:

  • 不经过整个网络,就得不到预测值。
  • 没有预测值,就无法计算 loss。
  • 没有 loss,就无法计算 gradient。
  • 没有 gradient,就无法更新 weights。

7.5 普通 Gradient Descent 与 SGD 的更新次数 ​

在普通 gradient descent 中:

  • 一个 epoch 是一次完整遍历。
  • 一个 epoch 只做一次权重更新。

在 SGD 中:

  • 一个 epoch 仍然是一次完整遍历。
  • 但每个 batch 之后都会更新一次。
  • 更新次数等于 ceil(training_set_size / batch_size)。

7.6 SGD 的优势 ​

学生总结:使用 SGD 的优势是,处理完第一个 batch 后,第二个 batch 已经可以使用更好的系数。

老师确认这个理解是正确的。

虽然单个 batch 只是数据的一小部分,梯度估计不如全量数据精确,但通常仍能朝着正确方向更新。这样可以避免等待整个数据集处理完再更新。

学生问:SGD 是得到更好的解,还是节省计算?

老师回答:两者都有。具体原因已在上一讲中讨论。

八、Overfitting、Underfitting 与 Regularization ​

进入 Colab 前,老师补充了 overfitting 和 regularization。

当模型越来越复杂时,训练集误差通常会下降。

例如:

  • 简单回归模型有一定误差。
  • 加入 interaction terms、logarithms 等复杂变换后,训练集误差通常下降。

但模型复杂度继续增加时,验证集或真实泛化表现可能会先变好,再变差。

这对应三个区域:

  • underfitting:模型还太简单,仍有明显改进空间。
  • 合适区域:模型复杂度与数据模式匹配。
  • overfitting:模型开始拟合训练数据中的偶然性和特殊细节,而不是可泛化规律。

目标是找到中间的 sweet spot。

九、神经网络为什么容易 Overfit ​

在神经网络中,模型需要学习输入数据的 representations。

为了学习复杂 representation,通常会增加网络层数和参数数量。

老师举例,GPT-3 大约有 96 层。

一般来说:

  • 层数越多,表达能力越强。
  • 层数越多,参数越多。
  • 参数越多,模型复杂度越高。
  • 模型复杂度越高,overfitting 风险越大。

因此,神经网络训练中特别需要考虑 regularization。

regularization 的目标是:

降低过拟合风险,让模型既能拟合数据,又不过度贴合训练集中的噪声。

十、Early Stopping ​

本节课会用到的第一种 regularization 方法是 early stopping。

老师提到,Geoff Hinton 将 early stopping 称为一种 “beautiful free lunch”。Geoff Hinton 是深度学习先驱之一,也获得过图灵奖。

early stopping 的基本方法是:

  1. 将训练数据拆成训练集和验证集。
  2. 持续训练模型。
  3. 训练过程中,训练集 loss 通常会继续下降。
  4. 同时监控验证集表现。
  5. 如果验证集表现开始停滞甚至变差,就停止训练。

关键点是:

验证集只用于评估,不用于计算梯度。

也就是说,验证集不会参与参数更新。

老师说明,Colab 中会先完整跑一遍,观察验证集曲线在哪里变平或变差,再判断应该在哪里停止。实际使用中,Keras 有更高效的方式,不一定要训练到最后再手动回退。

十一、Dropout ​

另一种 regularization 方法是 dropout。

老师说明,dropout 是一种非常巧妙的策略,但本节课不会使用。

本节课主要使用 early stopping。dropout 会在后续课程第一次使用时再详细解释。

十二、训练神经网络的实践清单 ​

老师将训练流程总结为:

  1. 准备数据。
  2. 设计网络结构。
  3. 决定隐藏层数量。
  4. 决定每层神经元数量。
  5. 选择合适的输出层。
  6. 选择与输出类型匹配的 loss function。
  7. 选择 optimizer。
  8. 选择 regularization 方法,例如 early stopping 或 dropout。
  9. 用 Keras 和 TensorFlow 启动训练。

优化器方面,SGD 有很多变体。

类似隐藏层中常把 ReLU 作为默认激活函数,优化器中常把 Adam 作为默认选择。老师说明,本节课会使用 Adam。

十三、什么是 Tensor ​

进入 TensorFlow 和 Keras 前,老师先解释 tensor。

学生最初回答 tensor 是输入数据,可以表示图像、时间序列等。老师指出这个方向接近,但 tensor 的概念更基础。

更准确地说:

tensor 是对 number、vector、table 等对象的统一推广。

不同 rank 的 tensor 可以这样理解:

对象Tensor rank含义
单个数字rank 0没有维度
向量rank 1一维数字列表
表格 / 矩阵rank 2二维数字表
一组表格rank 3可以理解为很多张表叠在一起
视频rank 4一串彩色图片

老师强调,tensor 不一定比矩阵复杂。单个数字本身也是 tensor。

十四、Tensor 的 Rank 与嵌套结构 ​

每个 tensor 都有 rank。

可以从嵌套列表角度理解 tensor:

  • rank 1 tensor 是数字列表。
  • rank 2 tensor 是列表的列表,也就是表格。
  • rank 3 tensor 是很多张表构成的列表。
  • rank 4 tensor 可以是很多彩色图片构成的序列。

例如,形状为 (7, 3) 的 rank 2 tensor 可以理解为 7 行、3 列的表格。老师还建议把 tensor 想成由方括号包起来的嵌套数组:外层每向内取一个元素,就进入低一阶的 tensor。

老师给出一个重要理解:

rank n tensor 可以看作一组 rank n-1 tensors。

例如:

  • 一个视频是 rank 4 tensor。
  • 一组视频就是 rank 5 tensor。
  • 一个 rank 10 tensor 可以看作一组 rank 9 tensors。

因此,对于任意 tensor,都可以沿第一个维度进行迭代。每取出一个元素,就得到低一阶的 tensor。

老师提到,tensor 概念来自 Einstein,它既直观又容易让人觉得滑。建议阅读教材 2.2 中关于 tensor 的讨论,并通过练习熟悉。

十五、图像与 Tensor 的关系 ​

老师提前指出,后面会看到:

  • 灰度图像通常表示为一张数字表,也就是 rank 2 tensor。
  • 彩色图像通常表示为三张数字表,对应颜色通道。
  • 视频可以看作一串彩色图像,因此是更高 rank 的 tensor。

这为后面计算机视觉部分做铺垫。

十六、TensorFlow 的作用 ​

TensorFlow 是一个深度学习库。

名字中的 TensorFlow 可以这样理解:

神经网络中流动的是 tensors,tensors 从输入端进入网络,经过层层计算,再从输出端流出。

TensorFlow 提供几个关键能力:

  1. 自动计算任意复杂 loss function 的 gradients。
  2. 提供各种 optimizers,包括 SGD 及其变体。
  3. 支持将计算分布到多个服务器。
  4. 自动组织计算以利用 GPU。

老师强调,手动计算复杂网络的梯度非常痛苦。TensorFlow 可以自动处理链式法则和梯度计算,这是它非常重要的价值。

并行计算方面,老师指出,不是所有计算都容易并行化。TensorFlow 会帮助处理这些复杂性。

GPU 是 Graphics Processing Unit,适合并行计算。即使只有一台有 GPU 的机器,也需要以特定方式组织计算才能充分利用硬件,TensorFlow 会自动完成很多工作。

老师还提到 TPU:

TPU 是 Tensor Processing Unit,可以理解为 Google 设计的类似 GPU 的硬件。

十七、Keras 与 TensorFlow 的关系 ​

Keras 位于 TensorFlow 之上。

可以理解为:

text
hardware → TensorFlow → Keras

TensorFlow 负责底层计算、梯度、优化和硬件利用。

Keras 提供更方便的高层抽象,例如:

  • layers
  • activation functions
  • 数据预处理工具
  • 模型训练接口
  • 指标报告
  • training loss
  • validation loss
  • validation accuracy
  • 预训练模型库

老师之前用过的 keras.Dense 就是一个 dense layer。

十八、为什么课程选择 TensorFlow/Keras ​

老师提到,很多学生可能熟悉 PyTorch。PyTorch 也是非常优秀的深度学习框架。

本课程选择 TensorFlow 和 Keras 的原因是:

  • 希望课程对编程背景较少的学生更友好。
  • PyTorch 从计算机科学角度要求更高。
  • PyTorch 更依赖对面向对象编程的理解。
  • TensorFlow/Keras 在能力上足够强,同时更容易上手。

老师认为,Keras 很像一个设计良好的 LEGO 积木环境,可以用相对简单的方式搭建复杂模型。

十九、Keras 的三种 API ​

Keras 有三种主要 API:

  • Sequential API
  • Functional API
  • Subclassing API

本课程几乎都会使用 Functional API。

心脏病预测模型也是用 Functional API 搭建的。

老师建议阅读教材 7.2.2,理解 Functional API 的具体工作方式。

老师还提到,相关网站上有许多 Keras 和 Colab 示例资源,可以作为课后练习材料。

二十、心脏病预测模型回顾 ​

回到上一节课设计的心脏病预测模型。

模型结构是:

  1. 输入层。
  2. 一个 dense hidden layer。
  3. hidden layer 有 16 个 ReLU neurons。
  4. 输出层使用 sigmoid。

因为这是二分类问题,所以输出是一个概率。

训练设置:

  • loss function:binary_crossentropy
  • optimizer:Adam
  • regularization:使用 early stopping 思路监控过拟合

老师提醒:

  • 如果预测任意连续数值,可以用 mean squared error。
  • 如果预测二分类概率,并与 0/1 标签比较,应使用 binary_crossentropy。

二十一、Colab 使用建议 ​

进入 Colab 前,老师给出实践建议:

  • 不必在课堂上立刻理解每一行代码。
  • 课后应逐行阅读和运行 notebook。
  • 学习新代码时,尽量不要直接复制粘贴。
  • 更推荐手动重打一遍代码,这样更容易理解。

对于课程发布的 Colab:

  1. 先使用 Copy to Drive 建立自己的副本。
  2. 如果 notebook 涉及自然语言处理或视觉任务,通常应该使用 GPU runtime。
  3. 之后再次打开同一个 notebook 时,可以直接从 runtime 设置开始。

老师也提到,网上有很多关于 Colab 的短教程,可以自行查看。

二十二、心脏病数据集 ​

心脏病预测 Colab 使用前面介绍过的数据集。

数据集包含:

  • 303 名患者。
  • 多个变量,包括年龄、人口统计信息、生物标志物等。
  • 目标变量是 0 或 1,表示是否有心脏病。

老师说明,课堂中不会实时运行每个 cell,因为运行完整 notebook 会占用课堂时间。他已经提前运行过,会逐步解释每部分代码的含义。

二十三、常用 Python 包 ​

每次训练深度学习模型时,通常会加载一组常见包。

本节课中包括:

  • tensorflow
  • keras
  • NumPy
  • Pandas
  • Matplotlib

用途分别是:

  • TensorFlow/Keras:构建和训练深度学习模型。
  • NumPy:处理矩阵、数组和 tensors。
  • Pandas:清洗、整理和转换表格数据。
  • Matplotlib:绘制 loss 曲线和 accuracy 曲线,辅助观察是否需要 early stopping。

老师特别指出,通常会先导入 TensorFlow,再从 TensorFlow 中导入 Keras。

二十四、训练中的随机性与 Random Seed ​

深度学习训练中存在多个随机性来源:

  1. 初始权重通常随机初始化。
  2. SGD 中会随机打乱数据,再形成 batches。
  3. 拆分 train、validation、test 时也可能涉及随机抽样。
  4. dropout 本身也带有随机性。

如果希望别人能复现结果,就需要设置 random seed。

课堂中使用:

text
set_random_seed(42)

老师说明,42 是对《The Hitchhiker's Guide to the Galaxy》的流行文化引用。

不过,即使设置 seed,也不保证完全得到相同数字。由于硬件、设备驱动等原因,bitwise reproducibility 并不总是有保证。

二十五、读入数据与查看类别比例 ​

老师提到,Francois Chollet 将这个数据整理成了 Pandas dataframe,可以从 CSV 读入。

读入后数据形状是:

text
303 rows, 14 columns

第一步通常查看前几行,理解变量含义和目标列。

对于二分类问题,老师会先检查正负类比例。

本数据中:

  • 72.6% 的患者没有心脏病。
  • 27.4% 的患者有心脏病。

这不是 50/50 的平衡数据集,而是负类明显更多。

二十六、Baseline Model ​

老师提出问题:如果不使用复杂模型,最简单的 baseline 是什么?

学生回答:

永远预测 0,也就是预测所有人都没有心脏病。

因为 72.6% 的样本属于 0 类,所以这个 baseline 的 accuracy 是:

text
72.6%

任何更复杂的模型都应该超过这个 baseline。否则,就没有使用复杂模型的价值。

二十七、数据预处理:分类变量与数值变量 ​

该数据集同时包含:

  • categorical variables
  • numeric variables

因此,通常先把两类变量分开处理。

27.1 Categorical Variables ​

神经网络不能直接处理类别输入。

与某些模型不同,例如 decision tree,神经网络需要数值输入。

因此,类别变量必须先数值化。

标准做法是:

text
one-hot encoding

在 Pandas 中,可以使用:

text
get_dummies

例如变量 thal 原来可能有:

  • fixed
  • normal
  • reversible

经过 one-hot encoding 后,会变成多个列:

  • thal_fixed
  • thal_normal
  • thal_reversible

27.2 Numeric Variables ​

神经网络通常在输入数值范围较小、尺度相近时训练效果更好。

因此,数值变量需要标准化:

text
standardized_value = (value - mean) / standard_deviation

也就是:

  1. 减去均值。
  2. 除以标准差。

标准化后,数值大多落在 0、1、-1 附近的范围,更适合神经网络训练。

二十八、为什么先划分 Test Set,再标准化 ​

老师强调,标准化之前应该先划分测试集。

流程应是:

  1. 先将数据划分为 training set 和 test set。
  2. 将 test set 锁起来,不参与建模过程。
  3. 只基于 training set 计算 mean 和 standard deviation。
  4. 用 training set 的 mean/std 标准化 training set 和 test set。

原因是:

如果在划分之前用全数据计算 mean/std,标准化过程就已经使用了 test set 的信息。

这样会导致数据泄漏。测试集就不再是完全独立的最终评估数据。

课堂中使用约 80% / 20% 的划分:

  • training set:242 rows
  • test set:61 rows

老师提到,dataframe.shape 可以查看数据维度。

二十九、转换为 NumPy Array ​

完成 one-hot encoding、标准化和 train/test split 后,数据已经全部是数值。

此时需要将 Pandas dataframe 转成 NumPy array,因为 Keras 可以直接接收 NumPy 数据。

使用方法:

text
to_numpy

老师指出,to_numpy 的名字非常直观。

转换后,train 和 test 就是 NumPy arrays,保存了同样的信息,但格式更适合送入 Keras。

三十、拆分 X 与 Y ​

原始 dataframe 中包含:

  • 输入特征 columns。
  • 目标变量 column。

训练时必须把两者分开:

  • X:输入特征。
  • Y:真实标签。

原因是:

  1. 模型只接收 X 做预测。
  2. 预测结果再与真实 Y 比较。
  3. 根据差异计算 loss。

课堂中,目标列是左起第 6 列。

处理后:

  • train_x 是 242 x 29。
  • test_x 是 61 x 29。
  • train_y 是长度为 242 的向量。
  • test_y 是长度为 61 的向量。

这也解释了上一节课中模型为什么有 29 个输入节点。

三十一、搭建心脏病预测模型 ​

数据预处理完成后,开始搭建模型。

模型是上一节课设计过的结构:

  • 输入:29 个 features。
  • hidden layer:16 个 ReLU neurons。
  • output layer:1 个 sigmoid 输出。

这是一个二分类问题,因此输出层用 sigmoid。

代码中老师给 layer 加了名字。layer name 是可选的,主要用于后续解释和查看模型结构。

三十二、model.summary() 与参数数量 ​

老师建议,模型建好后应立即运行:

text
model.summary()

model.summary() 会显示:

  • 每一层是什么类型。
  • 输入该层的 tensor shape。
  • 该层输出的 tensor shape。
  • 每层参数数量。

课堂模型总共有 497 个参数。

参数数量计算如下:

hidden layer:

text
29 * 16 + 16

其中:

  • 29 * 16 是输入到 hidden layer 的 weights。
  • 16 是 hidden layer 的 biases。

output layer:

text
16 * 1 + 1

其中:

  • 16 * 1 是 hidden layer 到 output layer 的 weights。
  • 1 是 output bias。

总数:

text
29 * 16 + 16 + 16 * 1 + 1 = 497

老师再次提醒,初学时应手动验证参数数量,确保理解网络结构。

也可以使用 plot_model 可视化网络拓扑。后面网络更大时,图形化结构会更有帮助。

三十三、compile:选择 Loss、Optimizer 与 Metrics ​

模型训练前需要调用 compile。

本例设置:

  • loss function:binary_crossentropy
  • optimizer:Adam
  • metrics:accuracy

老师强调,metrics 只用于报告,不用于优化。

例如 accuracy 会显示出来,方便观察模型表现,但不会直接参与梯度计算。

compile 的作用是:

将模型、loss、optimizer、metrics 等信息组织起来,使模型适合后续训练、并行计算和分布式计算。

这也是为什么在 Keras 中训练前需要一个 compilation step。

三十四、model.fit():开始训练 ​

真正训练模型使用:

text
model.fit(...)

需要传入:

  • x tensor。
  • y tensor。
  • epochs。
  • batch_size。
  • verbose。
  • validation_split。

本例选择:

  • batch_size = 32
  • epochs = 300
  • validation_split = 0.2
  • verbose = 1

其中,verbose = 1 表示训练时输出较多描述性日志,方便观察训练过程。

老师说明,32 是一个很常见的 batch size 默认值。实践中可以尝试 32、64、128 等。

有研究者的经验说法是:

使用机器内存能承受的最大 batch size 往往是一个可以尝试的方向。

但本例数据很小,从 32 开始即可。

关于 epoch 数,老师说:

  • 20 到 30 个 epochs 通常是不错的起点。
  • 本例为了观察是否会过拟合,特意跑 300 个 epochs。

validation_split = 0.2 表示:

从 training data 中拿出 20% 作为 validation set,不用于训练,只用于观察 validation loss 和 validation accuracy。

三十五、训练输出如何阅读 ​

model.fit 运行后会输出很多行。

每个 epoch 的输出中包含:

  • 当前 epoch 使用了多少 batches。
  • 每个 epoch 运行时间。
  • training loss。
  • training accuracy。
  • validation loss。
  • validation accuracy。

本例中,老师用第 300 个 epoch 的一行输出做解释:它显示 7/7 batches,表示该 epoch 使用了全部 7 个 batches;同一行还会显示 training loss、training accuracy,以及 epoch 结束后在 validation set 上计算出的 validation loss 和 validation accuracy。

课堂示例中,该 batch 的 training accuracy 显示为 98.5%。老师强调,这些数字都只是日志输出中的不同字段,直接盯着一大段数字不容易理解,因此通常会画成曲线。

这与前面的 batch 计算一致:

  • 从 training set 中再拿出 20% 做 validation 后,剩余训练样本约为 193 或 194。
  • batch_size = 32。
  • 向上取整后是 7 个 batches。

老师解释,前 6 个 batches 大约各有 32 个样本,最后一个 batch 只剩很少样本。

三十六、history 对象与绘图 ​

老师将训练结果保存为:

text
history = model.fit(...)

history 对象包含训练过程中的诊断信息。

其中:

text
history.history

是一个 dictionary,保存了各个 epoch 的:

  • loss
  • accuracy
  • validation loss
  • validation accuracy

这些值可以用 Matplotlib 绘制曲线,用于判断训练趋势和过拟合。

三十七、Validation Set 与 Test Set 的区别 ​

学生问:已经划分过 test set,为什么 model.fit 还要留出 validation set?

老师解释:

三类数据集的角色不同:

  • training set:用于训练和更新参数。
  • validation set:用于 early stopping 和 hyperparameter tuning。
  • test set:最终模型确定后,只使用一次,用于估计真实部署表现。

validation set 用来回答:

  • 是否应该 early stop。
  • 哪组 hyperparameters 更好。
  • 模型是否开始过拟合。

test set 则要一直锁起来,直到最终模型确定。

最后评估 test set 的目的不是改模型,而是了解模型部署到真实世界后的可能表现。

三十八、关于 Metrics 的问答 ​

学生问:能否不用 accuracy,而使用其他指标,例如 confusion matrix 相关指标?

老师回答:可以。

可用指标包括:

  • error rate
  • accuracy
  • F1
  • F-beta
  • 其他基于 confusion matrix 的指标

关键点是:

metrics 只是报告给建模者看的,不参与训练优化。

Keras 提供了很多可选 metrics。

三十九、Validation Split 的具体含义 ​

学生问:validation_split = 0.2 是从训练集中拿出 20%,还是从每个 batch 中拿出 20%?

老师回答:

从 training set 中拿出 20%。

拿出 validation set 后,剩下的数据才被分成 batches 进行训练。

因此,可用于计算 batch 数量的训练数据会减少。

老师进一步说明:

  • validation set 在训练开始前固定下来。
  • 每个 epoch 使用同一个 validation set。
  • 这不是 cross-validation。
  • 每个 epoch 不会重新抽一个新的 validation set。

另一个学生用具体数值确认:如果 training loss 已经到 0.0860,而 validation loss 是 0.660,是否说明已经越过较合适的停止点,最终部署时应使用前面那个更好的模型。老师确认这个判断方向,并说明后面会讲如何拿到对应的模型,例如是否需要重新从头训练到某个 epoch,或用更智能的方法保存最佳模型。

学生问:每个 epoch 有什么不同?

老师回答:

不同的是 weights 已经改变。

在一个 epoch 内,每个 minibatch 后 weights 都会更新。一个 epoch 结束后,模型已经经历了所有训练样本,然后再从头开始下一轮。

四十、观察 Loss 曲线 ​

老师用 Matplotlib 绘制:

  • training loss
  • validation loss

横轴是 epochs。

观察结果:

  • training loss 稳定下降。
  • validation loss 一开始下降。
  • 到某个阶段后变平。
  • 后面可能轻微上升。

这说明模型可能出现了一定程度的 overfitting。

不过,老师提醒:

binary_crossentropy 是一个数学上方便的 proxy,它能衡量预测与真实标签的差异,但实际部署时可能更关心 accuracy 或 error rate。

因此,不能只看 loss,也要看 accuracy。

四十一、观察 Accuracy 曲线 ​

老师继续绘制:

  • training accuracy
  • validation accuracy

观察结果:

  • training accuracy 随 epoch 增加而上升。
  • training accuracy 可以达到低到中 90% 的水平。
  • validation accuracy 大约在 50 个 epochs 附近变平。
  • 后面 validation accuracy 甚至又有所上升。

因此,虽然 validation loss 显示出一些 overfitting,但 validation accuracy 最后仍然变好。

老师的判断是:

这种 overfitting 可能可以接受,不一定需要立刻停止。

可以选择:

  • 严格按照 validation loss,在约 50 个 epochs 处停止。
  • 或者接受当前结果,因为 accuracy 后续仍有改善。

老师更倾向于关注与真实部署目标更接近的指标。如果真实世界中关心的是错误率或准确率,那么 accuracy 的信号也很重要。

四十二、Epoch 数量如何决定 ​

学生问:老师前面说 20 到 30 个 epochs 是起点,但这里跑了 300 个。如果只跑 20 到 30,可能还看不到过拟合,怎么办?

老师回答:

20 到 30 是起点,不是固定规则。

做法是:

  1. 先训练一段,例如 20 或 30 个 epochs。
  2. 查看 validation loss 是否仍在下降。
  3. 如果还在下降,就继续训练。
  4. 可以再运行 fit 继续训练 10 个 epochs。
  5. 如果 validation loss 开始上升,再停止或回退。

Keras 的特点是:

再次调用 fit 时,会从当前权重继续训练,而不是从头开始。

老师说明,手动观察曲线是为了建立直觉。实际中可以使用 callbacks。

callbacks 可以设置:

  • 当 validation loss 不再改善时自动停止。
  • 当 validation loss 不再改善时保存最佳模型。

这样就不必手动回到某个 epoch 重新训练。

四十三、为什么 Loss 变差时 Accuracy 还可能变好 ​

学生问:为什么 validation loss 变高时,accuracy 还能变好?

老师回答:

accuracy 和 loss 相关,但不是同一个东西。

accuracy 是离散指标。

例如二分类中:

  • 预测概率 0.49 可能被判为 0。
  • 预测概率 0.51 可能被判为 1。

从 0.49 到 0.51:

  • binary_crossentropy 变化可能很小。
  • 但 accuracy 会从错变成对,发生跳跃式变化。

因此,accuracy 是一个比较跳跃、离散、粗糙的指标,而 loss 是连续的优化目标。

老师还提到,可以尝试取某个 epoch 的权重,例如 epoch 50,并比较其验证表现。最终仍要看哪个指标更接近真实部署目标。

四十四、最终 Test Set 评估 ​

模型训练并完成判断后,使用:

text
model.evaluate(test_x, test_y)

此时才使用最开始保留的 test set。

老师运行结果显示,模型在 test set 上达到:

text
83.6% accuracy

前面的 baseline 是:

text
72.6% accuracy

因此,这个小型神经网络明显超过了简单 baseline。

老师提醒,许多 preprocessing 步骤也可以放进 Keras 内部完成,Keras 有相应的 preprocessing layers。

四十五、课后如何学习这个 Colab ​

老师建议课后:

  • 逐行阅读 notebook。
  • 修改每一行。
  • 重新运行。
  • 观察输出如何变化。

这种方式有助于建立训练模型的直觉。

四十六、关于 False Positive 与 False Negative 的问答 ​

学生问:是否可以构建一个模型,让它更少产生 false positives 或 false negatives?

老师回答:可以。

可以做两件事:

  1. 报告这些指标,例如 false positive rate、false negative rate。
  2. 使用更复杂的 loss functions,将 false positive 和 false negative 的不对称代价纳入训练。

老师没有在本节课展开细节,只说明这是可行的。

四十七、灰度图像如何表示 ​

进入计算机视觉部分后,老师先讲数字图像表示。

灰度图像,也就是黑白图像,可以表示为一张数字表。

图像中的每个位置叫 pixel。

每个 pixel 有一个光强值:

  • 0 表示没有光,对应黑色。
  • 255 表示非常亮,对应白色。
  • 中间数值表示不同灰度。

老师用数字 5 的图像举例:

  • 黑色区域通常是 0。
  • 白色笔画区域是更大的数。
  • 数值越接近 255,越亮。

如果离远一点看这些数字表,甚至可以看出数字 5 的形状。

四十八、像素光强的单位 ​

学生问:光强的单位是什么?

老师回答,本课程中只需要把它理解为一个归一化尺度。

真实世界中的模拟图像会经过数字化过程,被映射到 0 到 255 的范围。

这里不需要关心具体物理单位或 lumens 到数值的精确映射。不同设备和处理方式可能有很多变化。

对本课程来说,理解为:

每个 pixel 的光强被映射为 0 到 255 的相对数值。

即可。

四十九、彩色图像如何表示 ​

彩色图像中,每个 pixel 不再只有一个数字,而是有三个数字。

这三个数字表示颜色通道的强度:

  • red
  • green
  • blue

每个通道仍然是 0 到 255 之间的数。

因此,一张彩色图像可以表示为三张数字表:

  • red channel table
  • green channel table
  • blue channel table

在深度学习中,这些颜色维度通常称为 channels。

老师以 Killian Court 图片为例,说明一张彩色图片对应三张表,因此可以看作一个 rank 3 tensor。

五十、计算机视觉中的主要任务 ​

老师介绍了几类常见图像处理任务。

50.1 Image Classification ​

image classification 是最基础的任务。

问题形式是:

给定一张图片,判断它属于哪个类别。

经典例子是:

  • dog vs cat

也可以是多类别分类。

本节课后面会处理图像分类问题。

50.2 Localization ​

localization 不只判断图片中有什么,还要判断目标在图片中的位置。

例如:

  • 判断图片中有 sheep。
  • 同时输出 sheep 的位置。

通常用一个 bounding box 表示位置。

模型输出不仅包括类别,还包括 box 的坐标,例如:

  • top-left coordinate
  • bottom-right coordinate

50.3 Object Detection ​

object detection 处理更复杂的情况:

一张图片中可能有多个对象,需要识别每个对象并定位它们。

例如图片中有多只 sheep,需要分别框出:

  • sheep 1
  • sheep 2
  • sheep 3

老师提到,自动驾驶系统会不断进行 object detection。

摄像头系统会每秒多次识别和定位:

  • pedestrian
  • zebra crossing
  • dog
  • stroller
  • 其他道路对象

50.4 Semantic Segmentation ​

semantic segmentation 是对每个 pixel 进行分类。

它不是给整张图片一个类别,而是给每个像素一个类别。

例如:

  • 这些 pixels 是 road。
  • 这些 pixels 是 sheep。
  • 这些 pixels 是 grass。

因此,semantic segmentation 可以理解为:

对每个 pixel 做 multi-class classification。

50.5 Instance Segmentation ​

instance segmentation 更进一步。

它不仅要给每个 pixel 分类,还要区分同一类别中的不同实例。

例如:

  • 这些 pixels 属于 sheep 1。
  • 那些 pixels 属于 sheep 2。
  • 另一些 pixels 属于 sheep 3。

老师指出,这些都是非常常见且有用的计算机视觉任务,都适合用 deep learning 系统处理。

五十一、Fashion-MNIST 数据集 ​

接下来,老师进入图像分类示例:Fashion-MNIST。

Fashion-MNIST 包含:

  • 70,000 张服装图片。
  • 10 个类别。
  • 类别包括 boots、sweaters、T-shirts 等。

这是一个平衡数据集:

  • 每个类别大约占 10%。

因此,最简单的 naive baseline 是随机或固定预测某一类,其 accuracy 约为:

text
10%

老师说明,一个简单神经网络可以在这个任务上接近:

text
90% accuracy

五十二、图像输入为什么需要 Flatten ​

Fashion-MNIST 中每张图片是:

text
28 x 28

也就是一张 rank 2 tensor,一张数字表。

而前面构建的普通 dense neural network 接收的是向量。

因此,需要把 28 x 28 的表格转换成一个长向量。

这个过程叫:

text
flattening

具体做法可以理解为:

  1. 取第一行像素值。
  2. 接在向量开头。
  3. 取第二行像素值。
  4. 接在第一行后面。
  5. 持续把所有行串起来。

结果是:

text
28 * 28 = 784

因此,每张图片会变成长度为 784 的向量。

老师强调,flattening 本身没有做复杂学习,只是重新组织数据形状。

五十三、Fashion-MNIST 的简单网络结构 ​

flatten 后,就回到了熟悉的向量输入场景。

本节课中的简单网络结构是:

  1. 输入:长度为 784 的向量。
  2. hidden layer:256 个 ReLU neurons。
  3. output layer:处理 10 个类别。

老师说明,他尝试过几个不同 hidden layer 大小,256 个 neurons 表现不错,因此示例中使用 256。

五十四、多类别输出问题 ​

心脏病预测是二分类:

  • 输出 0 或 1。
  • 用一个 sigmoid 输出概率。

Fashion-MNIST 是 10 分类:

  • 类别包括 T-shirt、trouser、ankle boot 等服装类别。
  • 具体编号到类别名称的映射可以查看 Fashion-MNIST 的说明页面。

一张图片只能属于其中一个类别。

因此,模型输出应该是 10 个概率,并且这些概率需要满足:

text
sum(probabilities) = 1

五十五、为什么不能用 10 个 Sigmoid ​

学生回答了关键原因:

10 个独立 sigmoid 的输出不一定加起来等于 1。

sigmoid 可以把每个数压到 0 到 1,但如果独立使用 10 个 sigmoid,它们之间没有约束。

在 Fashion-MNIST 这种互斥分类中:

  • 只有一个类别是正确答案。
  • 模型需要输出一组彼此竞争的概率。
  • 所有类别概率应加起来为 1。

因此,需要使用 softmax。

五十六、Softmax Function ​

softmax 的作用是:

将任意一组数转换成一组非负概率,并保证它们加起来等于 1。

对于 10 分类:

  1. 网络最后先输出 10 个线性数值。
  2. 对每个数取指数,例如 e^a。
  3. 用每个指数值除以全部指数值之和。

形式可以理解为:

text
softmax(a_i) = exp(a_i) / sum(exp(a_j))

这样会带来两个结果:

  • exp(a_i) 一定为正。
  • 每个值都除以总和,所以所有输出加起来等于 1。

因此,softmax 可以把网络输出的任意 10 个数变成 10 个类别概率。

五十七、Softmax 与 GPT-4 的关系 ​

老师特别提醒,softmax 很重要,因为大型语言模型也使用类似思想。

他用 GPT-4 做类比:

  • 当模型生成输出时,每次发出的严格来说不是 word,而是 token。
  • 可以暂时把它想象成 word。
  • 每一步生成时,模型需要在大量可能 tokens 中选择下一个。
  • 老师举例说,这是一个大约 52,000 维的 softmax。

也就是说:

可以把语言模型的下一 token 预测理解为一个非常大的多分类问题。

每个 token 都是可能输出,模型通过 softmax 得到概率分布,再选择合适的输出。

五十八、输出层与 Loss Function 的对应关系 ​

老师总结了输出层和 loss function 的匹配关系。

任务输出输出层形式常用 loss
任意单个数值linear outputmean squared error
单个概率sigmoidbinary_crossentropy
多个任意数值多个 linear outputsmean squared error
多个互斥类别概率softmaxcategorical_crossentropy 或 sparse_categorical_crossentropy

选择 loss function 时,要看标签数据如何编码。

五十九、为什么输出概率而不是直接输出 0 或 1 ​

学生问:既然最终只有一个正确类别,为什么要输出概率,而不是直接输出 0 或 1?

老师回答:

不能强迫网络精确输出 0 或 1。

网络会产生它能产生的数值。建模者能做的是使用合适的输出层,把这些数值约束到需要的范围。

例如:

  • sigmoid 将输出约束在 0 到 1。
  • softmax 将多个输出约束为总和为 1 的概率分布。

六十、标签编码方式与 Cross-Entropy Loss ​

多分类标签可以有不同编码方式。

60.1 Binary Classification ​

心脏病预测中,标签是:

text
0 or 1

对应 loss:

text
binary_crossentropy

60.2 Sparse Encoding ​

Fashion-MNIST 中,标签可以是整数:

text
0, 1, 2, ..., 9

这种形式称为:

text
sparse encoded

对应 loss:

text
sparse_categorical_crossentropy

60.3 One-Hot Encoding ​

同样的 10 分类标签也可以写成 one-hot vector。

例如某一类对应:

text
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]

对应 loss:

text
categorical_crossentropy

老师说明,这些方式表达的是同一个分类任务,只是标签编码不同。应根据数据实际编码选择正确的 Keras loss function。

categorical_crossentropy 可以看作 binary_crossentropy 的多类别推广。老师没有展开数学细节,但直觉类似。

六十一、Fashion-MNIST Colab:加载数据 ​

进入第二个 Colab 后,老师沿用类似设置:

  • 导入 TensorFlow 和 Keras。
  • 导入常用的 NumPy、Pandas、Matplotlib。
  • 设置 random_seed 保证尽量可复现。

Fashion-MNIST 是 Keras 内置标准数据集,因此不需要另找数据文件。

使用:

text
load_data

即可加载。

六十二、为什么数据集自带 Train/Test Split ​

Keras 提供的 Fashion-MNIST 已经预先划分好了 training set 和 test set。

原因是:

这样不同研究者或学习者可以在同一个 test set 上比较模型表现。

如果每个人自己随机划分测试集,模型准确率之间就不一定可比。

六十三、Fashion-MNIST 的 Tensor Shape ​

训练输入数据是一个 rank 3 tensor。

可以理解为:

一组 rank 2 tensors。

具体形状是:

  • 60,000 张训练图片。
  • 每张图片是 28 x 28 的数字表。

因此:

text
train_x: 60000 images, each 28 x 28

输出标签是一个长度为 60,000 的向量:

text
train_y: 60000 labels

测试集是:

  • 10,000 张测试图片。
  • 每张同样是 28 x 28。
  • 对应 10,000 个标签。

六十四、类别编号与类别名称 ​

如果查看 train_y 的前几个值,会看到类似:

text
9, 0, 3, ...

这些数字是类别编号。

Fashion-MNIST 的类别映射可以从 GitHub 页面查看,例如:

  • 0:T-shirt
  • 1:trouser
  • 9:ankle boot

老师通常会创建一个类别名称列表,把数字标签映射成人类可读的类别名。

这样查看结果时,不必反复记忆数字和类别之间的对应关系。

六十五、查看原始图像数据 ​

老师查看第一张图片:

  • 它的标签对应 ankle boot。
  • 原始图像数据是一个 28 x 28 数字表。
  • 表中可以看到很多 0,也能看到 250、233 等较大的像素值。

这些数字就是灰度像素强度。

老师使用 Matplotlib 可视化前 25 张图片。

图片看起来比较小、模糊,但仍能看出服装轮廓。例如第一张是 ankle boot。

老师在本节课末尾暂停,说明下一次课会继续这个图像分类流程,并进一步进入彩色图像。

六十六、本节课核心总结 ​

本节课的知识链条可以概括为:

  • 神经网络训练通过 loss function 衡量预测与真实值差异。
  • optimizer 根据 gradient 更新 weights 和 biases。
  • epoch 是对训练集的一次完整遍历。
  • 普通 gradient descent 每个 epoch 更新一次。
  • SGD 将训练集分成 batches,每个 batch 后更新一次。
  • batch size 是建模者选择的,常见起点是 32。
  • 复杂神经网络容易 overfit,因此需要 regularization。
  • early stopping 通过 validation set 判断何时停止训练。
  • dropout 是另一种 regularization 方法,本节课只预告。
  • tensor 是 number、vector、matrix/table 及更高维数组的统一表示。
  • TensorFlow 负责 tensors 的计算流、自动梯度、优化器、分布式计算和 GPU 利用。
  • Keras 在 TensorFlow 之上提供 layers、training、metrics、preprocessing 和预训练模型等高层接口。
  • 心脏病预测模型使用 29 个输入、16 个 ReLU hidden neurons、sigmoid 输出,共 497 个参数。
  • 二分类任务使用 binary_crossentropy,优化器使用 Adam。
  • validation set 用于调参和 early stopping,test set 只在最终评估时使用。
  • 本例神经网络 test accuracy 为 83.6%,超过 72.6% baseline。
  • 灰度图像是 0 到 255 的像素强度表。
  • 彩色图像由 RGB 三个 channels 构成,可视为 rank 3 tensor。
  • 计算机视觉任务包括 classification、localization、object detection、semantic segmentation、instance segmentation。
  • Fashion-MNIST 是 70,000 张服装图片的 10 分类任务,baseline 为 10%。
  • 28 x 28 图像可以 flatten 成长度为 784 的向量。
  • 多类别互斥分类需要 softmax,而不是多个独立 sigmoid。
  • softmax 将任意一组数转换成总和为 1 的概率分布。
  • 根据标签编码不同,多分类任务可使用 sparse_categorical_crossentropy 或 categorical_crossentropy。

本节课最重要的实践结论是:

训练神经网络不仅是搭建网络结构,还包括数据预处理、batch/epoch 设置、validation/test 划分、loss 与 metrics 的选择,以及对训练曲线的诊断。

理解这些细节后,Keras 训练流程就不只是运行几行代码,而是一个可以被分析、调试和改进的建模过程。

最后更新于: