机器学习基础笔记(4):高级优化方法与模型诊断

吴恩达:机器学习
吴恩达的机器学习课程是入门ML的经典课程,直观易懂、数学要求适中。课程涵盖监督/无监督学习、线性/逻辑回归、神经网络、SVM、聚类、降维等核心算法,以及偏差方差、正则化等实用技巧。通过编程作业(如手写数字识别、异常检测)将理论应用于实践,帮助学员快速建立完整知识框架。
Adam 自适应矩估计
梯度下降作为优化算法有着广泛的适用性,但在实际训练过程中,其固定学习率常常成为效率瓶颈。观察一个椭圆形等高线图所代表的代价函数曲面,如果初始点位于长轴端点附近,梯度方向并非直指中心,而是近乎垂直于峡谷方向。此时固定的小步长会导致路径在谷壁之间反复震荡,前进缓慢;如果简单粗暴地增大学习率,又可能在接近谷底时因步幅过大而发散。
能否设计一种算法,自动根据优化进程动态调整每一步的步幅?当参数持续沿同一方向更新时,不妨迈得更大一些;当梯度方向频繁反转、出现震荡时,则主动收紧步伐。这正是自适应矩估计(Adaptive Moment Estimation,简称 Adam)算法的核心直觉。

Adam 为模型的每一个参数维护各自独立的学习率。设想一个拥有数十万参数的深度网络,权重 $w_1$ 与 $w_{10}$ 可能处于代价函数曲面上形态迥异的区域,对学习率的需求截然不同。Adam 通过追踪每个参数梯度的指数移动平均(一阶矩)以及梯度平方的指数移动平均(二阶矩),据此对每个参数计算出自适应的更新步长。具体而言,若某一参数的历史梯度符号稳定,说明更新方向可靠,算法会放大其有效步长;若历史梯度符号正负交替,表明当前区域崎岖震荡,算法便主动压缩步长。这一机制使得 Adam 对初始学习率的敏感度远低于普通梯度下降,在绝大多数任务中,只需设定一个初始值(例如 $10^{-3}$),算法便能在训练过程中自行调节。
在 TensorFlow 中启用 Adam 优化器极其简单。只需在模型编译阶段通过 optimizer 参数指定即可,通常还会配合上一节提到的数值稳定技巧(from_logits=True):
model = Sequential([
tf.keras.layers.Dense(units=25, activation='sigmoid'),
tf.keras.layers.Dense(units=15, activation='sigmoid'),
tf.keras.layers.Dense(units=10, activation='linear')
])
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
)
model.fit(X, Y, epochs=100)
Adam 凭借其鲁棒性和高效性,已成为当前深度学习实践中最主流的优化器之一。
卷积层
此前讨论的神经网络均由密集层(Dense Layer)堆叠而成。在密集层中,每一个输出神经元都与上一层的全部激活值相连。这种全连接结构固然通用,但对于图像、音频等具有空间或时序结构的数据而言,却可能造成参数量的浪费和过拟合风险。
卷积层(Convolutional Layer)采用了一种更节制的连接模式。每个神经元并不窥视上一层的全貌,而是只聚焦于输入的一个局部窗口。以心电图信号分类为例,输入是一段包含 100 个时间步的电压序列。第一个卷积层的神经元可能仅查看第 1 至第 20 个时间步,第二个神经元查看第 11 至第 30 个时间步,依此类推,窗口以固定步长在输入序列上滑动。这一操作被称为卷积(Convolution)。每个窗口内,同一个神经元使用的权重参数在所有位置上共享,这大幅削减了需要学习的参数量。随后,这些局部响应的激活值被送入后续的隐藏层,最终汇入输出层产生预测。

