交叉验证


评估泛化能力

机器学习的算法模型大多依赖于训练集数据,而前几篇日志中我们讨论了模型过拟合的问题。模型在未见过的数据上的表现通常被定性为模型的泛化能力,而交叉验证(Cross Validation)便是评估一个模型泛化能力的方法。

交叉验证是一种通过反复划分数据集来评估模型泛化能力的验证方法,其有多种形式。我们先介绍最简单的留出法,即把原训练集数据随机划分为70%数据量的训练集30%数据量的测试集(Test Set),并凭借模型对测试集数据的表现进行评估。

混淆矩阵(Confusion Matrix)是评估分类模型表现的重要指标。以二分类问题为例,假设对于测试集样本 (x,y),y{0,1}(x,y),y\in\{0,1\},模型的预测结果为 Y{0,1}Y\in\{0,1\},有以下几种情况。

Y=1Y=1 Y=0Y=0
y=1y=1 真正例 TPTP 假反例 FNFN
y=0y=0 假正例 FPFP 真反例 TNTN
  • TPTP:被正确预测的正例个数
  • TNTN:被正确预测的反例个数
  • FPFP:被错误预测的正例个数
  • FNFN:被错误预测的反例个数

下面定义四个统计量,他们从不同角度评估了一个模型表现的优劣

  1. 精确率(Precision):模型预测为正例的样本中,真正为正例的比例

P=TPTP+FP\text{P}=\frac{TP}{TP+FP}

  1. 准确率(Accuracy):模型预测正确的样本占总样本的比例

Acc=TP+TNTP+FP+TN+FN\text{Acc}=\frac{TP+TN}{TP+FP+TN+FN}

  1. 召回率(Recall):实际为正例的样本中,被模型正确预测为正例的比例

R=TPTP+FN\text{R}=\frac{TP}{TP+FN}

  1. F1值:精确率和召回率的调和平均数,综合反映模型性能

F=2PRP+RF=2\cdot\frac{\text{PR}}{\text{P+R}}

精确率关注预测结果,准确率关注整体预测,召回率关注实际样本,F1值平衡两者。四个指标从不同角度反映了一个模型的表现情况。

选择超参数

超参数(Hyperparameter)是用于控制模型的行为和性能的一种参数类型。例如,学习率 α\alpha、迭代次数、正则化参数 λ\lambda、隐藏层的神经元数量 sls_l 等都是常见的超参数。选择合适的超参数可以借助交叉验证方法实现。

我们可以把原训练集随机划分为三个部分

  • 60%的数据作为训练集,代价函数记为 Jtrain(θ)J_{train}(\boldsymbol{\theta})
  • 20%的数据作为交叉验证集(Cross Vadilation Set),代价函数记为 Jcv(θ)J_{cv}(\boldsymbol{\theta})
  • 20%的数据作为测试集,代价函数记为 Jtest(θ)J_{test}(\boldsymbol{\theta})

我们以多项式回归为例,多项式次数 d=1,2,,n,d=1,2,\cdots,n,\cdots 便是一个超参数。我们可以通过以下步骤确定一个较为合适的 dd 值。

  1. 划分数据集
  2. 对于次数为 dd 的多项式回归模型,进行训练使得 minJtrain(θ)\min J_{train}(\boldsymbol{\theta}),得到参数 θ(d)\boldsymbol{\theta}^{(d)}
  3. 计算该参数对交叉验证集数据的代价 Jcv(θ(d))J_{cv}(\boldsymbol{\theta}^{(d)})
  4. 确定一个范围 1dp1\leqslant d\leqslant p,重复2,3步并选取使得 Jcv(θ(d))J_{cv}(\boldsymbol{\theta}^{(d)}) 最小的 θ(d0){\boldsymbol{\theta}}^{(d_0)}
  5. 确定超参数 d=d0d=d_0,并通过测试集计算准确率 Acc\text{Acc},评估模型
