返回介绍

第 16 章 使用 Dropout 正则化防止过拟合

发布于 2025-02-19 23:22:48 字数 6036 浏览 0 评论 0 收藏 0

Dropout 虽然简单,但可以有效防止过拟合。本章关于如何在 Keras 中使用 Dropout。本章包括:

  • dropout 的原理
  • dropout 的使用
  • 在隐层上使用 dropout

我们开始吧。

16.1 Dropout 正则化

译者鄙校的 Srivastava 等大牛在 2014 年的论文《 Dropout: A Simple Way to Prevent Neural Networks from Overfitting 》提出了 Dropout 正则化。Dropout 的意思是:每次训练时随机忽略一部分神经元,这些神经元 dropped-out 了。换句话讲,这些神经元在正向传播时对下游的启动影响被忽略,反向传播时也不会更新权重。

神经网络的所谓“学习”是指,让各个神经元的权重符合需要的特性。不同的神经元组合后可以分辨数据的某个特征。每个神经元的邻居会依赖邻居的行为组成的特征,如果过度依赖,就会造成过拟合。如果每次随机拿走一部分神经元,那么剩下的神经元就需要补上消失神经元的功能,整个网络变成很多独立网络(对同一问题的不同解决方法)的合集。

Dropout 的效果是,网络对某个神经元的权重变化更不敏感,增加泛化能力,减少过拟合。

16.2 在 Keras 中使用 Dropout 正则化

Dropout 就是每次训练按概率拿走一部分神经元,只在训练时使用。后面我们会研究其他的用法。

以下的例子是声呐数据集(第 11 章),用 scikit-learn 进行 10 折交叉检验,这样可以看出区别。输入变量有 60 个,输出 1 个,数据经过正则化。基线模型有 2 个隐层,第一个有 60 个神经元,第二个有 30 个。训练方法是随机梯度下降,学习率和动量较低。下面是基线模型的代码:

import numpy
import pandas
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.wrappers.scikit_learn import KerasClassifier
from keras.constraints import maxnorm
from keras.optimizers import SGD
from sklearn.cross_validation import cross_val_score
from sklearn.preprocessing import LabelEncoder
from sklearn.cross_validation import StratifiedKFold
from sklearn.preprocessing import StandardScaler
from sklearn.grid_search import GridSearchCV
from sklearn.pipeline import Pipeline
# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)
# load dataset
dataframe = pandas.read_csv("sonar.csv", header=None)
dataset = dataframe.values
# split into input (X) and output (Y) variables
X = dataset[:,0:60].astype(float)
Y = dataset[:,60]
# encode class values as integers
encoder = LabelEncoder()
encoder.fit(Y)
encoded_Y = encoder.transform(Y)

# baseline
def create_baseline():
    # create model
    model = Sequential()
    model.add(Dense(60, input_dim=60, init='normal', activation='relu')) model.add(Dense(30, init='normal', activation='relu')) model.add(Dense(1, init='normal', activation='sigmoid'))
    # Compile model
    sgd = SGD(lr=0.01, momentum=0.8, decay=0.0, nesterov=False)
    model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy']) 
    return model
numpy.random.seed(seed)
estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=300,
    batch_size=16, verbose=0)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(y=encoded_Y, n_folds=10, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Accuracy: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

不使用 Dropout 的准确率是 82%。

Accuracy: 82.68% (3.90%)

16.3 对输入层使用 Dropout 正则化

可以对表层用 Dropout:这里我们对输入层(表层)和第一个隐层用 Dropout,比例是 20%,意思是每轮训练每 5 个输入随机去掉 1 个变量。

原论文推荐对每层的权重加限制,保证模不超过 3:在定义全连接层时用 W_constraint 可以做到。学习率加 10 倍,动量加到 0.9,原论文也如此推荐。对上面的模型进行修改:


# dropout in the input layer with weight constraint
def create_model1():
    # create model
    model = Sequential()
    model.add(Dropout(0.2, input_shape=(60,)))
    model.add(Dense(60, init='normal', activation='relu', W_constraint=maxnorm(3))) model.add(Dense(30, init='normal', activation='relu', W_constraint=maxnorm(3))) model.add(Dense(1, init='normal', activation='sigmoid'))
    # Compile model
    sgd = SGD(lr=0.1, momentum=0.9, decay=0.0, nesterov=False)
    model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy']) 
    return model
numpy.random.seed(seed)
estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasClassifier(build_fn=create_model1, nb_epoch=300,
    batch_size=16, verbose=0)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(y=encoded_Y, n_folds=10, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Accuracy: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

准确率提升到 86%:

Accuracy: 86.04% (6.33%)

16.4 对隐层使用 Dropout 正则化

隐层当然也可以用 Dropout。和上次一样,这次对两个隐层都做 Dropout,概率还是 20%:

# dropout in hidden layers with weight constraint
def create_model2():
    # create model
    model = Sequential()
    model.add(Dense(60, input_dim=60, init='normal', activation='relu',
W_constraint=maxnorm(3)))
    model.add(Dropout(0.2))
    model.add(Dense(30, init='normal', activation='relu', W_constraint=maxnorm(3))) 
    model.add(Dropout(0.2))
    model.add(Dense(1, init='normal', activation='sigmoid'))
    # Compile model
    sgd = SGD(lr=0.1, momentum=0.9, decay=0.0, nesterov=False)  
    model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy']) 
    return model
numpy.random.seed(seed)
estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasClassifier(build_fn=create_model2, nb_epoch=300,
    batch_size=16, verbose=0)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(y=encoded_Y, n_folds=10, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Accuracy: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

然而并没有什么卯月,效果更差了。有可能需要多训练一些吧。

Accuracy: 82.16% (6.16%)

16.5 使用 Dropout 正则化的技巧

原论文对很多标准机器学习问题做出了比较,并提出了下列建议:

  1. Dropout 概率不要太高,从 20%开始,试到 50%。太低的概率效果不好,太高有可能欠拟合。
  2. 网络要大。更大的网络学习到不同方法的几率更大。
  3. 每层都做 Dropout,包括输入层。效果更好。
  4. 学习率(带衰减的)和动量要大。直接对学习率乘 10 或 100,动量设到 0.9 或 0.99。
  5. 限制每层的权重。学习率增大会造成权重增大,把每层的模限制到 4 或 5 的效果更好。

16.6 总结

本章关于使用 Dropout 正则化避免过拟合。总结一下:

  • Dropout 的工作原理是什么
  • 如何使用 Dropout
  • Dropout 的最佳实践是什么

16.6.1 下一章

在训练中调节学习率会提升性能。下一章会研究不同学习率的效果,以及如何在 Keras 中使用。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文