卷积层的优势体现在两个层面。其一,计算效率更高。由于每个神经元仅与局部区域相连,且权重共享,前向传播和反向传播的矩阵乘法规模显著缩小。其二,统计效率更高。更少的参数意味着模型对训练数据量的渴求降低,且更不易陷入过拟合。正是这些特性,使得以卷积层为核心构建的卷积神经网络(Convolutional Neural Network,简称 CNN)在计算机视觉领域取得了统治级的表现。
模型评估与数据划分
当训练好的模型在测试数据上表现不佳时,需要有一套系统的方法来诊断症结所在,而不是漫无目的地尝试各种技巧。假设已经实现了一个带正则化项的线性回归模型来预测房价,代价函数为:
$$ J(\vec{w}, b) = \frac{1}{2m} \sum_{i=1}^{m} \left( f_{\vec{w}, b}(\vec{x}^{(i)}) - y^{(i)} \right)^2 + \frac{\lambda}{2m} \sum_{j=1}^{n} w_j^2 $$
尽管已经加入正则化,预测误差依然大到难以接受。此时可供选择的改进方向包括:获取更多训练样本、减少或增加特征数量、引入多项式特征、调整正则化参数 $\lambda$。但这些选项并非放之四海而皆准,有些适用于过拟合场景,有些适用于欠拟合场景。盲目尝试只会浪费算力与时间。
为了做出有理有据的决策,首先需要建立一套客观评估模型表现的方法。最基础的做法是将手头的数据集划分为训练集(Training Set)和测试集(Test Set)。常见的比例是七三开,70% 的数据用于训练模型参数,30% 的数据用于评估模型在未见样本上的泛化性能。
对于线性回归任务,训练过程是最小化带正则化的代价函数以求得最优参数 $\vec{w}, b$。随后,分别在训练集和测试集上计算均方误差,且计算时不应再包含正则化项:
$$ J_ {\text{train}}(\vec{w}, b) = \frac{1}{2m_{\text{train}}} \sum_{i=1}^{m_{\text{train}}} \left( f_{\vec{w}, b}(\vec{x}{\text{train}}^{(i)}) - y{\text{train}}^{(i)} \right)^2 $$
$$ J_ {\text{test}}(\vec{w}, b) = \frac{1}{2m_{\text{test}}} \sum_{i=1}^{m_{\text{test}}} \left( f_{\vec{w}, b}(\vec{x}{\text{test}}^{(i)}) - y{\text{test}}^{(i)} \right)^2 $$
分类问题的评估逻辑与此平行。对于逻辑回归,训练阶段最小化的是带正则化的交叉熵损失。评估时,则分别在训练集和测试集上计算不带正则化的交叉熵误差。此外,对于分类任务还可以使用一种更直观的指标——误分类率(Misclassification Rate),即预测标签与真实标签不一致的样本所占比例:
$$ J_ {\text{test}}(\vec{w}, b) = \frac{1}{m_{\text{test}}} \sum_{i=1}^{m_{\text{test}}} \mathbf{1}_{\hat{y}^{(i)} \neq y^{(i)}} $$
这里 $\hat{y}^{(i)}$ 是由模型输出概率经阈值(通常为 0.5)二值化后得到的预测类别。误分类率直接对应业务场景中的准确率,但其作为 0/1 损失函数不可导,因此不能用于训练,仅作为评估指标。
模型选择与交叉验证
实际建模过程中,很少会只训练一个模型就宣告完工。通常需要在一系列候选模型中做出选择,例如决定多项式回归的次数 $d$。候选模型可能包括 $d=1$ 的简单线性模型,$d=2$ 的二次多项式,一直到 $d=10$ 的高次多项式。如果直接用测试集上的表现来挑选 $d$,那么测试集就已经被卷入了模型选择的过程,由此得到的测试误差将是对泛化性能的乐观估计,无法客观反映模型在全新数据上的真实水平。
正确的做法是将数据划分为三个互不重叠的子集。训练集(Training Set)用于拟合模型的具体参数 $\vec{w}, b$。交叉验证集(Cross-validation Set),也称开发集(Dev Set),用于在多个候选模型之间进行比较和选择,例如挑选多项式次数 $d$ 或调节正则化参数 $\lambda$。测试集(Test Set)则被严格封存,仅在最终阶段用于评估已选定模型的泛化性能,且只使用一次。一个典型的划分比例是 60% 训练、20% 交叉验证、20% 测试。
偏差与方差的诊断
拥有了训练误差 $J_ {\text{train}}$ 和交叉验证误差 $J_ {\text{cv}}$ 这两个指标,便可以对模型的状态做出定量诊断。当模型欠拟合(高偏差)时,它在训练集上的表现本身就很糟糕,$J_ {\text{train}}$ 维持在高位;由于缺乏足够的拟合能力,它在交叉验证集上的表现同样糟糕,$J_ {\text{cv}}$ 也高,且两者数值较为接近。当模型过拟合(高方差)时,它几乎完美地记住了训练集的每一个细节,$J_ {\text{train}}$ 极低;然而这种对训练数据的死记硬背无法泛化到新样本,因此 $J_ {\text{cv}}$ 会远高于 $J_ {\text{train}}$。一个恰如其分的模型,其 $J_ {\text{train}}$ 和 $J_ {\text{cv}}$ 都保持在较低水平,且差距不大。

