上篇分析了Keras实现Dropout层的原理Keras防止过拟合(一)Dropout层源码细节,Dropout层的加入,可以很好的缓解过拟合问题。除此之外,我们在Keras的模型搭建中,也可以使用L1 L2正则化。
L1正则化与L2正则化如果对L1、L2正则化完全不了解的,推荐这篇文章机器学习中正则化项L1和L2的直观理解,讲解的十分清楚。
L2正则化比L1更适合解决过拟合问题(L2正则化最后可以得到一个参数都比较小的模型,抗扰动能力强),L1正则化则有利于产生稀疏矩阵、特征选择。所以在解决过拟合问题
实现L1、L2正则化的方法十分简单。L1正则化是将系数的绝对值之和加入损失函数,L2正则化是将系数绝对值平方之和加入损失函数。总结为两步:
1.计算L1或L2正则化的值
2.将其加入最终损失函数
源码位于kerasregularizers.py中:
class L1L2(Regularizer): """Regularizer for L1 and L2 regularization. # Arguments l1: Float; L1 regularization factor. l2: Float; L2 regularization factor. """ def __init__(self, l1=0., l2=0.): self.l1 = K.cast_to_floatx(l1) self.l2 = K.cast_to_floatx(l2) def __call__(self, x): regularization = 0. if self.l1: regularization += self.l1 * K.sum(K.abs(x)) if self.l2: regularization += self.l2 * K.sum(K.square(x)) return regularization def get_config(self): return {'l1': float(self.l1), 'l2': float(self.l2)} def l1(l=0.01): return L1L2(l1=l)def l2(l=0.01): return L1L2(l2=l)def l1_l2(l1=0.01, l2=0.01): return L1L2(l1=l1, l2=l2)计算部分没什么好说的,需要注意的是参数x是正则化系数,最后面的def l1(),def l2()和def l1_l2()。在层中定义正则化时会使用到。
如何将其加入最终损失函数,拿Dense层为例:
#Dense层部分代码def __init__(self, units, activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None, **kwargs): self.kernel_regularizer = regularizers.get(kernel_regularizer) self.bias_regularizer = regularizers.get(bias_regularizer) self.activity_regularizer = regularizers.get(activity_regularizer)def build(self, input_shape): assert len(input_shape) >= 2 input_dim = input_shape[-1] self.kernel = self.add_weight(shape=(input_dim, self.units), initializer=self.kernel_initializer, name='kernel', regularizer=self.kernel_regularizer, constraint=self.kernel_constraint)可以看到,正则化的添加,kernel,bias,activity是分开的。构建模型时,想用哪个,定义哪个。
将正则化值添加进损失函数,主要表现在add_weight部分,keras层都继承自kerasenginebase_layer.py,其中有add_weight的定义:
add_weight函数是用来添加参数的,在其定义中,专门有将正则化值加入损失函数的部分。
模型中加入L1 L2正则化在Keras已经定义好的层中加入正则化十分简单,在定义层时加入即可:
若我们想给Dense层kernel部分(output=Wx+b中的W)加入正则化(系数设置为0.01)
LSTM中加入:
LSTM(128, input_shape=(3,256), kernel_regularizer=keras.regularizers.l2(0.01))也将偏置和激活函数加入:
Dense(256, kernel_regularizer=keras.regularizers.l1(0.01),bias_regularizer=keras.regularizers.l1(0.01),activity_regularizer=keras.regularizers.l1(0.01))上面也提过,def l1()、def l2() 、def l1_l2(),用来在定义层时调用(keras.regularizers.l1,keras.regularizers.l2,keras.regularizers.l1_l2)。
自定义层加入正则化关于自定义层如何定义,不在此说明,若有不懂,可以随便搜一下,有很多讲解,keras官方文档也有相关教程。
自定义层如同所有定义好的层一样,继承于base_layer,其参数定义也使用的是add_weight,说到这里,相信大家都明白了。只需要在定义层时,加入regularizers的定义即可,例如LSTM,其中的recurrent部分:
给自己定义的参数部分加上你想要的正则化,在_init_中定义,build中的add_weight加入。