TensorFlow学习系列:
TensorFlow_1参数初始化方法
TensorFlow_2学习率
TensorFlow_3激活函数
TensorFlow_4正则化
TensorFlow_5dropout
TensorFlow_6断点续训与Tensorboard可视化
TensorFlow_7优化器
TensorFlow_8损失函数
避免过拟合的方法之一是增加训练数据数量。那么,还有没有别的方法能让我们避免过拟合呢?一种可能的方法是减小网络的规模。然而,我们并不情愿减小规模,因为大型网络比小型网络有更大的潜力。幸好,哪怕使用固定的网络和固定的训练数据,我们还有别的方法来避免过拟合。这就是所谓的正则化(regularization)技术。
一 、正则化的目的:解决过拟合
1.1 过拟合现象
如图,在线性回归中:
- 最左边的图:使用一条直线进行数据的拟合,但是这个模型并没有很好的拟合数据,产生很大的偏差。这种现象称为欠拟合。
- 中间的图:使用一个二次函数进行拟合,得到很好的拟合结果。
- 右边的图:使用更高阶的多项式进行拟合,这个模型通过了所有的训练数据,使代价函数 约等于0甚至等于0。但是这是一条极度不规律扭曲的曲线,它并不是一个好的模型。这种现象称为过拟合。
过拟合现象:如果我们使用高阶多项式,变量(特征)过多,那么这个函数能够很好的拟合训练集,但是却会无法泛化到新的数据样本中(泛化:一个假设模型能够应用到新样本的能力)。当存在较多的变量,较少的训练数据,使得没有足够的训练集来约束这个变量过多的模型,就会导致过拟合的现象。
1.2 解决过拟合问题思路
- 1)减少变量的个数:舍弃一些变量,保留更为重要的变量。但是,如果每个特征变量都对预测产生影响。当舍弃一部分变量时,也就舍弃了一些信息。所以,希望尽量保留所有的变量。
- 2)增加样本数量
- 3)Droput:会单独写一篇。
- 4)正则化:保留所有的变量,将一些不重要的特征的权值置为0或权值变小使得特征的参数矩阵变得稀疏,使每一个变量都对预测产生一点影响。
二、 正则化
2.1 常见正则化方法
回想一下,在线性回归等问题中,我们定义了损失函数:
注:这里的θ是指所有的参数,包括权重w等
我们发现,这样学习的模型虽然在测试集上比较好,但是泛化能力一般,于是就有了参数惩罚的思路,直接给J()后面加个惩罚项(拖住学习的节奏),也就是正则化项,损失函数变成了:
其中α∈[0,∞)是惩罚系数,那么这个惩罚项Ω(θ) 是什么呢?在神经网络中又是怎样使用呢?
在神经网络中,参数包括每一层仿射变换的权重和偏置,我们通常只对权重做惩罚而不对偏置做正则惩罚。精确拟合偏置所需的数据通常比拟合权重少得多,且每个权重会指定两个变量如何相互作用。我们需要在各种条件下观察这两个变量才能良好地拟合权重。而每个偏置仅控制一个单变量。这意味着,我们不对其进行正则化也不会导致太大的方差。另外,正则化偏置参数可能会导致明显的欠拟合。因此,我们使用向量 w 表示所有应受范数惩罚影响的权重,而向量 θ 表示所有参数 (包括 w 和无需正则化的参数)。
在神经网络的情况下,有时希望对网络的每一层使用单独的惩罚,并分配不同 的 α系数。寻找合适的多个超参数的代价很大,因此为了减少搜索空间,我们会在所有层使用相同的权重衰减(L2正则化)。
2.2 L2正则化
说起L2正则化,它指权值向量w中各个元素的平方和然后再求平方根(可以看到Ridge回归的L2正则化项有平方符号),通常表示为 数学表示为:
其目的是使权重更加接近原点1。在其他学术圈, L2 也被称为岭回归或 Tikhonov 正则。那它是怎么实现权重衰减的呢?我们用线性代数表示一下损失函数:
我们对权重求取梯度得到:
β为梯度下降的步长,最终我们得到了:
我们可以看到,加入权重衰减后会引起学习规则的修改,即在每步执行通常的梯度更 新之前先收缩权重向量(将权重向量乘以一个常数因子)。其实L2的本质是:L2正则化能让学习算法 ‘‘感知’’ 到具有较高方差的输入 x,因此与输出目标的协方差较小(相对增加方差)的特征的权重将会收缩。
Tensoflow的实现方式:
import tensorlfow as tf
tf.contrib.layers.l2_regularizer(
scale,
scope=None
)
"""
Returns a function that can be used to apply L2 regularization to weights.
Small values of L2 can help prevent overfitting the training data.
Args:
scale: A scalar multiplier Tensor. 0.0 disables the regularizer.
scope: An optional scope name.
"""
# 具体的实现方式
def get_weight(shape):
return tf.Variable(tf.random_normal(shape),dtype=tf.float32)
def get_loss(shape,lambda):
var = get_weight(shape)
loss = tf.reduce_mean(tf.square(y_ - cur_layer))+tf.contrib.layers.l2_regularizer(lambda)(var))
return loss
2.3 L1正则化
说起L1正则化,它和L2之间区别很小,是指权值向量w中各个元素的绝对值之和,通常表示为,表示为:
那么损失函数就变成了:
求解梯度后就和L2之间有点区别了,它的梯度为:
其中 sign(w) 只是简单地取 w 各个元素的正负号,我们立刻发现 L1 的正则化效果与 L2 大不一样。
具体来说,我们可以看到正则化对梯度的影响不再是线性地缩放每个 wi;而是添加了一项与 wi 同号的常数。使用这种形式的梯度之后,我们不一定能得到 J(X;y;w)二次近似的直接算术解(L2正则化时可以)。
另外一个比较特征就是 L2正则化不会使参数变得稀疏,而L1正则化有可能通过足够大的α实现稀疏。由 L1正则化导出的稀疏性质已经被广泛地用于特征选择(feature selection)机制。 特征选择从可用的特征子集选择出有意义的特征,化简机器学习问题。
同样的道理,L1正则化的tensorlfow代码只是使用了不同的接口而已,L2换成L1即可
import tensorlfow as tf
tf.contrib.layers.l1_regularizer(
scale,
scope=None
)
# 具体的实现方式
def get_weight(shape):
return tf.Variable(tf.random_normal(shape),dtype=tf.float32)
def get_loss(shape,lambda):
var = get_weight(shape)
loss = tf.reduce_mean(tf.square(y_ - cur_layer))+tf.contrib.layers.l1_regularizer(lambda)(var))
return loss