Tensorflow——MNIST数据集/过拟合问题/Dropout算法

一、过拟合、欠拟合问题

  • 出现过拟合的原因:在机器学习模型中,若果模型的参数太多,但训练样本又少,训练出来的模型容易产生过拟合现象,具体表现为,模型在训练数据上,损失函数较小,预测准确率较高;在测试数据集上,损失函数较大,预测准确率较低。

1、欠拟合

 根本原因是特征维度过少,模型过于简单,导致拟合的函数无法满足训练集,误差较大。

2、过拟合

根本原因是特征维度过多,模型假设过于复杂,参数过多,训练数据过少,噪声较多,导致拟合的函数完美的预测训练集,但对新数据的测试集预测结果差,过度的拟合了训练数据,而没有考虑泛化能力。 

 

二、解决过拟合的方法

1、降低数据量:数据量过多可能会导致过于拟合。

2、使用合适的模型:减少网络的层数、神经元个数等均可以限制网络的拟合能力;

3、正则化方法:在代价函数后面增加正则项,在训练时限制权重变大,

                                              C = C_{0} +\frac{\lambda }{2n}\sum w^{2}

公式右边第一项是代价函数,后面增加的是正则项,训练时,使得权重w变小,限制权重值变大,其目的就是减小网络的复杂度。

4、Dropout方法:在训练神经网络时,使得部分神经元工作,部分神经元不工作。

5、增加噪声:在随机化初始权重时,加入噪声

6、数据清洗:将错误的label纠正或者删除错误数据

三、Dropout算法去除过拟合

1、以MNIST数据集作为处理的数据,先设计比较复杂的神经网络进行MNIST数据集的训练测试,模拟过拟合现象(但是此处这样演示的确有点不太合理,但是以此为参考)

  • 代码实现:

加入了Dropout方法,Dropout算法中keep_prob参数是设置有多少的神经元是工作的,在训练时,通过feed操作将确切值传入,一开始我们设置此参数为1.0,即dropout算法不起作用,增大网络层数,增大神经元个数,相当于就复杂化了训练网络,模拟数据过拟合现象。

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
#载入数据集
mnist = input_data.read_data_sets("MNIST_data",one_hot=True)
#每个批次的大小
batch_size = 100
#计算一共需要多少个批次
n_batch = mnist.train.num_examples // batch_size

#定义两个占位符(placeholder)
x = tf.placeholder(tf.float32,[None,784])
y = tf.placeholder(tf.float32,[None,10])
#再定义一个placeholder,后面设置Dropout参数
keep_prob = tf.placeholder(tf.float32)

#创建一个简单的神经网络

#新的初始化方式,此种效果更好

#第一个隐藏层
#权重
W1 = tf.Variable(tf.truncated_normal([784,2000],stddev = 0.1))  #截断的正态分布中输出随机值,标准差:stddev
#偏置值
b1 = tf.Variable(tf.zeros([2000]) + 0.1)
#使用激活函数,获得信号输出,即此层神经元的输出
L1 = tf.nn.tanh(tf.matmul(x, W1) + b1)
#调用tensorflow封装好的dropout函数,keep_prob参数是设置有多少的神经元是工作的,在训练时,通过feed操作将确切值传入
L1_drop = tf.nn.dropout(L1, keep_prob)

#第二个隐藏层:2000个神经元
W2 = tf.Variable(tf.truncated_normal([2000,2000],stddev = 0.1)) 
b2 = tf.Variable(tf.zeros([2000]) + 0.1)
L2 = tf.nn.tanh(tf.matmul(L1_drop, W2) + b2)
L2_drop = tf.nn.dropout(L2, keep_prob)

#第三个隐藏层:1000个神经元
W3 = tf.Variable(tf.truncated_normal([2000,1000],stddev = 0.1)) 
b3 = tf.Variable(tf.zeros([1000]) + 0.1)
L3 = tf.nn.tanh(tf.matmul(L2_drop, W3) + b3)
L3_drop = tf.nn.dropout(L3, keep_prob)

#最后一层输出层:10个神经元
W4 = tf.Variable(tf.truncated_normal([1000,10],stddev = 0.1)) 
b4 = tf.Variable(tf.zeros([10]) + 0.1)

prediction = tf.nn.softmax(tf.matmul(L3_drop,W4) + b4)

#方法一:二次代价函数
#loss = tf.reduce_mean(tf.square(y - prediction))

#方法二:交叉熵代价函数(cross-entropy)的使用
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))


