欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Tensorflow学习笔记-过度拟合问题

程序员文章站 2024-03-15 13:48:53
...

Tensorflow学习笔记-过度拟合问题

  神经网络在训练是,并不是希望模型尽量模拟训练的数据,而是希望模型对未来的数据具有准确的判断。因此,模型在训练数据上的表现并不代表对未来数据的表现。如果模型可以完全记住训练数据而使得损失函数为0,这就是引起过度拟合的问题。
  过度拟合训练数据中的随机噪声,虽然可以得到非常小的损失函数,但对未知数据很难做出判断。
  训练处理的模型一般变现出三种情况:
  Tensorflow学习笔记-过度拟合问题
  1、模型过于简单:它不能很好地给出数据变化的趋势。
  2、合理的模型:它能很好的预测数据变化的趋势,并且也不会过于关注数据中的噪声。
  3、过拟合:这种模型非常完美的区分不同的类别,由于它过度拟合训练集中的噪声,而忽略了数据变化的整体趋势,因此它不能很好的对未来数据做出判断。
  为了避免过度拟合问题,一个常用的方法就是正则化(Regularization),正则化的思想是在损失函数中加入刻画模型复杂程度的指标。假设一个模型的损失函数为J(θ),但正则化不是直接优化损失函数,而是优化J(θ) + λR(w):
    R(w)刻画的模型的复杂度。
    λ表示模型的复杂度在总损失中的比例。
    θ:模型中的所有参数,包括权重w和偏置项b。
   一般来说模型的复杂度只有w决定,刻化模型复杂度的模型的函数R(w)一般有两种:L1正则化和L2正则化.
   L1正则化:
  

R(w)=||w||1=i|wi|

   L2正则化:
  
R(w)=||w||21=i|w2i|

   无论是哪一种正则化,目的都是为了限制w的权重大小,使得模型不能过意拟合训练数据中的噪音。但这两种正则化也有很大的区别:
   1. L1正则化会使参数变得稀疏,也就是说使更多的参数变为0,而L2正则化则不会。
   2. L1正则化不可导,而L2正则化可导。
   因此,在优化时,需要计算损失函数的偏导数,所以对含有L2正则化损失函数的优化更加简洁。
   有时在实际的使用中,会将L1正则化结合L2正则化使用:
R(w)=ia|wi|+(1a)w2i

   例如:

w = tf.Variable(tf.random_normal([2,1],stddev=1,seed=1))
y = tf.matmul(x,w)
loss = tf.reduce_mean(tf.square(y-y_)+tf.contrib.layers.l2_regularizer(λ)(w))

   loss损失函数包含两个部分,第一个部分为均方误差的损失函数,它刻化了模型在训练集的表现,第二部分是L2正则化,它防止模型过度拟合训练集中的噪音。
   下面通过例子来说明L1和正则化的计算:

weights = tf.constant([[1.0,-2.0],[-3.0,4.0]])
with tf.Session() as sess:
    # 5
    print(sess.run(tf.contrib.layers.l1_regularizer(.5)(weights)))
    # 7.5
    print(sess.run(tf.contrib.layers.l2_regularizer(.5)(weights)))

   在简单的神经网络中,通过上述的方法,可以很好计算带正则化的损失函数。但如果神经网络比较复杂,那么损失函数的定义就会变得比较复杂,这样对造成代码的可读性变差。并且随着神经网络的层数增加,神经网络的定义部分和损失函数的计算不在同一个函数,就可能就会引起出错。因此,为了增强代码的可读性及避免网络结构的设计部分与损失函数的计算不在同一个函数,而需要使用Tensorflow提供的集合,它可以很方便的管理具有同一名称的变量。

# 定义神经网络的权重,并将损失函数加入到collection中
def get_weight(shape,lamba):
    var = tf.Variable(tf.random_normal(shape),dtype=tf.float32)
    tf.add_to_collection('losses',tf.contrib.layers.l2_regularizer(lamba)(var))
    return var

batch_size = 8

# 使用seed=1 保证每次的出初始化的值都是相同的
w1 = tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2 = tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))

x = tf.placeholder(tf.float32,shape=[None,2],name='x-input')
y_ = tf.placeholder(tf.float32,shape=[None,1],name='y-input')

# 定义每层的节点数
layer_dimension = [2,10,10,10,2]
n_layers = len(layer_dimension)
cur_layer = x
in_dimension = layer_dimension[0]

for i in range(1,n_layers):
    out_dimension = layer_dimension[i]
    # 生成当前的权重变量,并将它的L2正则化加入图上的集合
    weight = get_weight([in_dimension,out_dimension],0.001)
    bias = tf.Variable(tf.constant(0.1,shape=[out_dimension]))
    cur_layer = tf.nn.relu(tf.matmul(cur_layer,weight) + bias)
    in_dimension = layer_dimension[i]

# 将模型在训练数据中表现的损失函数加入集合中
mse_loss = tf.reduce_mean(tf.square(y_ - cur_layer),name='mes_loss')
tf.add_to_collection('losses',mse_loss)
# 将每个环节的损失函数加起来就是最终的损失函数。
loss = tf.add_n(tf.get_collection('losses'))