DDA5001 HW3 复习笔记:正则化、PCA 与神经网络
从带噪声的多项式拟合到特征脸,再用手写数字实验理解线性层、ReLU 和验证集选模型。
做这次作业时,我重新捡起了几个已经听过、但一时解释不清的概念。系数的 L2 范数为什么能帮助控制过拟合?交叉验证之后,最终模型到底用哪些数据拟合?PCA 算出来的特征脸又怎么拼回一张人脸?这篇笔记从这些问题出发,留给以后忘记细节的自己。
速查
| 问题 | 先记住什么 |
|---|---|
| L2 正则化 | 在拟合误差之外惩罚系数平方和。系数小是一种偏好,效果需要验证。 |
| 五折交叉验证 | 每折留一组验证,其余拟合。比较平均验证误差,选定超参数后用全部训练数据重拟合。 |
| PCA 与重建 | 先减平均值,在选定基上求坐标。重建时做基的加权和,再把平均值加回来。 |
| SVD 与特征脸 | 中心化矩阵的左奇异向量给出 PCA 方向。前面的方向对应更大的奇异值。 |
| 线性层与 ReLU | 两层仿射变换仍是仿射变换。中间加入 ReLU 后可以表示非线性映射。 |
| 验证集选 checkpoint | 训练损失继续下降时,验证损失可能回升。用验证集选训练轮次,测试集留作最后评价。 |
L2 正则化
HW2 用 Legendre 多项式做线性组合。HW3 第一题改用 作为基函数。模型对输入 可以是弯曲的曲线,但对待拟合的系数 仍然是线性的。把每个样本的基函数值放成一行,就得到设计矩阵 ,预测为 。
真实目标是 ,训练标签含噪声。八次多项式比较灵活,可能为了贴近少数带噪声的点而大幅摆动。L2 正则化在误差之外加入系数平方和:
我原先把它理解成“直接惩罚过拟合程度”。更准确的说法是,它直接惩罚的是系数大小。比如系数从 2 增到 4,平方惩罚从 4 增到 16。拟合得更紧带来的误差下降,必须与更大的惩罚权衡。合适的惩罚可能减少对噪声的追随;太强则可能欠拟合。
系数范数可作为模型复杂度的一种约束,但它不是曲线弯曲程度的直接度量。例如常数函数 的截距很大,图像却是水平线。系数大小还依赖特征的尺度,最终效果要看验证结果。
这次题目的误差项是均值,所以推导中要保留 :
这道题把截距也放进惩罚项,所以 包含截距对应的位置。 时左边矩阵正定。代码用 np.linalg.solve 解线性方程,避免显式求逆。每折拟合时 ,最终拟合时 。如果目标写的是残差平方和,正则化项的比例就需要重新核对,不能直接套这个 。
五折交叉验证
验证集用来选择模型或超参数,测试集留给选择完成后的最终评价。SGD 的 minibatch 从训练数据中取出,用于计算梯度并更新参数;验证集用来评估,通常不参与梯度更新。
这次有 10 个训练点。题目规定五组验证点的原始行编号为 、、、、。对每个候选 ,轮流留出一组,在另外 8 个点上拟合并计算这组的 MSE。每个点恰好验证一次,五次误差取平均。这里不是每轮独立随机抽两个点,否则有些点可能被验证多次,有些一次都没被验证。
用平均验证 MSE 选出 之后,固定它,再用全部 10 个训练点重新拟合系数 。交叉验证中的五个模型主要用于比较候选值,最终模型是重新拟合出来的。最后用独立测试集评价。测试集上的误差估计已选流程在新数据上的表现,并不等于真实分布上的样本外期望误差。
本次五折选出 ,平均验证 MSE 约为 。最终拟合的比较如下:
| 模型 | 训练 MSE | 测试 MSE |
|---|---|---|
| 无正则化 | 0.000904 | 2.080034 |
| 正则化, | 0.009334 | 0.040213 |
无正则化曲线几乎踩中训练点,却在点之间和边缘大幅摆动。正则化模型的训练误差更高,本次测试误差却更低。这里的测试结果只用于最终比较。若反复根据同一测试集挑选和修改方案,便不能再把它当成对整个选择过程的独立评价。交叉验证也只是估计,尤其在数据很少时仍可能波动。
PCA 与重建
一开始我把 PCA 想成先聚类,再以每个簇的平均值为基底。这次人脸实验的做法是对 400 张脸一起求平均脸,再找一组共同的方向。平均脸是中心化后的坐标原点,特征脸方向才是基向量。
每张 的灰度图展开为 ,放在 的一列,故 的形状为 。平均脸和中心化数据是
PCA 找正交方向,使前 个方向构成的子空间能够尽可能准确地重建中心化数据。将这些方向排列为 ,每张脸的坐标和重建为
可以把平均脸想成共同起点,特征脸想成共同基向量,每张脸的坐标则是自己的配方。若 ,没有方向可加回去,每张脸都重建为平均脸。若只保留一部分方向,重建通常是近似值。
全部图片一起计算时, 的形状为 ,坐标矩阵 是 。它的一列是一张脸的 个坐标,不是 400 个数。重建矩阵是 。
保留前 100 个方向包含保留前 20 个方向的所有信息。使用同一组正交 PCA 方向做投影时,增加方向不会使平方重建误差增大。比如三维点 ,只保留第一个坐标时平方误差是 ;保留前两个坐标时变为 。重建点更接近的是原始数据点,不是必然更接近原点。
本次 时全部图片的像素重建 MSE 为 ,图像比较模糊; 时降到 ,保留了更多五官细节。保留更多方向也需要为每张脸存更多坐标。若要估算实际存储,还应计入共享的平均脸和基向量。
SVD 与特征脸
SVD(奇异值分解)将中心化矩阵分解成 。 的列是数据空间中的正交方向,每列可重排为一张特征脸;奇异值按从大到小排列。因为
的列也是 的特征向量,对应特征值是奇异值的平方。它们给出 PCA 的方向,奇异值平方对应各方向上的总平方变化量。实际不用构造 的矩阵。
薄 SVD 是保留足够重建原矩阵的尺寸。对 的 ,薄 是 ,奇异值数组有 400 个数。中心化后各列之和为零,秩最多为 399,因此至少一个奇异值理论上为零。NumPy 使用 np.linalg.svd(X_c, full_matrices=False),再取 U[:, :k]。与完整 SVD 相比,这避免构造巨大的完整 。
线性层与 ReLU
MNIST 实验把 图片展开为 784 个输入,输出 10 个类别分数(logits)。三个模型分别是
| 模型 | 从输入到输出 |
|---|---|
| A | ,一个仿射层 |
| B | ,中间无激活 |
| C |
两个仿射层叠加后仍能合并:
这里输出维度为 10,隐藏宽度为 64,足以表示 A 能表示的所有仿射映射。表达能力相同并不保证训练结果相同。A 直接更新 ,B 分别更新 ,因而等效矩阵 的优化路径可能不同。
ReLU 定义为 。它对负数输出零,对正数保留原值,整体是有拐点的分段线性函数。C 可以表示非线性映射,具体参数下也可能得到仿射映射。B 与 C 有相同的层宽和参数数量,架构上只差 ReLU,适合观察本次实验中激活函数的作用。
PyTorch 中,nn.Linear(784, 64) 按输入、输出维度构造层,而其权重矩阵形状是 。C 用 Linear(784, 64)、ReLU()、Linear(64, 10) 顺序组合。给定的交叉熵损失接收 logits,所以输出端不另加 Softmax。A 有 7,850 个参数,B 和 C 各有 50,890 个。
验证集选 checkpoint
固定划分和训练设置下,各模型使用验证交叉熵最低的 epoch,对应结果是:
| 模型 | 选中 epoch | 验证交叉熵 | 测试交叉熵 | 测试准确率 |
|---|---|---|---|---|
| A | 9 | 0.3183 | 0.2772 | 91.45% |
| B | 4 | 0.3366 | 0.2901 | 90.80% |
| C | 14 | 0.1862 | 0.1705 | 95.20% |
本次验证集选择 C。A 与 B 的结果有差异,说明函数类相同并不要求训练轨迹相同;单次运行不能确认差异的唯一原因。匹配的 B 与 C 中,C 的验证交叉熵更低,结果与 ReLU 扩展表达能力的预测一致,但不是所有数据或训练设置下的必然排名。
C 在第 14 轮的验证交叉熵是 。到第 30 轮,训练交叉熵降至约 ,验证交叉熵却升到约 。模型继续贴合训练数据,却没有继续改善验证表现。框架因此保留验证误差最小的 checkpoint,而测试指标对应那个 checkpoint。
回想问题
- 五折结束后,为什么用全部训练点重新拟合,而测试集仍要单独保留?
- PCA 的平均脸、特征脸方向、每张脸的坐标各是什么?如果 ,重建结果是什么?
- 为什么两个线性层可以合并成一个仿射映射,而插入 ReLU 后一般不能?
- 训练损失下降但验证损失上升时,为什么最后一个 epoch 不一定是合适的 checkpoint?
相关课程回顾见 HW1 和 HW2。L2 正则化与权重衰减也可以参考 《动手学深度学习》Weight Decay。