#使用梯度下降法
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)

#初始化变量
init = tf.global_variables_initializer()

#结果存放在一个布尔型列表中
#equal中的两个值,若是一样,则返回True,否则返回False。argmax函数:返回最大值所在的索引值,即位置
correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))
#求准确率
#将上一步的布尔类型转化为32位浮点型,即True转换为1.0,False转换为0.0,然后计算这些值的平均值作为准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

#定义会话
with tf.Session() as sess:
    #初始化变量
    sess.run(init)
    #迭代21个周期
    for epoch in range(31):
        #n_batch:之前定义的批次
        for batch in range(n_batch):
            #获得100张图片,图片的数据保存在batch_xs中,图片的标签保存在batch_ys中
            batch_xs,batch_ys = mnist.train.next_batch(batch_size)
            #使用Feed操作,此步执行训练操作的op,将数据喂给他,keep_prob设置为1.0就相当于Dropout没有起作用
            sess.run(train_step,feed_dict = {x:batch_xs,y:batch_ys,keep_prob:1.0})
        #训练一个周期后就可以看下准确率,使用Feed方法,此步执行计算准确度的op操作,将其对应的参数喂给它
        test_acc = sess.run(accuracy,feed_dict = {x:mnist.test.images,y:mnist.test.labels,keep_prob:1.0})
        #用训练集做测试
        train_acc = sess.run(accuracy,feed_dict = {x:mnist.train.images,y:mnist.train.labels,keep_prob:1.0})
        print("Iter " + str(epoch) + ",Testing Accuracy " + str(test_acc) + ",Training ccuracy" + str(train_acc))
  • 结果:
Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
Iter 0,Testing Accuracy 0.9472,Training ccuracy0.9584909
Iter 1,Testing Accuracy 0.9588,Training ccuracy0.97572726
Iter 2,Testing Accuracy 0.9639,Training ccuracy0.98285455
Iter 3,Testing Accuracy 0.9661,Training ccuracy0.9862
Iter 4,Testing Accuracy 0.9686,Training ccuracy0.9883636
Iter 5,Testing Accuracy 0.9687,Training ccuracy0.9896909
Iter 6,Testing Accuracy 0.9696,Training ccuracy0.9908182
Iter 7,Testing Accuracy 0.9699,Training ccuracy0.99183637
Iter 8,Testing Accuracy 0.9703,Training ccuracy0.9924545
Iter 9,Testing Accuracy 0.9717,Training ccuracy0.9927818
Iter 10,Testing Accuracy 0.9719,Training ccuracy0.9930909
Iter 11,Testing Accuracy 0.972,Training ccuracy0.9932909
Iter 12,Testing Accuracy 0.9717,Training ccuracy0.9934545
Iter 13,Testing Accuracy 0.9725,Training ccuracy0.9936909
Iter 14,Testing Accuracy 0.9728,Training ccuracy0.9939091
Iter 15,Testing Accuracy 0.9725,Training ccuracy0.9941091
Iter 16,Testing Accuracy 0.9723,Training ccuracy0.9942909
Iter 17,Testing Accuracy 0.9725,Training ccuracy0.9944364
Iter 18,Testing Accuracy 0.9729,Training ccuracy0.9945273
Iter 19,Testing Accuracy 0.9728,Training ccuracy0.99465454
Iter 20,Testing Accuracy 0.9724,Training ccuracy0.9948182
Iter 21,Testing Accuracy 0.972,Training ccuracy0.9949091
Iter 22,Testing Accuracy 0.9725,Training ccuracy0.99505454
Iter 23,Testing Accuracy 0.972,Training ccuracy0.9951091
Iter 24,Testing Accuracy 0.9722,Training ccuracy0.9952
Iter 25,Testing Accuracy 0.9718,Training ccuracy0.9952545
Iter 26,Testing Accuracy 0.9721,Training ccuracy0.9953455
Iter 27,Testing Accuracy 0.9724,Training ccuracy0.99545455
Iter 28,Testing Accuracy 0.9731,Training ccuracy0.99552727
Iter 29,Testing Accuracy 0.9731,Training ccuracy0.99554545
Iter 30,Testing Accuracy 0.9734,Training ccuracy0.9955818


结果分析:过拟合会出现,模型能够完美的预测训练数据,但对于新的数据作为测试集,其预测结果很差,通过准确率可以看到的确Testing Accuracy和Training ccuracy存在一定的差距。

