2020-07-25 14:36:03

作者 | BoCong-Deng

责编 | 屠敏

出品 | CSDN 博客

封图 | CSDN 付费下载自东方 IC

写在前面

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

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

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

    作者 | BoCong-Deng 编辑 | 屠敏 封图 | 自东方 IC 出品 | CSDN 博客 写在前面 在我们进行模型训练时,如果你只是想要让模型具有不错的性能,那么盲目地尝试网络架构足以达到目 ...

  2. Spring Boot 2.2 正式发布,性能大幅提升、Java 13 支持|CSDN博文精选

    作者 | 程序猿DD 责编 | 郭芮 出品 | CSDN博客 之前 Spring Boot 2.2没能按时发布,是由于 Spring Framework 5.2 的发布受阻而推迟.这次随着 Sprin ...

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

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

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

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

  5. 提高模型泛化能力的几大方法

    作者:OpenMMLab 链接:https://www.zhihu.com/question/540433389/answer/2629056736 来源:知乎 著作权归作者所有.商业转载请联系作者获 ...

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

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

  7. 使用CSS提高网站性能的30种方法

    根据httparchive.org的页面重量报告,CSS在平均70个请求和2MB的网页上占7个HTTP请求和70Kb的代码.这并不是网站性能糟糕的最坏原因(我正看着你呢,JavaScript),但CS ...

  8. 提高电脑性能增加fps的方法

    1.显卡设置 鼠标设置 键盘设置 电源管理 高级系统设置 360设置

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

最新文章

  1. C#二叉树遍历算法实现浅析
  2. 第二周 表格、字典、元组、集合 知识点
  3. 斯坦福大学深度学习与自然语言处理第二讲:词向量
  4. 内存墙,多核CPU的终结者?
  5. Linux基础学习五:软件的相关安装(JDK,Tomcat,Yum)
  6. [转载] Python数据分析与可视化学习笔记(一)数据分析与可视化概述
  7. Fragment控件初始化
  8. android 7.0添加菜单,Android 7.0 settings中添加/删除菜单
  9. halcon 深度学习英伟达显卡部署
  10. docker安装nessus
  11. stc15单片机c语言 pdf,stc15单片机编程指南.pdf
  12. Android 三方数据库ObjectBox使用
  13. 同态加密之Paillier算法
  14. 一分钟整明白web前端和Java后端的就业前景
  15. 飞思卡尔单片机PLL时钟总线模块
  16. 《痞子衡嵌入式半月刊》 第 24 期
  17. 一个简单的定时任务调度中心设计方案
  18. codewars--js--Pete, the baker
  19. Android手机修改hosts文件
  20. 国际NFT交易所排行榜前10名

热门文章

  1. mysql計劃任務_MySQL計劃任務 | 學步園
  2. python读取浮点数与源文件不同
  3. Some inputs do not have OOB scores. This probably means too few trees were used to compute any relia
  4. udacity 同学 pca 客户细分实例操作
  5. PATH 与CLASSPATH区别
  6. 修改完 字符串单词首字母大写
  7. 人机语言(MML: Man-Machine Language)
  8. oracle 9i 在安装到Oracle Database Configuration assistant....的时候
  9. 计算机如何用计算机语言显示汉字,计算机是如何执行程序的呢?什么是编程语言?中国怎么不用中文编程?...
  10. Flex 3权威指南