全部

DDA5001 HW3 复习笔记:正则化、PCA 与神经网络

从带噪声的多项式拟合到特征脸,再用手写数字实验理解线性层、ReLU 和验证集选模型。

4 分钟阅读

做这次作业时,我重新捡起了几个已经听过、但一时解释不清的概念。系数的 L2 范数为什么能帮助控制过拟合?交叉验证之后,最终模型到底用哪些数据拟合?PCA 算出来的特征脸又怎么拼回一张人脸?这篇笔记从这些问题出发,留给以后忘记细节的自己。

速查

问题先记住什么
L2 正则化在拟合误差之外惩罚系数平方和。系数小是一种偏好,效果需要验证。
五折交叉验证每折留一组验证,其余拟合。比较平均验证误差,选定超参数后用全部训练数据重拟合。
PCA 与重建先减平均值,在选定基上求坐标。重建时做基的加权和,再把平均值加回来。
SVD 与特征脸中心化矩阵的左奇异向量给出 PCA 方向。前面的方向对应更大的奇异值。
线性层与 ReLU两层仿射变换仍是仿射变换。中间加入 ReLU 后可以表示非线性映射。
验证集选 checkpoint训练损失继续下降时,验证损失可能回升。用验证集选训练轮次,测试集留作最后评价。

L2 正则化

HW2 用 Legendre 多项式做线性组合。HW3 第一题改用 1,x,…,x81,x,\ldots,x^8 作为基函数。模型对输入 xx 可以是弯曲的曲线,但对待拟合的系数 θ\theta 仍然是线性的。把每个样本的基函数值放成一行,就得到设计矩阵 XX,预测为 XθX\theta。

真实目标是 y=x2y=x^2,训练标签含噪声。八次多项式比较灵活,可能为了贴近少数带噪声的点而大幅摆动。L2 正则化在误差之外加入系数平方和:

L(θ)=1m∥Xθ−y∥22+λ∥θ∥22,∥θ∥22=∑jθj2.L(\theta)=\frac{1}{m}\lVert X\theta-y\rVert_2^2+\lambda\lVert\theta\rVert_2^2, \qquad \lVert\theta\rVert_2^2=\sum_j\theta_j^2.

我原先把它理解成“直接惩罚过拟合程度”。更准确的说法是,它直接惩罚的是系数大小。比如系数从 2 增到 4,平方惩罚从 4 增到 16。拟合得更紧带来的误差下降,必须与更大的惩罚权衡。合适的惩罚可能减少对噪声的追随;太强则可能欠拟合。

系数范数可作为模型复杂度的一种约束,但它不是曲线弯曲程度的直接度量。例如常数函数 f(x)=10f(x)=10 的截距很大,图像却是水平线。系数大小还依赖特征的尺度,最终效果要看验证结果。

这次题目的误差项是均值,所以推导中要保留 1/m1/m:

∇L(θ)=2mX⊤(Xθ−y)+2λθ=0⟹(X⊤X+mλI)θ^=X⊤y.\nabla L(\theta)=\frac{2}{m}X^\top(X\theta-y)+2\lambda\theta=0 \quad\Longrightarrow\quad (X^\top X+m\lambda I)\hat\theta=X^\top y.

这道题把截距也放进惩罚项,所以 II 包含截距对应的位置。λ>0\lambda>0 时左边矩阵正定。代码用 np.linalg.solve 解线性方程,避免显式求逆。每折拟合时 m=8m=8,最终拟合时 m=10m=10。如果目标写的是残差平方和,正则化项的比例就需要重新核对,不能直接套这个 mλm\lambda。

五折交叉验证

验证集用来选择模型或超参数,测试集留给选择完成后的最终评价。SGD 的 minibatch 从训练数据中取出,用于计算梯度并更新参数;验证集用来评估,通常不参与梯度更新。

