Deep Learning with Python 系列笔记(二):深度学习基础

机器学习基础

评估一个模型通常可以归结为将可用的数据分成三组:训练、验证和测试集。一旦模型准备就绪,将在测试数据上进行最后一次测试。
这里写图片描述

Hold-out validation

num_validation_samples = 10000
# Shuffling the data is usually appropriate
np.random.shuffle(data)

# Define the validation set
validation_data = data[:num_validation_samples]
data = [num_validation_samples:]

# Define the training set
training_data = data[:]

# Train a model on the training data
# and evaluate it on the validation data
model = get_model()
model.train(training_data)
validation_score = model.evaluate(validation_data)

# At this point you can tune your model,
# retrain it, evaluate it, tune it again...
# Once you have tuned your hyperparameters,
# is it common to train your final model from scratch
# on all non-test data available.

model = get_model()
model.train(np.concatenate([training_data,
validation_data]))
test_score = model.evaluate(test_data)

这是最简单的操作步骤,而且它有一个缺陷:如果可用的数据很少,那么验证集和测试集可能包含的样本太少,无法从统计上代表手头的数据。这是很容易注意到的:如果不同的随机打乱的数据产生了非常不同的模型性能度量,那么您就有了这个问题**。K-fold validation和iterated K-fold validation 是解决这一问题的两种方法。**

K-fold validation

将数据分割成大小相等的K个分区。对于每个分区i,在剩余的N-1分区上训练一个模型,并在分区i上进行计算,最后的分数将是获得的K值的平均值。当模型的性能显示出基于训练测试不同表现的显著差异时,这个方法是有帮助的。
这里写图片描述

k = 4
num_validation_samples = len(data) // k
np.random.shuffle(data)
validation_scores = []

for fold in range(k):
	# Select the validation data partition
	validation_data = data[num_validation_samples * fold: num_validation_samples * (fold + 1)]
	# The remainder of the data is used as training data.
	# Note that the "+" operator below is list concatenation, not summation
	training_data = data[:num_validation_samples * fold] + data[num_validation_samples * (fold + 1):]
	
# Create a brand new instance of our model (untrained)
model = get_model()
model.train(training_data)

validation_score = model.evaluate(validation_data)
validation_scores.append(validation_score)

# This is our validation score:
# the average of the validation scores of our k folds
validation_score = np.average(validation_scores)

# We train our final model on all non-test data available
model = get_model()
model.train(data)
test_score = model.evaluate(test_data)

在选择评估模型时,需要注意一些事情:
1. 数据的代表性。
通常希望训练集和测试集都能代表手边的数据:例如你想分类的图像数字,你从一个数组的样品拆分,数组的第一个80%作为训练集,其余20%为测试集。测试将导致你的训练集只训练0-7,而你的测试集只有类别8 - 9。这似乎是一个荒唐的错误,但却出奇的普遍。出于这个原因,需要在将数据分割成训练和测试集之前,随机地对数据进行洗牌。
2. 时间的指向。
如果你试图预测未来(例如明天的天气、股票走势等等),你不应该在拆分数据之前随机打乱数据,因为这会造成“时间漏洞”:你的模型将有效地接受未来数据的训练。在这种情况下,应该始终确保测试集中的所有数据都是在训练集中的数据后面。
3. 数据冗余
如果某些数据点在你的数据(与现实世界的数据相当普遍)出现两次,然后把数据分成训练集和测试集将导致冗余。实际上,可以测试训练数据的一部分,这是最糟糕的事情你可以做的,确保训练集和测试集是不相交的。

数据预处理

向量化
神经网络中的所有输入和目标必须是浮点数据的张量(或者在特定的情况下,是整数的张量)。无论处理声音、图像、文本的任何数据,必须首先将其转换为张量,这一步骤称为“数据向量化”。例如,在我们前面的两个文本分类示例中,我们从文本表示为整数的列表(代表单词的序列),我们使用“one-hot encoding”将它们转换为float32数据的张量。

数值归一化

在我们的数字分类示例中,我们从编码为0-255范围内的整数的图像数据开始,编码灰度值。在我们将这些数据放入我们的网络之前,我们必须将其转换为float32并除以255,这样我们就会得到0-1范围内的浮点值。类似地,在我们的房价预测例子中,我们从一系列的特性开始,这些特性包括一些具有小浮点值的特性,还有一些具有相当大的整数值。在我们将这些数据输入到我们的网络之前,我们必须对每个特性进行独立的规范化,以便每个特性的标准偏差为1,平均值为0。

数据应该:

  1. 取“小”值:通常大多数值应该在0-1范围内。
  2. 同质性,即所有特征都应该在相同的范围内取值。

此外,以下更严格的规范化实践是常见的,而且肯定会有所帮助,尽管它并不总是必要的(例如,我们在数字分类示例中没有这样做):

  1. 使每个特征独立,均值为0。
  2. 将每个特征独立,标准偏差为1。
