公众号:月来客栈,欢迎关注!微信: nulls8

模型产生过拟合的现象表现为: 在训练集上误差较小,而在测试集上误差较大。并且笔者还说到,之所以产生过拟合现象是由于训练数据中存在一定的噪音,而我们为了尽可能的做到拟合每一个样本点(包括噪音),往往就会使用复杂的模型。最终使得训练出来的模型很大程度上受到了噪音数据的影响,例如真实的样本数据可能更符合一条直线,但是由于个别噪音的影响使得训练出来的是一条弯曲的曲线,从而使得模型在测试集上表现糟糕。因此,我们可以将这一过程看作是 糟糕的训练集导致了糟糕的泛化误差。但仅仅从过拟合的表现形式来看 糟糕的测试集(噪音多)也能导致糟糕的泛化误差。接下来,本篇文章就分别从这两个角度来介绍一下 正则化(regularization) 方法中最常用的 正则化是如何解决这个问题的。

1 正则化

以线性回归为例,假设现在我们给线性回归的目标函数后面再加上一个 正则化项,看看会发生什么样的变化:

公式 中的红色部分便是我们新加入的 正则化项,它有什么作用呢?根据先前的介绍可以得知,当真实值与预测值之间的误差越小(表现为损失值趋于 ),也就代表着模型的预测效果越好,并且可以通过最小化目标函数来达到这一目的。由公式 可知,为了最小化目标函数 ,红色项的结果也必将逐渐的趋于 。这使得最终优化求解得到的 均趋于 附近,进而得到一个平滑的预测模型。那这样做的好处是什么呢?

1.1 糟糕的测试集导致糟糕的泛化误差

所谓糟糕的测试集导致糟糕的泛化误差是指:训练集本身没有多少噪音,但是由于测试集含有大量噪音,使得训练出来的模型在测试集上没有足够的泛化能力,而产生了较大的误差。这种情况可以看作是模型过于准确而出现了过拟合现象。那正则化方法是怎么解决这个问题的呢?

假如式子 就是根据 中的目标函数训练得到的预测模型:

现在新输入样本(含噪声)的某个特征维度由训练时的 变成了现在的 ,那么其预测输出就由训练时的 变成了现在的 ,即产生了 的误差。但是,由于 接近于 附近,所以这使得最终只会产生很小的误差。且如果 越是接近于 ,产生的误差就越小,也就意味着模型越能够抵抗噪音的干扰,一定程度提升了模型的泛化能力[1]。

由此便可以知道,通过在原始目标函数中加入正则化项,便能够使得训练得到的参数趋于平滑,进而能够使得模型对噪音数据不再那么敏感,缓解了模型过拟合的现象

1.2 糟糕的训练集导致糟糕的泛化误差

所谓糟糕的训练集导致糟糕的泛化误差是指:由于训练集中包含有部分噪音,我们在训练过程中为了能够尽可能的最小化目标函数而使用了较为复杂的模型,使得最终得到模型并不能在测试集上有较好的泛化能力。但这种情况就完全是因为模型不准确而出现了过拟合的现象,这也是最常见的过拟合原因。那 正则化方法又是怎么解决在训练过程中就能够能够降低对噪音数据的敏感度的呢?为了便于后面理解,我们先从图来直观理解一下正则化到底对目标函数做了什么。

如图所示,左右两边红色曲线为原始目标函数,蓝色曲线为加了 正则化后的目标函数。可以看出红色曲线的极值均发生了改变,也就是产生极值的极值点均发生了改变,且不约而同的都更靠近原点了。再来看一张等高线的投影图:

图中红色曲线同样为原始目标函的等高线,蓝色曲线为施加正则化后目标函数的等高线。可以看出,目标函数的极值点同样发生了变化,从原始的 变成了 ,而且也是更靠近原点( 变得更小了)。到此我们似乎可以发现, 正则化具有能够使得原始目标函数极值点发生改变,且同时还有使参数变小的作用。 事实上也正是因为这个原因才使得正则化具有缓解过拟合的作用,但原因在哪儿呢?

以目标函数 为例,其取得极值的极值点为 ,且 在极值点处的梯度为 。当对其施加正则化 时,由于 的梯度方向是远离原点的(因为 为一个二次曲面),所以给 目标函数加上正则化,实际上就等价于给目标函数施加了一个远离原点的梯度[2]。说得通俗点就是,正则化给原始目标函数的极值点施加了一个远离原点的梯度(甚至可以想象成是施加了一个力的作用)。因此,这也就意味着对于施加正则化后的目标函数 来说, 的极值点(上图蓝色圆点)相较于 的极值点(上图红色原点)更加的靠近与原点。而这也就是正则化本质之处。做完了铺垫,下面进入正题:

假如有一个模型 ,它在含有噪音的训练集上表示异常出色,使得目标函数 的损失值等于 (也就是拟合到了每一个样本点),即在 处取得了极值。现在,我们在 的基础上加入了正则化项构成新的目标函数 ,然后我们来分析一下通过最小化 求得的模型 到底产生了什么样的变化。

由于 是由 加正则化项构成,同时根据先前的铺垫可知, 将在离原点更近的极值点 处取得 的极值,也即是通过最小化含正则化项的目标函数 ,我们将得到 这个最优解。但是请注意,此时的 将不再是 的最优解,即 。因此通过最小化 求得的最优解 将使得 ,而这就意味着模型 比模型 更简单了,也就代表着从一定程度上缓解了 的过拟合现象。

同时,由公式 可知,通过增大参数 的取值则可以增大正则化项对应的梯度,而这将使得最后求解得到更加简单的模型(参数值更加的趋近于 0)。也就是 ** 越大,一定程度上越能缓解模型的过拟合现象**。因此,参数 又叫做惩罚项或者惩罚系数。最后,从上面的分析可知,在第一种情况中正则化可以看作是使得训练好的模型不再对噪音数据那么敏感;而对于第二种情况来说,正则化则可以看作是使得模型不再那么复杂。但其实两者归结起来都是一回事儿,那就是通过较小的参数取值,使得模型变得更加简单。

1.3 简单模型

通过上面的介绍,现在我们已经知道了 正则化是如何来简化模型的。但是有的朋友可能还存在着一个疑惑(或者误解):认为高次数多项式表示的模型一定比低次数多项式表示的模型复杂,例如 5 次多项式就要比 2 次多项式复杂,而这是错的[3]。高次项代表的是更大的模型空间,其中既包含了复杂的模型,也同时包含了简单的模型。而我们只需要将复杂模型对应位置的权重参数调整到更接近于 ,就可以将其进行简化。

2 参数更新

在给目标函数施加正则化后也就意味着其关于参数的梯度发生了变化,幸运的是正则化是被加在原有目标函数中的,因此其关于参数 的梯度也只是加上了对应梯度的参数,同时关于偏置 的梯度并没有改变。下面就总结一下线性回归和逻辑回归算法加上 正则化后的变化。

2.1 线性回归

其中红色部分为加入 正则化后所发生的变化。

2.2 逻辑回归

其中红色部分为加入 正则化后所发生的变化。

2.3 梯度下降

其中红色部分为加入 正则化后所发生的变化,可以看出 正则化令权重 先自身乘以小于 的数,再减去不含惩罚项的梯度。因此, 正则化又叫权重衰减[4]。

3 示例

由于文章篇幅有限,在这里就只展示部分关键代码,完整示例可参见文末引用[5]。

  • 损失函数
1
2
3
4
5
 def cost_function(X, y, W, bias, lam):
    m, n = X.shape
    y_hat = prediction(X, W, bias)
    J = 0.5 * (1 / m) * np.sum((y - y_hat) ** 2)
 return J + lam / (2 * n) * np.sum(W ** 2)
  • 梯度下降
1
2
3
4
5
6
 def gradient_descent(X, y, W, bias, alpha, lam):
 #...修改梯度公式,添加正则化对应的梯度
    grad_w = -(1 / m) * np.matmul(X.T, (y - y_hat)) + (lam / n) * W
    grad_b = -(1 / m) * np.sum(y - y_hat)  # 求解梯度
 #...........
 return W, bias

下图所示左边为未添加正则化项时,训练误差和测试误差的走势,可以明显看出测试误差远大于训练误差,这是典型的过拟合现象。右图为使用正则化后训练误差和测试误差的走势,可以看出虽然训练误差有些许的增加,但是测试误差得到了很大程度上的缓解[4]。

4 总结

在这篇文章中,笔者首先通过示例详细介绍了如何通过 正则化方法来缓解模型的过拟合现象,以及介绍了为什么 正则能够使模型变得更简单。其次笔者介绍了加入正则化后原有梯度更新公式的变化之处,其仅仅只是加上的正则化项对应的梯度。最后笔者通过一个示例来展示了 正则化的效果。但与此同时,这篇文章笔