区别 训练集 交叉验证集 测试集
比例 60% 20% 20%
是否参与模型训练
训练对象 普通参数 超参数 -
评估对象 - 超参数 模型表现

我们可以更直观的画出下图

  • dd 过小时,模型欠拟合
    • JtrainJ_{train}JcvJ_{cv} 都较大
    • 模型偏差较大
  • dd 过大时,模型过拟合
    • JtrainJ_{train} 很小,JcvJ_{cv} 较大
    • 模型方差较大
  • dd 适中时,模型表现良好

类似的,我们也可以凭借此方法确定合适的正则化参数 λ\lambda

学习曲线

学习曲线(Learning Curve)是评估模型准确率的一种图示,一般可以表示为训练集和验证集在不同训练样本数量 mtrainm_{train} 或特征数量 nn 下表现的变化趋势。下图分别展现了高偏差,高方差和良好模型的学习曲线。

高偏差模型 高方差模型 良好模型
误差收敛 误差之间有大的差距 误差收敛
误差很高 误差较小 误差较小

支持向量机


接下来,我们来介绍支持向量机(Support Vector Machine, SVM)。正式介绍其定义之前,我们需要先介绍一些基本内容。

Hinge Loss

先回顾一下 Logistic 回归模型,我们曾经定义了单样本代价函数

Cost=ylogh(x)(1y)log(1h(x))\text{Cost}=-y\log h(\boldsymbol{x})-(1-y)\log(1-h(\boldsymbol{x}))

上述代价(损失)函数称为交叉熵损失函数(Cross-Entropy Loss Function),其中 h(x)=g(θTx)=11+eθTxh(\boldsymbol{x})=g(\boldsymbol{\theta}^T\boldsymbol{x})=\dfrac{1}{1+e^{-\boldsymbol{\theta}^T\boldsymbol{x}}} 是 Sigmoid 函数形式。令 z=θTxz=\boldsymbol{\theta}^T\boldsymbol{x},代入原代价函数有

Cost=ylog11+ez(1y)log(111+ez)\text{Cost}=-y\log \frac{1}{1+e^{-z}}-(1-y)\log\left(1-\frac{1}{1+e^{-z}}\right)

之前的日志中,我们曾经讨论过 zz 的取值和真实类别 yy 之间的关系

  • y=1y=1 时,zz 应该尽可能的大(z0z\gg 0),此时有

Cost=log11+ez0\text{Cost}=-\log \frac{1}{1+e^{-z}}\to 0

  • y=0y=0 时,zz 应该尽可能的小(z0z\ll 0),此时有

Cost=log(111+ez)0\text{Cost}=-\log \left(1-\frac{1}{1+e^{-z}}\right)\to 0

事实上,我们可以用下图的两条紫色折线近似代替此代价函数。

把两种情况的紫色折线函数称作Hinge损失函数,定义为