若以多项式次数 $d$ 为横轴,分别绘制 $J_ {\text{train}}$ 和 $J_ {\text{cv}}$ 的曲线,这一规律会呈现得更加清晰。$J_ {\text{train}}$ 随着 $d$ 的增加单调递减,因为模型容量越大,对训练数据的拟合就越彻底。而 $J_ {\text{cv}}$ 则呈现一条 U 形曲线:$d$ 过小时因欠拟合而偏高,$d$ 过大时因过拟合而再度上扬,中间存在一个使交叉验证误差最小的最佳复杂度。

正则化参数 $\lambda$ 对偏差与方差的影响呈现出相反的趋势。仍以 $d=4$ 的多项式回归为例。当 $\lambda$ 被设为极大值时,正则化项在代价函数中占据绝对主导,算法被迫将所有权重 $w_j$ 压缩至接近零,模型退化为 $f \approx b$ 的常数预测,陷入高偏差的欠拟合状态。当 $\lambda$ 被设为极小值(甚至为零)时,正则化形同虚设,高次项权重不受约束地膨胀,模型轻易滑向高方差的过拟合。为了找到合适的 $\lambda$,可以在一系列候选值(如 0, 0.01, 0.02, 0.04, 0.08, …, 10)上分别训练模型,计算对应的 $J_ {\text{cv}}$,选择令 $J_ {\text{cv}}$ 最小的那个 $\lambda$。
将 $J_ {\text{train}}$ 和 $J_ {\text{cv}}$ 作为 $\lambda$ 的函数绘制出来,$J_ {\text{cv}}$ 在中间某处取得最小值;$J_ {\text{train}}$ 则随 $\lambda$ 增大而单调上升,因为正则化越强,模型对训练数据的拟合就越受压制。

建立性能基线
在解读 $J_ {\text{train}}$ 和 $J_ {\text{cv}}$ 的绝对数值时,一个容易被忽视的问题是:什么样的误差水平才算“好”?例如一个语音识别系统,训练集词错误率为 10.8%,交叉验证集为 14.8%。单看 14.8% 似乎不低,但若得知人类在该任务上的平均错误率为 10.6%,评价便会截然不同——训练误差仅比人类水平高出 0.2 个百分点,而交叉验证误差与训练误差之间也只相差 4 个百分点。这说明模型的学习能力已接近人类上限,主要瓶颈在于泛化而非拟合不足。
因此,在项目启动之初,设定一个合理的性能基线(Baseline)至关重要。基线可以参考人类水平表现、领域内竞争算法的公开结果、或基于过往经验的估计值。基线提供了一个标尺,用于衡量后续优化的潜在空间和实际价值。
学习曲线
另一种强大的诊断工具是学习曲线(Learning Curve)。它将训练集大小 $m_ {\text{train}}$ 作为自变量,观察 $J_ {\text{train}}$ 和 $J_ {\text{cv}}$ 如何随数据量的增加而演变。一般而言,当训练样本极少时,模型可以轻易完美拟合所有数据点,$J_ {\text{train}}$ 接近于零;而 $J_ {\text{cv}}$ 则因缺乏足够信息而极高。随着训练样本增多,模型拟合所有点的难度加大,$J_ {\text{train}}$ 逐渐上升;同时模型学到了更普适的规律,$J_ {\text{cv}}$ 逐渐下降。两条曲线最终都趋向于某个稳态值,且 $J_ {\text{train}}$ 始终位于 $J_ {\text{cv}}$ 下方。

