深度学习初级课程
Dropout 这个单词 原义是退学学生;拒绝传统社会的人;【计算机】磁盘信息失落;漏失信息,丢失信息
在这里是丢弃部分单元(神经元)的含义,如果从树的搜索概念来讲用剪枝
这个词更能休现其真正的意境。
正文
介绍
深度学习的世界不仅仅是密集的层次。可以向模型中添加几十种图层。(尝试浏览Keras文档以获取示例!)有些像致密层,定义神经元之间的连接,而另一些可以进行预处理或其他类型的转换。
在这节课中,我们将学习两种特殊的层,它们本身不包含任何神经元,但它们添加了一些功能,有时可以以各种方式使模型受益。两者都是现代体系结构中常用的。
Dropout (剪枝)
第一个是dropout layer
,它可以帮助纠正过拟合。
在上一课中,我们讨论了网络学习训练数据中的虚假模式是如何导致过度拟合的。为了识别这些虚假模式,网络通常会依赖非常特定的权重组合,这是一种权重的“阴谋”。由于如此具体,它们往往是脆弱的:移除一个,阴谋就会瓦解。
这就是droput
背后的想法。为了打破这些阴谋,我们在训练的每一步都随机删除一层输入单元的一小部分,这使得网络更难从训练数据中学习这些虚假模式。相反,它必须寻找广泛的、一般的模式,其权重模式往往更稳健。
在这里,在两个隐藏层之间添加了 50% 的 dropout
。
你也可以把辍学看作是创造一种网络的集合。这些预测将不再由一个大型网络做出,而是由一个由小型网络组成的委员会做出。委员会中的每个人往往会犯各种各样的错误,但同时也要正确,使委员会作为一个整体比任何个人都好。(如果你熟悉随机森林作为决策树的集合,这是同样的想法。)
增加 Dropout
在Keras中,dropout rate 参数rate
定义了要关闭的输入单元的百分比。将 Dropout 层放在要应用 dropout 的层之前:
keras.Sequential([
# ...
layers.Dropout(rate=0.3), # apply 30% dropout to the next layer
layers.Dense(16),
# ...
])
批量标准化
我们将看到的下一个特殊层执行“batch normalization”(或“batchnorm”),这有助于纠正缓慢或不稳定的训练。
对于神经网络,将所有数据放在一个通用的尺度上通常是个好主意,也许可以使用scikit-learn的StandardScaler或MinMaxScaler之类的工具。原因是,SGD将根据数据产生的激活量按比例改变网络权重。倾向于产生不同大小激活的功能可能会导致不稳定的训练行为。
现在,如果在数据进入网络之前对其进行规范化是好的,那么在网络内部进行规范化可能会更好!事实上,我们有一种特殊的层可以做到这一点, batch normalization layer
批量标准化层。批次标准化层在每个批次进入时查看它,首先用其自身的平均值和标准偏差对该批次进行标准化,然后用两个可训练的重新缩放参数将数据放在一个新的尺度上。实际上,Batchnorm对其输入执行一种协调的重新缩放作用。
大多数情况下,batchnorm是作为优化过程的辅助工具添加的(尽管它有时也有助于预测性能)。使用batchnorm的模型往往需要较少的时间来完成训练。此外,batchnorm还可以解决可能导致训练“停滞”的各种问题。考虑为模型添加批量标准化,尤其是在训练期间遇到问题时。
添加批量标准化
看起来,批量标准几乎可以在网络中的任何一点上使用。你可以把它放在一层之后…
layers.Dense(16, activation='relu'),
layers.BatchNormalization(),
# 或放在层与其激活功能之间:
layers.Dense(16),
layers.BatchNormalization(),
layers.Activation('relu'),
如果你把它作为网络的第一层,它可以充当一种自适应预处理器,代替sk-learn的StandardScaler。
示例-使用剪枝和批量标准化
让我们继续研究红酒模型。现在,我们将进一步增加容量,但添加dropout以控制过度拟合和批量标准化以加快优化。这一次,我们还将停止标准化数据,以演示批量标准化如何稳定训练。
# Setup plotting
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
# Set Matplotlib defaults
plt.rc('figure', autolayout=True)
plt.rc('axes', labelweight='bold', labelsize='large',
titleweight='bold', titlesize=18, titlepad=10)
import pandas as pd
red_wine = pd.read_csv('../input/dl-course-data/red-wine.csv')
# Create training and validation splits
df_train = red_wine.sample(frac=0.7, random_state=0)
df_valid = red_wine.drop(df_train.index)
# Split features and target
X_train = df_train.drop('quality', axis=1)
X_valid = df_valid.drop('quality', axis=1)
y_train = df_train['quality']
y_valid = df_valid['quality']
添加dropout 时,可能需要增加密集层中的单元数。
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Dense(1024, activation='relu', input_shape=[11]),
layers.Dropout(0.3),
layers.BatchNormalization(),
layers.Dense(1024, activation='relu'),
layers.Dropout(0.3),
layers.BatchNormalization(),
layers.Dense(1024, activation='relu'),
layers.Dropout(0.3),
layers.BatchNormalization(),
layers.Dense(1),
])
这次我们的训练安排没有什么可改变的。
model.compile(
optimizer='adam',
loss='mae',
)
history = model.fit(
X_train, y_train,
validation_data=(X_valid, y_valid),
batch_size=256,
epochs=100,
verbose=0,
)
# Show the learning curves
history_df = pd.DataFrame(history.history)
history_df.loc[:, ['loss', 'val_loss']].plot();
如果在将数据用于训练之前对其进行标准化,通常会获得更好的性能。然而,我们完全能够使用原始数据,这表明在更困难的数据集上,批量标准化是多么有效。
轮到你了
继续改进Spotify数据集的预测,看看批量标准化如何帮助处理困难的数据集。
练习部分
介绍
在本练习中,您将向练习4中的Spotify模型添加dropout,并了解批量标准化如何让您在困难的数据集上成功地训练模型。
运行下一个单元格开始!
# Setup plotting
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
# Set Matplotlib defaults
plt.rc('figure', autolayout=True)
plt.rc('axes', labelweight='bold', labelsize='large',
titleweight='bold', titlesize=18, titlepad=10)
plt.rc('animation', html='html5')
# Setup feedback system
from learntools.core import binder
binder.bind(globals())
from learntools.deep_learning_intro.ex5 import *
加载 Spotify数据集
import pandas as pd
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import make_column_transformer
from sklearn.model_selection import GroupShuffleSplit
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras import callbacks
spotify = pd.read_csv('../input/dl-course-data/spotify.csv')
X = spotify.copy().dropna()
y = X.pop('track_popularity')
artists = X['track_artist']
features_num = ['danceability', 'energy', 'key', 'loudness', 'mode',
'speechiness', 'acousticness', 'instrumentalness',
'liveness', 'valence', 'tempo', 'duration_ms']
features_cat = ['playlist_genre']
preprocessor = make_column_transformer(
(StandardScaler(), features_num),
(OneHotEncoder(), features_cat),
)
def group_split(X, y, group, train_size=0.75):
splitter = GroupShuffleSplit(train_size=train_size)
train, test = next(splitter.split(X, y, groups=group))
return (X.iloc[train], X.iloc[test], y.iloc[train], y.iloc[test])
X_train, X_valid, y_train, y_valid = group_split(X, y, artists)
X_train = preprocessor.fit_transform(X_train)
X_valid = preprocessor.transform(X_valid)
y_train = y_train / 100
y_valid = y_valid / 100
input_shape = [X_train.shape[1]]
print("Input shape: {}".format(input_shape))
Input shape: [18]
在Spotify模型中添加dropout
这是练习4中的最后一个模型。添加两个dropout 层,一个位于128个单元的密集层之后,另一个位于64个单元的密集层之后。将两者的dropout_rate设置为0.3。
# YOUR CODE HERE: Add two 30% dropout layers, one after 128 and one after 64
# 以下代码各添加两个30% dropout 的层
model = keras.Sequential([
layers.Dense(128, activation='relu', input_shape=input_shape),
layers.Dense(64, activation='relu'),
layers.Dense(1)
])
# Check your answer
q_1.check()
现在运行下一个单元来训练模型,看看添加dropout的效果。
model.compile(
optimizer='adam',
loss='mae',
)
history = model.fit(
X_train, y_train,
validation_data=(X_valid, y_valid),
batch_size=512,
epochs=50,
verbose=0,
)
history_df = pd.DataFrame(history.history)
history_df.loc[:, ['loss', 'val_loss']].plot()
print("Minimum Validation Loss: {:0.4f}".format(history_df['val_loss'].min()))
Minimum Validation Loss: 0.1908
2) 评估dropout情况
回想练习4,该模型倾向于过拟合第5epoch 前后的数据。这次增加dropout似乎有助于防止过度拟合吗?
从学习曲线可以看出,即使训练损失继续减少,验证损失仍保持在一个恒定的最小值附近。所以我们可以看到,增加dropout确实防止了这次的过拟合。此外,通过使网络更难适应虚假模式,dropout可能会鼓励网络寻找更多真实模式,也可能会改善验证损失(有些情况下也是如此)。
现在,我们将切换话题,探索批处理规范化如何解决训练中的问题。
加载具体的数据集。这次我们不会进行任何标准化。这将使批量标准化的效果更加明显。
import pandas as pd
concrete = pd.read_csv('../input/dl-course-data/concrete.csv')
df = concrete.copy()
df_train = df.sample(frac=0.7, random_state=0)
df_valid = df.drop(df_train.index)
X_train = df_train.drop('CompressiveStrength', axis=1)
X_valid = df_valid.drop('CompressiveStrength', axis=1)
y_train = df_train['CompressiveStrength']
y_valid = df_valid['CompressiveStrength']
input_shape = [X_train.shape[1]]
运行下面的单元,在非标准的具体数据上训练网络。
model = keras.Sequential([
layers.Dense(512, activation='relu', input_shape=input_shape),
layers.Dense(512, activation='relu'),
layers.Dense(512, activation='relu'),
layers.Dense(1),
])
model.compile(
optimizer='sgd', # SGD is more sensitive to differences of scale
loss='mae',
metrics=['mae'],
)
history = model.fit(
X_train, y_train,
validation_data=(X_valid, y_valid),
batch_size=64,
epochs=100,
verbose=0,
)
history_df = pd.DataFrame(history.history)
history_df.loc[0:, ['loss', 'val_loss']].plot()
print(("Minimum Validation Loss: {:0.4f}").format(history_df['val_loss'].min()))
Minimum Validation Loss: nan
你有没有得到一张空白的图表?尝试在此数据集上训练此网络通常会失败。即使它确实收敛(由于幸运的权重初始化),它也倾向于收敛到一个非常大的数字。
3) 添加批量标准化层
批处理规范化可以帮助纠正这样的问题。
添加四个层,每个密集层前一个。(请记住将input_shape参数移动到新的第一层。)
# YOUR CODE HERE: Add a BatchNormalization layer before each Dense layer
# 以下代码添加批量标准化
model = keras.Sequential([
layers.Dense(512, activation='relu', input_shape=input_shape),
layers.Dense(512, activation='relu'),
layers.Dense(512, activation='relu'),
layers.Dense(1),
])
# Check your answer
q_3.check()
运行下一个单元格,看看批量标准化是否能让我们训练模型。
model.compile(
optimizer='sgd',
loss='mae',
metrics=['mae'],
)
EPOCHS = 100
history = model.fit(
X_train, y_train,
validation_data=(X_valid, y_valid),
batch_size=64,
epochs=EPOCHS,
verbose=0,
)
history_df = pd.DataFrame(history.history)
history_df.loc[0:, ['loss', 'val_loss']].plot()
print(("Minimum Validation Loss: {:0.4f}").format(history_df['val_loss'].min()))
Minimum Validation Loss: 3.7906
4) 评估批量标准化
添加批量标准化有帮助吗?
您可以看到,与第一次尝试相比,添加批量标准化是一个很大的改进!通过在数据通过网络时自适应地缩放数据,批量标准化可以让您在困难的数据集上训练模型。
继续前进
创建用于二分类的神经网络。
答案
# 1)增加dropout
model = keras.Sequential([
layers.Dense(128, activation='relu', input_shape=input_shape),
layers.Dropout(0.3),
layers.Dense(64, activation='relu'),
layers.Dropout(0.3),
layers.Dense(1)
])
# 3)增加批量标准化
model = keras.Sequential([
layers.BatchNormalization(input_shape=input_shape),
layers.Dense(512, activation='relu'),
layers.BatchNormalization(),
layers.Dense(512, activation='relu'),
layers.BatchNormalization(),
layers.Dense(512, activation='relu'),
layers.BatchNormalization(),
layers.Dense(1),
])