2、Dropout算法去除过拟合现象

(1)Dropout的介绍

Dropout可以作为训练深度神经网络的一种trick供选择,在每个训练批次中,通过忽略一半的特征检测器(让一半的隐藏层节点值为0),可以明显的减少过拟合现象,这种方式可以减少特征检测器(隐藏层节点)间的相互作用。检测器相互作用是指某些检测器依赖其他检测器才能发挥作用。

Dropout说的简单一点就是:我们在前向传播的时候,让某个神经元的激活值以一定的概率p停止工作,这样可以使模型泛化性更强,因为它不会太依赖某些局部的特征。

 

(2)Dropout的具体工作流程

                                                  图1   标准的神经网络

                                      图2    部分临时被删除的神经元

 

没使用Dropout之前:假设输入是x输出是y,首先把x通过网络前向传播,把误差反向传播,决定如何更新参数(修权重等参数)让网络进行学习。

 

使用Dropout之后:

1)首先随机(临时)删掉网络中一半的隐藏层的神经元,输入输出神经元保持不变,如图2所示虚线为部分临时被删除的神经元。

2)把输入x通过修改后的网络进行前向传播,然后把得到的损失结果反向传播,一小批训练样本执行完这个过程后,在没有被删除的神经元网络上按照梯度下降法更新对应的参数(w,b),权重和偏置;

3)重复此步骤:

      恢复被删除的神经元(此时被删除的神经元保持原样,而没有被删除的神经元已经有了更新:2)完成的);从隐藏层神经元中随机选择一个一半大小的神经元子集临时删除掉(备份被删除神经元的参数);对一小批训练样本,先前向传播后反向传播,使用梯度下降法更新权重和偏置值(w,b),没有被删除的那一部分神经元的参数得到了更新,被删除的神经元参数保持被删除前的结果。

不断重复上述过程。

(3)程序测试

sess.run(train_step,feed_dict = {x:batch_xs,y:batch_ys,keep_prob:1.0})

中通过Feed方法传入的keep_prob进行修改,将     keep_prob:1.0     变成      keep_prob:0.7

意思是使用70%的神经元进行训练

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
#载入数据集
mnist = input_data.read_data_sets("MNIST_data",one_hot=True)
#每个批次的大小
batch_size = 100
#计算一共需要多少个批次
n_batch = mnist.train.num_examples // batch_size

#定义两个占位符(placeholder)
x = tf.placeholder(tf.float32,[None,784])
y = tf.placeholder(tf.float32,[None,10])
#再定义一个placeholder,后面设置Dropout参数
keep_prob = tf.placeholder(tf.float32)

#创建一个简单的神经网络

#新的初始化方式,此种效果更好

#第一个隐藏层
#权重
W1 = tf.Variable(tf.truncated_normal([784,2000],stddev = 0.1))  #截断的正态分布中输出随机值,标准差:stddev
#偏置值
b1 = tf.Variable(tf.zeros([2000]) + 0.1)
#使用激活函数,获得信号输出,即此层神经元的输出
L1 = tf.nn.tanh(tf.matmul(x, W1) + b1)
#调用tensorflow封装好的dropout函数,keep_prob参数是设置有多少的神经元是工作的,在训练时,通过feed操作将确切值传入
L1_drop = tf.nn.dropout(L1, keep_prob)

#第二个隐藏层:2000个神经元
W2 = tf.Variable(tf.truncated_normal([2000,2000],stddev = 0.1)) 
b2 = tf.Variable(tf.zeros([2000]) + 0.1)
L2 = tf.nn.tanh(tf.matmul(L1_drop, W2) + b2)
L2_drop = tf.nn.dropout(L2, keep_prob)

#第三个隐藏层:1000个神经元
W3 = tf.Variable(tf.truncated_normal([2000,1000],stddev = 0.1)) 
b3 = tf.Variable(tf.zeros([1000]) + 0.1)
L3 = tf.nn.tanh(tf.matmul(L2_drop, W3) + b3)
L3_drop = tf.nn.dropout(L3, keep_prob)

#最后一层输出层:10个神经元
W4 = tf.Variable(tf.truncated_normal([1000,10],stddev = 0.1)) 
b4 = tf.Variable(tf.zeros([10]) + 0.1)

prediction = tf.nn.softmax(tf.matmul(L3_drop,W4) + b4)

#方法一:二次代价函数
#loss = tf.reduce_mean(tf.square(y - prediction))