学习曲线的形态能清晰揭示偏差与方差的性质。在高偏差(欠拟合)情况下,由于模型容量本身不足(例如用直线拟合曲线数据),即使训练样本无限增加,$J_ {\text{train}}$ 也会迅速趋于一个高于基线的高原,$J_ {\text{cv}}$ 同样悬在高位且与 $J_ {\text{train}}$ 接近。此时收集更多数据几乎徒劳,正确的改进方向是提升模型复杂度,如增加特征、引入多项式项或减小正则化强度。在高方差(过拟合)情况下,$J_ {\text{train}}$ 可以维持在很低的水平(甚至接近人类基线),但 $J_ {\text{cv}}$ 却居高不下,两条曲线之间存在显著的鸿沟。随着训练样本增加,$J_ {\text{cv}}$ 会持续下降并逐渐向 $J_ {\text{train}}$ 靠拢,表明更多数据能够有效弥合泛化差距。
基于上述诊断逻辑,便可以构建出一张清晰的决策表格。若面临高偏差,应当尝试增加特征、引入多项式特征、或减小 $\lambda$。若面临高方差,则应当尝试获取更多训练数据、精简特征集、或增大 $\lambda$。每一个操作都有其明确的适用前提,不再是无的放矢。
神经网络的偏差与方差
这套偏差-方差分析框架同样适用于神经网络。实践中,一个简洁有效的迭代流程是:首先关注训练集表现。若 $J_ {\text{train}}$ 本身不尽如人意,说明网络容量不足或优化不到位,此时应优先考虑增大网络规模(增加层数或每层神经元数)。反复调整直至 $J_ {\text{train}}$ 达到一个令人满意的水平(例如接近或略优于人类基线)。然后转向交叉验证集。若 $J_ {\text{cv}}$ 显著高于 $J_ {\text{train}}$,说明存在过拟合,此时再考虑增加训练数据,或施加更强的正则化。重复这一循环,直到两个指标均达到预期。
一个值得强调的经验法则是,在计算资源允许且正则化得当的前提下,较大型的神经网络几乎总是优于小型网络。大型网络拥有更强的表示能力,只要辅以合适的正则化手段(如 L2 正则化、Dropout 等),其过拟合风险完全可控,而它逼近复杂函数的潜力却是小型网络难以企及的。
在 TensorFlow 中为全连接层添加 L2 正则化只需在层定义时指定 kernel_regularizer 参数:
from tensorflow.keras.regularizers import L2
layer_1 = Dense(units=25, activation="relu", kernel_regularizer=L2(0.01))
layer_2 = Dense(units=15, activation="relu", kernel_regularizer=L2(0.01))
layer_3 = Dense(units=1, activation="sigmoid", kernel_regularizer=L2(0.01))
model = Sequential([layer_1, layer_2, layer_3])
正则化项会被自动附加到总损失中,在训练过程中一同被优化。
误差分析与数据策略
在诊断出模型大致处于高偏差还是高方差之后,进一步的性能提升往往依赖于细致的误差分析(Error Analysis)。以垃圾邮件分类器为例,与其笼统地观察整体准确率,不如人工抽查那些被错误分类的邮件,统计其中由于蓄意拼写错误、图片夹杂文本、或伪造发件人地址等原因导致的失败各占多少比例。这一分析结果能够直接指导后续的数据收集和特征工程工作,让每一分努力都投向最有价值的改进方向。
当获取全新标注数据的成本过高时,数据增强(Data Augmentation)是一种极具性价比的替代方案。其思想是对现有训练样本施加各种保持语义不变的变换,从而创造出更多样的训练实例。在图像领域,常见的变换包括随机旋转、缩放、裁剪、水平翻转、颜色抖动等。在语音识别中,可以向原始音频叠加背景噪声,如咖啡馆的人声、街道车流声、电话按键音等,使模型对现实世界中千奇百怪的声学环境更具鲁棒性。