这次有 10 个训练点。题目规定五组验证点的原始行编号为 {6,0}\{6,0\}、{3,9}\{3,9\}、{2,1}\{2,1\}、{4,8}\{4,8\}、{5,7}\{5,7\}。对每个候选 λ\lambda,轮流留出一组,在另外 8 个点上拟合并计算这组的 MSE。每个点恰好验证一次,五次误差取平均。这里不是每轮独立随机抽两个点,否则有些点可能被验证多次,有些一次都没被验证。

用平均验证 MSE 选出 λ\lambda 之后,固定它,再用全部 10 个训练点重新拟合系数 θ\theta。交叉验证中的五个模型主要用于比较候选值,最终模型是重新拟合出来的。最后用独立测试集评价。测试集上的误差估计已选流程在新数据上的表现,并不等于真实分布上的样本外期望误差。

本次五折选出 λ=0.01\lambda=0.01,平均验证 MSE 约为 0.048270.04827。最终拟合的比较如下:

模型训练 MSE测试 MSE
无正则化0.0009042.080034
正则化,λ=0.01\lambda=0.010.0093340.040213

无正则化曲线几乎踩中训练点,却在点之间和边缘大幅摆动。正则化模型的训练误差更高,本次测试误差却更低。这里的测试结果只用于最终比较。若反复根据同一测试集挑选和修改方案,便不能再把它当成对整个选择过程的独立评价。交叉验证也只是估计,尤其在数据很少时仍可能波动。

PCA 与重建

一开始我把 PCA 想成先聚类,再以每个簇的平均值为基底。这次人脸实验的做法是对 400 张脸一起求平均脸,再找一组共同的方向。平均脸是中心化后的坐标原点,特征脸方向才是基向量。

每张 112×92112\times92 的灰度图展开为 xi∈R10304x_i\in\mathbb R^{10304},放在 XX 的一列,故 XX 的形状为 10304×40010304\times400。平均脸和中心化数据是

μ=1400∑i=1400xi,Xc=X−μ1⊤.\mu=\frac1{400}\sum_{i=1}^{400}x_i,\qquad X_c=X-\mu\mathbf1^\top.

PCA 找正交方向,使前 kk 个方向构成的子空间能够尽可能准确地重建中心化数据。将这些方向排列为 Ak=[a1,…,ak]A_k=[a_1,\ldots,a_k],每张脸的坐标和重建为

θi=Ak⊤(xi−μ),x^i=μ+Akθi=μ+∑j=1kajθi[j].\theta_i=A_k^\top(x_i-\mu),\qquad \hat x_i=\mu+A_k\theta_i=\mu+\sum_{j=1}^{k}a_j\theta_i[j].

可以把平均脸想成共同起点,特征脸想成共同基向量,每张脸的坐标则是自己的配方。若 k=0k=0,没有方向可加回去,每张脸都重建为平均脸。若只保留一部分方向,重建通常是近似值。

全部图片一起计算时,AkA_k 的形状为 10304×k10304\times k,坐标矩阵 Θk=Ak⊤Xc\Theta_k=A_k^\top X_c 是 k×400k\times400。它的一列是一张脸的 kk 个坐标,不是 400 个数。重建矩阵是 X^k=μ1⊤+AkΘk\widehat X_k=\mu\mathbf1^\top+A_k\Theta_k。

保留前 100 个方向包含保留前 20 个方向的所有信息。使用同一组正交 PCA 方向做投影时,增加方向不会使平方重建误差增大。比如三维点 (3,4,5)(3,4,5),只保留第一个坐标时平方误差是 42+52=414^2+5^2=41;保留前两个坐标时变为 52=255^2=25。重建点更接近的是原始数据点,不是必然更接近原点。

本次 k=20k=20 时全部图片的像素重建 MSE 为 0.0073470.007347,图像比较模糊;k=100k=100 时降到 0.0027160.002716,保留了更多五官细节。保留更多方向也需要为每张脸存更多坐标。若要估算实际存储,还应计入共享的平均脸和基向量。

SVD 与特征脸

SVD(奇异值分解)将中心化矩阵分解成 Xc=UΣV⊤X_c=U\Sigma V^\top。UU 的列是数据空间中的正交方向,每列可重排为一张特征脸;奇异值按从大到小排列。因为

