深度学习正则化Tricks——dropout

来源:互联网 发布:淘宝都什么时候发红包 编辑:程序博客网 时间:2024/05/19 15:25

drop Out——神经网络中的模型平均

写在前面

带我入机器学习的伟大导师Andrew Ng曾经做过一个非常好的比喻。他把深度学习比作火箭,对于一个火箭来说,最重要的一部分必然是引擎,而在这个领域,目前来看引擎的核心是神经网络。但是要让一个火箭运行,除了的有引擎还要有燃料。在深度学习领域,数据则充当了燃料的角色。

这里写图片描述

对于深度网络来说,模型的容量都很高(因为其具有很多层,每层具有很有神经元),一般来说都会大于实际问题需要的表示容量。在这样的情况下,如果训练数据不够,很容易导致模型简单的记住有限的训练数据,导致过拟合。因此,深度学习中许多Trick都是用于正则化,减小模型的泛化误差。这里主要记录下自己关于dropout的学习理解,有不正确的地方希望各位提出来。

什么是dropout

简单来说,dropout就是在神经网络训练过程中,每一个神经元(不包括输出层神经元)以一定的暂时概率被丢弃。这里丢弃是暂时性的,并不是说抛弃了,很有可能这一次被丢弃的神经元会出现在下一次训练的网络中。由于丢弃神经元的随机性,在每一次训练过程中,神经网络的结构可能都不同。训练结束以后,保留所有的节点用于测试。

这里写图片描述


为什么dropout可以提高泛化能力

  • 斯坦福CS231n课上面给出了一种形象解释:因为每次在训练过程中都会损失一些神经元,网络表达能力减小,为了保证训练结果的正确性,未被丢失的神经元不得不承担起更大的“责任”,因此在测试的时候会有更好的结果。

  • 一些神经元在训练过程中被丢失,这样会促使神经网络依赖更多的特征。

  • 训练过程中会随机丢失一些神经元,不同的过程丢失神经元不同,行程不同结构的网络。最后测试的时候,保留所有的神经元,相当于对前面所有的网络结构做了一个模型平均。
    这里解释一下为什么模型平均能够提高模型的泛化能力。
    模型平均奏效的原因是不同的模型通常不会在测试集上面产生完全相同的错误。
    考虑k个模型的例子。假设每个模型在每个例子上面的误差是ϵi , 这个误差服从零均值方差为 E[ϵ2i]=v 且协方差是E[ϵiϵj]=c 的多维正态分布。通过所有集成模型的平均预测的误差所得的误差是1kiϵi。 集成预测器平方误差的期望是:

E[(1kiϵi)2]=1k2E[i(ϵ2i+ijϵiϵj)]=1kv+k1kc

在误差完全相关,即c = v的情况下,均方误差为v,模型平均没有任何帮助,但是在误差完全不相关的,即 c= 0的情况下,均方误差个为1kv,这意味着模型平均的均方误差会随着模型数量增多而线性地减小。


在tensorflow中如何使用dropout

用MNIST为例,用CNN做分类器,其中使用了dropout, 直接上代码

from tensorflow.examples.tutorials.mnist import input_dataimport tensorflow as tfmnist = input_data.read_data_sets("MNIST_data/", one_hot=True)sess = tf.InteractiveSession()  #创建一个交互式的session# 权重初始化方法def weight_variable(shape):    init = tf.truncated_normal(shape, stddev=0.1)    return tf.Variable(init)# 偏置初始化方法def bias_variable(shape):    init = tf.constant(0.1, shape=shape)    return tf.Variable(init)# 构造卷积层def conv2d(x, W):    return tf.nn.conv2d(x, W,strides=[1, 1, 1, 1], padding='SAME')# 构造pooling层def max_pool_2x2(x):    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')# 创建占位符x = tf.placeholder(tf.float32, [None, 784]) # 用于把数据喂入网络中y_ = tf.placeholder(tf.float32, [None, 10]) # 用于把标签喂入网络中keep_prob = tf.placeholder(tf.float32) # dropout的占位符,用于输入我们设置的dropoutx_image = tf.reshape(x, [-1, 28, 28, 1])# 第一层,包括卷积、poolingW_conv1 = weight_variable([5, 5, 1, 32])b_conv1 = bias_variable([32])h_conv1 = conv2d(x_image, W_conv1)h_pool1 = max_pool_2x2(h_conv1)# 第二层,包括卷积、poolingW_conv2 = weight_variable([5, 5, 32, 64])b_conv2 = bias_variable([64])h_conv2 = conv2d(h_pool1, W_conv2)h_pool2 = max_pool_2x2(h_conv2)# 全连接层1W_fc1 = weight_variable([7*7*64, 1000])b_fc1 = bias_variable([1000])h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)# dropout,以keep_prob的概率随机丢弃一些神经元h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)# 全连接层2W_fc2 = weight_variable([1000, 10])b_fc2 = bias_variable([10])y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2))cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y_conv), axis=1))correct_prediction = tf.equal(tf.argmax(y_, 1), tf.argmax(y_conv, 1))accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))train = tf.train.AdamOptimizer(0.0001).minimize(cross_entropy)tf.global_variables_initializer().run()for i in range(1000):    batch = mnist.train.next_batch(128)    if i % 100 == 0:        train_accuracy = accuracy.eval(feed_dict={x: batch[0], y_: batch[1], keep_prob:1.0})        print("step: %d, accuracy %g" %(i, train_accuracy))    train.run(feed_dict={x: batch[0], y_: batch[1], keep_prob:0.75})print("test accuracy %g" %accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels, keep_prob:1.0}))

drop out一些小扩展

权重比例推断规则:设置drop_out = p,训练结束之后把权重乘以p,然后像平常一样使用模型。这个结论详细介绍在benjio的deep learning第七章中有更加详细的介绍。这里举一个例子帮助理解:
这里写图片描述
在上述例子中,drop_out = 0.5,根据模型平均的想法,最终使用的时候需要对最终的权重做一个乘以0.5的操作。


写在后面
Benjor在介绍完dropout后写到,另一种深度学习算法——batch normalization有时会使Dropout变得没有必要,博主在一个项目中确实尝试了一下,batch normalization 真神器,BN之后,dropout、weight_decay、learning_rate变得不关键了。

原创粉丝点击