数据增强必须遵循一条铁律:变换后的样本仍应处于测试集可能出现的分布之内。若将猫的图片上下颠倒用于训练,而实际应用中几乎不会有人倒拿手机拍摄猫咪,那么这种增强非但无益,甚至可能引入混淆。
数据合成(Data Synthesis)则更进一步,完全使用计算机程序生成人工训练样本。在光学字符识别(Optical Character Recognition,简称 OCR)任务中,可以编写脚本,用成百上千种字体、字号、颜色和背景纹理渲染出巨量的文本行图像。这种方法在计算机视觉领域尤为有效,但在其他数据模态中应用相对有限。
上述实践反映了一个更宏观的范式转变。机器学习系统的构建不仅仅是在现有固定数据集上运行算法,对数据本身的工程操作——收集、清洗、标注、增强、合成——往往占据着项目周期的绝大部分精力,并且常常是拉开模型性能差距的关键所在。
迁移学习
当目标任务的数据量捉襟见肘时,迁移学习(Transfer Learning)提供了一条优雅的解决路径。其基本思路是,将一个在大规模通用数据集上预训练好的模型,迁移到数据稀缺的目标任务上进行微调。
以手写数字识别为例。假设仅有少量带标签的数字图片,但拥有一个已在数百万张自然图像上训练好的物体分类模型(可识别猫、狗、汽车等 1000 类物体)。该预训练模型的浅层已经学会了检测边缘、纹理、简单形状等通用视觉基元。可以将这些层的参数保留下来,仅将最后的 1000 类输出层替换为一个适合 10 类数字识别的新输出层。随后,既可以选择只训练新添加的输出层参数(适用于目标数据极少的情况),也可以选择以较小的学习率对整个网络的所有参数进行微调(Fine-tuning)。
这种先在大型数据集上进行有监督预训练(Supervised Pretraining),再在小型目标数据集上微调的两阶段策略,已成为深度学习应用的事实标准。如今,互联网上可以轻易获取到在 ImageNet 等大规模基准上预训练好的模型权重,下载后稍作调整,便能在特定任务上取得令人满意的效果。
迁移学习之所以能够跨领域生效是因为不同视觉任务在底层特征上存在广泛的共性。无论最终的识别对象是猫还是数字,模型在最浅层都需要检测边缘和角点,这些局部模式的检测器是任务无关的通用组件。因此,预训练模型的前几层可以被视为一种可复用的视觉特征提取器。
机器学习项目的完整周期
训练出一个表现良好的模型,仅仅是机器学习项目生命周期中的一环。一个完整的项目通常经历以下阶段。
首先是项目范围的界定。明确业务目标,评估技术可行性,并框定输入输出形式。接着进入数据收集阶段。定义数据需求,设计采集方案,并进行标注。有了初步数据后,开始模型的构建与训练。在此阶段,偏差-方差诊断、误差分析将与数据收集反复交替进行,形成一个紧密的迭代闭环。当模型性能达到部署标准后,便进入生产部署阶段。模型被封装为推理服务,通过 API 接收客户端请求,执行前向传播,并返回预测结果。
部署也不是终点,生产环境需要配套的软件工程保障,以确保预测服务的高可用、低延迟、可扩展,同时还需建立日志记录、系统监控和模型版本更新机制。这一整套生产实践被统称为机器学习运维(MLOps)。此外,模型上线后可能因数据分布随时间漂移而性能衰退,此时便需触发新一轮的数据收集与模型迭代。
公平性与伦理考量
机器学习系统在带来效率提升的同时,也可能无意中放大社会既有的偏见。一个用于简历筛选的招聘模型,若训练数据中历史录用记录本身就存在对特定性别或种族的系统性偏好,模型会忠实地学习并再现这种歧视。深度伪造技术(Deepfakes)则可能被用于制造虚假视频、散布煽动性言论,对社会信任造成侵蚀。因此伦理意识必须贯穿项目的始终。在组建团队时,应尽可能多元化背景,以便从多角度审视潜在风险,尤其关注技术对弱势群体可能造成的伤害。在设计阶段,需针对所在行业的相关法规与伦理指南进行文献调研。在部署之前,应对系统进行全面的伤害性审计。制定缓解计划,并在上线后持续监控系统的实际影响。这些步骤并非技术细节的点缀,而是负责任地构建机器学习系统不可或缺的组成部分。