XcXc⊤=U(ΣΣ⊤)U⊤,X_cX_c^\top=U(\Sigma\Sigma^\top)U^\top,

UU 的列也是 XcXc⊤X_cX_c^\top 的特征向量,对应特征值是奇异值的平方。它们给出 PCA 的方向,奇异值平方对应各方向上的总平方变化量。实际不用构造 10304×1030410304\times10304 的矩阵。

薄 SVD 是保留足够重建原矩阵的尺寸。对 10304×40010304\times400 的 XcX_c,薄 UU 是 10304×40010304\times400,奇异值数组有 400 个数。中心化后各列之和为零,秩最多为 399,因此至少一个奇异值理论上为零。NumPy 使用 np.linalg.svd(X_c, full_matrices=False),再取 U[:, :k]。与完整 SVD 相比,这避免构造巨大的完整 UU。

线性层与 ReLU

MNIST 实验把 28×2828\times28 图片展开为 784 个输入,输出 10 个类别分数(logits)。三个模型分别是

模型从输入到输出
A784→10784\to10,一个仿射层
B784→64→10784\to64\to10,中间无激活
C784→64→ReLU→10784\to64\to\mathrm{ReLU}\to10

两个仿射层叠加后仍能合并:

W2(W1x+b1)+b2=(W2W1)x+(W2b1+b2).W_2(W_1x+b_1)+b_2=(W_2W_1)x+(W_2b_1+b_2).

这里输出维度为 10,隐藏宽度为 64,足以表示 A 能表示的所有仿射映射。表达能力相同并不保证训练结果相同。A 直接更新 WW,B 分别更新 W1,W2W_1,W_2,因而等效矩阵 W2W1W_2W_1 的优化路径可能不同。

ReLU 定义为 max⁡(0,z)\max(0,z)。它对负数输出零,对正数保留原值,整体是有拐点的分段线性函数。C 可以表示非线性映射,具体参数下也可能得到仿射映射。B 与 C 有相同的层宽和参数数量,架构上只差 ReLU,适合观察本次实验中激活函数的作用。

PyTorch 中,nn.Linear(784, 64) 按输入、输出维度构造层,而其权重矩阵形状是 64×78464\times784。C 用 Linear(784, 64)、ReLU()、Linear(64, 10) 顺序组合。给定的交叉熵损失接收 logits,所以输出端不另加 Softmax。A 有 7,850 个参数,B 和 C 各有 50,890 个。

验证集选 checkpoint

固定划分和训练设置下,各模型使用验证交叉熵最低的 epoch,对应结果是:

模型选中 epoch验证交叉熵测试交叉熵测试准确率
A90.31830.277291.45%
B40.33660.290190.80%
C140.18620.170595.20%

本次验证集选择 C。A 与 B 的结果有差异,说明函数类相同并不要求训练轨迹相同;单次运行不能确认差异的唯一原因。匹配的 B 与 C 中,C 的验证交叉熵更低,结果与 ReLU 扩展表达能力的预测一致,但不是所有数据或训练设置下的必然排名。

C 在第 14 轮的验证交叉熵是 0.18620.1862。到第 30 轮,训练交叉熵降至约 0.00300.0030,验证交叉熵却升到约 0.21490.2149。模型继续贴合训练数据,却没有继续改善验证表现。框架因此保留验证误差最小的 checkpoint,而测试指标对应那个 checkpoint。

回想问题

  1. 五折结束后,为什么用全部训练点重新拟合,而测试集仍要单独保留?
  2. PCA 的平均脸、特征脸方向、每张脸的坐标各是什么?如果 k=0k=0,重建结果是什么?
  3. 为什么两个线性层可以合并成一个仿射映射,而插入 ReLU 后一般不能?
  4. 训练损失下降但验证损失上升时,为什么最后一个 epoch 不一定是合适的 checkpoint?

相关课程回顾见 HW1 和 HW2。L2 正则化与权重衰减也可以参考 《动手学深度学习》Weight Decay。