#方法二:交叉熵代价函数(cross-entropy)的使用
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))


#使用梯度下降法
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)

#初始化变量
init = tf.global_variables_initializer()

#结果存放在一个布尔型列表中
#equal中的两个值,若是一样,则返回True,否则返回False。argmax函数:返回最大值所在的索引值,即位置
correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))
#求准确率
#将上一步的布尔类型转化为32位浮点型,即True转换为1.0,False转换为0.0,然后计算这些值的平均值作为准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

#定义会话
with tf.Session() as sess:
    #初始化变量
    sess.run(init)
    #迭代21个周期
    for epoch in range(31):
        #n_batch:之前定义的批次
        for batch in range(n_batch):
            #获得100张图片,图片的数据保存在batch_xs中,图片的标签保存在batch_ys中
            batch_xs,batch_ys = mnist.train.next_batch(batch_size)
            #使用Feed操作,此步执行训练操作的op,将数据喂给他,keep_prob设置为1.0就相当于Dropout没有起作用
            sess.run(train_step,feed_dict = {x:batch_xs,y:batch_ys,keep_prob:0.7})
        #训练一个周期后就可以看下准确率,使用Feed方法,此步执行计算准确度的op操作,将其对应的参数喂给它
        test_acc = sess.run(accuracy,feed_dict = {x:mnist.test.images,y:mnist.test.labels,keep_prob:1.0})
        #用训练集做测试
        train_acc = sess.run(accuracy,feed_dict = {x:mnist.train.images,y:mnist.train.labels,keep_prob:1.0})
        print("Iter " + str(epoch) + ",Testing Accuracy " + str(test_acc) + ",Training ccuracy" + str(train_acc))

结果:

Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
Iter 0,Testing Accuracy 0.9187,Training ccuracy0.91203636
Iter 1,Testing Accuracy 0.9305,Training ccuracy0.92694545
Iter 2,Testing Accuracy 0.9377,Training ccuracy0.9355818
Iter 3,Testing Accuracy 0.9422,Training ccuracy0.9413273
Iter 4,Testing Accuracy 0.9453,Training ccuracy0.94609094
Iter 5,Testing Accuracy 0.9476,Training ccuracy0.94963634
Iter 6,Testing Accuracy 0.949,Training ccuracy0.95158184
Iter 7,Testing Accuracy 0.9542,Training ccuracy0.9554
Iter 8,Testing Accuracy 0.9562,Training ccuracy0.9574182
Iter 9,Testing Accuracy 0.9568,Training ccuracy0.95983636
Iter 10,Testing Accuracy 0.9581,Training ccuracy0.9603818
Iter 11,Testing Accuracy 0.9585,Training ccuracy0.9618
Iter 12,Testing Accuracy 0.9607,Training ccuracy0.96345454
Iter 13,Testing Accuracy 0.9623,Training ccuracy0.96450907
Iter 14,Testing Accuracy 0.9612,Training ccuracy0.9655273
Iter 15,Testing Accuracy 0.9638,Training ccuracy0.9674
Iter 16,Testing Accuracy 0.9636,Training ccuracy0.96772724
Iter 17,Testing Accuracy 0.9651,Training ccuracy0.96925455
Iter 18,Testing Accuracy 0.9662,Training ccuracy0.97072726
Iter 19,Testing Accuracy 0.966,Training ccuracy0.97083634
Iter 20,Testing Accuracy 0.9673,Training ccuracy0.97187275
Iter 21,Testing Accuracy 0.9665,Training ccuracy0.9726727
Iter 22,Testing Accuracy 0.9681,Training ccuracy0.9730727
Iter 23,Testing Accuracy 0.9683,Training ccuracy0.97383636
Iter 24,Testing Accuracy 0.9687,Training ccuracy0.9743636
Iter 25,Testing Accuracy 0.9677,Training ccuracy0.9751091
Iter 26,Testing Accuracy 0.9708,Training ccuracy0.97596365
Iter 27,Testing Accuracy 0.9702,Training ccuracy0.9764909
Iter 28,Testing Accuracy 0.9698,Training ccuracy0.9770182
Iter 29,Testing Accuracy 0.9709,Training ccuracy0.97778183
Iter 30,Testing Accuracy 0.9709,Training ccuracy0.9779818

结果分析:Testing Accuracy和Training ccuracy的值的确差缩小,过拟合现象看似是被解决了。

猜你喜欢

转载自blog.csdn.net/gaoyu1253401563/article/details/86192473