作者 | BoCong-Deng

编辑 | 屠敏

封图 | 自东方 IC

出品 | CSDN 博客

写在前面

在我们进行模型训练时,如果你只是想要让模型具有不错的性能,那么盲目地尝试网络架构足以达到目的。而在本文中, 我们将为你提供一套用于构建最先进深度学习模型的必备技术的快速指南,从而让模型由“具有不错的性能”上升到“性能卓越且满足我们的一些需要”。本文的叙述以及代码的编写时基于TensorFlow中Keras来进行表述的。

高级架构模式

残差连接

残差连接(residual connection)是一种常见的类图网络组件,在 2015 年之后的许多网络架构 (包括Xception)中都可以见到。2015 年末,来自微软的何恺明等人在ILSVRC ImageNet 挑战赛 中获胜,其中引入了这一方法。残差连接解决了困扰所有大规模深度学习模型的两个共性问题:梯度消失和表示瓶颈。

通常来说,向任何多于 10 层的模型中添加残差连接,都可能会有所帮助。残差连接是让前面某层的输出作为后面某层的输入,从而在序列网络中有效地创造了一条 捷径。前面层的输出没有与后面层的激活连接在一起,而是与后面层的激活相加(这里假设两 个激活的形状相同)。

如果它们的形状不同,我们可以用一个线性变换将前面层的激活改变成目标形状(例如,这个线性变换可以是不带激活的 Dense 层;对于卷积特征图,可以是不带激活 1×1 卷积)。如果特征图的尺寸相同,在 Keras 中实现残差连接的方法如下,用的是恒等残差连接(identity residual connection)。这个例子假设我们有一个四维输入张量 x。

from keras import layersx = ... y = layers.Conv2D(128, 3, activation='relu', padding='same')(x) y = layers.Conv2D(128, 3, activation='relu', padding='same')(y) y = layers.Conv2D(128, 3, activation='relu', padding='same')(y)  y = layers.add([y, x])

如果特征图的尺寸不同,实现残差连接的方法如下,用的是线性残差连接(linear residual connection)。同样,假设我们有一个四维输入张量 x。

from keras import layers  x = ... y = layers.Conv2D(128, 3, activation='relu', padding='same')(x) y = layers.Conv2D(128, 3, activation='relu', padding='same')(y) y = layers.MaxPooling2D(2, strides=2)(y)  residual = layers.Conv2D(128, 1, strides=2, padding='same')(x)    y = layers.add([y, residual])

批标准化

标准化(normalization)是一大类方法,用于让机器学习模型看到的不同样本彼此之间更加 相似,这有助于模型的学习与对新数据的泛化。最常见的数据标准化形式就是你已经在本书中 多次见到的那种形式:将数据减去其平均值使其中心为0,然后将数据除以其标准差使其标准 差为 1。实际上,这种做法假设数据服从正态分布(也叫高斯分布),并确保让该分布的中心为 0, 同时缩放到方差为 1。

normalized_data = (data - np.mean(data, axis=...)) / np.std(data, axis=...)

前面的示例都是在将数据输入模型之前对数据做标准化。但在网络的每一次变换之后都应该考虑数据标准化。即使输入 Dense 或 Conv2D 网络的数据均值为0、方差为1,也没有理由 假定网络输出的数据也是这样。

