深度学习初级课程
正文
介绍
到目前为止,在本课程中,我们已经了解了神经网络如何解决回归问题。现在我们将把神经网络应用于另一个常见的机器学习问题:分类。到目前为止,我们所学到的大部分知识仍然适用。主要区别在于我们使用的损耗函数,以及我们希望最后一层产生什么样的输出。
二分类
分类为一个常见的机器学习问题之一。你可能想预测客户是否有可能进行购买,信用卡交易是否存在欺诈,宇宙信号是否显示有新行星的证据,或者医学检测有疾病的证据。这些都是二分类问题。
在原始数据中,类可能由“Yes”和“No”或“Dog”和“Cat”等字符串表示。在使用这些数据之前,我们将分配一个类标签:一个类将是0,另一个将是1。指定数字标签将数据置于神经网络可以使用的形式。
精度与交叉熵
准确度
是衡量分类问题成功与否的众多指标之一。准确度是正确预测与总预测的比率:准确度=正确数/总数
。一个总是正确预测的模型的准确度得分为1.0。在所有其他条件相同的情况下,每当数据集中的类以大约相同的频率出现时,准确度是一个合理的指标。
准确性(以及大多数其他分类指标)的问题在于,它不能用作损失函数。SGD需要一个平稳变化的损失函数,但精度,作为计数的比率,在“跳跃”中变化。因此,我们必须选择一个替代品作为损失函数。这个替代品是交叉熵函数。
现在,回想一下损失函数定义了训练期间网络的目标。通过回归,我们的目标是最小化预期结果和预测结果之间的距离。我们选择了MAE来测量这个距离。
对于分类,我们想要的是概率之间的距离,这就是交叉熵提供的。交叉熵是一种度量从一个概率分布到另一个概率分布的距离的方法。
准确度和交叉熵-----图
交叉熵惩罚错误的概率预测
我们希望我们的网络以1.0的概率预测正确的分类。预测概率离1.0越远,交叉熵损失越大。
我们使用交叉熵的技术原因有点微妙,但从这一节中我们要了解的主要内容是:使用交叉熵来进行分类损失;你可能关心的其他指标(如准确性)也会随之提高。
用Sigmoid函数求概率
交叉熵和精度函数都需要概率作为输入,即0到1之间的数值。为了将密集层产生的实值输出转化为概率,我们附加了一种新的激活函数,即sigmoid激活函数。
S形图是一个“S”形,水平渐近线位于左侧0处,右侧1处
sigmoid函数将实数映射到区间[0,1]
为了得到最终的类预测,我们定义了一个阈值概率。通常这将是0.5,因此四舍五入将为我们提供正确的类别:低于0.5表示标签为0的类别,0.5或以上表示标签为1的类别。0.5阈值是Keras默认使用的精度指标。
示例-二分类
现在让我们试试看!
电离层数据集包含从聚焦于地球大气层电离层的雷达信号中获得的特征。其任务是确定信号是显示存在某种物体,还是仅显示空空气。
import pandas as pd
from IPython.display import display
ion = pd.read_csv('../input/dl-course-data/ion.csv', index_col=0)
display(ion.head())
df = ion.copy()
df['Class'] = df['Class'].map({'good': 0, 'bad': 1})
df_train = df.sample(frac=0.7, random_state=0)
df_valid = df.drop(df_train.index)
max_ = df_train.max(axis=0)
min_ = df_train.min(axis=0)
df_train = (df_train - min_) / (max_ - min_)
df_valid = (df_valid - min_) / (max_ - min_)
df_train.dropna(axis=1, inplace=True) # drop the empty feature in column 2
df_valid.dropna(axis=1, inplace=True)
X_train = df_train.drop('Class', axis=1)
X_valid = df_valid.drop('Class', axis=1)
y_train = df_train['Class']
y_valid = df_valid['Class']
V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 | … | V26 | V27 | V28 | V29 | V30 | V31 | V32 | V33 | V34 | Class | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 0 | 0.99539 | -0.05889 | 0.85243 | 0.02306 | 0.83398 | -0.37708 | 1.00000 | 0.03760 | … | -0.51171 | 0.41078 | -0.46168 | 0.21266 | -0.34090 | 0.42267 | -0.54487 | 0.18641 | -0.45300 | good |
2 | 1 | 0 | 1.00000 | -0.18829 | 0.93035 | -0.36156 | -0.10868 | -0.93597 | 1.00000 | -0.04549 | … | -0.26569 | -0.20468 | -0.18401 | -0.19040 | -0.11593 | -0.16626 | -0.06288 | -0.13738 | -0.02447 | bad |
3 | 1 | 0 | 1.00000 | -0.03365 | 1.00000 | 0.00485 | 1.00000 | -0.12062 | 0.88965 | 0.01198 | … | -0.40220 | 0.58984 | -0.22145 | 0.43100 | -0.17365 | 0.60436 | -0.24180 | 0.56045 | -0.38238 | good |
4 | 1 | 0 | 1.00000 | -0.45161 | 1.00000 | 1.00000 | 0.71216 | -1.00000 | 0.00000 | 0.00000 | … | 0.90695 | 0.51613 | 1.00000 | 1.00000 | -0.20099 | 0.25682 | 1.00000 | -0.32382 | 1.00000 | bad |
5 | 1 | 0 | 1.00000 | -0.02401 | 0.94140 | 0.06531 | 0.92106 | -0.23255 | 0.77152 | -0.16399 | … | -0.65158 | 0.13290 | -0.53206 | 0.02431 | -0.62197 | -0.05707 | -0.59573 | -0.04608 | -0.65697 | good |
5 rows × 35 columns
我们将定义我们的模型,就像我们为回归任务所做的那样,只有一个例外。在最后一层中加入“sigmoid”激活,这样模型将产生类概率。
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Dense(4, activation='relu', input_shape=[33]),
layers.Dense(4, activation='relu'),
layers.Dense(1, activation='sigmoid'),
])
将交叉熵损失和精度度量添加到模型及其编译方法中。对于二分类问题,请确保使用“二进制”版本。(多分类的问题将略有不同。)Adam优化器也适用于分类,所以我们将继续使用它。
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['binary_accuracy'],
)
这个特定问题中的模型可能需要很多时间才能完成训练,因此为了方便起见,我们将包括一个提前停止回调。
early_stopping = keras.callbacks.EarlyStopping(
patience=10,
min_delta=0.001,
restore_best_weights=True,
)
history = model.fit(
X_train, y_train,
validation_data=(X_valid, y_valid),
batch_size=512,
epochs=1000,
callbacks=[early_stopping],
verbose=0, # hide the output because we have so many epochs
)
我们将一如既往地查看学习曲线,并检查我们在验证集上获得的损失和准确性的最佳值。(请记住,提前停止会将权重恢复到获得这些值的权重。)
history_df = pd.DataFrame(history.history)
# Start the plot at epoch 5
history_df.loc[5:, ['loss', 'val_loss']].plot()
history_df.loc[5:, ['binary_accuracy', 'val_binary_accuracy']].plot()
print(("Best Validation Loss: {:0.4f}" +\
"\nBest Validation Accuracy: {:0.4f}")\
.format(history_df['val_loss'].min(),
history_df['val_binary_accuracy'].max()))
Best Validation Loss: 0.6364
Best Validation Accuracy: 0.7143
轮到你了
利用酒店取消数据集,使用神经网络预测酒店预订中的取消问题。
练习部分
介绍
在本练习中,您将使用二分类器构建一个模型来预测酒店取消。
# 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.ex6 import *
首先,加载酒店取消数据集。
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline
from sklearn.compose import make_column_transformer
hotel = pd.read_csv('../input/dl-course-data/hotel.csv')
X = hotel.copy()
y = X.pop('is_canceled')
X['arrival_date_month'] = \
X['arrival_date_month'].map(
{'January':1, 'February': 2, 'March':3,
'April':4, 'May':5, 'June':6, 'July':7,
'August':8, 'September':9, 'October':10,
'November':11, 'December':12}
)
features_num = [
"lead_time", "arrival_date_week_number",
"arrival_date_day_of_month", "stays_in_weekend_nights",
"stays_in_week_nights", "adults", "children", "babies",
"is_repeated_guest", "previous_cancellations",
"previous_bookings_not_canceled", "required_car_parking_spaces",
"total_of_special_requests", "adr",
]
features_cat = [
"hotel", "arrival_date_month", "meal",
"market_segment", "distribution_channel",
"reserved_room_type", "deposit_type", "customer_type",
]
transformer_num = make_pipeline(
SimpleImputer(strategy="constant"), # there are a few missing values
StandardScaler(),
)
transformer_cat = make_pipeline(
SimpleImputer(strategy="constant", fill_value="NA"),
OneHotEncoder(handle_unknown='ignore'),
)
preprocessor = make_column_transformer(
(transformer_num, features_num),
(transformer_cat, features_cat),
)
# stratify - make sure classes are evenlly represented across splits
X_train, X_valid, y_train, y_valid = \
train_test_split(X, y, stratify=y, train_size=0.75)
X_train = preprocessor.fit_transform(X_train)
X_valid = preprocessor.transform(X_valid)
input_shape = [X_train.shape[1]]
[63]
1) 定义模型
我们这次使用的模型将同时具有批量标准化和dropout层。为了便于阅读,我们将图表分为几个部分,但您可以像往常一样逐层定义它。
用下图给出的架构定义模型:
网络架构图:BatchNorm,Dense,BatchNorm,Dropout,Dense,BatchNorm,Dropout,Dense
二分类器的示意图。
from tensorflow import keras
from tensorflow.keras import layers
# YOUR CODE HERE: define the model given in the diagram
model = ____
# Check your answer
q_1.check()
现在运行下一个单元来训练模型,看看添加dropout的效果。
2)添加优化器、损失和度量
现在使用Adam优化器和交叉熵损失和精度度量的二进制版本编译模型。
# YOUR CODE HERE
__________
# Check your answer
q_2.check()
最后,运行这个单元来训练模型并查看学习曲线。它可能会运行大约60到70个epochs,这可能需要一两分钟。
early_stopping = keras.callbacks.EarlyStopping(
patience=5,
min_delta=0.001,
restore_best_weights=True,
)
history = model.fit(
X_train, y_train,
validation_data=(X_valid, y_valid),
batch_size=512,
epochs=200,
callbacks=[early_stopping],
)
history_df = pd.DataFrame(history.history)
history_df.loc[:, ['loss', 'val_loss']].plot(title="Cross-entropy")
history_df.loc[:, ['binary_accuracy', 'val_binary_accuracy']].plot(title="Accuracy")
Epoch 1/200
175/175 [==============================] - 6s 29ms/step - loss: 0.4780 - binary_accuracy: 0.7725 - val_loss: 0.4326 - val_binary_accuracy: 0.8021
Epoch 2/200
175/175 [==============================] - 4s 25ms/step - loss: 0.4230 - binary_accuracy: 0.8019 - val_loss: 0.4015 - val_binary_accuracy: 0.8129
Epoch 3/200
175/175 [==============================] - 4s 24ms/step - loss: 0.4085 - binary_accuracy: 0.8074 - val_loss: 0.3939 - val_binary_accuracy: 0.8179
Epoch 4/200
175/175 [==============================] - 4s 25ms/step - loss: 0.4028 - binary_accuracy: 0.8118 - val_loss: 0.3898 - val_binary_accuracy: 0.8186
Epoch 5/200
175/175 [==============================] - 4s 24ms/step - loss: 0.3970 - binary_accuracy: 0.8158 - val_loss: 0.3854 - val_binary_accuracy: 0.8238
...
Epoch 34/200
175/175 [==============================] - 4s 24ms/step - loss: 0.3450 - binary_accuracy: 0.8401 - val_loss: 0.3513 - val_binary_accuracy: 0.8406
Epoch 35/200
175/175 [==============================] - 4s 24ms/step - loss: 0.3441 - binary_accuracy: 0.8402 - val_loss: 0.3534 - val_binary_accuracy: 0.8408
3)训练和评估
你觉得学习曲线怎么样?它看起来像是模型不合身还是过合身?交叉熵损失是准确度的一个很好的替代品吗?
虽然我们可以看到训练损失继续下降,但提前停止的回调阻止了任何过度调整。此外,准确度的上升速度与交叉熵的下降速度相同,因此,最小化交叉熵似乎是一个很好的替代。总而言之,这次训练看起来很成功!
结论
祝贺您已经完成了kaggle的深度学习入门课程!
有了新的技能,您就可以使用更高级的应用程序,如计算机视觉和情感分类。你接下来想做什么?
为什么不试试我们的入门比赛呢?
- 使用TPU将图像分类为花瓣到金属
- 用GANs创作艺术我自己也是个画家
- 对推文进行真实分类与否?NLP发布灾难推文
- 发现矛盾和牵连 Contradictory, My Dear Watson
直到下一次,kagglers!
答案
# 1)定义模型
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.BatchNormalization(input_shape=input_shape),
layers.Dense(256, activation='relu'),
layers.BatchNormalization(),
layers.Dropout(0.3),
layers.Dense(256, activation='relu'),
layers.BatchNormalization(),
layers.Dropout(0.3),
layers.Dense(1, activation='sigmoid'),
])
# 2)添加优化器,损失和度量
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['binary_accuracy'],
)