大家好,我技术人Howzit,这是深度学习入门系列第十一篇,欢迎大家一起交流!
深度学习入门系列1:多层感知器概述
深度学习入门系列2:用TensorFlow构建你的第一个神经网络
深度学习入门系列3:深度学习模型的性能评价方法
深度学习入门系列4:用scikit-learn找到最好的模型
深度学习入门系列5项目实战:用深度学习识别鸢尾花种类
深度学习入门系列6项目实战:声纳回声识别
深度学习入门系列7项目实战:波士顿房屋价格回归
深度学习入门系列8:用序列化保存模型便于继续训练
深度学习入门系列9:用检查点保存训练期间最好的模型
深度学习入门系列10:从绘制记录中理解训练期间的模型行为
深度学习入门系列11:用Dropout正则减少过拟合
深度学习入门系列12:使用学习规划来提升性能
深度学习入门系列13:卷积神经网络概述
深度学习入门系列14:项目实战:基于CNN的手写数字识别
深度学习入门系列15:用图像增强改善模型性能
深度学习入门系列16:项目实战:图像中目标识别
深度学习入门系列17:项目实战:从电影评论预测情感
深度学习入门系列18:递归神经网络概述
深度学习入门系列19:基于窗口(window)的多层感知器解决时序问题
深度学习入门系列20:LSTM循环神经网络解决国际航空乘客预测问题
深度学习入门系列21:项目:用LSTM+CNN对电影评论分类
深度学习入门系列22:从猜字母游戏中理解有状态的LSTM递归神经网络
深度学习入门系列23:项目:用爱丽丝梦游仙境生成文本
Dropout是Srivastava等人针对神经网络提出的正则化技术。在他们2004论文中 Dropout:A simple way to prevent neural networks from overfitting。Dropout是在训练时随机忽略一些神经元的技术。他们被随机丢弃(drop-out)。这意味着在前向计算时会移除对下游神经元激活函数的贡献,并且在反向传输时也不会更新那些权重。
随着神经网络模型不断地学习,神经元的权值会与整个网络的上下文相匹配。神经元的权重针对某些特征进行调优,具有一些特殊化。周围的神经元则会依赖于这种特殊化,如果过于特殊化,模型会因为对训练数据过拟合而变得脆弱不堪。神经元在训练过程中的这种依赖于上下文的现象被称为复杂的协同适应(complex co-adaptations)。你能想象在训练期间随机丢弃一些神经元,其他神经元不得不对丢失的神经的表示进行预测。我们想象这导致网络学习到多个独立的内部表示。
结果是网络对神经元的特定权重变得不那么敏感。反过来,这将导致网络具有更好的泛化能力,并且不太可能对训练数据过度拟合。
11.2 在Keras中使用Dropout正则化Dropout 通过随机选择节点能够轻松实现,而这些节点在每次权重更新周期内以一定概率(如20%)丢弃。这就是Keras中如何实现Dropout的。Dropout仅仅在训练模型中使用,并不在评估模型时使用这个技巧。接下来,我们将探索Keras中Dropout的不同使用方法。
这个例子将使用Sonar二分类数据集。我们将使用scikit-learn中10折交叉验证来评估已开发的模型,为了更好获取不同的结果。网络中有60输入值和一个输出值,而且使用这些输入值前都被标准化了。基准神经网络模型有两个隐藏层。第一层60个,第二层30个。训练模型时使用随机梯度下降,用相对较低学习率和动量(momentum)。完整基准模型如下:
# Baseline Model on the Sonar Datasetimport numpy
from pandas import read_csv
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.wrappers.scikit_learn import KerasClassifier
from tensorflow.keras.constraints import max_norm
from tensorflow.keras.optimizers import SGD
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import StratifiedKFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline # fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)# load dataset
dataframe = 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():model = Sequential()model.add(Dense(60, input_dim=60, activation="relu"))model.add(Dense(30, activation="relu"))model.add(Dense(1, activation="sigmoid"))# Compile modelsgd = SGD(lr=0.01, momentum=0.8, decay=0.0, nesterov=False)model.compile(loss="binary_crossentropy", optimizer=sgd, metrics=["accuracy"])return modelnumpy.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(n_splits=10, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Baseline: %.2f%% (%.2f%%)" % (results.mean() * 100, results.std() * 100))
运行这个基准模型,没有使用Dropout生成的近似分类准确率为82%
Baseline: 86.04% (4.58%)
11.3 在输入层上使用Dropout
输入神经元又称之为可见层,能够使用Dropout。在下面这个例子,我们在输入层和第一可见层之间加了Dropout层。Dropout率被设置为20%,意味着有1/5的神经元会在更新周期被随机排除在外。
另外,按照有关Dropout的原始论文的建议,每个神经元施加一个约束,确保权重最大范数不超过3。当我构建层时,在Dense类中设置W_constraint参数。学习速率也提高了一个数量级而且动量增加到0.9。原论文也推荐增加学习速率。从下面基准例子继续,下面代码使用同样网络练习输入层Dropout。
# Baseline Model on the Sonar Dataset
import numpy
from pandas import read_csv
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.wrappers.scikit_learn import KerasClassifier
from tensorflow.keras.constraints import max_norm
from tensorflow.keras.optimizers import SGD
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import StratifiedKFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline # fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)# load datasetdataframe = 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():model = Sequential()model.add(Dropout(0.2, input_shape=(60,)))model.add(Dense(60, input_dim=60, activation="relu"))model.add(Dense(30, activation="relu"))model.add(Dense(1, activation="sigmoid"))# Compile modelsgd = SGD(lr=0.01, momentum=0.8, decay=0.0, nesterov=False)model.compile(loss="binary_crossentropy", optimizer=sgd, metrics=["accuracy"])return modelnumpy.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(n_splits=10, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)print("Baseline: %.2f%% (%.2f%%)" % (results.mean() * 100, results.std() * 100))
运行可见层带有Dropout层的例子,在分类精度上很好提升到86%
Visible: 83.52% (7.68%)
11.4 在隐藏层上使用Dropout
Dropout也可以应用在在你的网络模型上的隐藏神经元。下面这个例子中Dropout可以应用在连个隐藏层之间和最后一个隐藏层与输出层之间。Dropout率为20%再次被使用在这些层权重约束上。
# Baseline Model on the Sonar Datasetimport numpyfrom pandas import read_csv
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.wrappers.scikit_learn import KerasClassifier
from tensorflow.keras.constraints import max_norm
from tensorflow.keras.optimizers import SGD
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import StratifiedKFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline # fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)# load dataset
dataframe = 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():model = Sequential()model.add(Dense(60, input_dim=60, activation="relu", W_constraint=max_norm(3)))model.add(Dropout(0.2))model.add(Dense(30, activation="relu", W_constraint=max_norm(3)))model.add(Dropout(0.2))model.add(Dense(1, activation="sigmoid"))# Compile modelsgd = SGD(lr=0.01, momentum=0.8, decay=0.0, nesterov=False)model.compile(loss="binary_crossentropy", optimizer=sgd, metrics=["accuracy"])return modelnumpy.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(n_splits=10, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Baseline: %.2f%% (%.2f%%)" % (results.mean() * 100, results.std() * 100))
我们能看到,对于这个问题和选择的这个网络,在隐藏层上使用了Dropout没有提升。实际上性能比较基准还差。可能需要增加训练次数或者进一步调节学习速率。
Hidden: 83.59% (7.31%)
11.5 使用Dropout提示
Dropout原论文在一套标准机器学习问题上提供实验性结果。因此他们提供了很多有用的启发式考虑在实践时使用Dropout:
这节课你已发现深度学习模型下的Dropout正则技术。你已学到:
另外一个重要的改善你模型的技术是训练期间调整学习速率。在接下来课程中,你将学习不同学习速率的schedules并且你能够在你的问题上通过Keras使用他们。