tensorflow中如何预防过拟合

方法概述

避免过拟合的方法有很多,常用的方法有early stopping、数据集扩增、正则化、dropout。下面就概述一下,具体请参照优化算法(1)

early stoping:在发生过拟合之前提前结束。理论上是可以的,但是这个点不好把握。

数据集扩增:就是让模型见到更多的情况,可以最大化地满足全样本,但实际应用中对于未来事件的预测不理想。

正则化:通过映入范数,增强模型的泛化能力。包括L1、L2.

dropout:是网络模型中的一种方法。每次训练时舍去一些节点来增强泛化能力。

下面我们来具体看看如何实现后两种方法。

正则化

所谓的正则化, 其实就是在神经网络计算损失值的过程中, 在损失后面再加一项。 这样损失值所代表的输出与标准结果间的误差就会受到干扰, 导致学习参数w和b无法按照目标方向来调整, 实现模型无法与样本完全拟合的结果, 从而达到防止过拟合的效果

这个干扰项一定要有下面这样的特性:

1、当欠拟合时,希望它对模型误差的影响越小越好,以便让模型快速拟合实际

2、当过拟合时,希望他对模型误差的影响越大越好,以便让模型不要产生过拟合的情况。

由上面两个特性,引入两个范数:L1和L2

L1:所有学习参数w的绝对值的和。

L2:所有学习参数w的平方和然后求平方根

上图中的第一个式子是L1范式,另一个就是L2范式。loss为等式左边的结果,less(0)代表真实的loss值,less(0)后面的那一项就代表正则化,λ为一个可以调整的参数,用来控制正则化对loss的影响。对于L2,将其乘以1/2是为了反向传播时对其求导可以将数据规整。

tensorflow中的正则化

L1正则化:tf.contrib.layers.l1_regularizer(lambda)(w):lambda是正则化参数

L2正则化:tf.contrib.layers.l2_regularizer(lambda)(w):lambda是正则化参数

但是对于高版本的tensorflow的contrib不稳定,从而在高级一点的版本中删除了contrib这个库。如果想使用L2正则化就得用下面的办法:

L2的正则化函数为:tf.nn.l2_loss(t,name=None)

L1的正则化函数在tensorflow是没有自己组装的,可以自己写:tf.reduce_sum(tf.abs(w))

通过正则化改善过拟合

使用contrib里的方法:

tf.add_to_collection(‘list1’,var):将变量加入到列表list1中。

tf.get_collection(‘list1’):获得列表list1里面的所有变量。

tf.add_n(list1):将列表list1中所有的变量加起来并返回。

1
2
3
4
5
6
7
8
import tensorflow as tf
tf.add_to_collection('losses', tf.constant(2.2))
tf.add_to_collection('losses', tf.constant(3.))
with tf.Session() as sess:
print(sess.run(tf.get_collection('losses')))
print(sess.run(tf.add_n(tf.get_collection('losses'))))
#[2.2, 3.0]
#5.2
1
2
3
4
5
6
7
8
9
#使用方法
def get_weight(shape , lambda=0.0001):
var = tf.Variable(tf.random_normal( shape ), dtype = tf.float32)
tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(lambda)(var))
return var

mse_loss = tf.reduce_mean( tf.square(y_ - y))
tf.add_to_collection('losses', mse_loss)
loss = tf.add_n(tf.get_collection('losses'))

使用nn里的方法:

使用正则化非常简单,只需要在计算损失值时加上loss的正则化。

1
2
reg=0.01
loss=tf.reduce_mean((y_pred-y)**2)+tf.nn.l2_loss(weights['h1'])*reg+tf.nn.l2_loss(weight['h2'])*reg

dropout

还有一种防止过拟合的方法是dropout。这个方法的做法是:在训练过程中,每次随机选择一部分节点不要去“学习”

因为从样本数据的分析来看,数据本身是不可能很纯净的,也就是任何一个模型不能100%把数据完全分开,在某一类中一定会有一些异常数据,过拟合的问题恰恰是把这些异常数据当初规律来学习了。我们希望把异常数据过滤掉,只关心有用的规律数据。

异常数据的特点是,它与主流样本中的规律都不同,但是量非常少,相当于在一个样本中出现的概率比主流数据出现的概率低很多。我们可以利用这一点,通过在每次模型中忽略一些节点的数据学习,将小概率的异常数据获得学习的机会降低,这样这些异常数据对模型的影响就会更小了。

注意:由于dropout让一部分节点不去“学习”,所以在增加模型的泛化能力的同时,会使学习速度降低,使模型不太容易学成。所以在使用的过程中需要合理地调节到底丢弃多少节点,并不是丢弃的节点越多越好。

tensorflow中的dropout

tf.nn.dropout(x,keep_prob,noise_shape=None,seed=None,name=None)

x: 输入的模型节点。
keep_prob: 保持率。 如果为1, 则代表全部进行学习; 如果为0.8, 则代表丢弃20%的节点, 只让80%的节点参与学习。
noise_shape: 代表指定x中, 哪些维度可以使用dropout技术。 为None时, 表示所有维度都使用dropout技术。 也可以将某个维度标志为1, 来代表该维度使用dropout技术。 例如: x的形状为[n, len, w, ch], 使用noise_shape为[n, 1, 1,ch], 这表明会对x中的第二维度len和第三维度w进行dropout。
seed: 随机选取节点的过程中随机数的种子值。

全连接网络的深浅关系

在实际中,如果想使用浅层神经网络拟合复杂非线性函数,就需要靠增加的神经元个数来实现。神经元过多意味着需要训练的参数过多,这会增加网络的学习难度,并影响网络的泛化能力。因此,在增加网络结构时,一般倾向于使用更多的模型,来减少网络中所需要神经元的数量,使网络有更好的泛化能力。

----本文结束,感谢您的阅读。如有错,请指正。----
大哥大嫂过年好!支持我一下呗
0%