批标准化(batch normalization)是Ioffe 和 Szegedy 在 2015 年提出的一种层的类型 a(在 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_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。

深度可分离卷积

如果我告诉你,有一个层可以替代 Conv2D,并可以让模型更加轻量(即更少的可训练权 重参数)、速度更快(即更少的浮点数运算),还可以让任务性能提高几个百分点,你觉得怎么样?我说的正是深度可分离卷积(depthwise separable convolution)层(SeparableConv2D)的作用。这个层对输入的每个通道分别执行空间卷积,然后通过逐点卷积(1×1 卷积)将输出通道混合,如下图。这相当于将空间特征学习和通道特征学习分开,如果你假设输入的 空间位置高度相关,但不同的通道之间相对独立,那么这么做是很有意义的。它需要的参数要少很多,计算量也更小,因此可以得到更小、更快的模型。因为它是一种执行卷积更高效的方法, 所以往往能够使用更少的数据学到更好的表示,从而得到性能更好的模型。

超参数优化

构建深度学习模型时,你必须做出许多看似随意的决定:应该堆叠多少层?每层应该 包含多少个单元或过滤器?激活应该使用 relu 还是其他函数?在某一层之后是否应该使用 BatchNormalization ?应该使用多大的dropout 比率?还有很多。这些在架构层面的参数叫作超参数(hyperparameter),以便将其与模型参数区分开来,后者通过反向传播进行训练。

在实践中,经验丰富的机器学习工程师和研究人员会培养出直觉,能够判断上述选择哪些 可行、哪些不可行。也就是说,他们学会了调节超参数的技巧。但是调节超参数并没有正式成 文的规则。如果你想要在某项任务上达到最佳性能,那么就不能满足于一个容易犯错的人随意 做出的选择。即使你拥有很好的直觉,最初的选择也几乎不可能是最优的。你可以手动调节你 的选择、重新训练模型,如此不停重复来改进你的选择,这也是机器学习工程师和研究人员大 部分时间都在做的事情。但是,整天调节超参数不应该是人类的工作,最好留给机器去做。

因此,你需要制定一个原则,系统性地自动探索可能的决策空间。你需要搜索架构空间, 并根据经验找到性能最佳的架构。这正是超参数自动优化领域的内容。这个领域是一个完整的 研究领域,而且很重要。

超参数优化的过程通常如下所示。

  • 选择一组超参数(自动选择)。

  • 构建相应的模型。

  • 将模型在训练数据上拟合,并衡量其在验证数据上的最终性能。

  • 选择要尝试的下一组超参数(自动选择)。

  • 重复上述过程。

  • 最后,衡量模型在测试数据上的性能。

这个过程的关键在于,给定许多组超参数,使用验证性能的历史来选择下一组需要评估的 超参数的算法。有多种不同的技术可供选择:贝叶斯优化、遗传算法、简单随机搜索等。训练模型权重相对简单:在小批量数据上计算损失函数,然后用反向传播算法让权重向正确的方向移动。与此相反,更新超参数则非常具有挑战性。我们来考虑以下两点。

  • 计算反馈信号(这组超参数在这个任务上是否得到了一个高性能的模型)的计算代价可能非常高,它需要在数据集上创建一个新模型并从头开始训练。

  • 超参数空间通常由许多离散的决定组成,因而既不是连续的,也不是可微的。因此,你通常不能在超参数空间中做梯度下降。相反,你必须依赖不使用梯度的优化方法,而这些方法的效率比梯度下降要低很多。

这些挑战非常困难,而这个领域还很年轻,因此我们目前只能使用非常有限的工具来优 化模型。通常情况下,随机搜索(随机选择需要评估的超参数,并重复这一过程)就是最好的 解决方案,虽然这也是最简单的解决方案。但有一种工具确实比随机搜索更好,它就是 Hyperopt。它是一个用于超参数优化的Python 库,其内部使用Parzen 估计器的树来预测哪组超 参数可能会得到好的结果。另一个叫作Hyperas 的库将Hyperopt 与 Keras 模型集成在一起。一 定要试试。

模型集成

想要在一项任务上获得最佳结果,另一种强大的技术是模型集成(model ensembling)。集 成是指将一系列不同模型的预测结果汇集到一起,从而得到更好的预测结果。观察机器学习竞赛, 特别是Kaggle 上的竞赛,你会发现优胜者都是将很多模型集成到一起,它必然可以打败任何单 个模型,无论这个模型的表现多么好。

集成依赖于这样的假设,即对于独立训练的不同良好模型,它们表现良好可能是因为不同 的原因:每个模型都从略有不同的角度观察数据来做出预测,得到了“真相”的一部分,但不 是全部真相。你可能听说过盲人摸象的古代寓言:一群盲人第一次遇到大象,想要通过触摸来 了解大象。每个人都摸到了大象身体的不同部位,但只摸到了一部分,比如鼻子或一条腿。这 些人描述的大象是这样的,“它像一条蛇”“像一根柱子或一棵树”,等等。这些盲人就好比机器 学习模型,每个人都试图根据自己的假设(这些假设就是模型的独特架构和独特的随机权重初 始化)并从自己的角度来理解训练数据的多面性。每个人都得到了数据真相的一部分,但不是 全部真相。将他们的观点汇集在一起,你可以得到对数据更加准确的描述。大象是多个部分的 组合,每个盲人说的都不完全准确,但综合起来就成了一个相当准确的故事。

我们以分类问题为例。想要将一组分类器的预测结果汇集在一起[即分类器集成(ensemble the classifiers)],最简单的方法就是将它们的预测结果取平均值作为预测结果。

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)  final_preds = 0.5 * preds_a + 0.25 * preds_b + 0.1 * preds_c + 0.15 * preds_d

还有许多其他变体,比如你可以对预测结果先取指数再做平均。一般来说,简单的加权平均, 其权重在验证数据上进行最优化,这是一个很强大的基准方法。想要保证集成方法有效,关键在于这组分类器的多样性(diversity)。多样性就是力量。如 果所有盲人都只摸到大象的鼻子,那么他们会一致认为大象像蛇,并且永远不会知道大象的真 实模样。是多样性让集成方法能够取得良好效果。用机器学习的术语来说,如果所有模型的偏 差都在同一个方向上,那么集成也会保留同样的偏差。如果各个模型的偏差在不同方向上,那么这些偏差会彼此抵消,集成结果会更加稳定、更加准确。

版权声明:本文为CSDN博主「BoCong-Deng」的原创文章。

原文:

https://blog.csdn.net/DBC_121/article/details/107515163

