优化网络的原理与方法(5)--过拟合问题的解决

过拟合和欠拟合

欠拟合(Underfitting)是指模型不能够在训练集上获得足够低的误差。

过拟合(Overfitting)是指训练误差和测试误差太大。(训练集上得到的误差较小,实际测试时并不能很好的拟合)

 

泛化误差(或称测试误差)是指模型在未知的新输入数据上运行所得到的误差。

正则化(Regularization)

正则化是为了避免过拟合问题而常常采用的方法,其思想就是在损失函数中加入被称为正则化项(Regularizer)的惩罚。

import tensorflow as tf
weights = tf.constant([[1.0,2.0],
                       [-3.0,-4.0]])

#regularizer_l2是l2_regularizer()函数返回的函数,即R(W),用来计算L2正则化项的值
regularizer_l2 = tf.contrib.layers.l2_regularizer(.5)

#regularizer_l1是l1_regularizer()函数返回的函数
regularizer_l1 = tf.contrib.layers.l1_regularizer(.5)
with tf.Session() as sess:
    print(sess.run(regularizer_l2(weights)))
    #输出7.5
    print(sess.run(regularizer_l1(weights)))
    #输出5.0

带L2正则化损失函数的4层全连神经网络

import tensorflow as tf
import  numpy as np

#定义训练轮数
training_steps = 30000

#定义输入的数据和对应的标签并在for循环内进行填充
data = []
label = []
for i in range(200):
    x1 = np.random.uniform(-1, 1) #随机生成一个float类型的变量
    x2 = np.random.uniform(0, 2)
    #设置标签,这里对产生的x1和x2进行判断,如果产生的点落在半径为1的圆内,则label值为0
    #否则label值为1
    if x1**2 + x2**2 <= 1:
        data.append([np.random.normal(x1, 0.1),np.random.normal(x2,0.1)])
        #numpy.random.normal(loc=均值, scale=标准差, size=None(输出的shape,默认为None,只输出一个值))  正态分布
        label.append(0)
        #append()方法用于将传入的对象附加(添加)到现有列表中。
    else:
        data.append([np.random.normal(x1, 0.1), np.random.normal(x2, 0.1)])
        label.append(1)

#numpy的hstack()函数用于在水平方向将元素堆起来
#函数原型numpy.hstack(tup),参数tup可以是元组、列表、或者numpy数组,
#返回结果为numpy的数组。reshape()函数的参数-1表示行列进行翻转。
#这样处理的结果为data变成了200x2大小的数组,而label是100x1
data = np.hstack(data).reshape(-1,2)
label = np.hstack(label).reshape(-1, 1)

#定义完成前向传播的隐层
def hidden_layer(input_tensor,weight1,bias1,weight2,bias2,weight3,bias3):
    layer1=tf.nn.relu(tf.matmul(input_tensor,weight1)+bias1)
    layer2 = tf.nn.relu(tf.matmul(layer1, weight2) + bias2)
    return tf.matmul(layer2,weight3)+bias3


x = tf.placeholder(tf.float32, shape=(None, 2),name="x-input")   #x1,x2
y_ = tf.placeholder(tf.float32, shape=(None, 1),name="y-output")  #y_  标签值

#定义权重参数和偏置参数
weight1 = tf.Variable(tf.truncated_normal([2,10],stddev=0.1))   #layer1包含10个神经元
bias1 = tf.Variable(tf.constant(0.1, shape=[10]))
weight2 = tf.Variable(tf.truncated_normal([10,10],stddev=0.1))   #layer2包含10个神经元
bias2 = tf.Variable(tf.constant(0.1, shape=[10]))
weight3 = tf.Variable(tf.truncated_normal([10,1],stddev=0.1))
bias3 = tf.Variable(tf.constant(0.1, shape=[1]))

#用len()函数计算data数组的长度
sample_size = len(data)

#得到隐层前向传播结果
y= hidden_layer(x,weight1,bias1,weight2,bias2,weight3,bias3)

#自定义的损失函数。pow()函数用于计算幂函数,原型为pow(x,y,name=None)
#返回结果为x的y次幂,这里返回结果为(y_-y)^2用于衡量计算值与实际值的差距
error_loss = tf.reduce_sum(tf.pow(y_ - y, 2)) / sample_size
tf.add_to_collection("losses", error_loss)      #加入集合的操作,将元素error_loss添加到列表losses中

#在权重参数上实现L2正则化
regularizer = tf.contrib.layers.l2_regularizer(0.01)
regularization = regularizer(weight1)+regularizer(weight2)+regularizer(weight3)
tf.add_to_collection("losses",regularization)     #加入集合的操作,再将元素regularization添加到列表losses中

#get_collection()函数获取指定集合中的所有个体,这里是获取所有损失值
#并在add_n()函数中进行加和运算
loss = tf.add_n(tf.get_collection("losses"))

#定义一个优化器,学习率为固定为0.01,注意在实际应用中这个学习率数值应该大于0.01
train_op = tf.train.AdamOptimizer(0.01).minimize(loss)

