正则化
正则化是机器学习中一种常见的概念。正则化不仅在深度学习中有,在传统的机器学习中也有。
单纯从名字上不好理解。但是其实它的意义还是比较简单的。
泛化能力
机器学习中,通常通过大量样本放入模型中训练然后得到待定的系数。
而不论是哪种模型我们都希望这种模型在精确的前提下尽可能的简洁。这里我们所说的精确不止是在测试集上精确就够了。
泛化能力好: 模型在测试集以及其他验证集上也要表现的同样好。
日常: 对于观察到的各种认知对象来说,描述共性的东西越抽象,越简洁,其泛化性也就越好。
相反,越是精确描述个体的东西,通常“个性化”的特点就非常明显,越具体,越复杂,泛化性就越差。
泛化能力举例
我们描述一个物体是方的。通常指这是一个四边形,两两平行,并两两垂直。

忽略了颜色,大小等诸多特征。参数变多了,有了约束性,泛化性变低。
描述的更为具体,参数更多,泛化性就会是这三个词中最低的一个。
正则化的过程就是来为我们找到更为简洁的描述方式的量化过程。
L1正则化
对于损失函数的改造。

这就是改造完毕,带有正则化项的损失函数。我们之前接触到的损失函数只有C0这一部分。没有后面的:

前面的损失函数值C0,我们称之为经验风险.

后面的表达式加入了正则项的,叫做结构风险

结构风险就是我们刚刚提到的风险,我们希望这种描述能够简洁来保证泛化性的良好。
这个正则项含义是把整个模型中所有的权重w绝对值加起来之后除以样本的总数量n。
这里n上面的分子 拉姆达 不是我们在机器学习中所提到的学习率,而是一个权重,称之为正则化系数或惩罚系数。
表示对这部分有多重视,如果你很重视结构风险,很不希望结构风险太大。我们就加大 拉姆达 的值,迫使损失函数向着权值减小的方向快速移动。
换句话说就是w的值越大,整个因子的值就越大。也就是我们说的越不简洁。
这里我们说的正则化因子其实叫做L1正则化项。
L2正则化项

只不过将绝对值变成了w的平方,将n变成了2n
L1正则项的损失函数导数

我们求偏c/ 偏w和以前不一样了。

我们反向更新的时候,也和以前不一样了。
sgn函数表示取w的符号。大于0表示正1,小于0表示负1

整个导数,除了经验风险对w贡献的部分,还有后面结构风险对于w求导贡献的部分。

L2正则项的导数

可视化正则化的实现过程。
假设在一个模型中只有两个维度,w1和w2作为待定的系数,最终的理想解在圆心或者说抛物线的最低点。

这里在第一象限只是我们画出来在第一象限。由于w1和w2在初始化时可能在空白处的
任何地方,那么在训练的过程中,w1和w2就会逐步从从初始化的位置,向圆心靠拢。
圆心就是我们的最优解,在训练过程中w1和w2会从上下左右任何可能的方向向圆心靠拢。
因为w1和w2在初始化的时候可以在任何的位置。圆心周围的这一圈蓝色的线,代表损失函数的等高线。也就是w1 w2组成的坐标点在这一圈上的任意位置产生的损失值是相同大小。
随机初始化,因此w1和w2可能出现在圈上的任意位置。显然离坐标系原点(0,0)更远的点(w1,w2)会产生更大的结构风险。因为离坐标系原点更远的点w1 w2坐标的值就会更大。
这里我们再看下黄色圆圈和黄色正方形所围成的面积,就分别代表L1和L2正则化公式所产生的损失值。
左边是L2的,右边是L1的。边缘的圆圈线和直线分别表示他们各自的损失函数值的等高线。

看左边的公式就可以知道L2围成一个圆形,L1围成一个正方形。这里加入正则化项之后损失就会由两部分组成,一个是上面的这个蓝色圈圈,一个是下面黄色的部分。
那么在训练时,上面的部分会约束w向着圆心收敛,下面这一部分会约束w1向着原点收敛。

最后的解会兼顾这两部分,也就是图中的w星这点。
L2正则项的导数
如何在代码中添加正则化项。我们准备在代码里添加L2正则化项。

L2正则化项主要是改变了W的更新公式。这里出现了一个变量 拉姆达。
这个变量是我们人工指定的。
首先SGD方法中添加一个lmbda变量,默认值0.0
def SGD(self, training_data, epochs, mini_batch_size, eta,
lmbda = 0.0,
test_data=None):
找到w的更新公式。将lmbda传进去。
# 训练mini_batch
for mini_batch in mini_batches:
self.update_mini_batch(mini_batch, eta, lmbda, n)
同时我们也要传入训练集的总个数n,接着我们要处理update_mini_batch方法。
# 更新mini_batch
def update_mini_batch(self, mini_batch, eta, lmbda, n):
为w的更新方程添加后面那一项。

# 更新权重和偏置 Wn+1 = wn - eta * nw
self.weights = [(1 - eta*(lmbda/n))*w - (eta / len(mini_batch)) * nw
for w, nw in zip(self.weights, nabla_w)]
self.biases = [b - (eta / len(mini_batch)) * nb
for b, nb in zip(self.biases, nabla_b)]
提取公因式。

网友评论