推荐阅读

  • 98年“后浪”科学家,首次挑战图片翻转不变性假设,一作拿下CVPR最佳论文提名

  • 残差网络的前世今生与原理 | 赠书

  • 适合 Python 入门的 8 款强大工具

  • 芯片破壁:摩尔定律的一次次“惊险”续命

  • 观点 | ETH 2.0 经济模型分析报告简述

如何提高模型性能?这四大方法值得尝试 | CSDN 博文精选相关推荐

  1. 如何提高模型性能?这几个方法值得尝试 | CSDN 博文精选

    2020-07-25 14:36:03 作者 | BoCong-Deng 责编 | 屠敏 出品 | CSDN 博客 封图 | CSDN 付费下载自东方 IC 写在前面 在我们进行模型训练时,如果你只是 ...

  2. 人工干预如何提高模型性能?看这文就够了!

    作者 | Preetam Joshi 译者 | 吴家帆 出品 | AI科技大本营(ID:rgznai100) 有一些行业对误报非常敏感,如金融行业,在对信用卡欺诈检测时,如果检测系统将用户的行为错误地 ...

  3. PyTorch实现L2和L1正则化的方法 | CSDN博文精选

    作者 | pan_jinquan 来源 | CSDN博文精选 目录 1.torch.optim优化器实现L2正则化 2.如何判断正则化作用了模型? 2.1未加入正则化loss和Accuracy 2.1 ...

  4. 【调参10】:如何通过组合多个神经网络提高模型性能

    文章目录 前言 1. 使用融合模型减少模型的方差 2. 如何融合神经网络模型 2.1 使用不同的训练数据 2.2 使用不同的模型 2.3 使用不同的融合方式 3. tensorflow keras 实 ...

  5. 【深度学习】常见的提高模型泛化能力的方法

    前言 模型的泛化能力是其是否能良好地应用的标准,因此如何通过有限的数据训练泛化能力更好的模型也是深度学习研究的重要问题.仅在数据集上高度拟合而无法对之外的数据进行正确的预测显然是不行的.本文将不断总结 ...

  6. 提高网站性能的常见方法

    Web前端性能优化 浏览器访问优化 减少http请求:HTTP协议是无状态的应用层协议,意味着每次HTTP请求都需要简历通信链路,进行数据传输,而在服务器端,每个HTTP都需要启动独立的线程去处理,这 ...

  7. 提高cube性能的一些方法(一)

    1. 尽量不要在Cube里放太detail的数据,这种需求首先考虑R3用ABAP解决,如果非要在BW,可以考虑在DSO出明细报表,在Cube出汇总报表,通过RRI接口调用明细报表.关于RRI,请看: ...

  8. YOLOv7改进Transformer主干系列:最新结合BoTNet Transformer结构,一种简单却功能强大的backbone,自注意力提高模型性能

  9. 怎么把音乐中的伴奏提取出来?这几个方法值得尝试一番

    大家平时在KTV唱歌的时候,是喜欢跟着原声一起唱,还是喜欢跟着伴奏唱歌呢?大家应该知道,伴奏就是将歌曲中的人声提取出来,只有音乐的声音.那么当你想唱歌的时候,找了半天却没有伴奏,需要怎么办好呢?其实我 ...

最新文章

  1. 推荐系统笔记:Introduction
  2. JavaScript基础8——弹窗案例
  3. 云痕大数据考试中途可以退出吗_2020CPA考试出考率,创新低?
  4. Python+OpenCV人脸识别技术详解
  5. IDEA 中tomcat上面有个x 而且找不到配置tomcat的选项
  6. Asp.Net页面传值的方法简单总结【原创】
  7. JTable常见用法细则
  8. vuex的命名空间有哪些_Vuex在vue路由器中访问命名空间模块的getter
  9. 项目构建之springboot集成lomback.xml,和log4j基于properties方式的日志配置记录
  10. 【英语学习】【Level 08】U01 Let's Read L2 Of fairies and princesses
  11. transformer模型_【预训练模型】万字长文梳理NLP预训练模型!从transformer到albert...
  12. 纳米丸穿透癌细胞(癌症)
  13. 开源中国软件频道_编程小黑马
  14. AI人工智能+区块链+物联网+大数据可视化平台建设综合解决方案
  15. 记一次刷路由器固件的经历
  16. 学计算机高中应选什么科目,新高考选哪些科目可以报计算机?高中生如何进步?...
  17. 虚拟现实大作业——太阳系
  18. 游戏程序员的2012年终总结
  19. UNITY 模拟手机滑屏功能
  20. OpenGL基础渲染

热门文章

  1. 22.CSS边框与背景【上】
  2. 《HTML5游戏编程核心技术与实战》——2.8 小结
  3. Tesseract 3 语言数据的训练方法
  4. expdp数据泵导出操作
  5. POJ 3070 Fibonacci
  6. 更加安全的存取账户密码
  7. 诊断IIS中的ASP0115错误
  8. linux下网卡状态,linux-网络状态
  9. android h5 多图上传源码,JS移动端/H5同时选择多张图片上传并使用canvas压缩图片...
  10. 贪心  POJ - 3617 ​​​​​​​Best Cow Line