python深度学习——高级的深度学习最佳实践

Keras 函数式 API
使用函数式 API,可以直接操作张量,也可以把层当作函数来使用,接收张量并返回张量。

from keras import Input, layers
input_tensor = Input(shape=(32,)) 
# 一个层是一个函数
dense = layers.Dense(32, activation='relu') 
# 可以在一个张量上调用一个层,它会返回一个张量
output_tensor = dense(input_tensor)

函数式API举例

from keras.models import Sequential, Model 
from keras import layers 
from keras import Input 

#  Sequential 模型
seq_model = Sequential()
seq_model.add(layers.Dense(32, activation='relu', input_shape=(64,))) 
seq_model.add(layers.Dense(32, activation='relu')) 
seq_model.add(layers.Dense(10, activation='softmax')) 

 # 对应的函数式 API 实现
input_tensor = Input(shape=(64,))   
x = layers.Dense(32, activation='relu')(input_tensor) 
x = layers.Dense(32, activation='relu')(x) 
output_tensor = layers.Dense(10, activation='softmax')(x) 
 
model = Model(input_tensor, output_tensor)   
 
model.summary()

高级架构模式

1. 批标准化
批标准化(batch normalization)是Ioffe 和 Szegedy 在 2015 年提出的一种层的类型(在 Keras 中是 BatchNormalization,即使在训练过程中均值和方差随时间发生变化,它也可以 适应性地将数据标准化。批标准化的工作原理是,训练过程中在内部保存已读取每批数据均值和方差的指数移动平均值。批标准化的主要效果是,它有助于梯度传播(这一点和残差连接很像),因此允许更深的网络。对于有些特别深的网络,只有包含多个 BatchNormalization 层时才能进行训练。例如,BatchNormalization 广泛用于Keras 内置的许多高级卷积神经网络架构,比如 ResNet50、Inception V3 和 Xception。
BatchNormalization 层通常在卷积层或密集连接层之后使用。

# 在卷积层之后使用
conv_model.add(layers.Conv2D(32, 3, activation='relu'))   
conv_model.add(layers.BatchNormalization()) 
 # 在Dense层之后使用
dense_model.add(layers.Dense(32, activation='relu'))  
dense_model.add(layers.BatchNormalization())

BatchNormalization 层接收一个axis 参数,它指定应该对哪个特征轴做标准化。这个参数的默认值是-1,即输入张量的最后一个轴。对于 Dense 层、Conv1D 层、RNN 层和将 data_format 设为"channels_last"(通道在后)的 Conv2D 层,这个默认值都是正确的。 但有少数人使用将 data_format 设为 “channels_first”(通道在前)的 Conv2D 层,这时 特征轴是编号为 1 的轴,因此,BatchNormalization 的 axis 参数应该相应地设为 1。
2. 深度可分离卷积
是深度可分离卷积(depthwise separable convolution)层(SeparableConv2D)可以替代 Conv2D,并可以让模型更加轻量(即更少的可训练权 重参数)、速度更快(即更少的浮点数运算),还可以让任务性能提高几个百分点。
这个层对输入的每个通道分别执行空间卷积,然后通过逐点卷积(1×1 卷积)将输出通道混合,如下图所示:
python深度学习——高级的深度学习最佳实践_第1张图片
相当于将空间特征学习和通道特征学习分开,如果你假设输入中的 空间位置高度相关,但不同的通道之间相对独立,那么这么做是很有意义的。它需要的参数要 少很多,计算量也更小,因此可以得到更小、更快的模型。因为它是一种执行卷积更高效的方法, 所以往往能够使用更少的数据学到更好的表示,从而得到性能更好的模型。
3. 超参数优化
超参数优化的过程通常如下所示。
(1) 选择一组超参数(自动选择)。
(2) 构建相应的模型。
(3) 将模型在训练数据上拟合,并衡量其在验证数据上的最终性能。
(4) 选择要尝试的下一组超参数(自动选择)。
(5) 重复上述过程。
(6) 最后,衡量模型在测试数据上的性能。
这个过程的关键在于,给定许多组超参数,使用验证性能的历史来选择下一组需要评估的超参数的算法。有多种不同的技术可供选择:贝叶斯优化、遗传算法、简单随机搜索等。
训练模型权重相对简单:在小批量数据上计算损失函数,然后用反向传播算法让权重向正确的方向移动。与此相反,更新超参数则非常具有挑战性。我们来考虑以下两点。
‰ 计算反馈信号(这组超参数在这个任务上是否得到了一个高性能的模型)的计算代价可能非常高,它需要在数据集上创建一个新模型并从头开始训练。
‰ 超参数空间通常由许多离散的决定组成,因而既不是连续的,也不是可微的。因此,你通常不能在超参数空间中做梯度下降。相反,你必须依赖不使用梯度的优化方法,而这 些方法的效率比梯度下降要低很多。
这些挑战非常困难,而这个领域还很年轻,因此我们目前只能使用非常有限的工具来优 化模型。通常情况下,随机搜索(随机选择需要评估的超参数,并重复这一过程)就是最好的 解决方案,虽然这也是最简单的解决方案。但我发现有一种工具确实比随机搜索更好,它就是 Hyperopt。它是一个用于超参数优化的Python 库,其内部使用Parzen 估计器的树来预测哪组超 参数可能会得到好的结果。另一个叫作Hyperas 的库将Hyperopt 与 Keras 模型集成在一起。
在进行大规模超参数自动优化时,有一个重要的问题需要牢记,那就是验证集过拟合。 因为你是使用验证数据计算出一个信号,然后根据这个信号更新超参数,所以你实际上 是在验证数据上训练超参数,很快会对验证数据过拟合。请始终记住这一点。

4. 模型集成
集成依赖于这样的假设,即对于独立训练的不同良好模型,它们表现良好可能是因为不同 的原因:每个模型都从略有不同的角度观察数据来做出预测,得到了“真相”的一部分,但不是全部真相。
以分类问题为例。想要将一组分类器的预测结果汇集在一起[即分类器集成(ensemble the classifiers)],最简单的方法就是将它们的预测结果取平均值作为预测结果。

# 使用4 个不同的模型来 计算初始预测
preds_a = model_a.predict(x_val)   
preds_b = model_b.predict(x_val) 
preds_c = model_c.predict(x_val) 
preds_d = model_d.predict(x_val) 
 # 这个新的预测数组应该 比任何一个初始预测都 更加准确
final_preds = 0.25 * (preds_a + preds_b + preds_c + preds_d)

只有这组分类器中每一个的性能差不多一样好时,这种方法才奏效。如果其中一个分类器 性能比其他的差很多,那么最终预测结果可能不如这一组中的最佳分类器那么好。

将分类器集成有一个更聪明的做法,即加权平均,其权重在验证数据上学习得到。通常来说,更好的分类器被赋予更大的权重,而较差的分类器则被赋予较小的权重。为了找到一组好 的集成权重,你可以使用随机搜索或简单的优化算法(比如 Nelder-Mead 方法)。

preds_a = model_a.predict(x_val)  
preds_b = model_b.predict(x_val)  
preds_c = model_c.predict(x_val)  
preds_d = model_d.predict(x_val) 
 # 假设 (0.5, 0.25, 0.1, 0.15) 这些权重是根据经验学到的
final_preds = 0.5 * preds_a + 0.25 * preds_b + 0.1 * preds_c + 0.15 * preds_d 

还有许多其他变体,比如你可以对预测结果先取指数再做平均。一般来说,简单的加权平均, 其权重在验证数据上进行最优化,这是一个很强大的基准方法。

想要保证集成方法有效,关键在于这组分类器的多样性(diversity)。是多样性让集成方法能够取得良好效果。用机器学习的术语来说,如果所有模型的偏 差都在同一个方向上,那么集成也会保留同样的偏差。如果各个模型的偏差在不同方向上,那 么这些偏差会彼此抵消,集成结果会更加稳定、更加准确。 因此,集成的模型应该尽可能好,同时尽可能不同。这通常意味着使用非常不同的架构, 甚至使用不同类型的机器学习方法。有一件事情基本上是不值得做的,就是对相同的网络,使 用不同的随机初始化多次独立训练,然后集成。如果模型之间的唯一区别是随机初始化和训练 数据的读取顺序,那么集成的多样性很小,与单一模型相比只会有微小的改进。
有一种方法在实践中非常有效(但这一方法还没有推广到所有问题领域),就是将基 于树的方法(比如随机森林或梯度提升树)和深度神经网络进行集成。值得一提的是,集成中的某一个模型来源于与其他模型都不相同的方法(它是正 则化的贪婪森林),并且得分也远远低于其他模型。不出所料,它在集成中被赋予了一个很小的 权重。但出乎我们的意料,它极大地改进了总体的集成结果,因为它和其他所有模型都完全不同, 提供了其他模型都无法获得的信息。这正是集成方法的关键之处。集成不在于你的最佳模型有 多好,而在于候选模型集合的多样性。

近年来,一种在实践中非常成功的基本集成方法是宽且深(wide and deep)的模型类型, 它结合了深度学习与浅层学习。这种模型联合训练一个深度神经网络和一个大型的线性模型。 对多种模型联合训练,是实现模型集成的另一种选择。

你可能感兴趣的:(深度学习)