L(θTx)=L(z)={max(0,1z)=L1(z),y=1max(0,1+z)=L0(z),y=0L(\boldsymbol{\theta}^T\boldsymbol{x})=L(z)=\begin{cases}\max(0,1-z)=L_1(z),&y=1\\\max(0,1+z)=L_0(z),&y=0\end{cases}

为此,我们可以写出一个全新的代价函数 JJ,形式如下

J(θ)=Ci=1m[y(i)L1(θTx(i))+(1y(i))L0(θTx(i))]+12j=1nθj2=Ci=1mL(θTx(i))+12j=1nθj2,C is a hyperparameter\begin{aligned}J(\boldsymbol{\theta})&=C\sum_{i=1}^m\Big[y^{(i)}L_1(\boldsymbol{\theta}^T\boldsymbol{x}^{(i)})+(1-y^{(i)})L_0(\boldsymbol{\theta}^T\boldsymbol{x}^{(i)})\Big]+\frac{1}{2}\sum_{j=1}^n \theta^2_j\\&=C\sum_{i=1}^mL(\boldsymbol{\theta}^T\boldsymbol{x}^{(i)})+\frac{1}{2}\sum_{j=1}^n \theta_j^2,\quad\text{$C$ is a hyperparameter}\end{aligned}

尽管上述代价函数形式和之前介绍的有所区别,但优化目标是等价的。

本日志讨论的 SVM 便使用了上述形式的代价函数。

反过来思考

前面提到了Hinge损失函数的形式,仔细观察会发现

  • y=1y=1 时,只有 z=θTx1z=\boldsymbol{\theta}^T\boldsymbol{x}\geqslant 1 时代价为0
  • y=0y=0 时,只有 z=θTx1z=\boldsymbol{\theta}^T\boldsymbol{x}\leqslant -1 时代价为0

令 SVM 算法的假设函数形式为

h(x)={1,θTx00,θTx<0h(\boldsymbol{x})=\begin{cases}1,&\boldsymbol{\theta}^T\boldsymbol{x}\geqslant 0\\0,&\boldsymbol{\theta}^T\boldsymbol{x}<0 \end{cases}

可以发现,只要 θTx0\boldsymbol{\theta}^T\boldsymbol{x}\geqslant 0 时,模型就预测其类型为正,但此时其代价可能不为0;类似的,当 θTx<0\boldsymbol{\theta}^T\boldsymbol{x}<0 时,模型就预测其类型为负,但此时其代价也可能不为0。这就是 SVM 的一个有趣性质。

由于我们的优化目标是 minJ(θ)\min J(\boldsymbol{\theta}),因此每一个样本的代价都应该尽可能的小。考虑代价函数中 CC 取一个很大的数字,比如 114514114514

min[114514i=1mL(θTx(i))+12j=1nθj2]i=1mL(θTx(i))0\min \Big[114514\sum_{i=1}^mL(\boldsymbol{\theta}^T\boldsymbol{x}^{(i)})+\frac{1}{2}\sum_{j=1}^n \theta_j^2\Big]\Rightarrow \sum_{i=1}^mL(\boldsymbol{\theta}^T\boldsymbol{x}^{(i)})\to 0

这一步是显然的:要想让整体最小,由于前一项的因子很大,所以在合适的训练后其值应当几乎为0。换言之,对于训练好的参数 θ\boldsymbol{\theta},下述条件几乎成立

  • h(x)=1h(\boldsymbol{x})=1 时:θTx1\boldsymbol{\theta}^T\boldsymbol{x}\geqslant 1
  • h(x)=0h(\boldsymbol{x})=0 时:θTx1\boldsymbol{\theta}^T\boldsymbol{x}\leqslant -1

我们不妨就把代价函数的前一项看做0,此时优化目标等价于

min12j=1nθj2,s.t. x(i) with θ{θTx(i)1,y(i)=1θTx(i)1,y(i)=0\min \frac{1}{2}\sum_{j=1}^n \theta_j^2,\quad \text{s.t. $\forall \boldsymbol{x}^{(i)}$ with $\boldsymbol{\theta}$, }\begin{cases}\boldsymbol{\theta}^T\boldsymbol{x}^{(i)}\geqslant 1,&y^{(i)}=1\\\boldsymbol{\theta}^T\boldsymbol{x}^{(i)}\leqslant -1,&y^{(i)}=0\end{cases}

原代价函数的前一项为0时,后一部分的约束条件(s.t.)必须对于所有的样本都成立。这种思想是一种反推思想,初次接触可能较难理解。

大间隔分类器

假设现在有一个线性可分(Linearly Separable)的训练集,即决策边界可以是一条直线、一个平面,或者更高维度的超平面。以下图为例,通过上述我们讨论的内容,SVM 可以找到一条黑色直线,其相比于其他的直线似乎更能区分开两个类别的样本数据。更一般的表述为

  • 可以找到两条平行于黑色直线的蓝色直线,保证两条蓝色线中间没有任何数据点,且黑色直线被包含其中
  • 这两条蓝色线可以充当边界,他们区分了两种类别的数据
  • 黑色线到两条蓝色线的距离等距,这个距离称作间隔(Margin)
  • SVM 模型总是试图寻找具有大间隔的决策边界

因此,SVM也被称作大间隔分类器

当然,上述内容都建立在 CC 很大的假设上。我们前面提到过,SVM 的代价函数形式和一般的代价函数是有区别的。他们之中的超参数分别是 CCλ\lambda,而且不难发现 C1λC\Leftrightarrow \dfrac{1}{\lambda},因此 CC 很大就意味着 λ\lambda 很小,此时模型很容易过拟合。

因此,超参数 CC 不应该设置的过大,下图直观地展现了这一观点。

直观理解

接下来先讨论一个线性可分,特征数 n=2n=2θ0=0\theta_0=0 的二分类问题。

给定两个平面向量 u=(u1,u2)T,v=(v1,v2)T\boldsymbol{u}=(u_1,u_2)^T,\boldsymbol{v}=(v_1,v_2)^T,定义内积

u,v=uTv=uv=u1v1+u2v2R\langle\boldsymbol{u},\boldsymbol{v}\rangle=\boldsymbol{u}^T\boldsymbol{v}=\boldsymbol{u}\cdot\boldsymbol{v}=u_1v_1+u_2v_2\in \mathbb{R}

根据中学知识,两个向量的内积可以看做其在同一个方向上投影的乘积。设 ppv\boldsymbol{v}u\boldsymbol{u} 上的有向投影,那么内积的定义式等价于

u,v=puR\langle\boldsymbol{u},\boldsymbol{v}\rangle=p\cdot\|\boldsymbol{u}\|\in \mathbb{R}

其中 u\|\boldsymbol{u}\| 表示 u\boldsymbol{u} 的模长或范数,即 u=u12+u22R\|\boldsymbol{u}\|=\sqrt{u^2_1+u^2_2}\in \mathbb{R}

给定线性可分的训练集,目前的优化目标为

min12(θ12+θ22),s.t. x(i) with θ{θTx(i)1,y(i)=1θTx(i)1,y(i)=0\min \frac{1}{2}(\theta_1^2+\theta_2^2),\quad \text{s.t. $\forall \boldsymbol{x}^{(i)}$ with $\boldsymbol{\theta}$, }\begin{cases}\boldsymbol{\theta}^T\boldsymbol{x}^{(i)}\geqslant 1,&y^{(i)}=1\\\boldsymbol{\theta}^T\boldsymbol{x}^{(i)}\leqslant -1,&y^{(i)}=0\end{cases}

根据范数的定义,目标优化函数可以改写成 12θ2\dfrac{1}{2}\|\boldsymbol{\theta}\|^2。对于训练样本 (x(i),y(i))(\boldsymbol{x}^{(i)},y^{(i)}),由于 θ,x(i)\boldsymbol{\theta},\boldsymbol{x}^{(i)} 在此例子中都视作一个二维向量(θ0=0\theta_0=0),因此有

θTx(i)=θ1x1+θ2x2=p(i)θ,p(i) is the projection of x(i) on θ\boldsymbol{\theta}^T\boldsymbol{x}^{(i)}=\theta_1x_1+\theta_2x_2=p^{(i)}\|\boldsymbol{\theta}\|,\quad p^{(i)} \text{ is the projection of $\boldsymbol{x}^{(i)}$ on $\boldsymbol{\theta}$}

因此可以改写目标优化的限制条件为

x(i) with θ{p(i)θ1,y(i)=1p(i)θ1,y(i)=0\text{$\forall \boldsymbol{x}^{(i)}$ with $\boldsymbol{\theta}$, }\begin{cases}p^{(i)}\|\boldsymbol{\theta}\|\geqslant 1,&y^{(i)}=1\\p^{(i)}\|\boldsymbol{\theta}\|\leqslant -1,&y^{(i)}=0\end{cases}

设有一过原点直线 LL ,其法向量为 θ\boldsymbol{\theta},也就是说 θ\boldsymbol{\theta} 与直线 LL 垂直。由于我们要优化 θ\|\boldsymbol{\theta}\| 最小,介于限制条件,此时我们需要让每个样本点对参数向量的投影 p(i)p^{(i)} 都尽可能大,而投影 p(i)p^{(i)} 等价于该点到直线 LL 的有向距离,比如规定沿 θ\boldsymbol{\theta} 方向为正

下图给出了两个不同的 LL,可以发现右图是 SVM 选择的间隔更大的决策边界。也就是寻找使得不同类别样本点到自身距离都尽可能大的直线。这样就找到了具有最大间隔的决策边界,因为计算点到直线的距离是很简单的。

更一般的推导,我会以后单独开一篇日志。

核函数


非线性可分集

前面提到的几个 SVM 的例子都是线性可分的,即可以找到直线、平面等线性函数作为具有最大间隔的决策边界。通常情况下,决策边界无法表示成线性函数的形式,也就是说训练集数据是个非线性可分集。此时,我们可以考虑构造新的特征量,使得原始特征被映射到一个更高维的特征空间中,并且数据在这个更高维度空间中是线性可分的。这便是核函数(Kernel Function)的基本思想。

举例来说,假设有特征量 x1,x2x_1,x_2,我们想要把这些特征量映射为三个全新的特征量 f1,f2,f3f_1,f_2,f_3。如果 f1,f2,f3f_1,f_2,f_3 组成的新特征集合是一个线性可分集,那我们就可以使用大间隔分类器。

高斯核

不妨假设在 x1,x2x_1,x_2 的特征空间 R2\mathbb{R}^2 中选取了三个标记点(Landmarks) l(1),l(2),l(3)R2\boldsymbol{l}^{(1)},\boldsymbol{l}^{(2)},\boldsymbol{l}^{(3)}\in \mathbb{R}^2。定义高斯核函数(Gaussian Kernel Function)为

fi=K(x,l(i))=exp(xl(i)2σ2),σ2 is a hyperparameterf_i=K(\boldsymbol{x},\boldsymbol{l}^{(i)})=\exp\left(-\frac{\|\boldsymbol{x}-\boldsymbol{l}^{(i)}\|}{2\sigma^2}\right),\quad \sigma^2\text{ is a hyperparameter}

上述核函数源于高斯分布,又称正态分布。高斯核函数的作用是衡量 x\boldsymbol{x}l(i)\boldsymbol{l}^{(i)} 之间的相似度,其值域在 [0,1][0,1] 之间

  • xl(i)\boldsymbol{x}\approx \boldsymbol{l}^{(i)} 时,K(x,l(i))1K(\boldsymbol{x},\boldsymbol{l}^{(i)})\approx 1
  • xl(i)\|\boldsymbol{x}-\boldsymbol{l}^{(i)}\| 较大时时,K(x,l(i))0K(\boldsymbol{x},\boldsymbol{l}^{(i)})\approx 0
  • σ2\sigma^2 控制核函数的宽度,即影响的范围

下图给出了不同 σ2\sigma^2 的高斯核函数图像。

因此,我们对于每一个特征量 x=(x1,x2)T\boldsymbol{x}=(x_1,x_2)^T,经过高斯核函数映射后得到了新特征量 f=(f1,f2,f3)T\boldsymbol{f}=(f_1,f_2,f_3)^T。可以证明,合理的高斯核函数可以把低维度的非线性可分集映射为高维度的线性可分集。因此,假设函数改写为

h(x)={1,(θ)Tf00,(θ)Tf<0h(\boldsymbol{x})=\begin{cases}1,&(\boldsymbol{\theta'})^T\boldsymbol{f}\geqslant 0\\0,&(\boldsymbol{\theta'})^T\boldsymbol{f}<0 \end{cases}

记得在新参数向量和新特征向量中添加偏置项 θ0,f0=1\theta'_0,f_0=1

高斯核函数是最常用的一类核函数,此外还有线性核函数、多项式核函数、Sigmoid核函数等等。他们在模型上的表现,如计算效率和准确性等各不相同。

使用技巧

当样本数量较大时(m>nm>n),一种简单的选取标记点的方法便是把每一个样本的特征量 x(i)\boldsymbol{x}^{(i)} 看做标记 l(i)\boldsymbol{l}^{(i)}。此时,我们构造了从 Rn+1Rm+1\mathbb{R}^{n+1}\to\mathbb{R}^{m+1} 的映射,即有

x(i)=[x0(i)x1(i)x2(i)xn(i)][1K(x(i),l(1))K(x(i),l(2))K(x(i),l(m))]=[f0(i)f1(i)f2(i)fm(i)]\boldsymbol{x}^{(i)}=\begin{bmatrix}x_0^{(i)}\\x_1^{(i)}\\x_2^{(i)}\\\vdots\\x_n^{(i)}\end{bmatrix}\rightarrow \begin{bmatrix}1\\K(\boldsymbol{x}^{(i)},\boldsymbol{l}^{(1)})\\K(\boldsymbol{x}^{(i)},\boldsymbol{l}^{(2)})\\\vdots\\K(\boldsymbol{x}^{(i)},\boldsymbol{l}^{(m)})\end{bmatrix}=\begin{bmatrix}f_0^{(i)}\\f_1^{(i)}\\f_2^{(i)}\\\vdots\\f_m^{(i)}\end{bmatrix}

此时,令这个新特征量对应的参数为 θRm+1\boldsymbol{\theta}\in\mathbb{R}^{m+1},则目标优化函数为

min[Ci=1mL(θTf(i))+12j=1mθj2],under constrains\min \Big[C\sum_{i=1}^mL(\boldsymbol{\theta}^T\boldsymbol{f}^{(i)})+\frac{1}{2}\sum_{j=1}^m \theta_j^2\Big],\quad \text{under constrains}

其中,超参数 C,σ2C,\sigma^2 的取值对模型有所影响。

CC 过大 CC 过小 σ2\sigma^2 过大 σ2\sigma^2 过小
低偏差 高偏差 高偏差 低偏差
高方差 低方差 低方差 高方差

最后,我们来介绍一下目前为止几个分类模型的使用区别,这些都是前人的经验总结,对于特定情况可能不适用。选取合适的模型需要兼顾效率准确性等。

适用情形 线性/Logistic 回归 神经网络 SVM
mnm\approx n 可使用 可使用 可使用,不采用核函数
m>nm>n 不建议使用 可使用 可使用,采用核函数
mnm\gg n 可使用,添加新特征量 可使用 可使用,不采用核函数

KK 分类问题可以通过构造 KK 个 SVM,参考一对多分类。

代码实现


本代码基于经典的鸢尾花识别(Iris Detect)项目实现,可参考菜鸟教程

如果 Python 未安装 sklearn 包,在终端中输入

1
pip install scikit-learn -i https://pypi.tuna.tsinghua.edu.cn/simple

完整代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm, datasets
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 加载鸢尾花数据集
iris = datasets.load_iris()
X = iris.data[:, :2] # 只使用前两个特征
y = iris.target

# 将数据集划分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 创建SVM分类器
clf = svm.SVC(kernel='rbf') # 使用高斯核函数

# 训练模型
clf.fit(X_train, y_train)

# 在测试集上进行预测
y_pred = clf.predict(X_test)

# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy:.2f}")

# 绘制决策边界
def plot_decision_boundary(X, y, model):
h = .02 # 网格步长
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', marker='o')
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.title('SVM Decision Boundary')
plt.show()

plot_decision_boundary(X_train, y_train, clf)