MIT深度学习课程第二讲:神经网络训练
本节课围绕如何训练神经网络展开。课程先回顾神经网络设计中的可控部分,再以 Cleveland Clinic 心脏病预测数据集为案例,构建一个简单的二分类神经网络,并在此基础上引出训练、loss function、gradient descent、backprop 和 SGD 等核心概念。
一、神经网络设计回顾
上一节课区分了两类因素:
| 类型 | 含义 |
|---|---|
| 由问题给定的部分 | 输入是什么、输出是什么 |
| 由建模者决定的部分 | 隐藏层数量、每层神经元数量、激活函数等 |
输入层由问题本身决定,输出层也由任务目标决定。中间的隐藏层结构则由建模者选择,包括:
- 使用多少个隐藏层
- 每个隐藏层放多少个神经元
- 使用什么激活函数
隐藏层激活函数的默认选择通常是 ReLU。老师强调,实际设计网络时不需要在隐藏层激活函数上过度纠结,ReLU 是很好的默认选项。
网络设计的基本原则是:
- 从能想到的最简单网络开始。
- 如果简单网络已经能完成任务,就停止复杂化。
- 如果效果不够,再逐步增加复杂度。
这个原则贯穿后续所有网络设计:先用最简单结构建立基线,再根据表现调整。
二、案例:Cleveland Clinic 心脏病预测
本节课使用 Cleveland Clinic 提供的患者数据集作为案例。
数据集的背景如下:
- 患者进入 Cleveland Clinic 时,并不是因为心脏问题就诊。
- 他们可能只是体检,或因为其他原因来到医院。
- 医院记录了患者的多类信息。
- 随后跟踪这些患者在下一年内是否被诊断出心脏病。
记录的信息包括:
- 年龄
- 性别
- 是否有胸痛
- 血压
- 胆固醇
- 血糖
- 其他人口统计信息和生物标志物信息
这个任务的目标是:当患者进入医院时,即使他们不是因为心脏问题就诊,也尝试预测他们在未来一年内是否会被诊断为心脏病。
这是一个典型的机器学习问题。该问题也可以用决策树、随机森林、梯度提升等传统机器学习方法解决。本节课选择使用神经网络来解决它,目的是用结构化数据作为神经网络学习的起点。
这里的数据属于结构化数据:所有特征都以表格列的形式存在。课程后续会从结构化数据过渡到非结构化数据,例如图像、文本等。
三、模型选择:可解释性与预测准确率
课堂中有学生提问:什么时候使用 logistic regression,什么时候使用神经网络,什么时候使用随机森林等更复杂模型?
老师给出的判断维度主要有两个:
| 维度 | 说明 |
|---|---|
| 可解释性 | 是否需要向非技术用户解释模型内部逻辑 |
| 预测准确率 | 是否更看重最终预测效果 |
如果预测准确率压倒一切,可以优先选择效果更好的模型,即使模型更复杂。
如果模型需要被非技术用户理解,或使用者必须信任模型的决策过程,则可解释性变得很重要。这类情况下,更简单的模型通常更合适,例如:
logistic regressiondecision tree- 某些情况下的
random forest
老师也补充,神经网络等黑箱模型并不是完全无法解释。现在有一个研究方向叫 mechanistic interpretability,目标是理解大型黑箱模型内部到底发生了什么。因此,可解释性与黑箱模型之间的关系仍在发展中。
四、为心脏病预测设计神经网络
4.1 结构选择
对这个二分类任务,老师选择了一个简单网络:
- 输入层:29 个输入节点
- 隐藏层:1 层
- 隐藏层神经元数量:16
- 隐藏层激活函数:
ReLU - 输出层:1 个节点
- 输出层激活函数:
sigmoid
如果没有隐藏层,这个模型本质上就是 logistic regression。由于课程目标是学习神经网络,因此选择加入一个隐藏层,这是最简单的神经网络扩展。
隐藏层中 16 个神经元并不是理论推导出来的结果,而是经过尝试得到的。老师尝试过 4、8、16 等数量,16 的表现较好。继续增加到 16 以上时,模型表现开始变差,这与后续会讨论的 overfitting 有关。
老师也提到,人们常喜欢使用 2 的幂次作为神经元数量,因此 4、8、16 这类数值很常见。
ReLU 作为隐藏层激活函数的选择,来自大量经验结果。老师也提到,后续讲 gradient descent 时会补充与 ReLU 相关的一些理论直觉。
4.2 输出层为什么使用 sigmoid
该任务的输出是:
- 是否患心脏病
- 取值为 0 或 1
- 属于二分类问题
模型最终需要输出一个概率,因此使用 sigmoid 激活函数。sigmoid 的输出在 0 到 1 之间,适合作为“患病概率”的预测值。
隐藏层使用 ReLU 时,ReLU 的拐点固定在 0,不需要额外指定“弯折位置”。
4.3 输入为什么是 29 个节点
原始数据中有 13 个输入变量,但模型输入层有 29 个节点。原因是其中一些变量是 categorical variables,需要进行 one-hot encoding。
例如一个类别变量如果有 5 个水平,经过 one-hot encoding 后会变成 5 个列。13 个原始变量经过这种处理后,总输入维度变为 29。
在结构化数据任务中,默认假设是输入层中的每个输入节点都连接到隐藏层中的每个神经元。也就是说,这是一个 fully connected 的网络。后续在图像和语言任务中,会看到偏离这一默认假设的结构。
五、参数数量计算
老师强调,初学神经网络时要养成快速计算参数数量的习惯。这样可以清楚理解网络规模和过拟合风险。
本案例网络结构为:
- 输入层:29 个节点
- 隐藏层:16 个节点
- 输出层:1 个节点
参数数量计算如下:
| 参数来源 | 数量 |
|---|---|
| 输入层到隐藏层的权重 | 29 * 16 |
| 隐藏层偏置 | 16 |
| 隐藏层到输出层的权重 | 16 * 1 |
| 输出层偏置 | 1 |
总参数数量为:
29 * 16 + 16 + 16 * 1 + 1 = 497从一层到下一层时,权重数量大致是两层单元数的乘积。这个乘法结构会导致参数数量快速增长,也是后续需要控制 overfitting 的原因之一。
六、用 Keras 表达网络结构
老师将前面画出的网络翻译成 Keras 代码。
6.1 输入层
Keras 中定义输入层时使用:
keras.Input(shape=(29,))这里使用 shape 而不是 length,是因为 Keras 的输入不一定只是向量。后续输入可能是矩阵、三维张量、四维张量等,因此需要用 shape 描述输入形状。
本案例输入是一个长度为 29 的向量。
6.2 Dense 隐藏层
隐藏层使用 keras.layers.Dense。
Dense 表示该层会与前一层 fully connected。隐藏层设置为:
- 16 个节点
ReLU激活函数
定义完 Dense 层之后,还需要显式把前一层的输出传给它,否则该层不知道自己的输入来自哪里。
老师用变量名保存层输出,例如隐藏层输出可以命名为 h。变量名本身不重要,可以叫 h、output 或其他名称。
6.3 输出层
输出层也是一个 Dense 层:
- 节点数为 1
- 激活函数为
sigmoid
原因是该模型只需要输出一个概率值。
6.4 定义模型对象
层连接完成后,还需要创建 Keras model 对象:
keras.Model(inputs=input, outputs=output)模型对象使 Keras 能够执行训练、评估和预测等操作。
老师强调,一个看起来很复杂的“心脏病预测神经网络”,在 Keras 中可以用很少几行代码表达出来。这体现了 Keras 的抽象能力。
七、关于 Keras 和网络结构的课堂问答
7.1 是否可以自定义激活函数
可以。Keras 支持自定义激活函数。老师强调,Keras 的几行简单代码隐藏了很高的灵活性,后续可以像拼积木一样组合复杂网络结构。
7.2 多分类问题的输出层怎么设计
如果是多分类任务,例如把输入分成 10 类,则输出层通常有 10 个节点。多分类任务一般使用 softmax 函数,这部分会在后续课程讨论。
本节课只处理 binary classification。
7.3 Keras 是否有默认激活函数
老师表示,Keras 隐藏层默认激活函数可能是 ReLU,但他不完全确定,需要再确认。因此在实践中更稳妥的方式是显式指定激活函数。
这条是对课堂问答的记录,不应当当作 Keras API 结论。实际编码时应以当前 Keras 文档为准,并优先显式写出需要的 activation。
7.4 多层网络是否需要手写每一层
如果网络有很多层,不需要逐层复制粘贴。可以写循环自动创建层。
Keras 只需要知道模型的输入和输出,中间即使经过上百层或上千层复杂变换,也可以通过计算图追踪并处理。
老师将这一点称为抽象能力的体现。
八、训练的含义
训练神经网络的核心是:找到一组权重和偏置,使模型预测值尽可能接近真实值。
这与线性回归或 logistic regression 的思想类似:
- 先定义模型结构
- 给模型数据
- 通过训练过程估计参数
- 得到具体的系数、权重或偏置
在线性回归中,训练得到的是回归系数;在神经网络中,训练得到的是大量 weights 和 biases。
老师也给出一种理解方式:参数可以看作数据的压缩表达。训练的作用就是从数据中提取出这些参数值。
在传统建模工具中,这类估计过程通常由工具封装完成,例如 R 中的回归函数,或 scikit-learn、statsmodels 等库中的估计例程。神经网络训练同样是在求参数,只是模型函数更复杂、参数数量更多。
训练之前必须先定义网络结构。因为如果结构未定义,Keras 无法根据输入计算输出,也无法比较预测和真实标签。
九、损失函数的作用
训练需要一个目标函数来衡量预测与真实值之间的差异。这个函数在深度学习中称为 loss function。
老师刻意使用 discrepancy 这个词,而不是简单使用 error。原因是:
error容易让人联想到predicted - actualdiscrepancy的定义可以更灵活- 很多深度学习突破来自设计巧妙的
discrepancy度量
**损失函数的作用是量化模型“有多坏”。**预测越接近真实值,loss 越接近 0;完美模型的 loss 为 0。
深度学习论文中经常会出现各种不同的 loss function。损失函数设计本身就是研究创新的重要来源。
**损失函数必须和输出类型匹配。**连续数值输出、二分类概率输出、多分类输出等任务,对 discrepancy 的定义方式并不相同。
十、回归任务的损失函数:MSE
如果输出是连续数值,例如预测某商品下周需求量:
- 预测值:23
- 实际值:21
这类情况下可以直接计算差值,并进一步使用平方误差。
对第 i 个数据点:
y_i表示真实值model(x_i)表示模型预测值
平方误差为:
(y_i - model(x_i))^2对所有数据点求平均,就得到 Mean Squared Error,简称 MSE。
MSE 是回归任务中最基础的损失函数之一。
十一、二分类任务的损失函数直觉
心脏病预测模型输出的是 sigmoid 概率:
0 <= predicted probability <= 1真实标签是:
y = 0 或 y = 1问题是:如何度量一个概率值与 0/1 标签之间的 discrepancy?
11.1 当真实值 y = 1
如果患者实际患有心脏病,即 y = 1:
- 预测概率接近 1 时,
loss应该接近 0。 - 预测概率接近 0 时,
loss应该非常高。
因此需要一个函数,使预测概率越低,惩罚越重。一个合适的函数是:
-log(p)其中 p 是模型预测为 1 的概率。
这个函数满足:
p = 1时,loss为 0。p = 0.5时,loss约为 1。p接近 0 时,loss会变得非常大。
课堂中也提到,理论上可以使用线性惩罚,但陡峭的曲线能在预测严重错误时给出更强惩罚,并且对后续 gradient descent 更有效。
11.2 当真实值 y = 0
如果患者实际没有心脏病,即 y = 0:
- 预测概率接近 0 时,
loss应该接近 0。 - 预测概率接近 1 时,
loss应该非常高。
此时可以使用:
-log(1 - p)这个函数会在 p 接近 1 时给出很大的惩罚。
11.3 合并成一个表达式
如果分别为 y = 1 和 y = 0 写两个公式,会出现 if-then 结构,不利于求导。可以用一个表达式同时覆盖两种情况:
-[ y_i * log(p_i) + (1 - y_i) * log(1 - p_i) ]其中:
y_i是第i个样本的真实标签,只能是 0 或 1。p_i是模型对第i个样本预测为 1 的概率。
当 y_i = 1 时,第二项消失,公式变为:
-log(p_i)当 y_i = 0 时,第一项消失,公式变为:
-log(1 - p_i)对所有数据点求平均,就得到 binary cross entropy loss。
老师补充,如果一个大型深度神经网络处理的是 binary classification,很大概率会使用这类 binary cross entropy loss。
十二、关于二分类损失函数的问答
12.1 能否更重地惩罚 false negative
可以。老师说明,本节课先讲对称损失的基本情况。实际中可以设计不对称损失,让过高预测或过低预测受到不同程度的惩罚。
老师提到,如果对这类损失感兴趣,可以查 pinball loss。
12.2 为什么用 log 函数
学生问为什么必须使用 log,而不是其他形状的函数。
老师回答:
- 并不是只能使用
log。 - 可以设计其他函数。
- 选择
binary cross entropy的原因是它容易处理、梯度好、数学性质好,并且经验上有效。
因此,binary cross entropy 是常见且有效的选择,但不是唯一选择。
12.3 loss 是衡量模型好坏还是坏坏
老师指出,loss 更准确地说是衡量模型“有多差”。训练就是最小化这种 badness。
十三、最小化函数:从导数到梯度下降
为了理解如何最小化 loss function,老师先从一个单变量 toy function 开始,例如一个四次函数。
目标是找到函数的最小值点。
13.1 导数提供的信息
导数表示函数在某一点附近的变化率。
对单变量函数 g(w):
- 如果导数为正,稍微增加
w会让函数值上升。 - 如果导数为负,稍微增加
w会让函数值下降。 - 如果导数接近 0,稍微改变
w对函数值影响很小。
如果目标是最小化函数:
- 导数为正时,应减小
w。 - 导数为负时,应增大
w。 - 导数接近 0 时,可以停止。
13.2 不直接求导数为 0 的原因
在简单函数中,可以把导数设为 0 来求极值点。但在复杂函数中,尤其是神经网络的 loss function 中,很难直接解出让导数为 0 的点。
因此,更可行的做法是使用迭代方法逐步更新参数。
13.3 梯度下降公式
单变量梯度下降的更新公式为:
w_new = w_old - alpha * g'(w_old)其中:
w_old是当前参数值w_new是更新后的参数值g'(w_old)是当前点的导数alpha是 learning rate
这个公式同时覆盖导数为正、为负和接近 0 的情况。
gradient descent 由 Cauchy 在 1847 年提出。老师特别强调,现代大型模型仍然基于这个非常古老但强大的思想。
在课堂示例中,如果从 w = 2.5 这样的随机点出发,并设置 alpha = 1,gradient descent 会沿着函数曲线逐步移动,经过数次迭代后接近该 toy function 的最小值。老师也提到有对应动画可以帮助观察这一过程。
迭代停止不只发生在梯度接近 0 时;如果训练已经耗尽时间或计算预算,也会停止。这一点在大模型训练中尤其常见。
十四、学习率 alpha
学习率 alpha 控制每次更新参数时迈出的步长。
导数只描述当前点附近的局部情况,因此不能一次走太远。如果步子太大,局部导数信息可能失效。
学习率通常取较小的值,例如:
- 0.1
- 0.01
- 更小的数值
老师提到,在深度学习论文中,研究者经常会去附录查看训练使用的 learning rates,因为学习率是模型训练方法的重要组成部分,通常需要大量试错。
学习率并不是单纯由计算资源决定。它主要取决于在当前点沿梯度方向前进时,模型是否可以较有把握地继续下降。如果地形变化复杂,就不能轻易使用过大的学习率。
十五、多变量函数与梯度
神经网络的参数不是一个,而是很多个。GPT-3 有 1750 亿参数,GPT-4 的参数数量未公开,老师提到外界推测可能更大。
课堂中提到,GPT-4 的具体参数规模没有公开,外界曾有“可能约为 GPT-3 八倍”的猜测。这里的重点不是具体数字,而是说明现代模型的参数量可以达到极高维度。
当函数有多个变量时,需要使用 partial derivative。
对函数 g(w1, w2):
- 对
w1求偏导时,把w2看作常数。 - 对
w2求偏导时,把w1看作常数。
把所有偏导数组成一个向量,就得到 gradient。
梯度通常用 nabla 符号表示。
多变量梯度下降公式为:
w_new = w_old - alpha * gradient这里的 w 是包含所有参数的向量。无论参数是 2 个还是 1750 亿个,公式形式相同。
十六、局部最小值与鞍点
gradient descent 会在梯度接近 0 的地方停止,但停止点不一定是全局最小值。
可能的停止点包括:
local minimumsaddle point- 其他梯度接近 0 的区域
16.1 为什么没有全局最优保证
复杂函数可能有很多 local minima。gradient descent 从不同初始点出发,可能停在不同位置,因此没有保证一定找到 global minimum。
16.2 为什么这在深度学习中仍然有效
老师指出,实践中这并没有阻止深度学习成功,原因包括:
- 对复杂神经网络而言,找到一个足够好的解通常已经能解决问题。
- 不一定需要找到最优中的最优。
- 如果过度追求训练集上的最优,反而可能
overfit。 - 在高维空间中,真正的
local minimum条件非常苛刻。
在高维空间中,如果一个点是 local minimum,意味着所有方向都向上。参数维度达到数十亿时,所有方向都向上的概率很低;更常见的是某些方向向上、某些方向向下,形成 saddle point。
因此,高维神经网络优化中,saddle point 可能比 local minimum 更常见,而实践上仍然可以得到足够好的结果。
老师还用大型模型训练作类比:实际训练常常因为时间和资金成本而停止,并不一定已经到达 local minimum,更不一定到达 global minimum。只要得到的解已经足以解决任务,训练就可能被认为可接受。
十七、将梯度下降应用到神经网络训练
对于神经网络,loss function 最终是参数的函数。
虽然 loss 表达式中包含:
- 输入
x - 真实标签
y - 模型输出
model(x)
但 x 和 y 是数据,不是优化变量。真正需要优化的是模型内部的 weights 和 biases。
老师强调,公式里看起来是 model(x),但模型本身包含所有权重和偏置。因此,把模型展开后,loss function 就是关于所有 w 的普通函数。
训练神经网络就是最小化这个关于参数的 loss function。
课堂中也提到,当新闻说 Meta 发布 Llama 2 的 weights 时,这些 weights 正是大量计算、时间和研究投入之后训练得到的结果,因此非常有价值。
十八、全局最小值与泛化问题
学生问:如果能达到 global minimum,是否意味着没有 hallucination?
老师回答:
global minimum只是在训练数据上的最小点。global minimum不代表模型完美。- 即使训练
loss最小,测试数据或未来数据上的loss可能不同。 - 训练数据上的最佳解可能并不是测试数据上的最佳解。
- 过度优化训练
loss可能导致overfitting。
因此,训练集上的 global minimum 不等同于泛化能力最强,也不能保证复杂模型不出错。
十九、反向传播 backprop
老师强调,在深度学习社区中通常说 backprop,而不是完整说 backpropagation。
backprop 的作用是:高效计算 loss function 对所有参数的梯度。
如果模型有十亿个参数、数据有千万条,那么每一步梯度下降都需要计算巨量梯度。用朴素方式计算会非常昂贵。
backprop 利用神经网络的层级结构,把模型组织成 computational graph。
计算过程大致如下:
- 从输出端开始。
- 计算
loss对输出的梯度。 - 向左移动一层,计算当前层输出对前一层输出的梯度。
- 持续向前一层传播。
- 复用已经计算过的中间结果,避免重复计算。
backprop 的核心优势:
- 避免重复计算。
- 将复杂求导组织成一系列可复用步骤。
- 最终变成大量
matrix multiplications。
backprop 本质上是把 calculus 中的 chain rule 按神经网络的层级结构组织起来。
课堂中还有一个澄清:gradient descent 是参数更新算法,而 gradient calculation 是其中必需的一步。训练神经网络时,g(w) 可以理解为 loss function;每次更新都需要先计算当前参数处的 loss gradient,再代入 w_new = w_old - alpha * gradient。
二十、GPU 与深度学习革命
backprop 的计算可以转化为矩阵乘法,而 GPU 擅长矩阵和线性代数计算。
GPU 最初是为了加速电子游戏渲染而发展出来的硬件。电子游戏渲染中的核心计算也包含大量矩阵乘法。因此,当研究者意识到深度学习梯度计算同样需要大量矩阵乘法时,GPU 就成为训练神经网络的关键硬件。
老师指出:
backprop组织计算的方式GPU对矩阵乘法的加速
这两者结合,使得快速计算 loss gradient 成为可能。如果没有这一点,就不会有后来的深度学习革命。
老师提到,GPU 用于深度学习大约在 2005、2006 年前后已经出现早期案例,但真正让世界注意到深度学习的是 2012 年 AlexNet 在著名计算机视觉竞赛中的突破。AlexNet 的成功使深度学习进入主流视野。
老师也提到,现代 GPU 的产业价值与这种矩阵计算能力密切相关。深度学习训练对 GPU 的需求,是当代硬件产业格局变化的重要背景之一。
二十一、权重初始化
学生问:神经网络的初始权重如何确定?
老师回答:
- 权重通常随机初始化。
- 随机初始化不是任意乱选。
- 有专门的
initialization schemes。 Keras中已经内置有效的默认初始化方式。
老师提到的初始化方法包括:
He initializationXavier/Glorot initialization
老师建议初学时使用 Keras 默认初始化即可。
谨慎初始化的原因是:如果初始化不好,梯度在网络中反向传播时可能出现:
exploding gradientvanishing gradient
好的初始化方案可以让梯度在不同层之间更稳定。
初始化通常会一次性对整个网络完成。如果不初始化所有层,就无法完成前向计算,也无法得到预测值。初始化方案也会考虑相邻层的节点数量,例如一侧 10 个节点、另一侧 32 个节点时,节点数量会影响初始化方式。
二十二、随机梯度下降 SGD
完整 gradient descent 每次都使用全部数据计算 loss 和 gradient。对于大数据集和大模型,这非常昂贵,甚至可能无法放入内存。
SGD 的思想是:每次迭代只随机选取一小部分数据来估计梯度。
老师将 SGD 称为深度学习的 workhorse。它比完整 gradient descent 更便宜,同时在实践中非常有效。
这部分数据称为 batch 或 minibatch。
实际深度学习中常见 batch size 包括:
- 32
- 64
- 其他较小数值
严格来说,理论上的 stochastic gradient descent 每次只使用一个数据点。实践中更常用 minibatch gradient descent,但通常也宽泛地称为 SGD。
SGD 的特点:
- 每次只处理少量样本,计算效率高。
- 不需要把全部数据一次性用于梯度计算。
- 得到的梯度只是完整梯度的近似。
- 尽管只是近似,实践效果非常好。
老师强调,SGD 为什么如此有效仍然是研究中的重要问题,目前有很多有趣的研究方向,但还没有完全统一的理论解释。
二十三、SGD 为什么可能帮助逃离局部最小值
由于 SGD 使用的是 minibatch loss,而不是完整训练集 loss,因此每次更新使用的是完整梯度的近似。
这会带来一种有用的扰动:
- 在完整
loss function上看似处于local minimum。 - 在某个
minibatch对应的近似loss function上,可能并不是local minimum。 - 因此
SGD可能跳出完整loss function的某些local minima。
老师把这点作为 SGD 有效性的一个直觉解释:它少做了计算,却有时能得到更好的优化行为。
二十四、Adam 优化器
SGD 有很多变体。老师把它称为一个大家族。
本课程后续将默认使用 Adam 这一变体。Adam 的细节会在 Colab 实践时再讲。
老师展示过一个真实神经网络 loss function 的可视化图像,其中包含复杂的山峰、谷地和裂缝。这与前面用于讲解的简单碗形函数不同,说明真实神经网络优化地形非常复杂。
二十五、minibatch、iteration 与 epoch 的问答
25.1 每个 minibatch 是否训练到最优再换下一个
不是。
每个 minibatch 通常对应一次 iteration:
- 取一个
minibatch。 - 计算该
minibatch上的loss。 - 通过
backprop计算gradient。 - 用
gradient更新weights。 - 取下一个
minibatch。
不会在同一个 minibatch 上反复优化到最优再换下一个。
原因包括:
- 不能保证找到该
minibatch的全局最优。 - 持续引入新的
minibatch可以不断获得新信息。 - 后续还可以在其他
epoch中再次看到同一个minibatch或同一批数据。
batch size 和 epoch 的细节会在 Colab 中进一步展开。
25.2 每个 minibatch 得到的权重如何合并
不是为每个 minibatch 得到一套独立权重再合并。
训练过程是连续更新:
- 当前有一组权重
w1。 - 用第一个
minibatch计算gradient。 - 更新得到新权重
w2。 - 下一个
minibatch使用w2做预测和计算loss。 - 再更新到下一组权重。
因此权重是在训练过程中逐步演化的,不存在多个 minibatch 权重需要合并的问题。
二十六、backprop 的执行次数与方向
学生问:backprop 是从靠近输出的层开始往回走,这个过程是执行一次还是循环很多次?
老师回答:
- 对每一次
gradient calculation,backprop执行一次。 - 每个
minibatch计算一次梯度时,执行一次backprop。 - 训练过程中因为会有很多
minibatch和很多轮更新,所以整体会反复发生。
从输出层往回计算的原因是可以复用中间量,避免同一中间梯度被重复计算。若从输入方向直接展开,很多路径会重复计算相同数量。
二十七、整体训练流程
老师最后总结了神经网络训练的整体流程:
- 输入数据进入网络。
- 数据经过一系列层。
- 模型产生预测。
- 将预测值与真实标签比较。
- 用
loss function得到loss。 optimizer根据loss计算gradient。- 使用梯度下降公式更新每一层的
weights。 - 重复该过程。
核心更新公式仍然是:
w_new = w_old - alpha * gradient老师强调,这个流程适用于本节课的小型心脏病预测网络,也适用于更大的系统,例如 GPT、AlphaFold、AlphaGo 等。
二十八、激活函数选择与 ReLU 的优势
学生问:是否可以使用任意激活函数?
老师回答,可以使用很多激活函数,但需要考虑它们对 backprop 中梯度流动的影响。
激活函数需要尽量避免:
- 梯度被压扁
- 梯度爆炸
这也是 ReLU 流行的原因之一。ReLU 在正值区域的导数为 1,因此当输入为正时,反向传播过来的梯度会乘以 1 后继续传递,不会被压缩或放大。
ReLU 在提供非线性的同时,对正值区域的梯度传播非常友好。
老师将其概括为:ReLU 在注入足够非线性的同时,尽可能少地破坏梯度。
二十九、是否可以对特征做 minibatch
学生问:在高维特征情况下,是否可以不对 observation 做 minibatch,而是对 features 做 minibatch?
也就是说,保留所有样本,但每次只取一部分特征训练。
老师回答,关键问题是模型能否在缺少部分特征时计算预测。
通常情况下,模型预测需要所有输入特征。如果只选择部分特征,则需要为剩余特征设置默认值。但一旦设置默认值,本质上仍然是在使用所有特征。因此常规 minibatch 通常是在 observations 上取样,而不是在 features 上取样。
三十、课堂中的实践提示
本节课主要讲概念,老师说明这是整学期中较为理论和概念密集的一节课。后续进入 Colab 实践后,课程会更具体地展示如何训练模型。
老师还提到,会在 Canvas 上提供一个手算 backprop 的例子,对比普通方式计算梯度与 backprop 方式计算梯度的差别,以帮助理解效率提升来自哪里。
课程临近结束时,老师没有继续展开 regularization 和 overfitting,而是将相关内容留到后续课程中系统讲解。
三十一、本节课核心脉络
本节课的知识链条可以概括为:
- 设计网络结构
- 用
Keras表达模型 - 定义
loss function - 将训练理解为最小化
loss - 用
gradient descent更新参数 - 用
backprop高效计算gradient - 用
SGD/minibatch降低计算成本 - 用
Adam等优化器执行实际训练
其中最核心的思想是:
- 网络结构决定模型如何从输入计算输出。
loss function定义“预测有多差”。- 训练就是找到让
loss尽可能低的weights和biases。 gradient descent给出更新参数的方向。backprop高效计算每个参数的梯度。SGD用少量样本近似完整梯度,使大规模训练可行。
这些机制共同构成了现代深度学习训练的基础。