with tf.Session() as sess:
    #在使用这个结构之前, 必须先初始化所有之前定义的Variable
    #tf.global_variables_initializer().run()
    init = tf.global_variables_initializer()  
    sess.run(init) 
    #在for循环内进行30000训练
    for i in range(training_steps):
        sess.run(train_op, feed_dict={x: data, y_: label})  #placeholder

        #训练30000轮,但每隔2000轮就输出一次loss的值
        if i % 2000 == 0:
            loss_value = sess.run(loss, feed_dict={x: data, y_: label})
            print("After %d steps, loss_value is: %f" % (i,loss_value))

 上面这个模型可以作为一个模板,以后的编程实践中,基本都会围绕这个模型的思路展开。

Bagging(装袋)方法

从原始样本中获得多个训练集分别进行训练,得到多个模型,最终取最优的或者取平均。

 

1)从原始样本集中抽取训练集。 每轮从原始样本集中使用有放回随机抽样的方法抽取m个训练样本(训练样本集都和原始样本集的样本数量相同)。共进行T轮抽取,得到T个训练集。

Bagging的优势在于当原始样本中有噪声数据时,通过bagging抽样,那么就有(1-1/n)^n的噪声样本不会被训练。对于受噪声影响的学习器,bagging对模型是有帮助的。所以说bagging可以使模型不容易受噪声的影响,广泛应用在不稳定的模型,或者倾向于过拟合的模型。

2)每次使用一个训练集得到一个模型,T个训练集共得到T个模型。

3) 对分类问题:将上步得到的T个模型采用投票的方式得到分类结果;对回归问题,计算上述模型的均值作为最后的结果。

Dropout方法

dropout是指在神经网络训练过程中,以一定的概率随机丢弃神经元(注意是暂时丢弃),以减少神经元之间的依赖性,从而提高模型的泛化能力。

左边:在训练时,每个神经单元都可能以概率p存在。

右边:在测试阶段,每个神经元都是存在的,权重参数w要乘以p,成为pw

测试过程,神经元一直都在,在测试阶段必须仿真出在训练阶段使用的网络集的行为,一种”补偿“的方案就是每个神经元的权重都乘以一个p,这样在“总体上”使得测试数据和训练数据是大致一样的。比如一个神经元的输出是x,那么在训练的时候它有p的概率参与训练,(1-p)的概率丢弃,那么它输出的期望是px+(1-p)0=px。因此测试的时候把这个神经元的权重乘以p可以得到同样的期望。

在算法中的体现是“被保留下的元素会被乘以1/keep_prob”

按照论文说法,测试阶段有

如果训练阶段直接得到测试用的W' ,训练阶段公式

这样的话训练阶段就等价的完成了对W'的训练,测试阶段不丢弃神经元直接运下面的式子

import numpy as np
def dropout(x, keep_prob,type="train"):
    if keep_prob < 0. or keep_prob>= 1:  # dkeep_prob是概率值,必须在0~1之间
        raise Exception('Dropout level must be in interval [0, 1].')
    if type=="train":
        scale = 1. / keep_prob
        mask_vec = np.random.binomial(n=1, p=keep_prob,size=x.shape)  # 即将生成一个0、1分布的向量,0表示这个神经元被屏蔽,不工作了,也就是dropout了
        print (mask_vec)

        x *= mask_vec     # 0、1与x相乘,我们就可以屏蔽某些神经元,让它们的值变为0
        x *= scale       #再乘上scale系数
        
    return x

x=np.array([100,29.5,1,2.0,3,4,23,12,34,45,667,76])
keep_prob=0.5

dropout(x,keep_prob,"train")
print(x)

#TensorFlow中实现Dropout功能的函数
#tf.nn.dropout(
    x,
    keep_prob,
    noise_shape=None,
    seed=None,
    name=None
    )
import tensorflow as tf

#定义x作为需要进行dropout处理的数据
x = tf.Variable(tf.ones([10, 10]))  #tf.ones()函数是进行初值为0的矩阵的生成,

#定义dro作为dropout处理时代keep_prob参数
dro = 0.5

#定义一个dropout操作
#函数原型dropout(x,keep_prob,noise_shape,seed,name)
y = tf.nn.dropout(x, dro)

init = tf.initialize_all_variables()
with tf.Session() as sess:
    sess.run(init)
    print (sess.run(y))

 

A Practical Guide for Training Dropout Networks:

(1)Learning Rate and Momentum: 
  dropout的引入产生了很多噪声,为了降低噪声的影响,可以通过以下两种方式:Learning Rate的取值是普通网络的10-100倍;momentum:momentum对于标准网络一般采用0.9,对于dropout网络一般是0.95-0.99。两种可以同时使用
  
(2)Max-norm Regularization: 
  大的Learning Rate and Momentum会造成网络参数太大,一般给参数权重设置一个约束上限c,c一般取值3-4。 
  
(3)Dropout Rate 
  一般取值0.5~0.8。经过交叉验证,隐藏层节点dropout率等于0.5的时候效果最好,原因是0.5的时候dropout随机生成的网络结构最多。

 

参考文献:Dropout  A Simple Way to Prevent Neural Networks from

 

欢迎交流指正!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值