# Assuming x is a 2D data matrix of shape (samples, features)
x -= x.mean(axis=0)
x /= x.std(axis=0)

减少过拟合

1. 减少网络的大小

防止过度拟合的最简单方法是减小模型的大小,即模型中可学习参数的数量(由层数和每层的单位数决定)。在深度学习中,模型中可学习的参数的数量通常被称为model’s “capacity”。
直观地说,一个具有更多参数的模型将有更多的“记忆容量”,因此能够很容易地学习到一个完美的字典式的映射,在训练样本和它们的目标之间,一个没有任何泛化能力的映射。要记住这一点:深度学习模式往往很适合训练数据,但真正的挑战是泛化,而不是拟合。

不幸的是,没有一个神奇的公式可以确定正确的层数,或者每一层的正确大小。不得不要评估一系列不同的体系结构(在验证集上,而不是在测试集上),以便为数据找到合适的模型大小。要找到合适的模型大小,一般的工作流程是先从相对较少的层和参数开始,然后开始增加层的大小,或者添加新的层,直到看到验证损失的收益递减。

原始的模型:

from keras import models
from keras import layers
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

减少参数后的模型:

model = models.Sequential()
model.add(layers.Dense(4, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(4, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

结果对比如下:
这里写图片描述

2. 增加权重的正则化项
L1正则化 / L2 正则化

from keras import regularizers
model = models.Sequential()
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
		activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
		activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

L2 (0.001) means that every coefficient in the weight matrix of the layer will add
0.001 * weight_coefficient_value to the total loss of the network.

同样,可以使用其他的正则化项:

from keras import regularizers
# L1 regularization
regularizers.l1(0.001)
# L1 and L2 regularization at the same time
regularizers.l1_l2(l1=0.001, l2=0.001)

3. 加入Drop Out 层

# At training time: we drop out 50% of the units in the output
layer_output *= np.randint(0, high=2, size=layer_output.shape)

# At test time:
layer_output *= 0.5

或者:

# At training time:
layer_output *= np.randint(0, high=2, size=layer_output.shape)
# Note that we are scaling *up* rather scaling *down* in this case
layer_output /= 0.5

这里写图片描述
在Keras 网络中添加Drop Out 层:

model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1, activation='sigmoid'))

机器学习的通用流程

我们在这里展示的是一个通用的蓝图,可以用来解决任何机器学习问题,将学习到的不同概念联系在一起:问题定义、评估、特征工程和解决过拟合。

  1. 定义问题并准备数据集

首先,您必须定义当前的问题:

你的输入数据会是什么?你想要预测什么?如果你有可用的训练数据,你只能学会预测一些事情,例如,如果你有电影评论和情感注解,你只能学会对电影评论的情绪进行分类。因此,在这个阶段,数据的可用性通常是限制因素(除非你有办法付钱让人们为你收集数据)。

你面临的是什么类型的问题?多层次分类?标量回归?向量回归?多层次、多标记分类?其他的,比如聚类、生成或强化学习?识别问题类型将指导来选择模型架构、损失函数等等。

直到知道输入和输出是什么,否则无法继续下一步,以及您将使用什么数据。注意你在这个阶段所做的假设:
假设你的输入可以预测你的输出;
假设你的可用数据提供了足够的信息,以了解输入和输出之间的关系;

选择一个衡量成功的标准。

要控制某样东西,你需要能够观察它。为了获得成功,你必须定义你所说的成功的准确性?Precision-Recall吗?客户保持率?你的成功度量会指导你选择你的损失函数,即你的模型将优化的选择。它应该与你的更高层次的目标直接一致。

决定一个评估协议。

一旦你知道你的目标是什么,你必须确定你将如何衡量你目前的进展。我们之前回顾了三种常见的评估协议:

  1. 建立一个完整的验证集:当你有足够多的数据时,这是一种方法。
  2. 做K-fold交叉验证:当你的样本太少时,这是一种可靠方法。
  3. 做迭代K-fold验证:这是为了在没有可用的情况下执行高度精确的模型评估。

准备你的数据集

一旦你知道你正在训练什么,你正在优化什么,以及如何评估你的方法,你几乎已经准备好开始训练模型了。但是首先,你应该以一种可以被输入到机器学习模型的方式来格式化你的数据,我们会假设一个深度神经网络:

  1. 正如我们前面所看到的,数据应该被格式化为张量。
  2. 这些张量所取的值一般应按小数值计算,例如在[- 1,1]范围或[0,1]范围内。
  3. 如果不同的特性在不同的范围(异构数据)中取值,那么数据应该是标准化的。
  4. 你可能想要做一些特性工程,特别是对于小数据问题。

一旦你的输入数据和目标数据的张量就绪,您就可以开始训练模型了。

开发一个比基准线更好的模型

在这个阶段,你的目标是实现“统计能力”,即开发一种比基准线更好的小模型。在我们的MNIST数字分类例子中,任何高于0.1的精度都可以被认为具有统计能力;在IMDB的例子中,它的精度高于0.5。

请注意,实现统计能力并不总是可行的。如果在尝试了多个合理的架构之后,如果还不能胜过一个随机的基准线,那么可能是所提出问题的答案实际上并没有出现在输入数据中。记住,你在做两个假设:

  1. 你假设你的输入可以预测你的输出。
  2. 你假设你的可用数据提供了足够的信息,以了解输入和输出之间的关系。

这些假设很可能是假的,在这种情况下,你必须回到开始。

假设事情进展顺利,你需要做三个关键的选择来建立你的第一个工作模型:

  1. 选择最后一层激活。这在网络的输出上建立了有用的约束:例如,在我们的IMDB分类示例中,我们在最后一层使用了sigmoid,在回归示例中,我们没有使用任何最后一层激活等。
  2. 损失函数的选择。它应该与您要解决的问题类型相匹配:例如,在我们的IMDB分类示例中,我们使用了binary_crossentropy,在我们回归示例中使用mse等。
  3. 优化配置的选择:您将使用什么优化器?它的学习速率是多少?在大多数情况下,使用Rmsprop和它的默认学习速率是安全的。

关于损失函数的选择:请注意,不总是可以直接优化度量问题上成功的度量标准。有时候,没有一种简单的方法可以把一个度量变成一个损失函数。毕竟,损失函数只需要提供一个小批量的数据(理想情况下,一个损失函数应该可以计算为单个数据点),并且需要是可微的(否则就不能使用反向传播来训练网络)。例如,被广泛使用的分类指标ROC-AUC(曲线下的接收器操作特征面积)不能直接优化。因此,在分类任务中,通常会对ROC-AUC的一个辅指标进行优化,比如交叉熵。一般来说,人们可以希望交叉熵值越低,ROC - AUC越高。

这里有一个表可以帮助您选择最后一层激活和一些常见问题类型的损失函数。
这里写图片描述

扩大规模:开发一种适合的模式
一旦你获得了一个具有统计能力的模型,问题就变成:你的模型足够强大吗?它是否有足够的层和参数来正确地模拟手头的问题?例如,一个带有两个单位的隐藏层的网络在MNIST上具有统计功能,但不足以解决问题。记住机器学习中的普遍张力是在优化和泛化之间,理想的模型是在拟合和过度拟合之间的边界处。在某些时刻,过度拟合,要弄清楚这条边界在哪里,首先你必须穿过它。

要想弄清楚你需要多大的模型,你必须开发一个适合的模型。这是相当容易的:

  1. 增加层数
  2. 让每一层变大
  3. 训练更多的epochs

始终监控训练损失和验证损失,以及所关心的任何指标的训练和验证值。当看到验证数据上的模型的性能开始下降时,已经过度拟合了。

调整模型并调整超参数
这部分将花费最多的时间:你将反复修改模型,训练它,评估验证数据(而不是测试数据),再修改它,直到模型达到它所能得到的为止。

你可以尝试以下方法:

  1. 增加 dropout层
  2. 尝试不同的层,增加或减少层
  3. 增加 L1 / L2 正则化
  4. 尝试不同的超参数(比如每层的神经元,优化函数的学习率)
  5. 可选地迭代特性工程:添加新特性,删除那些看起来不太有用的特性。

注意以下几点:每次使用验证过程中的反馈来调整模型时,这都将验证过程的信息泄漏到的模型中。仅仅重复几次,这是无害的,但是在许多迭代中有系统地进行,最终会导致模型过于适合验证过程(即使没有模型直接接受任何验证数据的培训)。这让你的评估过程不那么可靠,所以要记住。

一旦你建立了一个看似足够好的模型配置,你可以训练你的最终产品模型数据(训练和验证)和并在测试集上评估。如果事实证明测试集上的表现明显比验证数据要差,这可能意味着验证过程并不可靠,或者它可能意味着开始过度拟合模型的验证数据。在这种情况下,你可能希望切换到更可靠的评估协议(例如,迭代K-fold验证)。

总之,这是机器学习的通用工作流程:

  1. 定义手头的问题和你将要接受的数据,如果需要,收集这些数据或用标签标注。
  2. 选择如何在你的问题上衡量成功,你将在验证数据上监视哪些指标?
  3. 确定你的评估协议:取消验证?K-fold验证?你应该使用哪个部分的数据进行验证?
  4. 开发一个比基本基线更好的模型:具有“统计能力”的模型。
  5. 开发一个适合的模型。
  6. 根据验证数据的性能,调整模型并调优其超参数。

很多机器学习研究往往只关注最后一步,但要记住全局。

猜你喜欢

转载自blog.csdn.net/hanzy88/article/details/79589022
今日推荐