TowardsDataScience 博客中文翻译 2021(三百九十四)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

如何在数据流上训练深度神经网络

原文:https://towardsdatascience.com/how-to-train-deep-neural-networks-over-data-streams-fdab15704e66?source=collection_archive---------10-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源

历史上,已经开发了许多机器学习算法来处理和学习传入的数据流。例如,支持向量机和逻辑回归机等模型已被推广到学习者无法获得整个数据集的情况,训练必须在输入的连续数据流上进行[1,2]。类似地,许多聚类算法已经被提出用于数据流的学习[3]。这些方法迫使底层模型从一个连续的数据流中学习,该数据流一次只提供一个示例,从而消除了立即提供整个数据集的需要。有趣的是,尽管已经为更传统的机器学习算法开发了流学习的方法,但是流学习并没有被广泛地用于深度神经网络,其中离线训练(即,在整个数据集上执行若干循环/时期)占主导地位。

为了缩小这一差距,深度学习社区最近的工作探索了通过流式传输训练深度网络的可能性。在深度学习领域中,流可以被描述为一种学习设置,其中 (i) 数据集一次学习一个示例(即,数据集被呈现为传入的数据流) (ii) 数据集中的每个唯一示例仅出现一次, (iii) 流中数据的排序是任意的, (iv) 正在训练的模型可以在数据流中的任何点进行评估。与训练神经网络的典型离线方法相比,这种设置可能看起来相当苛刻,这解释了为什么在流设置中实现高性能通常很困难。尽管如此,流式学习反映了工业中的许多应用,并且如果正确使用,为深度学习实践者提供了强大的工具。

在这篇文章中,我将概述深度学习中的流。我将从激励使用流学习开始,重点关注流学习在实际应用中的效用。然后,我将概述在流设置中训练深度神经网络的现有方法,强调在实践中最有用的方法。通过这篇文章,我的目标是 i) 说明流学习和深度学习之间的关系,以及 ii) 概述在实际应用中利用流学习的力量的有用发现。

为什么选择流式学习?

**分流与其他培训模式有何关系?**在提出流学习[4]之前,研究了许多训练设置,这些训练设置探索了不同的策略,这些策略将部分不相交的数据子集顺序暴露给模型,而不是以离线方式对整个数据集进行训练。在这篇文章中,我将把所有这样的方法(包括流学习)统称为“在线”学习设置。通常,在线学习将数据集分成几个不相交的“批”数据,模型一次只暴露一批。一旦学习了一批数据,该模型就不能在以后的训练过程中返回到该批数据(即,只有“当前”数据可以被直接访问以训练该模型)。

已经提出了在线学习的许多不同变体(例如,终身学习、持续学习、批量/班级增量学习、流学习等)。).这些不同的变体中的每一个都涉及上述在线学习的相同概念,通常对实验设置有微小的改变。例如,终身学习倾向于按顺序学习不同的任务(即,每个任务可以被认为是来自包含所有任务的数据集中的数据的子集/批次),而类增量学习针对每个批次内的总体分类问题学习严格的类子集(例如,CIFAR100 的前 20 个类)。值得注意的是,在线学习过程中的每一批数据都可能非常大。例如,类增量学习实验经常在 ImageNet 上进行,其中每批包含完整数据集的 100 个类子集(即~130K 数据示例)。

流式学习也可以被解释为上述在线学习描述的变体,其中每个“批”数据只是来自数据集的单个示例。然而,流学习似乎比其他相关的方法更偏离通常的在线学习设置。也就是说,流式学习,因为它被限制为一次学习一个实例的数据集,所以不能在每次有新的一批数据可用时执行任意数量的离线训练。这是因为一次只有一个数据示例可供模型使用,而按顺序对同一数据执行多次更新会迅速降低模型性能。因此,流式学习方法倾向于在新数据可用时执行简短的实时模型更新,而其他在线学习方法通常执行昂贵的离线培训程序来学习每一批新数据。

为什么在线学习很难?当一个人第一次遇到在线学习的话题时,他们可能会认为解决这个问题很容易。为什么不在新数据可用时对模型进行微调呢?这种幼稚的方法在某些情况下是有效的。特别是,如果传入数据流是 i.i.d. ,它将工作,这意味着每一段传入数据都是从所有可能的数据示例中均匀采样的。在这种情况下,从数据流中学习等同于为每个训练迭代从数据集中均匀地采样一个例子(即,这只是随机梯度下降!),而且幼稚的微调也挺管用的。然而,我们不能总是确保传入的数据是独立身份的。事实上,许多值得注意的实际应用的特征在于非独立身份的数据流(例如,视频流、个性化行为跟踪、对象跟踪等。).

虽然当输入数据是独立身份数据时,在线学习很容易解决,但当数据是非独立身份数据时,会出现一个有趣的现象-模型从新数据中学习,但很快就会忘记之前学习的所有内容。例如,在类增量学习的情况下,模型可能开始学习如何对马进行分类(即,它以前没有遇到过的某个类),但是完全忘记了如何对狗、猫、松鼠以及过去已经学会分类的所有其他动物进行分类。这个问题——通常被称为灾难性遗忘[5,6]——是所有在线学习技术面临的基本问题。也就是说,因为数据流通常是非独立的,以在线方式学习的模型通常会遭受灾难性的遗忘,这极大地影响了它们的性能(尤其是在最近没有观察到的数据上)。

**流学习更实用。**现在,我们对流式学习、一般的在线学习以及二者所面临的问题有了更好的理解,有人可能会问这样一个问题:*为什么要特别关注流式学习?*主要原因是流学习 i) 实时发生, ii) 更好地反映了实践中出现的常见学习范式。

因为学习在流内一次发生一个示例,所以模型更新往往是简短的(即,每个示例一次或几次向前/向后传递)。因此,在新数据示例到达和底层模型适应该数据示例之间存在最小的延迟— 当新数据可用时,模型会实时更新。相比之下,当 i) 等待足够大批量的新数据积累,或者 ii) 在新一批数据可用之后更新模型时,其他通常研究的在线学习设置可能会遭受延迟——必须执行许多向前/向后传递,以更新大批量数据的模型,特别是如果对数据执行了几次循环。虽然从研究的角度来看,这种在线学习的替代实验设置很有趣,但是当他们有能力在每个新样本到来后更新模型时,为什么任何从业者都要等待数据积累呢?

流学习使模型实时适应数据流的能力在工业中也有广泛的应用。例如,考虑一个推荐系统,该系统在用户每次与网站交互时(例如,购买、点击或者甚至鼠标的移动)执行动态更新。或者,可以利用深度网络来执行视频插值(例如,在给定前几帧的情况下,预测人在下一帧中的位置),并利用流学习来基于其在每一帧中所犯的错误在视频流上更新该模型。流式学习的可能性几乎是无限的,因为它适用于深度网络应该立即从输入数据中学习的任何情况。因此,它(在我看来)是一个值得深度学习从业者关注的话题。

深度流学习的方法

现在,流学习已经被定义和激励,是时候学习如何在数据流上实际训练神经网络,而不会严重降低它们的性能。最近,在深度学习社区中提出了几种以流方式训练深度神经网络的算法[4,7,8]。对于每个算法,我将概述该方法的主要组件和细节,并强调在实践中实现该算法的主要实际考虑。在这一节中,我将重点介绍每种方法的主要细节,这些细节可以让实践者更好地理解哪种方法最适合给定的应用程序。

ExStream [4]

ExStream 于 2019 年 2 月提出,是一种基于重放的流式学习方法。这里,“重放”(也称为预演)用于描述将来自传入数据流的先前遇到的数据存储在缓冲区中的方法。然后,当新数据变得可用时,基于重放的方法将新数据与来自重放缓冲区的数据样本混合,并使用这种新旧数据的混合来更新模型,从而确保先前的知识得以保留。简而言之,这些方法用新旧数据的混合来训练网络,以确保网络暴露于来自数据流的一组平衡的示例。重播是在线学习中广泛使用的一种方法,既简单又有效,但它需要存储以前的数据,这会产生不可忽略的内存占用。

虽然 ExStream 证明了“完全”重放(即,将所有传入数据存储在重放缓冲区中,并在每次遇到新数据时循环通过重放缓冲区中的所有示例)消除了灾难性遗忘,但是还探索了不需要存储整个数据流的更节省存储器的重放机制。使用 ResNet50 [9]来执行图像分类,ExStream 预训练并固定底层模型的卷积层(即,在流式传输过程中不会更新任何卷积层参数),并专注于以流式传输方式学习最终的全连接层。因此,存储在重放缓冲器中的所有例子都是简单的向量(即,ResNet 的特征提取器/主干的输出)。使用这些特征向量作为输入,ExStream 为每类数据维护一个单独的固定大小的重放缓冲区(即,每类只能存储c个向量),并旨在发现一种算法,该算法使 i) 最大限度地减少必须存储以供重放的向量数量(即,这限制了内存开销) ii) 保持最先进的分类性能(即,可与完全重放相比)。

为了实现这些目标,ExStream 利用以下规则集在流式传输期间维护其重放缓冲区:

  • 保持c簇质心(即,只是向量!)每个类,每个类都有一个与之相关联的“计数”。
  • 在数据流中遇到一个类的c示例之前,只需将每个向量添加到重放缓冲区,计数为 1。
  • 一旦给定类的缓冲区已满,并且该类的新示例到达,找到两个最近的聚类质心(基于欧几里德距离),并通过基于它们各自的计数对向量进行加权平均来将它们合并在一起。将结果质心的计数设置为前两个质心的计数之和。
  • 一旦两个质心合并(从而为新的质心腾出空间),将新的数据示例添加到缓冲区中,计数为 1。

使用如上所述维护的重放缓冲区,ExStream 然后通过采样和混合来自不同类的聚类质心与传入数据来执行重放,以对模型参数执行更新。与用于在重放缓冲区内维护聚类质心的几种其他算法(例如,在线 k-means、CluStream [10]、HPStream [11]等)相比,),ExStream 表现出最佳性能。此外,通过调整重放缓冲区内每个类所允许的质心数量,可以很容易地调整算法的内存占用量(尽管重放缓冲区太小可能会导致较差的性能)。ExStream 在 Core50 和 iCUB 数据集上表现良好,但在后来的工作发表之前,没有应用于大规模分类问题(如 ImageNet)。

深沉的 SLDA [7]

深度流线性判别分析(SLDA)于 2020 年 4 月提出,是深度流学习的另一种方法,它脱离了基于重放的方法(即,它不保持任何重放缓冲)。因此,与需要重放缓冲区的 ExStream 等方法相比,它的内存效率非常高,从而(潜在地)使其适合内存受限的学习场景(例如,设备上学习)。SLDA 是一个已经建立的算法[12],已经用于数据挖掘社区中的数据流分类。在深度 SLDA 中,通过使用固定的 ResNet18 [9]主干的 i) 将 SLDA 算法与深度神经网络相结合,以获得每个数据示例的特征向量,并通过使用 SLDA 的【T2 ii)以流的方式对这些特征向量进行增量分类。同样,除了最终分类模块(即,SLDA 组件),所有网络层在深度 SLDA 的流式传输过程中是固定的。

用 SLDA 以递增的方式对特征向量进行分类的细节超出了本文的范围——这种算法很复杂,可能需要一篇完整的博文来真正理解它。然而,在高层次上,SLDA 通过 i) 用相关计数维护每个类的单个平均向量,以及 ii) 构建表征类表示之间关系的共享协方差矩阵来操作。当新数据变得可用时,为每个类更新均值向量,而协方差矩阵可以保持固定(在训练数据子集上的一些基础初始化之后)或者在流式传输过程中递增地更新。在测试时,可以使用平均类向量与协方差矩阵的逆矩阵的封闭形式的矩阵乘法来推断新数据示例的类输出。

与 ExStream 等基于重放的方法相比,SLDA 具有优势,因为它显著降低了内存需求,只需存储每个类的一个向量和一个共享协方差矩阵。此外,即使在 ImageNet 这样的大规模数据集上,SLDA 也能产生令人印象深刻的分类性能,优于 ExStream [4]、iCarl [13]和端到端增量学习[14]等流行方法;参见[8]中的表 1。此外,与大规模数据集上的正常离线神经网络训练相比,深层 SLDA 的挂钟训练时间几乎可以忽略不计。总的来说,该方法在规模上令人惊讶地有效,因为它的计算和内存需求最小

提醒[8]

REMIND 于 2020 年 7 月发布,是最近提出的一种基于重放的深度流学习方法。REMIND 不像 ExStream 那样在重放缓冲区中维护簇质心,而是为传入流中遇到的每个数据示例存储单独的缓冲区条目。在以前的工作中,这是通过在重放缓冲器[13,14]中存储原始图像来完成的。然而,在 REMIND 中,作者提出,神经网络中的中间激活(即,这些激活不仅仅是一个向量——它们可能具有空间维度)应该存储在重放缓冲区中,而不是原始图像中,这 i) 极大地减少了每样本的内存需求,而 ii) 模拟了海马索引理论概述的大脑中压缩记忆的重放。

为了使上述策略成为可能,REMIND 采用了 ResNet18 [9]架构,并冻结了网络的初始层,使得这些层的参数在流式传输过程中不会改变。类似于深度 SLDA,这些冻结参数的值是使用某个基础初始化阶段在训练数据的子集上设置的。然后,对于在流式传输期间遇到的每个示例,REMIND i) 通过网络的冻结层传递示例以提取中间激活, ii) 使用乘积量化(PQ)策略压缩激活张量[15],并且 iii) 将量化的向量存储在重放缓冲器中。然后,使用新数据(在它已经被量化之后)和来自重放缓冲器的采样激活的组合作为输入,在最终网络层(即,那些没有被冻结的网络层)上执行在线更新。在实践中,REMIND 对从重放缓冲区采样的激活执行随机裁剪和混合,这提供了正则化的好处,并产生适度的性能改进。

由于 REMIND 的内存高效的重放方法,它可以用有限的开销维护非常大的重放缓冲区。例如,在 ImageNet 数据集上,REMIND 可以维护大约 1M 样本的缓冲区,其内存占用与 10K 原始图像的重放缓冲区相同。因此,REMIND 在许多在线学习的常见基准测试中明显优于 ExStream 和 Deep SLDA;参见[8]中的表 1。在大规模数据集(例如 Imagenet)上,REMIND 的性能优势尤其明显,在这种情况下,REMIND 能够在有限的内存中存储许多重放示例,这使得它真正脱颖而出。目前,REMIND 是在流领域训练深度网络的最佳方法。

与一般在线学习的联系

现在已经概述了深度流学习的现有方法,人们可能会开始问这些方法如何与为其他在线学习设置(例如,批量增量学习或终身学习)提出的方法相关联。为了更全面地描述在线学习的所有方法,我推荐我之前关于这个话题的文章。然而,我试图在下面的高层次上概述这些方法。

  • Replay: 广泛用于流学习和在线学习。
  • **知识蒸馏:**广泛应用于在线学习技术中,但还没有探索用于流学习。虽然知识提炼可以为流式学习技术提供一些好处,但最近的几篇论文认为,当与重放结合时,知识提炼提供的好处很少[16,17]。
  • **偏差修正:**未在流设置内测试,但对增量学习非常有益。

在线学习的若干其他方法还没有在流设置中探索过(例如,架构修改或基于正则化的方法)。然而,这些方法中的许多在当前的在线学习研究中不太受欢迎,因为它们在应用于大规模问题时表现不佳。因此,这些方法不太可能胜过大规模流式学习的成熟方法,如 REMIND。

实践中用什么最好?

尽管这篇文章中概述的深度流学习的所有方法都是有用的,但从业者可能想知道哪种方法最适合他们的应用。在性能方面,REMIND 是迄今为止为深度流学习提出的性能最好的方法。这可以从 REMIND [8]论文的表 1 中看出,REMIND 的表现明显优于 ExStream 和 Deep SLDA。此外,REMIND 甚至已经扩展到问题领域,如对象检测[16],从而展示了它在图像分类以外的应用中的效用。

ExStream 和 REMIND 都需要存储一个重放缓冲区,并且具有相似的计算效率,因此 REMIND 是两者之间显而易见的选择。然而,深度 SLDA 不需要维护这样的重放缓冲器,并且可以非常快速地被训练。因此,即使 REMIND 实现了更好的性能,深度 SLDA 在内存或计算资源有限的情况下可能是有利的。否则,REMIND 在实践中是深度流学习的最佳选择,因为它可以实现令人印象深刻的性能,并通过量化最小化重放缓冲区的内存占用。

对于那些感兴趣的人来说,REMIND [17]和 Deep SLDA [18]的实现都可以通过 github 公开获得。

结论

在这篇文章中,我概述了数据流上深度神经网络的训练,包括讨论为什么这样的训练范式实际上是相关的,并描述了以这种方式训练深度网络的现有方法。在深度流学习的相关方法中,REMIND 实现了最佳性能,而深度 SLDA 等方法可能在内存或计算资源有限的情况下有用。

非常感谢你阅读这篇文章。如果你有任何反馈或总体上喜欢这篇文章,并希望了解我未来的工作,请随时在 twitter 上关注我或访问我的网站。这项工作是我在 Alegion 做研究科学家和在莱斯大学做博士生工作的一部分。如果你喜欢这篇文章中的内容,我鼓励你去看看 Alegion 的空缺职位,或者联系我的研究实验室

引文

[1]https://arxiv.org/abs/1412.2485

[2]https://ieeexplore.ieee.org/abstract/document/8622392

[3]https://epubs.siam.org/doi/abs/10.1137/1.9781611974317.7

[4]https://arxiv.org/abs/1809.05922

[5]https://www . science direct . com/science/article/ABS/pii/s 0079742108605368

https://arxiv.org/abs/1708.02072

https://arxiv.org/abs/1909.01520

https://arxiv.org/abs/1910.02509

https://arxiv.org/abs/1512.03385

https://www.vldb.org/conf/2003/papers/S04P02.pdf

[11]https://www . semantic scholar . org/paper/A-Framework-for-Projected-Clustering-of-High-Data-Aggarwal-Han/317 c 0 F3 A 829 ee 8 f 0 B3 d 7 E5 A 915 A 93 c 52 baa 7 a9 e 8

https://ieeexplore.ieee.org/document/1510767

https://arxiv.org/abs/1611.07725

https://arxiv.org/abs/1807.09536

[15]https://lear . inrialpes . fr/pubs/2011/JD S11/jegou _ searching _ with _ quantization . pdf

https://arxiv.org/abs/2008.06439

https://github.com/tyler-hayes/REMIND

https://github.com/tyler-hayes/Deep_SLDA

如何用 PyGAD 遗传算法训练 Keras 模型

原文:https://towardsdatascience.com/how-to-train-keras-models-using-the-genetic-algorithm-with-pygad-9d9d626782d1?source=collection_archive---------19-----------------------

PyGAD 是一个开源的 Python 库,用于构建遗传算法和训练机器学习算法。它提供了广泛的参数来定制遗传算法,以处理不同类型的问题。

PyGAD 拥有自己的模块,支持构建和训练神经网络(NNs)和卷积神经网络(CNN)。尽管这些模块运行良好,但它们是在 Python 中实现的,没有任何额外的优化措施。这导致即使是简单的问题也需要相对较长的计算时间。

PyGAD2 . 8 . 0(2020 年 9 月 20 日发布)开始,一个名为kerasga的新模块支持训练 Keras 模型。尽管 Keras 是用 Python 构建的,但速度很快。原因是 Keras 使用 TensorFlow 作为后端,TensorFlow 高度优化。

本教程讨论如何使用 PyGAD 训练 Keras 模型。讨论内容包括使用顺序模型或函数式 API 构建 Keras 模型、构建 Keras 模型参数的初始群体、创建合适的适应度函数等等。

您也可以跟随本教程中的代码,并在来自 ML Showcase 的渐变社区笔记本上免费运行它。

完整的教程大纲如下:

  • 开始使用 PyGAD
  • pygad.kerasga模块
  • 使用 PyGAD 训练 Keras 模型的步骤
  • 确定问题类型
  • 创建一个 Keras 模型
  • 实例化pygad.kerasga.KerasGA
  • 准备培训数据
  • 损失函数
  • 适应度函数
  • 生成回调函数(可选)
  • 创建一个pygad.GA类的实例
  • 运行遗传算法
  • 健身与世代图
  • 有关已定型模型的统计信息
  • 回归的完整代码
  • 使用 CNN 分类的完整代码

让我们开始吧。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自 Unsplash:https://unsplash.com/photos/zz_3tCcrk7o

PyGAD 入门

要开始本教程,安装 PyGAD 是必不可少的。如果您已经安装了 PyGAD,检查__version__属性以确保根据下一个代码至少安装了 PyGAD 2.8.0。

import pygadprint(pygad.__version__)

可以从 PyPI (Python 包索引)获得,然后可以使用pip安装程序进行安装。确保安装 PyGAD 2.8.0 或更高版本。

pip install pygad>=2.8.0

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PyGAD 标志

安装完成后,您就可以开始了。阅读文档阅读文档:pygad . readthedocs . io。该文档包括一些示例。

下一段代码解决了一个简单的优化线性模型参数的问题。

import pygad
import numpyfunction_inputs = [4,-2,3.5,5,-11,-4.7] # Function inputs.
desired_output = 44 # Function output.def fitness_func(solution, solution_idx):
    output = numpy.sum(solution*function_inputs)
    fitness = 1.0 / (numpy.abs(output - desired_output) + 0.000001)
    return fitnessnum_generations = 100
num_parents_mating = 10
sol_per_pop = 20
num_genes = len(function_inputs)ga_instance = pygad.GA(num_generations=num_generations,
                       num_parents_mating=num_parents_mating,
                       fitness_func=fitness_func,
                       sol_per_pop=sol_per_pop,
                       num_genes=num_genes)ga_instance.run()ga_instance.plot_result()

pygad.kerasga模块

从 PyGAD 2.8.0 开始,引入了一个名为kerasga的新模块。它的名字是 KerasGgenicA算法的简称。该模块提供以下功能:

  • 使用KerasGA类构建解决方案的初始群体。每个解决方案都包含 Keras 模型中的所有参数。
  • 使用model_weights_as_vector()功能将 Keras 模型的参数表示为染色体(即 1D 向量)。
  • 使用model_weights_as_matrix()功能从染色体中恢复 Keras 模型的参数。

pygad.kerasga模块有一个名为KerasGA的类。这个类的构造函数接受两个参数:

  1. model:Keras 车型。
  2. num_solutions:群体中解的数量。

基于这两个参数,pygad.kerasga.KerasGA类创建了 3 个实例属性:

  1. model:对 Keras 模型的引用。
  2. num_solutions:群体中解的数量。
  3. population_weights:保存模型参数的嵌套列表。该列表在每一代之后更新。

假设 Keras 模型保存在model变量中,下一段代码创建一个KerasGA类的实例,并将其保存在keras_ga变量中。num_solutions参数被赋值为 10,这意味着群体有 10 个解。

构造函数创建一个长度等于num_solutions参数值的列表。列表中的每个元素在使用model_weights_as_vector()函数转换成 1D 向量后,为模型的参数保存不同的值。

基于KerasGA类的实例,初始群体可以从population_weights属性返回。假设模型有 60 个参数,有 10 个解,那么初始种群的形状就是10x60

import pygad.kerasgakeras_ga = pygad.kerasga.KerasGA(model=model,
                                 num_solutions=10)initial_population = keras_ga.population_weights

下一节总结了使用 PyGAD 训练 Keras 模型的步骤。每一个步骤都将在单独的章节中讨论。

使用 PyGAD 训练 Keras 模型的步骤

使用 PyGAD 训练 Keras 模型的步骤总结如下:

  • 确定问题类型
  • 创建一个 Keras 模型
  • 实例化pygad.kerasga.KerasGA
  • 准备培训数据
  • 损失函数
  • 适应度函数
  • 生成回调函数(可选)
  • 创建一个pygad.GA类的实例
  • 运行遗传算法

接下来的小节将讨论这些步骤。

确定问题类型

问题类型(分类或回归)有助于准备以下内容:

  1. 损失函数(用于构建适应度函数)。
  2. Keras 模型中的输出图层。
  3. 训练数据。

对于回归问题,损失函数可以是平均绝对误差、均方误差或本页中列出的另一个函数,该页总结了回归的 Keras 损失函数:keras.io/api/losses/regression_losses

对于分类问题,损失函数可以是二进制交叉熵(对于二进制分类)、分类交叉熵(对于多类问题),或者在本页中列出的另一个函数,其总结了 Keras 分类损失函数:keras.io/api/losses/probabilistic_losses

输出层中的激活函数根据问题是分类还是回归而不同。对于分类问题,与回归的线性相比,它可能是 softmax

如果问题是回归,那么每个样本的输出相对于分类问题中的类标签是一个连续的数。

总之,确定问题的类型以便正确选择训练数据和损失函数是至关重要的。

创建一个 Keras 模型

构建 Keras 模型有 3 种方式:

  1. 时序模型
  2. 功能 API
  3. 模型子类化

PyGAD 支持使用顺序模型和函数式 API 构建 Keras 模型。

顺序模型

对于顺序模型,这里有一个构建 Keras 模型的例子。简单地说,使用tensorflow.keras.layers模块创建每一层。然后,创建一个tensorflow.keras.Sequential类的实例。最后,使用add()方法将图层添加到模型中。

import tensorflow.kerasinput_layer  = tensorflow.keras.layers.Input(3)
dense_layer1 = tensorflow.keras.layers.Dense(5, activation="relu")
output_layer = tensorflow.keras.layers.Dense(1, activation="linear")model = tensorflow.keras.Sequential()
model.add(input_layer)
model.add(dense_layer1)
model.add(output_layer)

请注意,输出层的激活函数是linear,这意味着问题是回归。对于一个分类问题,函数可以是softmax。在下一行中,输出层有 2 个神经元(每个类 1 个),它使用softmax激活函数。

output_layer = tensorflow.keras.layers.Dense(2, activation="linear")

功能 API

对于功能性 API 案例,每一层通常都是作为顺序模型案例创建的。每一层,或者输入层,都被用作一个接受前一层作为参数的函数。最后,创建了一个tensorflow.keras.Model类的实例,它接受输入和输出层作为参数。

input_layer  = tensorflow.keras.layers.Input(3)
dense_layer1 = tensorflow.keras.layers.Dense(5, activation="relu")(input_layer)
output_layer = tensorflow.keras.layers.Dense(1, activation="linear")(dense_layer1)model = tensorflow.keras.Model(inputs=input_layer, outputs=output_layer)

创建 Keras 模型后,下一步是使用KerasGA类创建 Keras 模型参数的初始群体。

实例化pygad.kerasga.KerasGA

通过创建一个pygad.kerasga.KerasGA类的实例,就创建了一个 Keras 模型参数的初始群体。下一段代码将前一节中创建的 Keras 模型传递给KerasGA类构造函数的model参数。

import pygad.kerasgakeras_ga = pygad.kerasga.KerasGA(model=model,
                                 num_solutions=10)

下一节将创建用于训练 Keras 模型的训练数据。

准备培训数据

基于问题的类型(分类或回归),准备训练数据。

对于有 1 个输出的回归问题,这里有一个随机生成的训练数据,其中每个样本有 3 个输入。

import numpy
​
# Data inputs
data_inputs = numpy.array([[0.02, 0.1, 0.15],
                           [0.7, 0.6, 0.8],
                           [1.5, 1.2, 1.7],
                           [3.2, 2.9, 3.1]])
​
# Data outputs
data_outputs = numpy.array([[0.1],
                            [0.6],
                            [1.3],
                            [2.5]])

对于 XOR 这样的二元分类问题,下面是它的训练数据。每个样本有 2 个输入。准备输出,以便输出层有 2 个神经元,每个类一个。

import numpy
​
# XOR problem inputs
data_inputs = numpy.array([[0, 0],
                           [0, 1],
                           [1, 0],
                           [1, 1]])
​
# XOR problem outputs
data_outputs = numpy.array([[1, 0],
                            [0, 1],
                            [0, 1],
                            [1, 0]])

下一节讨论回归和分类问题的损失函数。

损失函数

损失函数因问题类型而异。本节讨论 Keras 的tensorflow.keras.losses模块中用于回归和分类问题的一些损失函数。

回归

对于回归问题,损失函数包括:

  • tensorflow.keras.losses.MeanAbsoluteError()
  • tensorflow.keras.losses.MeanSquaredError()

查看本页了解更多信息。

下面是一个计算平均绝对误差的例子,其中y_truey_pred代表真实输出和预测输出。

mae = tensorflow.keras.losses.MeanAbsoluteError()
loss = mae(y_true, y_pred).numpy()

分类

对于分类问题,损失函数包括:

  • tensorflow.keras.losses.BinaryCrossentropy():二元分类。
  • tensorflow.keras.losses.CategoricalCrossentropy():多级分类。

查看本页了解更多信息。

下面是一个计算二元类熵的例子:

bce = tensorflow.keras.losses.BinaryCrossentropy()
loss = bce(y_true, y_pred).numpy()

基于损失函数,根据下一部分准备适应度函数。

适应度函数

分类或回归问题的损失函数都是最小化函数。遗传算法的适应度函数是最大化函数。因此,适应值是作为损失值的倒数来计算的。

fitness_value = 1.0 / loss

用于计算模型的适应值的步骤如下:

  1. 从 1D 向量恢复模型参数。
  2. 设置模型参数。
  3. 做预测。
  4. 计算损失值。
  5. 计算适应值。
  6. 返回适应值。

回归适合度

下一段代码构建了完整的适应度函数,它与 PyGAD 一起处理回归问题。PyGAD 中的 fitness 函数是一个常规的 Python 函数,它必须接受两个参数。第一个表示要计算适应值的解。另一个参数是群体内解的指数,这在某些情况下可能是有用的。

传递给适应度函数的解是 1D 向量。为了从这个向量恢复 Keras 模型的参数,使用了pygad.kerasga.model_weights_as_matrix()

model_weights_matrix = pygad.kerasga.model_weights_as_matrix(model=model, weights_vector=solution)

一旦参数被恢复,那么它们就被set_weights()方法用作模型的当前参数。

model.set_weights(weights=model_weights_matrix)

基于当前参数,模型使用predict()方法预测输出。

predictions = model.predict(data_inputs)

预测输出用于计算损失值。平均绝对误差被用作损失函数。

mae = tensorflow.keras.losses.MeanAbsoluteError()

因为损失值可能是 0.0 ,那么最好像0.00000001一样给它加上一个小值,避免在计算适应值时跳水归零。

solution_fitness = 1.0 / (mae(data_outputs, predictions).numpy() + 0.00000001)

最后,返回适应值。

def fitness_func(solution, sol_idx):
    global data_inputs, data_outputs, keras_ga, model
​
    model_weights_matrix = pygad.kerasga.model_weights_as_matrix(model=model,
                                                                 weights_vector=solution)
​
    model.set_weights(weights=model_weights_matrix)
​
    predictions = model.predict(data_inputs)

    mae = tensorflow.keras.losses.MeanAbsoluteError()
    solution_fitness = 1.0 / (mae(data_outputs, predictions).numpy() + 0.00000001)
​
    return solution_fitness

二元分类的适合度

对于二进制分类问题,这里有一个适用于 PyGAD 的适应度函数。假设分类问题是二元的,它计算二元交叉熵。

def fitness_func(solution, sol_idx):
    global data_inputs, data_outputs, keras_ga, model
​
    model_weights_matrix = pygad.kerasga.model_weights_as_matrix(model=model,
                                                                 weights_vector=solution)
​
    model.set_weights(weights=model_weights_matrix)
​
    predictions = model.predict(data_inputs)

    bce = tensorflow.keras.losses.BinaryCrossentropy()
    solution_fitness = 1.0 / (bce(data_outputs, predictions).numpy() + 0.00000001)
​
    return solution_fitness

下一节将构建一个在每代结束时执行的回调函数。

生成回调函数(可选)

对于每一代,遗传算法对解进行改变。在每一次生成完成后,可以调用一个回调函数来计算一些关于最新达到的参数的统计数据。

这一步是可选的,仅用于调试目的。

生成回调函数实现如下。在 PyGAD 中,这个回调函数必须接受一个引用遗传算法实例的参数,通过该参数可以使用population属性获取当前群体。

在这个函数中,一些信息被打印出来,比如当前的代数和最佳解的适应值。这种信息使用户能够通过遗传算法的进展来更新。

def callback_generation(ga_instance):
    print("Generation = {generation}".format(generation=ga_instance.generations_completed))
    print("Fitness    = {fitness}".format(fitness=ga_instance.best_solution()[1]))

创建一个pygad.GA类的实例

使用 PyGAD 训练 Keras 模型的下一步是创建一个pygad.GA类的实例。这个类的构造函数接受许多参数,这些参数可以在文档中找到。

下一段代码通过使用该应用程序中最少的参数传递来实例化pygad.GA类,这些参数是:

  • num_generations:世代数。
  • num_parents_mating:要交配的亲本数量。
  • initial_population:Keras 模型参数的初始群体。
  • fitness_func:健身功能。
  • on_generation:生成回调函数。

请注意,在KerasGA类的构造函数中,群体中的解的数量先前被设置为 10。因此,要交配的亲本数量必须少于 10 个。

num_generations = 250
num_parents_mating = 5
initial_population = keras_ga.population_weights
​
ga_instance = pygad.GA(num_generations=num_generations, 
                       num_parents_mating=num_parents_mating, 
                       initial_population=initial_population,
                       fitness_func=fitness_func,
                       on_generation=callback_generation)

下一部分运行遗传算法来开始训练 Keras 模型。

运行遗传算法

pygad.GA类的实例通过调用run()方法来运行。

ga_instance.run()

通过执行这个方法,PyGAD 的生命周期按照下图开始。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PyGAD 生命周期。版权归作者所有。

下一节讨论如何对训练好的模型得出一些结论。

健身与世代图

使用pygad.GA类中的plot_result()方法,PyGAD 创建了一个图形,显示了适应值是如何逐代变化的。

ga_instance.plot_result(title="PyGAD & Keras - Iteration vs. Fitness", linewidth=4)

有关已定型模型的统计信息

pygad.GA类有一个名为best_solution()的方法,它返回 3 个输出:

  1. 找到最佳解决方案。
  2. 最佳解决方案的适应值。
  3. 群体中最佳解决方案的索引。

下一段代码调用best_solution()方法并输出最佳解决方案的信息。

solution, solution_fitness, solution_idx = ga_instance.best_solution()
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))
print("Index of the best solution : {solution_idx}".format(solution_idx=solution_idx))

下一段代码从最佳解决方案中恢复 Keras 模型的权重。基于恢复的权重,该模型预测训练样本的输出。您还可以预测新样本的输出。

# Fetch the parameters of the best solution.
best_solution_weights = pygad.kerasga.model_weights_as_matrix(model=model,
                                                              weights_vector=solution)
model.set_weights(best_solution_weights)
predictions = model.predict(data_inputs)
print("Predictions : \n", predictions)

假设使用的损失函数是平均绝对误差,下一个代码计算它。

mae = tensorflow.keras.losses.MeanAbsoluteError()
abs_error = mae(data_outputs, predictions).numpy()
print("Absolute Error : ", abs_error)

接下来的部分列出了使用 PyGAD 构建和训练 Keras 模型的完整代码。

回归的完整代码

对于一个使用平均绝对误差作为损失函数的回归问题,这里是它的完整代码。

import tensorflow.keras
import pygad.kerasga
import numpy
import pygad
​
def fitness_func(solution, sol_idx):
    global data_inputs, data_outputs, keras_ga, model
​
    model_weights_matrix = pygad.kerasga.model_weights_as_matrix(model=model,
                                                                 weights_vector=solution)
​
    model.set_weights(weights=model_weights_matrix)
​
    predictions = model.predict(data_inputs)
​
    mae = tensorflow.keras.losses.MeanAbsoluteError()
    abs_error = mae(data_outputs, predictions).numpy() + 0.00000001
    solution_fitness = 1.0 / abs_error
​
    return solution_fitness
​
def callback_generation(ga_instance):
    print("Generation = {generation}".format(generation=ga_instance.generations_completed))
    print("Fitness    = {fitness}".format(fitness=ga_instance.best_solution()[1]))
​
input_layer  = tensorflow.keras.layers.Input(3)
dense_layer1 = tensorflow.keras.layers.Dense(5, activation="relu")(input_layer)
output_layer = tensorflow.keras.layers.Dense(1, activation="linear")(dense_layer1)
​
model = tensorflow.keras.Model(inputs=input_layer, outputs=output_layer)
​
weights_vector = pygad.kerasga.model_weights_as_vector(model=model)
​
keras_ga = pygad.kerasga.KerasGA(model=model,
                                 num_solutions=10)
​
# Data inputs
data_inputs = numpy.array([[0.02, 0.1, 0.15],
                           [0.7, 0.6, 0.8],
                           [1.5, 1.2, 1.7],
                           [3.2, 2.9, 3.1]])
​
# Data outputs
data_outputs = numpy.array([[0.1],
                            [0.6],
                            [1.3],
                            [2.5]])
​
num_generations = 250
num_parents_mating = 5
initial_population = keras_ga.population_weights
​
ga_instance = pygad.GA(num_generations=num_generations, 
                       num_parents_mating=num_parents_mating, 
                       initial_population=initial_population,
                       fitness_func=fitness_func,
                       on_generation=callback_generation)
ga_instance.run()
​
# After the generations complete, some plots are showed that summarize how the outputs/fitness values evolve over generations.
ga_instance.plot_result(title="PyGAD & Keras - Iteration vs. Fitness", linewidth=4)
​
# Returning the details of the best solution.
solution, solution_fitness, solution_idx = ga_instance.best_solution()
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))
print("Index of the best solution : {solution_idx}".format(solution_idx=solution_idx))
​
# Fetch the parameters of the best solution.
best_solution_weights = pygad.kerasga.model_weights_as_matrix(model=model,
                                                              weights_vector=solution)
model.set_weights(best_solution_weights)
predictions = model.predict(data_inputs)
print("Predictions : \n", predictions)
​
mae = tensorflow.keras.losses.MeanAbsoluteError()
abs_error = mae(data_outputs, predictions).numpy()
print("Absolute Error : ", abs_error)

代码完成后,下一张图显示适应值在增加,这是一个好迹象,因为 Keras 模型正在正确学习。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自 PyGAD 文档。

以下是关于训练模型的更多细节。请注意,预测值接近正确值。平均相对误差为 0.018。

Fitness value of the best solution = 54.79189095217631
Index of the best solution : 0
Predictions : 
[[0.11471477]
 [0.6034051 ]
 [1.3416876 ]
 [2.486804  ]]
Absolute Error :  0.018250866

使用 CNN 分类的完整代码

下一个代码使用 Keras 构建一个卷积神经网络,用于对 80 幅图像的数据集进行分类,其中每幅图像的大小为100x100x3。注意,使用分类交叉熵是因为数据集有 4 个类。

可以从以下链接下载培训数据:

  1. dataset _ inputs . npy:https://github . com/ahmedfgad/NumPyCNN/blob/master/dataset _ inputs . npy
  2. dataset _ outputs . npy:https://github . com/ahmedfgad/NumPyCNN/blob/master/dataset _ outputs . npy
import tensorflow.keras
import pygad.kerasga
import numpy
import pygad
​
def fitness_func(solution, sol_idx):
    global data_inputs, data_outputs, keras_ga, model
​
    model_weights_matrix = pygad.kerasga.model_weights_as_matrix(model=model,
                                                                 weights_vector=solution)
​
    model.set_weights(weights=model_weights_matrix)
​
    predictions = model.predict(data_inputs)
​
    cce = tensorflow.keras.losses.CategoricalCrossentropy()
    solution_fitness = 1.0 / (cce(data_outputs, predictions).numpy() + 0.00000001)
​
    return solution_fitness
​
def callback_generation(ga_instance):
    print("Generation = {generation}".format(generation=ga_instance.generations_completed))
    print("Fitness    = {fitness}".format(fitness=ga_instance.best_solution()[1]))
​
# Build the keras model using the functional API.
input_layer = tensorflow.keras.layers.Input(shape=(100, 100, 3))
conv_layer1 = tensorflow.keras.layers.Conv2D(filters=5,
                                             kernel_size=7,
                                             activation="relu")(input_layer)
max_pool1 = tensorflow.keras.layers.MaxPooling2D(pool_size=(5,5),
                                                 strides=5)(conv_layer1)
conv_layer2 = tensorflow.keras.layers.Conv2D(filters=3,
                                             kernel_size=3,
                                             activation="relu")(max_pool1)
flatten_layer  = tensorflow.keras.layers.Flatten()(conv_layer2)
dense_layer = tensorflow.keras.layers.Dense(15, activation="relu")(flatten_layer)
output_layer = tensorflow.keras.layers.Dense(4, activation="softmax")(dense_layer)
​
model = tensorflow.keras.Model(inputs=input_layer, outputs=output_layer)
​
keras_ga = pygad.kerasga.KerasGA(model=model,
                                 num_solutions=10)
​
# Data inputs
data_inputs = numpy.load("dataset_inputs.npy")
​
# Data outputs
data_outputs = numpy.load("dataset_outputs.npy")
data_outputs = tensorflow.keras.utils.to_categorical(data_outputs)
​
num_generations = 200
num_parents_mating = 5
initial_population = keras_ga.population_weights
​
ga_instance = pygad.GA(num_generations=num_generations, 
                       num_parents_mating=num_parents_mating, 
                       initial_population=initial_population,
                       fitness_func=fitness_func,
                       on_generation=callback_generation)
​
ga_instance.run()
​
ga_instance.plot_result(title="PyGAD & Keras - Iteration vs. Fitness", linewidth=4)
​
# Returning the details of the best solution.
solution, solution_fitness, solution_idx = ga_instance.best_solution()
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))
print("Index of the best solution : {solution_idx}".format(solution_idx=solution_idx))
​
# Fetch the parameters of the best solution.
best_solution_weights = pygad.kerasga.model_weights_as_matrix(model=model,
                                                              weights_vector=solution)
model.set_weights(best_solution_weights)
predictions = model.predict(data_inputs)
# print("Predictions : \n", predictions)
​
# Calculate the categorical crossentropy for the trained model.
cce = tensorflow.keras.losses.CategoricalCrossentropy()
print("Categorical Crossentropy : ", cce(data_outputs, predictions).numpy())
​
# Calculate the classification accuracy for the trained model.
ca = tensorflow.keras.metrics.CategoricalAccuracy()
ca.update_state(data_outputs, predictions)
accuracy = ca.result().numpy()
print("Accuracy : ", accuracy)

下图显示了适应值是如何逐代演变的。只要适应度值增加,那么就增加代数,以达到更好的精度。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自 PyGAD 文档。

以下是有关已训练模型的一些信息。

Fitness value of the best solution = 2.7462310258668805
Categorical Crossentropy :  0.3641354
Accuracy :  0.75

本文原载于 Paperspace 博客 。你可以在渐变 上免费运行我的教程的代码

结论

本教程讨论了如何使用名为 PyGAD 的 Python 3 库,使用遗传算法来训练 Keras 模型。Keras 模型可以使用顺序模型或函数式 API 来创建。

使用pygad.kerasga模块,创建 Keras 模型权重的初始群体,其中每个解决方案为模型保存一组不同的权重。这个种群随后按照 PyGAD 的生命周期进化,直到所有世代完成。

由于 Keras 后端 TensorFlow 的高速特性, PyGAD 可以在合理的时间内训练复杂的架构。

如何像专业人士一样训练神经网络!

原文:https://towardsdatascience.com/how-to-train-neural-networks-like-a-pro-1d2362768c1?source=collection_archive---------13-----------------------

用于处理神经网络训练问题的完整包,如过拟合/欠拟合、消失梯度、局部最小值、学习率策略等。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

梅根·霍尔姆斯在 Unsplash 上的照片

在步入深度学习的世界时,许多开发人员试图建立神经网络,但结果令人失望。他们可能最终发现训练过程不能更新网络的权重,或者模型不能找到成本函数的最小值。这些是我们在训练神经网络时面临的非常常见的问题,因此,需要有一个好的策略来解决它们。

本博客将帮助读者在训练神经网络时理解和解决以下问题:

  1. 过度拟合 vs 欠拟合
  2. 消失渐变
  3. 局部最小值
  4. 设定正确的学习率策略
  5. 挑选迷你批次大小

我鼓励读者在继续下一步之前,查看以下博客,深入了解神经网络如何工作以及如何为不同的机器学习问题构建神经网络:

  1. 【了解神经网络基础知识(适用于初学者)
  2. 神经网络的激活函数和损失函数——如何选择合适的?

问题:过拟合与欠拟合

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

当模型学习训练数据中的细节和噪声达到对新数据的模型性能产生负面影响的程度时,就会发生过度拟合。这意味着训练数据中的噪声或随机波动被模型拾取并学习为概念。问题是这些概念不适用于新数据,并对模型的概括能力产生负面影响。非参数和非线性模型在优化损失函数时更具灵活性,因此更有可能出现过度拟合。

另一方面,欠拟合指的是既不能对训练数据建模也不能推广到新数据的模型。

过拟合/欠拟合的概念与方差/偏差权衡问题密切相关。方差是如果使用不同的训练数据,损失函数的估计将改变的量。

  • 低方差:建议随着训练数据集的改变,对目标函数的估计进行小的改变。
  • 高方差:表示目标函数的估计值随着训练数据集的变化而发生较大变化。

另一方面,偏差是指模型做出的简化假设,以使损失函数更容易学习。

  • 低偏差:暗示对损失函数形式的假设较少。
  • 高偏差:暗示关于损失函数形式的更多假设

为了识别模型的正确拟合,我们可以查看机器学习算法在训练迭代/时期的数量上对训练和测试数据集的性能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

随着算法的学习,模型在训练和测试数据上的误差下降。但是在某个点之后,训练数据集上的性能持续下降,但是模型也开始学习训练数据中的噪声。这可以从测试集中上升的误差看出来。最佳点是测试数据的误差开始上升之前的点(如上图所示)。

过拟合/欠拟合问题与历元数一起,是决定隐藏神经元数和隐藏层数的关键因素。它们决定了模型理解数据中复杂关系的能力。但是类似于纪元的数量,太多会导致过度拟合,太少会导致欠拟合。

解决办法

有三种流行的方法来克服这个问题:

  1. **提前停止:**提前停止(也称为“提前终止”)是一种方法,它允许我们指定大量的训练时期,一旦模型性能在测试数据集上停止改善,就停止训练。它监视训练的进度,但在满足某些条件时也会停止训练。TensorFlow 包中有两个预定义的停止监视器:a .StopAtStepHook:训练在一定步数后停止
    b. NanTensorHook:监视丢失,如果遇到 NaN 丢失则停止训练
  2. 正则化:这是一种回归形式,它要么消除(L1 正则化)系数,要么将(L2 正则化)系数估计值缩小到零。因此,它不鼓励拟合复杂的模型以避免过度拟合的风险
  3. Dropout: Dropout 基于在不同架构上并行训练多个神经网络的思想。基本思想是,在训练期间,某些层输出被随机丢弃。因此,在每次迭代之后,输出基于神经网络中神经元的不同组合。

除了这些选项,我们还可以尝试以下关于隐藏层数的启发式建议:

“在实践中,通常情况是 3 层神经网络将优于 2 层网络,但是甚至更深(4、5、6 层)也很少有帮助。这与卷积网络形成鲜明对比,在卷积网络中,深度被认为是一个好的识别系统的极其重要的组成部分(例如,大约 10 个可学习层)。”~安德烈·卡帕西

最后,为了选择隐藏层中神经元的数量,我们可以遵循以下规则:

  1. 隐藏神经元的数量应该介于输入层和输出层的大小之间。
  2. 最常见的隐藏神经元数目是
    sqrt(输入层节点输出层节点)*
  3. 在随后的层中,隐藏神经元的数量应该不断减少,以越来越接近输出层的结构。

值得注意的是,所有这些都是启发式规则,应该根据问题陈述进行调整。

问题:消失渐变

一些激活函数,如 sigmoid 函数,具有非常小的导数,尤其是当输入值远离函数中心时。这意味着神经网络权重的更新速率非常小。这个问题随着我们添加更多的隐藏层而变得更糟,因为来自不同层的导数相乘,因此,大量小数字相乘,导致最终变化接近于零。这意味着模型不能做出足够的反应来找到最优值。

解决方案:

处理消失渐变的最好方法是用 ReLU 或 Tanh 等其他函数替换隐藏层中的 sigmoid 激活函数。请参考我的博客中可用的激活功能列表以及在哪里使用它们。

问题:局部最小值

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

损失函数有许多波峰和波谷是很常见的。局部极小值是指在其邻域内但不在损失函数上的最小值。如上图所示,一旦我们的模型遇到局部最小值,简单的梯度下降算法无法找到任何方向来进一步最小化邻域中的损失函数,并将卡在那里。因此,我们将无法找到神经网络的最佳权重。

解决方案:

我们有两种选择来处理局部最小值问题:

  1. **随机重启:**基本意思是我们可以从损失函数的不同点出发,从所有的点进行梯度下降。这种方法大大增加了我们找到全局最小值的机会。
  2. **动量:**这种方法的灵感来自于一个物体在不平坦的表面上快速移动的想法,这样它的动量就会推动它越过小驼峰。基本思想是,在局部最小值处的梯度是零,但是在先前时段中的梯度将具有非零值,并且取它们的平均值将帮助我们在局部最小值处走出驼峰。形式上,动量是过去梯度的加权平均值,并且较大的权重被应用于最近的梯度,导致梯度的指数衰减平均值。权重通常称为速度,在 0 和 1 之间变化。找到速度值的最好方法是使用交叉验证。

问题:迷你批次大小

小批量梯度下降是梯度下降算法的一种变体,该算法将训练数据集分成小批量,用于计算模型误差和更新模型系数。这是梯度下降算法最常见的形式(其他选项是批处理和随机梯度下降)。批量大小由最小批量大小参数决定,我们选择它的方式会影响资源需求以及神经网络的训练速度。太少会导致训练进度缓慢,但有助于收敛到全局最小值。

选择高的迷你批次大小将导致更快的训练,但是需要更多的存储器和计算资源。它也有陷入局部最小值的风险。

解决方案:

32 的小批量是一个很好的开始,如果不行,我们也可以尝试 64、128 和 256。大多数问题最常用的一组值是:1、2、4、16、32、64、128 和 256。

问题:如何设置学习率

学习率是指在机器学习模型的训练过程中权重更新的量(也称为步长)。它是用于训练神经网络的重要超参数之一,通常的可疑值是 0.1、0.01、0.001、0.0001、0.00001、0.000001 和 0.000001。设置一个非常低的学习率,会使我们的模型在识别成本函数上的最小点方面非常慢,而选择一个高值会使我们错过最佳点,因为模型将继续大步前进。看看这种情况的极端版本,高学习率会导致模型的性能在训练时期之间振荡,这表明权重偏离了最佳值。在另一个极端,一个非常小的值可能会阻止模型收敛或陷入局部最小值。我们通常会面临三种情况:

  1. 训练期间验证误差快速下降:表示学习率选择良好
  2. 训练过程中验证误差下降非常缓慢:表示学习率需要提高
  3. 训练过程中验证误差缓慢增加:表示学习率需要降低

解决方案:

一些现代版本的随机梯度下降算法(如 Adam)允许自适应学习率,其中模型在训练数据集上的性能由算法监控,并且学习率作为响应进行调整。如果错误率开始下降,则学习率逐渐降低,如果错误率在多个时期内没有改善,则学习率增加。如果这不起作用,那么我们可以尝试其他优化器,如 AdaGrad 或 RMSProp(它们也有自适应学习速率机制)。在另一篇博客中,我将讨论可用于训练神经网络的各种优化器及其优缺点。

如果我们想要手动设置参数值,那么我们应该通过创建训练时期的损失线图来检查模型的学习动态,然后我们可以检查以下内容:

  • 学习的速度是快还是慢?
  • 指示低学习率值的错误率是否有非常小的变化?
  • 我们是否看到损失的振荡表明高学习率值?

我们也可以手动设置学习率计划,其中学习率在一定数量的时期后从最大值线性/指数地降低到最小值。

结论

我要感谢读者阅读了我的神经网络系列博客的最后一部分。这个博客的目的是帮助读者有效地训练他们的神经网络。我们了解到以下情况:

  1. 什么是欠拟合/过拟合和方差/偏差权衡,你如何处理它们?
  2. 哪个激活函数面临消失梯度问题?
  3. 随机重启和动量如何帮助我们避免局部极小问题?
  4. 如何设置迷你批次大小?
  5. 设定学习率的稳健策略是什么?

我将撰写一个单独的博客系列,介绍如何用 Python 实现这些解决方案(使用 Keras 和 Pytorch 库)。所以请保持关注!

你对这个博客有什么问题或建议吗?请随时留言。

感谢您的阅读!

如果你和我一样,对人工智能、数据科学或经济学充满热情,请随时添加/关注我的 LinkedInGithubMedium

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

马特·博茨福德在 Unsplash 上拍摄的照片

如何使用自定义数据集训练 StyleGAN2-ADA

原文:https://towardsdatascience.com/how-to-train-stylegan2-ada-with-custom-dataset-dc268ff70544?source=collection_archive---------6-----------------------

了解如何训练人工智能生成任何你想要的图像

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

生成的自行车插值[图片由作者提供]

你一直想知道如何训练自己的生成模型吗?第一次发现像这个人脸生成网站这样的 GAN 应用,一直在想怎么在其他东西上训练 GAN。幸运的是,作为我研究的一部分,我最近有机会训练一个自行车发电模型。在本文中,我将记录我在如何根据自己的图像训练 StyleGAN2-ADA 方面的经验。

StyleGAN 是 NVIDIA 最受欢迎的生成模型之一。StlyeGAN 的多个版本已经发布,我们将使用最新版本 StyleGAN2-ADA。为了避免重复,我不会解释 StyleGAN,因为有很多文章已经很好地解释了它。

https://jonathan-hui.medium.com/gan-stylegan-stylegan2-479bdf256299

训练 StyleGAN 的计算量很大。因此,如果你没有一个像样的 GPU,你可能想在云上训练。如果你决定在 Google Colab 上训练(这是免费的),有人为此制作了一个不错的笔记本

在教程中,我将使用自行车数据集 BIKED 。请随意使用您自己的数据集。只要确保所有的训练图像都是正方形的,并将它们放在同一个文件夹中。

在本文中,我将使用 StyleGAN2-ADA 的 Tensorflow 实现。确保使用 Tensorflow 版本 1,因为代码与 Tensorflow 版本 2 不兼容。或者,如果你喜欢 PyTorch,你可以使用最近发布的 PyTorch 版本。PyTorch 代码在性能上似乎稍快一些。如果您使用 PyTorch,您仍然可以遵循本教程,只是在数据集准备方面稍有不同。

要求

  • 64 位 Python 3.6 或 3.7。建议使用带有 numpy 1.14.3 或更新版本的 Anaconda3。
  • 建议使用 TensorFlow 1.14,但 Linux 上也支持 TensorFlow 1.15。不支持 TensorFlow 2.x。
  • 在 Windows 上,您需要使用 TensorFlow 1.14,因为标准的 1.15 安装不包括必要的 C++头文件。
  • 1-8 个高端 NVIDIA GPUs,至少 12 GB GPU 内存,NVIDIA 驱动程序,CUDA 10.0 工具包和 cuDNN 7.5

步伐

  1. 克隆 StyleGAN2-ADA 存储库并进入目录
git clone [https://github.com/NVlabs/stylegan2-ada.git](https://github.com/NVlabs/stylegan2-ada.git)
cd styelgan2-ada

2.下载或创建自己的数据集。我将使用我已经预处理过的 BIKED 数据集。你可以从 dropbox 下载我的预处理版本。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

BIKED 数据集 [ CreativeGAN 的样本图像

# Dowload dataset
wget "https://www.dropbox.com/s/0ybsudabqscstf7/biked_dataset.tar.gz" -q -O biked_dataset.tar.gz# extract dataset
tar -zxvf biked_dataset.tar.gz# Delete the tar.gz file
rm biked_dataset.tar.gz

提取内容后,您将拥有一个名为 BIKED 的文件夹,其中包含 4510 个自行车设计的正方形图像。

注意 :如果使用自己的数据集,创建一个文件夹,将所有训练图像放入文件夹中。确保所有的图像都是正方形的,大小相同。

3.正在准备数据集

因为代码需要数据集。tfrecords 格式。我们首先需要将数据集转换成这种格式。StyleGAN2-ADA 已经编写了一个脚本来简化这种转换。

# first argument is output and second arg is path to dataset
python dataset_tool.py create_from_images ./datasets/biked biked

这将创建一个多分辨率。/datasets/biked/文件夹中的 tfrecord 文件。

4.培训风格 GAN2-ADA

# snap is how often you want to save the model and sample results
# res is what image resolution you want to train on
# augpipe is augmentation pipes, such as 'blit', 'geom', 'color', 'filter', 'noise', 'cutout' or combination of thesepython train.py --outdir ./results --snap=10 --data=./datasets/biked --augpipe=bgcfnc --res=512

您还可以修改许多其他参数,请随意查看 train.py 代码以了解关于这些参数的更多信息。

一旦您运行该命令,它将开始训练并定期保存结果和模型文件(。pkl),基于您提供的快照参数(在本例中,每 10kimg)。一旦你认为结果足够好或者 FID 开始平台期,你可以停止训练,使用最后保存的。pkl 文件。

一旦你有了模型文件,你就可以使用这个命令生成图像。

python generate.py --outdir=out --trunc=0.5 --seeds=600-605 --network={path_to_pkl_model_file}

您可以为种子提供一个范围或逗号分隔值。trunc 是截断技巧的值。截断值越高,输出越多样化或极端,但可能会降低图像质量。该值越低,图像质量越高,但多样性可能会降低。最大值为 1。

但是,如果你想生成插值视频或图像网格。可以参考我之前的文章。

5.转移学习或恢复培训

如果你的训练因为某种原因停止或崩溃。您仍然可以从上次保存的进度继续训练。您只需要添加— resume 参数和模型的路径(。pkl)文件。

此外,你也可以把这个论点用于迁移学习。与其从头开始训练,通常最好从一个预先训练好的模型开始,即使数据集本身并不相似。只需更换。由 StyleGAN-ADA 提供的预训练模型之一的 pkl 路径。

在这个例子中,我将在 biked 数据集上从我的预训练模型恢复训练。

python train.py --outdir ./results --snap=10 --data=./datasets/biked --augpipe=bgcfnc --res=512 --resume=full-bike-network-snapshot-004096.pkl

培训结果

这是一个经过一天的训练后,在特斯拉 P100 GPU 上 256x256 分辨率的训练结果的动画。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1 天的 StyleGAN2-ADA 训练进度。[图片由作者提供]

如果你喜欢我的作品,看看我的其他文章!

参考

[1] Regenwetter,l .,Curry,b .,和 Ahmed,F. (2021 年)。BIKED:数据驱动自行车设计的数据集和机器学习基准。

[2]诺巴里,A. H .,拉沙德,M. F .,,艾哈迈德,F. (2021)。CreativeGAN:编辑用于创造性设计综合的生成性对抗网络

[3]t . Karras,m . Aittala,j . hells ten,Laine,s .,Lehtinen,j .,& Aila,T. (2020 年)。用有限数据训练生成性对抗网络

如何使用 Python 和 docTR 训练用于车辆识别号(VIN)提取的文本检测和识别模型

原文:https://towardsdatascience.com/how-to-train-text-detection-recognition-models-for-vehicle-identification-number-vin-extraction-76857d1c2927?source=collection_archive---------19-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

VIN(车辆识别号)是一个由数字和大写字母组成的 17 位字符串,作为汽车的指纹。它可以帮助识别任何汽车在其生命周期内,并获得有关它的具体信息。这个唯一的标识符在制造过程中被印在车辆的某个地方,以便人们在某些过程中需要时可以读取它,例如汽车租赁或销售。

几个月前,我们来自 Monk 的朋友联系了我们:这是一家人工智能公司,为汽车、保险和移动市场提供最先进的计算机视觉解决方案。他们正在开发一种视觉智能技术,能够在汽车生命周期的每个阶段检查世界上的任何汽车。

他们唯一关注的是建立最好的技术来检测、分类和评估车辆的损坏。能够自动读取 vin 对他们来说很重要,但不是核心业务,这是 Mindee 的优势所在。

VIN 使用案例

请注意,本文中车辆识别号的任何照片要么是故意伪造的,要么是模糊的。

问题的定义很简单:

  • 输入是写在汽车上的 VIN 的照片
  • 输出是一个 17 个字符长的字符串:VIN

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

端到端 VIN 提取

高精度地自动执行这项任务比看起来要难。主要困难是:

  • 输入的照片大多是在户外拍摄的,有很多噪声(亮度、水渍、阴影……),这使得检测和识别 VIN 变得困难
  • 虽然 VIN 是以非常标准的格式书写的,但是使用的字体并不标准,也不总是一样的,字母间距也有很大不同。
  • 校验和验证方法可以验证 vin,但并不适用于所有车辆。我们拒绝了这种后处理解决方案。
  • 最后但同样重要的是,VIN 并不总是照片中唯一的文字,使用传统的 OCR 方法是不够的,因为我们需要添加一层后处理来过滤掉不想要的字符。

噪声图像的几个例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

噪声车辆识别号图像

我们做的第一件事是从开源库和基于云的 API 运行现成的 ocr。由于问题的性质,在文本检测和识别上的结果不够好。vin 是写在汽车上的,而不是写在文档上的,这也不是字符识别技术的常见用例。我们必须找到另一种使用 Python 和 docTR 的方法。

为什么要用 docTR?

DocTR 是为数据科学家和开发人员提供的一个 PythonOopticalCcharacterRecognition 库。端到端 OCR 是使用两阶段方法实现的:文本检测(本地化单词),然后是文本识别(识别单词中的所有字符)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

端到端 OCR 体系结构

DocTR 包括用于检测和识别任务的预训练模型。任何人都可以用它从图像或 pdf 中提取单词。您可以非常容易地测试它(更多信息见 docTR 文档)

1.装置

pip install python-doctr

2.Python hello world

from doctr.io import DocumentFile
from doctr.models import ocr_predictormodel = ocr_predictor(pretrained=True)
# PDF
doc = DocumentFile.from_pdf("path/to/your/doc.pdf").as_images()
# Analyze
result = model(doc)

但是正如我们前面提到的,没有一个 OCR 能很好地解决我们的 VIN 问题。通用 ocr 不是此用例的好解决方案,因为:

  • ocr 应该是通用的,当涉及到像 vin 照片这样的“野生”数据时,文本检测和文本识别的问题非常困难。
  • 通用 ocr 的输出列出了图像中书写的字符,即使它们都被准确地检测到,你如何从中重建 VIN 字符串?

为了摆脱这些限制,我们决定在检测和识别任务中对 VIN 数据的 docTR 模型进行微调,以获得更好的性能。这样,检测将只提取 VIN 字符(而不是周围的字符),我们将有一个用于读取它们的微调模型。该库包括基于预训练模型的用于检测和识别阶段的那些训练能力。由于这些预训练的模型,可以非常容易地根据 VIN 数据微调我们的模型:我们应该获得高精度,因为它们是根据数百万种数据预训练的。

我们的贡献者经常将最先进的模型添加到库中。以下是截至今日的可用型号列表:

文本检测

文本识别

这就是我们如何与尼古拉斯·舒尔(Nicolas Schuhl)一起解决车辆识别号提取案的。

我们的数据集

我们有 5000 张不同设备拍摄的车辆识别号照片,都来自不同的车辆。这是一个好的开始!Nicolas 告诉我们,他们的移动应用程序中有一个用于照片拍摄的布局模板,强制用户以正确的方向拍照。这使得问题变得简单,因为我们可以假设输入图像的方向是正确的。这也有助于我们确保 vin 不会过于偏斜:我们可以考虑大约 5°的最大绝对偏斜角度。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

VIN 图像

我们的数据集包含方向错误的照片和角度超过 5°的倾斜 vin。我们从我们的数据集中删除了超过 5 加上一个小增量(不是 5,以保留训练集中的一些困难情况)的倾斜照片,并改变了方向,以使每张照片都是直的。

我们将 75%的数据用于训练,15%用于验证,10%用于测试集,我们小心地将它们放在一边。

注释文本检测数据集

DocTR 文本检测模型输出图像的分割热图,以及相对坐标中的插值多边形列表。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

VIN 文本检测

为了训练这个模型,我们需要为每个图像提供对应于我们正在寻找的文本位置的多边形集。你可以在 docTR 参考文献上找到更多信息。

在我们的例子中,每个图像的标签是一个多边形,代表 VIN 在图像中的位置。

训练集和验证集必须以这种方式在文件夹中构建:

├── images
│   ├── sample_img_01.png
│   ├── sample_img_02.png
│   ├── sample_img_03.png
│   └── ...
└── labels.json

labels.json 文件将输入文件名映射到其多边形标签:

{
    "sample_img_01.png" = {
        'img_dimensions': (900, 600),
        'img_hash': "theimagedumpmyhash",
        'polygons': [[[x1, y1], [x2, y2], [x3, y3], [x4, y4]],...]
     },
     "sample_img_02.png" = {
        'img_dimensions': (900, 600),
        'img_hash': "thisisahash",
        'polygons': [[[x1, y1], [x2, y2], [x3, y3], [x4, y4]],...]
     }
     ...
}

我们使用我们的内部工具来注释这些数据,但是你可以找到许多很棒的商业软件(如 V7Kili )或开源软件(一个很好的基准这里是)来做这件事。

注释文本识别数据集

在 docTR 端到端管道中,文本识别模型将在第一文本检测阶段检测到的输入图像的裁剪作为输入。然后,该算法将对这些作物执行“读取”任务,以获得机器编码的字符串。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

VIN 文本识别

注释识别数据集比检测要繁琐一些。我们再次使用我们的内部工具,它包括一个使用通用文本识别算法的预注释功能,以使它更容易。纠正几个字符确实比从头开始手动键入所有字符容易。你可以在很多商业注释软件上找到这个特性。

对于文本识别任务,docTR 要求数据集文件夹的结构与文本检测相同,并且labels.json文件应该用唯一的关联字符串映射每个输入文件名:

├── images
    ├── img_1.jpg
    ├── img_2.jpg
    ├── img_3.jpg
    └── ...
├── labels.json

labels.json文件将输入文件名映射到它们的输出字符串:

{
    labels = {
    'img_1.jpg': 'I',
    'img_2.jpg': 'am',
    'img_3.jpg': 'a',
    'img_4.jpg': 'Jedi',
    'img_5.jpg': '!',
    ...
}

训练模型

现在让我们跳到有趣的东西!正如您可能想象的那样,真实的过程实际上是在训练实验和数据清理之间来回多次以提高性能。但是出于本文的考虑,让我们考虑数据集第一次被完美地注释了。

我们将使用 TensorFlow 2 (TF)后端来训练我们的模型:这也可以使用 PyTorch 后端来实现,因为步骤非常相似。您可以通过以下方式使用 TF 或 PyTorch 后端安装 docTR:

张量流

pip install python-doctr[tf]

PyTorch

pip install python-doctr[torch]

确保您有 4 个必需的带注释数据的文件夹,例如:

├── detection_train
    ├── images
	├── train_det_img_1.jpg
	└── ...
	└── labels.json
├── detection_val
    ├── images
	├── val_det_img_1.jpg
	└── ...
	└── labels.json
├── recognition_train
    ├── images
	├── train_rec_img_1.jpg
	└── ...
	└── labels.json
├── recognition_val
    ├── images
	├── val_rec_img_1.jpg
	└── ...
	└── labels.json

文本识别模型训练

先说文本识别算法。

1.安装 docTR

pip install python-doctr[tf]

2.在您的笔记本电脑上克隆存储库

git clone [https://github.com/mindee/doctr](https://github.com/mindee/doctr)

3.导航到您刚刚克隆的 docTR repo,并进入识别参考文件夹。references/recognition 文件夹包含 TensorFlow 和 PyTorch 的培训脚本。

cd /path/to/doctr/references/recognition

4.使用 sar_resnet31 启动培训(此型号使用 resnet31 主干)

python train_tensorflow.py model=sar_resnet31  train_path=/path/to/your/train/recognition/dataset val_path=/path/to/your/val/recognition/dataset --vocab legacy_french --pretrained --wb --epochs 50

**—预训练:**将使用 Resnet31 主干训练模型的检查点从 docTR — SAR 开始训练模型。
— wb: 将启动一项关于权重&偏差的实验。如果你想使用 TensorBoard,你也可以使用
— tb:

根据您的机器规格,如果您没有足够的内存,您可能会得到一个内存不足(OOM)错误。如果出现此错误,请使用-b 参数减小批处理大小:

python train_tensorflow.py model=sar_resnet31 train_path=/path/to/your/train/recognition/dataset
val_path=/path/to/your/val/recognition/dataset --vocab legacy_french --pretrained --wb --epochs 50 -b 16

-b: 批量

验证步骤发生在每个时期之后,如果验证损失是所有时期中最低的,则检查点将保存在 references 文件夹中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

VIN 文本识别培训

该模型收敛非常快,并且能够在验证集上实现 80%的精确匹配。这可能看起来没那么多,但这是因为我们决定将倾斜的数据放在训练集中。我们将很快计算端到端指标,因为这是最重要的一项指标,然后看看进展如何。

文本检测模型训练

对于文本检测模型,步骤如下:

  1. 导航到/references/detection 文件夹
cd /path/to/doctr/references/detection

2.使用 db_resnet50 启动培训(此型号使用 resnet50 主干)

python train_tensorflow.py model=db_resnet50 train_path=/path/to/your/train/detection/dataset val_path=/path/to/your/val/detection/dataset --pretrained --wb

检测模型比识别模型更重要:在这个模型中,更有可能出现 OOM 错误。同样,如果发生这种情况,考虑减少批量大小。

使用预先训练好的模型来完成这项任务是非常重要的。docTR 模型被训练来检测图像中的任何单词,而我们只寻找 vin。通过只在 vin 上重新训练这个模型,我们对模型进行了微调,只检测 vin 并过滤掉任何周围的文本。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

VIN 文本检测培训

检测指标比识别指标更难分析。虽然精度看起来非常高,但由于 IoU 不容易操作,我们将通过测试端到端管道来计算模型的性能。

测试训练好的模型

我们的模型保存在克隆的 docTR 存储库的 reference 文件夹中。

要查看模型的运行情况,代码非常简单:

from doctr.io import DocumentFile
from doctr.models import ocr_predictorDET_CKPT = "file:///path/to/detection/model/db_resnet50_XXXX/weights"
REC_CKPT = "file://path/to/recognition/model/sar_resnet31_XXXX/weights"model = ocr_predictor(det_arch='db_resnet50', reco_arch='sar_resnet31',pretrained=True)
model.det_predictor.model.load_weights(DET_CKPT)
model.det_predictor.model.postprocessor.unclip_ratio = 2
model.reco_predictor.model.load_weights(REC_CKPT)if __name__ == "__main__":
    # Image loading
    doc = DocumentFile.from_images("./path/to/image")
    # Models inference
    result = model(doc)
    # Max proba post processing rule for selecting the right VIN value among docTR results
    vin = ""
    for word in result.pages[0].blocks[0].lines[0].words:
        if word.confidence > confidence:
	     vin = word.value
	     confidence = word.confidence
    # Display the detection and recognition results on the image
    result.show(doc)

没有理由说文本检测算法完全适合优化文本识别算法的框的大小。为了找到最佳的参数,我们根据验证集微调了 invoke _ ratio 参数。这是用于扩展来自检测模型的输出多边形的因子,以便生成可以输入到文本识别模型中的方形框。由于这两个模型是分别训练的,因此默认参数没有理由是优化文本识别性能的最佳参数。

在我们的测试集上测试了经过训练的模型之后,我们实现了 90%的端到端精确匹配,考虑到数据数量少和用例的复杂性,这是非常好的。如果我们愿意,我们可以花更多的时间用一些想法来优化模型:

  • 检测模型在方形盒子上训练。DocTR 将很快支持旋转框,这将使我们对倾斜的照片有更好的鲁棒性。
  • 超参数微调:我们没有在这上面花太多时间。例如,我们注意到学习衰退对训练有很大的影响。我们手动测试了一些值,但是我们可以花更多的时间来运行这些参数的网格搜索。输入大小也很重要,我们使用了默认的 docTR 参数。
  • 仅用于算法主干部分的文本识别预训练模型:虽然拥有预训练模型非常好,但我们在使用它们时不能随意使用我们想要的词汇。我们询问 docTR 团队是否可以只为文本识别算法的主干部分获得预训练的模型,这样我们就可以用我们特定的词汇表训练分类头。一个问题被打开,他们将很快解决这个问题。
  • 当然,更多的数据…

结论

这个案例是端到端文本提取问题的一个很好的例子,它需要重新训练检测和识别层以获得更好的性能。使用通用 OCR 并试图提取您想要的关键信息可能会非常繁琐。您需要在原始 OCR 结果的基础上建立大量的后处理,它不太可能在简单的文本检测和识别任务中表现良好。

如果你有类似的用例,可以随时加入 Mindee 的 slack 社区 ,或者试用docTR并给我们你的反馈:)

如何用 Ray v1 更快的训练时间序列预测?第二部分,共三部分。

原文:https://towardsdatascience.com/how-to-train-time-series-forecasting-faster-using-ray-part-2-of-2-aacba89ca49a?source=collection_archive---------13-----------------------

时间序列预测使用谷歌的时间融合变压器 LSTM 版的 RNN 与 PyTorch 预测和火炬闪电

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

显示纽约市黄色出租车的乘坐量,以及 1 周每小时的预测。根据验证数据集,蓝色=观察到的,橙色=预测到的。由 Pytorch forecasting 实现的使用 Google 的时间融合转换器算法生成的预测,并由 Ray 并行化以实现更快的运行时间,无论是在笔记本电脑上还是在任何云上。图片作者。

在第 1 部分中,我的前一篇博客解释了当每个模型都被独立训练时,如何应用令人尴尬的并行模式来加速预测,例如使用传统的预测算法 ARIMA、预言者和神经预言者。数据、训练和推理由 Ray 引擎分布在本地笔记本电脑内核上。这个概念类似于多处理池,除了 Ray 可以处理分布更复杂的类和函数。与多处理不同,完全相同的代码也可以在任何云中的任何集群上并行运行。

这篇文章将解释当训练一个大型全球模型以预测许多目标时间序列时,如何使用 Ray 来加速深度学习预测。为什么要这么做?嗯,通常情况下,一个公司想要预测的东西是相互关联的,比如体育用品、相同品牌和颜色的洗衣机和烘干机、经常一起购买的超市物品等等。然后,每个目标时间序列都被用作同一个模型的输入,每个目标时间序列都得到不同的输出。

为全局深度学习模型的分布式运行时并行化代码需要分布式数据并行和模型并行。这需要分布式计算工作者之间的协作来分割数据,在每个具有其自己的数据片的工作者之间共享梯度,并将梯度组合到单个全局模型中。Ray 处理数据和模型并行性,同时为开发人员保留一个简单的 API。此外,Ray 可以并行训练和推断深度学习模型,分布在单个笔记本电脑的内核或任何云中的计算节点上。

本博客分为以下几个主题:

  • 介绍用于预测的深度学习人工智能算法
  • 在 Pytorch 预测中使用 Google 的时态融合转换器(使用 py torch Lightning API)
  • 如何使用 Ray 加速模型训练和推理
  • 如何使用 Anyscale 加速任何云中的模型训练和推理

介绍用于预测的深度学习人工智能算法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

向左。RNN 的高级视图和展开的时间步骤。图片来源。中间。典型的 ANN 构造块,由 1 个输入层、2 个隐藏的密集层和 1 个输出层组成。图片来源。没错。示例 GRN 由 2 个致密层组成,具有 2 个激活函数(ELU 指数线性单位和 GLU 门控线性单位),以及脱落。图片来自时间融合转换器论文

递归神经网络 ( RNN )是一种常用于时间序列的神经网络,因为它按顺序处理数据。RNN 由一系列 ANN(人工神经网络)组成,通常每个时间步一个 ANN。RNN 架构允许顺序输入和顺序输出。每个 ANN 构件本身是一组神经元,分为输入层、隐藏层和输出层,其中每个神经元与其他神经元相连,每个连接具有可训练的权重。rnn 首先用于文本翻译。

以下是一些相关的概念术语。

**LSTM(长短期记忆)**是一种递归神经网络架构,旨在克服消失梯度问题(过去的事情可能接近 0 值权重)。LSTM 有 3 个记忆门,它们一起允许一个网络记住和忘记。

GRN 或门控剩余网络可以代替基本的 ANN 构建模块。具体包括:2 个致密层和 2 个激活函数(ELU 指数线性单元和谷氨酸门控线性单元)。这使得网络能够理解哪些输入转换是简单的,哪些需要更复杂的建模,以及哪些需要完全跳过。

编码器-解码器模型是一种 RNN,其中数据(训练数据)的输入序列可以与输出序列(验证或测试数据,也称为预测范围)具有不同的长度。位置编码被添加到输入嵌入中,以指示输入相对于整个时间序列的位置。

自我注意机制是为解决 LSTMs 的远程依赖问题(由于 LSTM 的遗忘门,重要信息可能丢失)而开发的一种进化。通过增加一个变压器,某些输入可以得到更多的“关注”,通过 RNN 网络进行前馈。在每个时间步,可学习的权重被计算为 Q 查询(具有特定的输入向量 w.r.t .其他输入)、 K ey(也包含该查询的输入嵌入)和 V 值(通常通过 Q,K 学习的权重的点积计算的输出向量)的函数。输出通过 RNN 网络进行前馈。由于 Q、K 都是从相同的输入中计算出来的,而这些输入又被应用于相同的输入,这个过程被称为“自我注意”。

多头注意力在每个时间步使用多个 Q,K 变换。纯自我关注使用每个时间步的所有历史数据。例如,如果 h=4 个注意头,则输入数据被分成 4 个块,然后使用 Q,K 矩阵将自我注意应用于每个块,以获得 4 个不同的 V 得分向量。这意味着单个输入被投射到 4 个不同的“表示子空间”上,并且通过 RNN 网络进行前馈。结果是更加细致入微的自我关注。从分布式计算的角度来看,这是理想的,因为来自多头注意力的每个块 h 可以在单独的处理器或工作器上异步运行。

**回测。**训练和验证数据被分割成滑动窗口的批次(每一批次是在未来移动 1 个值的前一批次)。这种技术被称为“回溯测试”,因为你不能像往常一样随机抽取 80/20 的训练/测试样本。顺序数据顺序必须保持不变。时间序列通常采用 context_length 大小的数据窗口进行训练,然后采用不同的 prediction_length 大小的窗口进行验证。

在 Pytorch 预测中使用 Google 的时态融合转换器实现的示例

本教程中使用的数据集是 8 个月的历史纽约市黄色出租车乘坐量。

我们的数据编码对象将是一个使用回溯测试技术重复折叠顺序数据的生成器。为了处理去趋势化,我们将使用 PyTorch Forecasting 的组规格化器,或每个 item_id 的批量规格化。每批分为 63 小时的训练输入和 168 小时或 1 周的预测目标。也就是说,使用 63/168 窗口长度对数据进行训练/有效采样,以保持数据的顺序完整。

网络设计将是 LSTM 版的 RNN,具有 GRN 构建块、编码器-解码器和多头注意力。我们将使用 PyTorch Forecasting 对谷歌的时间融合转换器的实现。PyTorch Forecasting 是为 PyTorch Lightning 开发的一套方便的 API。PyTorch Lightning 又是一套基于 PyTorch 之上的便利 API。这与 Keras 是 TensorFlow 之上的一组便利 API 的概念类似。

演示的代码是 github 上的

示例如何使用 Ray 加速模型训练和推理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Ray 是加州大学伯克利分校 RISELab 开发的开源库,该校还开发了 Apache Spark。Ray 使得并行化和分发 Python 代码变得很容易。代码可以在任何类型的内核上运行:a)你自己的笔记本电脑内核,AWS、GCP 或任何公共云中的集群。

这篇文章的其余部分假设你已经定义了一个 PyTorch 闪电模型,无论是通过普通的 PyTorch 闪电还是通过 PyTorch 预测。下面用粗体显示了您需要修改的代码部分,以使它能够在 Ray 上运行。

第一步。安装并导入RayRay 插件 为 PyTorch Lightning,以及any scale。确保您的 PyTorch Lightning 版本为 1.4。****

# Install these libraries in your conda environment  
conda install pytorch  
**pip install pytorch_lightning==1.4**   #required version for ray  
**pip install git+https://github.com/jdb78/pytorch-forecasting@maintenance/pip-install**  #used at time of writing this blog, check for updates  
**pip install ray  
pip install anyscale**  
**pip install ray_lightning**# Import these libraries in your .py or .ipynb code     
import torch   
import pytorch_lightning as pl    
import pytorch_forecasting as ptf   
**import ray**  
**from ray_lightning import RayPlugin**# PyTorch visualization uses Tensorboard
import tensorflow as tf #Tensorflow
import tensorboard as tb  #Tensorboard
#compatibility for PyTorch
tf.io.gfile = tb.compat.tensorflow_stub.io.gfile

第二步。根据笔记本电脑上的内核数量初始化 Ray (这是默认行为)。我的有 8 个内核。

# initialize ray, detects and uses all available CPU by default
**ray.init()**

第三步。初始化 Ray Lightning 插件,也是为了你笔记本电脑上的内核数量。

# initialize the Ray Lightning plugin **plugin = \      
   RayPlugin(           
      num_workers=8,  #fixed num CPU        
      num_cpus_per_worker=1,           
      use_gpu=False,  #True or False    
      find_unused_parameters=False, #skip warnings    
   )**

步骤四。像往常一样,将您的数据转换为 PyTorch 张量,并定义 PyTorch 预测数据加载器。PyTorch 预测数据加载器 API 方便地将张量自动折叠到训练/测试回溯测试窗口中。

接下来,修改 PyTorch 闪电训练器来使用射线插件。在下面添加**plugins=[ray_plugin]**参数。

注意:示例数据与代码位于同一个 github repo 中。数据已经汇总到纽约每个地点的每小时出租车乘坐次数中。

# read data into pandas dataframe
filename = "data/clean_taxi_hourly.parquet"
df = pd.read_parquet(filename)# keep only certain columns
df = df[["time_idx", "pulocationid", "day_hour",
         "trip_quantity", "mean_item_loc_weekday",
         "binned_max_item"]].copy()# convert data to PyTorch tensors and PyTorch Forecasting loaders 
# PyTorch Forecasting folds tensors into backtest windows
train_dataset, train_loader, val_loader = \
     convert_pandas_pytorch_timeseriesdata(df)# define the pytorch lightning trainer
trainer = pl.Trainer(      
     max_epochs=EPOCHS,      
     gpus=NUM_GPU,      
     gradient_clip_val=0.1,        
     limit_train_batches=30,       
     callbacks=[lr_logger, 
                early_stop_callback],      
     # how often to log, default=50      
     logger=logger,      
     # To go back to regular python - just comment out below      
     # Plugin allows Ray engine to distribute objects     
     plugins=[**ray_plugin**] 
     )

最后,像往常一样定义一个 PyTorch 闪电(或预测)模型。并像往常一样拟合模型。

# define a pytorch forecasting model
model = ptf.models.TemporalFusionTransformer.from_dataset(   
             train_dataset,      
             learning_rate=LR,      
             hidden_size=HIDDEN_SIZE,      
             attention_head_size=ATTENTION_HEAD_SIZE,      
             dropout=DROPOUT,    
             hidden_continuous_size=HIDDEN_CONTINUOUS_SIZE,   
             loss=ptf.metrics.QuantileLoss(),      
             log_interval=10,      
             reduce_on_plateau_patience=4, 
             )# fit the model on training data
trainer.fit(
     model,      
     train_dataloaders=train_loader,         
     val_dataloaders=val_loader, 
)# get best model from the trainer
best_model_path = trainer.checkpoint_callback.best_model_path
best_model = \
ptf.models.TemporalFusionTransformer.load_from_checkpoint(
     best_model_path
)

就是这样!现在您的 PyTorch Lightning 模型将分布式运行。在幕后,Ray Lightning 插件 API 和 Ray 一起自动分发数据和模型。输入数据被自动完全分片,数据分片和训练函数被放置在每个并行工作器上,在工作器之间共享梯度,产生一个全局模型,并且结果模型作为请求的类型(PyTorch Lightning 或 PyTorch Forecasting 模型类型)被返回。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Ray 在幕后将全局模型的学习分布到 N 个计算节点上。输入数据被完全分片,每个节点上的每个工人得到相同的训练函数,梯度在并行工人之间共享,并且产生一个全局模型。图片作者。

以前,我试图在我的笔记本电脑上训练这个模型,但几个小时后中断了运行,因为第一个时期还没有结束。用 Ray 分发代码后,同样的代码运行大约 1 小时。

这些小的调整使得在一个相当小的计算资源(我的笔记本电脑)上在大约 1 小时内训练一个非常精确的 DL 全球预测模型成为可能。

Ray 的另一个好处是,现在代码可以在我的笔记本电脑上并行运行,我可以使用 Anyscale 在任何云上运行相同的代码,接下来我将展示这一点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 8 核笔记本电脑上运行的模型训练输出。iPython %% time 输出显示,训练一个非常准确的预测大约需要 1 个小时。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 8 核笔记本电脑上运行的模型训练输出。使用对 1 周延迟验证数据的预测计算精确度。

如何使用 Anyscale 在任何云中加速模型训练和推理

接下来,为了更快地训练或进行推理,您可能希望在更大的实例或更大的集群上的云上运行相同的代码。为了在云上使用完全相同的射线代码,(AWS,GCP,…),你需要使用射线开源集群Anyscale 来简化任何云设置。

使用 Anyscale,您可以选择 a)在集群配置上进行 pip 安装和 github 克隆,或者 b)在运行时进行。更多信息见集群或运行时环境。首先使用集群配置,然后运行时配置(如果指定)将覆盖集群配置。

使用 Anyscale 在任何云上运行 Ray 代码的步骤如下:

第一步。 报名 参加 Anyscale 和 建立自己的账户

第二步。创建集群配置。我这样做是为了方便,因为我有许多非典型的、较新的 ML 库要安装,并带有依赖项。打开浏览器到 Anyscale 控制台,在Configurations左侧菜单下,点击Create new environment按钮。见下面 Anyscale 控制台的图片。

  1. Cluster environment name。给你的环境配置起一个名字。
  2. 选择 Python 版本。
  3. 选择一个基本 docker 图像。我选择了anyscale/ray-ml:1.9.0-python38-gpu
  4. Pip packages下,见下图了解要安装的软件包和顺序。
  5. Post build commands下,如果您想自动安装该演示代码和数据,请参见下图。
  6. 点击Create按钮。

记下您的cluster-config-name:version_number。在下面的截图中,我的名字是christy-forecast-pytorch:13。下一步你会需要这个。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Anyscale 控制台,显示配置左侧菜单。主屏幕显示了一个示例配置,在基本 docker 映像上安装了额外的 pip 和 github clone。

第三步。用云集群的名称和集群配置初始化光线

import anyscale # initialize ray on Anyscale to run on any cloud 
# name your cluster on the fly 
# set cluster_env parameter = your preconfigured cluster config name
ray.init(      
     **anyscale://my-cool-cluster**, #give your cluster any name   
     **cluster_env=christy-forecast-pytorch:13**, 
)

第四步。用 num_workers=N 初始化 Ray Lightning 插件,其中 N > num cpu 在你的云集群的头节点上。如果指定任意数字< = N,Anyscale 将不会向外扩展。对于任意数量的 N,Anyscale 自动缩放将自动触发,直到您的帐户中配置的限制。如果您可以访问 GPU,请设置 GPU。

plugin = \
     RayPlugin(
          num_workers=**10**,              
          num_cpus_per_worker=1,              
          use_gpu=**True**,                  
     )

现在,像平常一样运行 python 代码(或笔记本)。它会自动在任何云中并行运行!当您的应用程序运行时,您可以在Clusters下的 Anyscale 控制台中监控您的云集群使用情况。

结论

这篇博客展示了为用于时间序列预测的 PyTorch Lightning 模型启用数据和模型并行性是多么容易。只需要最少的代码更改。一旦针对 Ray 进行了修改,相同的代码可以在您的笔记本电脑上并行运行,或者通过 Anyscale 在任何云上并行运行。

演示的完整代码在 github 上的

感谢 Jan Beitner, PyTorch Forecasting 的作者,接受我的拉动请求并创建了一个维护版本,用于本演示。

资源

  1. 雷 doc 页数:https://docs.ray.io/en/latest/using-ray.html
  2. PyTorch 闪电雷外挂:https://github.com/ray-project/ray_lightning
  3. PyTorch 预测:https://pytorch-forecasting.readthedocs.io/en/stable/
  4. Anyscale doc 页数:https://docs.anyscale.com/get-started
  5. 时态融合变换算法论文:https://arxiv.org/pdf/1912.09363.pdf
  6. 用于预测的 RNN 背景资料:https://assets . Amazon . science/0b/93/4117 a 5014 a F5 DD 487d 7 ffd 74 ab/deep-state-space-models-for-time-series-Forecasting . pdf
  7. 时间序列预测算法背景介绍:https://towards data science . com/the-best-deep-learning-models-for-Time-Series-Forecasting-690767 bc63f 0
  8. 数据和模型并行性背景介绍:https://arxiv.org/abs/1404.5997

最初发表于https://www.anyscale.com**

如何在自定义数据集上训练 YOLOX

原文:https://towardsdatascience.com/how-to-train-yolox-on-a-custom-dataset-bb2f94cdb038?source=collection_archive---------7-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(引用)

YOLO 家族继续发展下一款产品:YOLOX。在本帖中,我们将介绍如何训练 YOLOX 识别自定义用例的对象检测数据。

出于本教程的目的,我们使用公共血细胞对象检测数据集。但是,您可以将自己的数据导入到 Roboflow 中,并将其导出以训练该模型来满足自己的需求。本教程使用的 YOLOX 笔记本 可以在 这里 下载。

感谢旷视科技团队发布了 底层知识库 ,这构成了我们笔记本的基础。

在本指南中,我们采取了以下步骤:

  • 安装 YOLOX 依赖项
  • 通过 Roboflow 下载自定义 YOLOX 对象检测数据
  • 下载 YOLOX 的预训练重量
  • 运行 YOLOX 训练
  • 评估 YOLOX 性能
  • 对测试图像运行 YOLOX 推理
  • 导出保存的 YOLOX 重量以供将来推断

更喜欢 YouTube?

YOLOX 有什么新功能?

YOLOX 是 YOLO 模型的最新版本,在速度和准确性方面都达到了极限。YOLOX 最近赢得了流媒体感知挑战(CVPR 2021 自动驾驶研讨会)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

相对于其他 YOLO 检测网络的 YOLOX 评估

最大的建模变化包括移除盒锚(提高模型到边缘设备的可移植性)和将 YOLO 检测头解耦到用于盒分类和盒回归的单独特征通道(提高训练收敛时间和模型准确性)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

YOLOX 中的分离头

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过YOLOX中的历元加快训练时间。我们认为yolov 5时代更快(我们还没有运行任何直接的面对面测试)

许多其他令人兴奋的训练和推理考虑都包括在论文中。你可以在 YOLOX 论文或这个视频中更深入地探究。

安装 YOLOX 依赖项

为了设置我们的开发环境,我们将首先克隆基本的 YOLOX 库并下载必要的需求:

!git clone https://github.com/roboflow-ai/YOLOX.git %cd YOLOX !pip3 install -U pip && pip3 install -r requirements.txt !pip3 install -v -e . !pip uninstall -y torch torchvision torchaudio # May need to change in the future if Colab no longer uses CUDA 11.0 !pip install torch==1.7.1+cu110 torchvision==0.8.2+cu110 torchaudio==0.7.2 -f [https://download.pytorch.org/whl/torch_stable.html](https://download.pytorch.org/whl/torch_stable.html)

我们还将安装 NVIDIA Apex 和 PyCocoTools,以使该存储库按预期工作:

%cd /content/ !git clone https://github.com/NVIDIA/apex %cd apex !pip install -v --disable-pip-version-check --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" ./ !pip3 install cython; pip3 install 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'

下载自定义 YOLOX 对象检测数据

在我们开始之前,您需要创建一个 Roboflow 帐户。我们将使用这个血细胞数据集,但是欢迎您使用任何数据集,无论是您自己加载到 Roboflow 的数据集还是其他公共数据集。

对于这个笔记本,我们将需要应用一些预处理步骤来确保数据能够与 YOLOX 一起工作。首先,创建一个 Roboflow 帐户(如果您还没有),然后派生数据集:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在分叉数据集之后,您将需要添加一个预处理步骤,将所有图像的大小调整为 640 x 640:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后简单地生成数据集的新版本,用“ Pascal VOC ”导出。您将收到一个类似于以下内容的 Jupyter 笔记本命令:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

复制该命令,并用 Roboflow 提供的命令替换笔记本中的下面一行:

!curl -L "[YOUR LINK HERE]" > roboflow.zip; unzip roboflow.zip; rm roboflow.zip

标注您的数据

如果你有自己的数据集,你可以在 Roboflow 中标注你的图像。

下载 YOLOX 的预训练重量

YOLOX 带有一些预训练的权重,以允许模型更快地训练并实现更高的精度。砝码有多种尺寸,但我们使用的砝码尺寸将基于小型 YOLOX 型号(YOLOX_S)。我们可以按如下方式下载:

%cd /content/ !wget https://github.com/Megvii-BaseDetection/storage/releases/download/0.0.1/yolox_s.pth %cd /content/YOLOX/

运行 YOLOX 训练

为了训练模型,我们可以运行tools/train.py文件:

!python tools/train.py -f exps/example/yolox_voc/yolox_voc_s.py -d 1 -b 16 --fp16 -o -c /content/yolox_s.pth

运行该命令的参数包括:

  • 经验文件:该文件允许我们在培训时更改基础模型的某些方面
  • 设备:我们的模型将训练的 GPU 数量— 1 是 Colab 提供的值 1
  • 批量大小:每批图像的数量
  • 预训练权重:指定您想要使用的权重的路径-这可以是我们下载的权重或您的模型的早期检查点

经过大约 90 个时代的训练,我们得到了以下 AP。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

评估 YOLOX 性能

要评估 YOLOX 的性能,我们可以使用以下命令:

MODEL_PATH = "/content/YOLOX/YOLOX_outputs/yolox_voc_s/latest_ckpt.pth.tar" !python3 tools/eval.py -n yolox-s -c {MODEL_PATH} -b 64 -d 1 --conf 0.001 -f exps/example/yolox_voc/yolox_voc_s.py

运行评估后,我们得到以下结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

YOLOX 模型的评估

性能看起来不错!

对测试图像运行 YOLOX 推理

我们现在可以在测试图像上运行 YOLOX 并可视化预测。要在测试映像上运行 YOLOX:

TEST_IMAGE_PATH = "/content/valid/BloodImage_00057_jpg.rf.1ee93e9ec4d76cfaddaa7df70456c376.jpg" !python tools/demo.py image -f /content/YOLOX/exps/example/yolox_voc/yolox_voc_s.py -c {MODEL_PATH} --path {TEST_IMAGE_PATH} --conf 0.25 --nms 0.45 --tsize 640 --save_result --device gpu

要在图像上可视化预测:

from PIL import Image OUTPUT_IMAGE_PATH = "/content/YOLOX/YOLOX_outputs/yolox_voc_s/vis_res/2021_07_31_00_31_01/BloodImage_00057_jpg.rf.1ee93e9ec4d76cfaddaa7df70456c376.jpg" Image.open(OUTPUT_IMAGE_PATH)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看起来模型像预期的那样工作!

导出保存的 YOLOX 重量以供将来推断

最后,我们可以将模型导出到我们的 Google Drive,如下所示:

from google.colab import drive drive.mount('/content/gdrive') %cp {MODEL_PATH} /content/gdrive/My\ Drive

结论

YOLOX 是一个令人难以置信的强大,最先进的对象检测模型。在本教程中,您可以学习如何:

  • 准备 YOLOX 环境
  • 使用 Roboflow 下载自定义对象检测数据
  • 运行 YOLOX 培训流程
  • 使用你训练过的 YOLOX 模型进行推理
  • 将您的模型导出到 Google Drive

快乐训练!

原载于 2021 年 8 月 2 日【https://blog.roboflow.com】

如何以分布式方式训练你的深度学习模型?

原文:https://towardsdatascience.com/how-to-train-your-deep-learning-models-in-a-distributed-fashion-43a6f53f0484?source=collection_archive---------8-----------------------

基于 Horovod 的 Azure ML 分布式训练实用方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

凯文·Ku 在 Unsplash 上的照片

深度学习算法非常适合大数据集,并且训练深度学习网络需要大的计算能力。由于 GPU/TPU 很容易按使用付费或免费获得(如 Google collab),今天有可能在类似云的 ImageNet 数据库上训练大型神经网络,例如 Resnet 152 (152 层),ImageNet 数据库有大约 1400 万张图像。但是一台支持多核 GPU 的机器是否足以训练庞大的模型呢?从技术上来说是的,但是训练这个模型可能需要几个星期。那么我们如何减少训练时间呢?任何可扩展性问题都可以使用两种方法来解决—纵向扩展或横向扩展。我们都知道,如果我们选择纵向扩展,容量会在某个时候达到极限,因此更好的替代方案是横向扩展。但是,你如何进行分布式训练,如果我使用 Jupyter 笔记本进行模型训练,我从哪里开始,我可以对任何深度学习模型进行分布式训练吗?这个博客旨在用一种实用的方法来回答这些问题。

在这篇博客中,我们将学习如何在云上应用横向扩展或者说分布式机器学习技术。我们将了解如何从 Jupyter 笔记本阶段(构建 ML 模型的最敏捷方式)过渡到可以在使用 Azure ML 和 Horovod 的 GPU 集群上运行的生产就绪型培训脚本。

如果你是分布式机器学习的新手,这里有一些概念/术语是你在继续学习之前应该知道的。

数据并行和模型并行

在数据并行方法中,整个模型被部署到一个集群的多个节点上,数据被分片(水平分割)。模型的每个实例都处理一部分数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据并行训练。

在模型并行方法中,模型的一个层(或一组层)被部署在集群的一个节点上,并且整个数据被复制到该节点,每个节点在完整的数据集上训练。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

模型平行训练。

最常见也最容易实现的是数据并行,我们将在接下来的章节中看到一种实用的方法。直观理解数据并行如何工作的一种方式是,在每个 GPU 节点中为一小批数据(比如一次 30 个图像)计算梯度,并且在网络的一轮前后传递结束时,更新的权重被发送回发起节点。来自每个节点的权重的加权平均值被应用于模型参数。更新的模型参数被发送回节点用于下一轮迭代。

这几乎类似于你以非分布式方式分批训练时发生的情况。然而,这里的关键问题是如何在数据并行方法中存储和更新模型参数。这就把我们带到了下一个话题,集中和去中心化的培训。

集中和分散培训。

在模型并行或数据并行训练中,关键是节点之间的通信,定义参数如何初始化、权重/偏差如何更新很重要。

有两种类型的沟通方式。这适用于数据并行和模型并行方法。在集中式通信模式中,存在负责同步模型参数的节点或节点组,该节点被称为参数服务器。这种方法的优点是很容易同步模型参数,另一方面,参数服务器本身可能成为大型集群的瓶颈。这也是一个单点故障。当然,通过引入多个并行服务器并确保应用适当的存储冗余,可以在一定程度上减少瓶颈问题。

在去中心化的通信模式中,每个节点与每个其他节点通信以更新参数。这种方法的优点是对等更新更快,稀疏更新可以通过仅交换已更改的内容来进行,并且没有单点故障。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

集中培训与分散培训。

同步和异步更新。

如果你熟悉深度学习并知道如何训练权重(如果不是,你可以在这里阅读我的文章),一旦损失函数的梯度可用,就计算更新的权重。在使用数据并行方法的分布式训练中,可以用两种方式更新模型参数,即权重和偏差。

1.同步地:假设我们正在处理 10k 图像和 10 个节点,每个节点被给予 1k 图像的子集,一旦它们完成第一次迭代,更新的模型参数被发送到参数服务器。这种方法大大提高了模型的准确性,但这种方法的缺点当然是服务器必须等待所有节点完成迭代,如果有一个非常慢的服务器,它可能会降低整个训练的速度。

2.异步:在这种情况下,不是等待所有节点发送权重更新,而是一旦它们可用就发送,这增加了集群利用率并提高了训练速度,但是当然导致了陈旧梯度问题。大多数实现异步更新的框架都应用了一些策略来降低影响,以利于更高的集群利用率。

请记住,同步或异步更新适用于集中式和分散式培训方法。类似地,同步和异步更新可以应用于权重和对权重的更新,即,根据等式权重(新)=权重(旧)LR *梯度损失,在每次迭代之后,仅可以发送关于权重的梯度损失。为了更好地理解这一点,让我们想象一下,我们建立了一个具有同步更新和集中训练的集群,这意味着还有一个单独的参数服务,每个节点发送更新,一旦参数服务器上接收到所有更新,就计算新的权重,然后在所有节点上复制该权重,用于下一次迭代。

在讨论了如何存储和更新模型参数的优点和缺点之后,选择最佳参数总是取决于问题、数据集、聚类大小和各种因素。没有一个解决所有问题的正确方法。

实现分布式机器学习的框架

Map/Reduce、Apache Spark、百度 All Reduce、Horovod、Caffe2、微软认知工具包(CNTK)、dist faith、Tensorflow、DIANNE、MXNet、Petumm 是分布式机器学习可用的顶级框架。在这里可以找到每一项的简要介绍。

其中,以下是 Azure today 在工作区(PaaS)模型中支持的——Apache Spark、Horovod(它在 Databricks 和 Azure ML 上都可用)、TensorFlow 分布式培训,当然还有 CNTK。

Horovod 和天蓝色 ML。

分布式训练可以在 Azure ML 上使用 PyTorch、TensorFlow 这样的框架来完成。Tensorflow 的分布式训练支持集中式和分散式训练方法(更多信息这里),如果你已经有一个使用分布式 TF 的笔记本,你可以很容易地将其导入 Azure ML。在这篇文章中,我们将了解霍洛佛德。

Horovod 是一个开源的分布式深度学习框架,适用于 TF、Keras、PyTorch 和 Apache MXNet,它通过减少对并行运行在多个 GPU 节点上的训练脚本所做的更改数量,简化了分布式训练。你可以在这里了解更多关于霍洛佛德的信息。

使用 Horovod 设置环境时,您不必担心太多,Azure ML 提供了精选的培训环境,可以使用各种框架轻松设置培训,其中一个框架预装了 TensorFlow 和 Horovod。如果需要,这些策划的框架还允许定制。

注意:你也可以在 Azure ML 上使用上面解释的集中式或分散式训练方法运行原生分布式 TensorFlow。

从笔记本阶段到分布式 ML 的训练过程。

在这个例子中,我试图使用 CNN 对两类图像进行分类。这些图像属于胸部 X 射线,一类图像包含检测到积液的图像,另一类不包含。有关学习过程、预处理、消融实验等的更多信息。我推荐你参观这里的代码。

下图解释了从笔记本阶段到以分布式方式在集群上运行训练实验的过程。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下面是我在一个支持 Horovod 的 4 节点分布式训练集群上运行单个 GPU 训练脚本的代码片段。

import osfrom azureml.core import ScriptRunConfigimport shutilfrom azureml.core import Experimentfrom azureml.core import Environmentfrom azureml.core.conda_dependencies import CondaDependenciesfrom azureml.widgets import RunDetailsfrom azureml.core.runconfig import MpiConfiguration## The training script capable of running in distributed environment is extracted to effusion_detector_distributed.pyproject_folder = './effusion_detector-distributed'os.makedirs(project_folder, exist_ok=True)shutil.copy('effusion_detector_distributed.py', project_folder)## choosing an experiment nameexperiment_name = 'tf-distributed-effusion-detector'experiment = Experiment(ws, name=experiment_name)# loading the env dependencies from conda configurationos.makedirs('./envs', exist_ok=True)tf_env = Environment.from_conda_specification(name="imageclassification", file_path="envs/distributed-tensorflow-with-horovod/conda_dependencies.yml")# Specify a GPU base imagetf_env.docker.enabled = Truetf_env.docker.base_image = 'mcr.microsoft.com/azureml/openmpi3.1.2-cuda10.1-cudnn7-ubuntu18.04'# using a cluster which can autoscale uptp 4 nodes.cluster_name = "gpus"compute_target = ComputeTarget(workspace=ws, name=cluster_name)# running the scriptargs = ['--data-folder', dataset.as_mount(), '--epochs', 20]src = ScriptRunConfig(source_directory=project_folder,script='effusion_detector_distributed.py',arguments=args,compute_target=compute_target,environment=tf_env, distributed_job_config=MpiConfiguration(node_count=4))run = experiment.submit(src)print(run)run.get_details()

这里有一个图像显示了培训的结果,第一个实验是使用分布式培训(4 个节点,每个节点 6 个 GPU 核心)完成的,第二个实验是使用一台具有 6 个 GPU 核心的机器完成的。用于单机和集群的处理单元 GPU — 1 个 NVIDIA Tesla K80

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

分布式训练和单机训练的实验结果。

我在分布式培训中没有发现什么明显的不同。

  1. 训练时间从 7.5 分钟减少到 5 分钟。
  2. 为运行配置了 20 个时期,每个节点运行 5 个时期。(注意:这也意味着不能应用最小容差设置为 5 个时期的提前停止,在单机训练中,由于提前停止规则,训练最终停止)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

该图显示了运行 5 个时期的工作进程 0。

3.每个工作进程都有一个私有 IP,日志显示它们都是相互连接的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

该图显示了给定私有 IP 的每个进程。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

显示工作进程 0 连接到工作进程 3 的图像。

https://github.com/sriksmachi/octopus

附加阅读

-https://stack overflow . com/questions/53498952/tensor flow-horo VOD-nccl-and-MPI #:~:text = MPI % 20 is % 20 used % 20 for % 20 CPU,used % 20 for % 20g pu % 2d GPU % 20 communication

如何训练自己的张量流模型,并在任何平台上运行它们

原文:https://towardsdatascience.com/how-to-train-your-own-tensorflow-models-and-run-them-on-any-platform-6a1303d4c2d6?source=collection_archive---------20-----------------------

探索全球芯片短缺危机的解决方案。

训练自己的 TensorFlow Lite 模型为您提供了一个创建自己的定制 AI 应用程序的机会。此外,使用像 WasmEdge 这样的运行时,您就有机会在许多不同的平台上运行您的定制 TensorFlow 应用程序。包括共享硬件。稍后将详细介绍共享硬件…

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由杰瑞米·零Unsplash 上拍摄

什么是 WasmEdge?

WasmEdge 是一个轻量级和高性能的 WebAssembly (WASM)虚拟机(VM ),针对边缘计算进行了优化。它广泛用于云无服务器功能(FaaS)、软件即服务(SaaS)、区块链智能合约和物联网以及实时汽车应用等场景。

CNCF 主办,WasmEdge 旨在成为 Wasm 及其 Edge 相关扩展的开源“参考实现”。

本文主要关注 WasmEdge 的 TensorFlow 扩展。可以通过 GitHub 了解更多 WasmEdge 如果您想为 WasmEdge 投稿,请参见该投稿人文档

我们为什么要使用 Wasm?

Wasm 生态系统仍处于早期阶段。然而,Wasm 相对于传统的执行环境有一些非常重要和独特的优势。

除了它的性能…

“在其超前(AOT)编译模式下,WasmEdge 是目前市场上速度最快的 Wasm 虚拟机.”[1]

…一个独特的主张是 Wasm 可执行文件在独立的、基于堆栈的 Wasm 虚拟机中运行。这意味着任何不受信任的 Wasm 程序都可以在共享硬件上与其他 Wasm 程序一起运行;没有副作用。

您为什么想要共享硬件?

就制造业的未来而言,这是一件大事。例如,丰田最近宣布,他们将“因全球芯片短缺而削减 40%的汽车产量”[2]。

所有领域的消费电子产品,不管是什么类型,都有不断满足消费者需求的动力。这些需求包括不同种类的娱乐、信息娱乐、安全、反垃圾邮件、语音识别、物体检测等等。

能够在共享硬件上训练和运行复杂的人工智能应用程序(可以帮助满足这些消费者需求)对生产来说至关重要。以下是全球制造商的一些报价,它们证明了这一点。

大众

“德国大众汽车表示,它可能还需要进一步减产,并预计第三季度的芯片供应将‘非常不稳定和紧张’。”

福特

“福特汽车表示,由于半导体相关零件短缺,将暂时关闭其制造最畅销的 F-150 皮卡的堪萨斯城组装厂”

学习人工智能模型和数据

开始学习如何训练 TensorFlow 的最好方法是查看一些现成的 TensorFlow 训练数据。

我们的第一个例子是专门针对自然语言情感分析的。我们要检查一些训练数据。一旦您理解了这个特定的数据集,您就可以继续创建自己的训练数据,然后为特定的用例(无论是什么)训练和运行自然语言模型。

在我们的第二个例子中,我们也将从查看一些现成的数据开始;深入到关于边界框坐标等等的细节。

一旦我们了解了单发探测器(SSD)边界框的工作原理,我们就可以创建自己的训练数据,然后针对特定用例训练和运行 SSD 模型。

让我们从一些动手演示开始;请继续阅读,即使你不是编码。有许多图表和解释将使这容易理解。

第一个例子—自然语言、情感分析

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

亚历山大·辛恩在 Unsplash 上拍摄的照片

在开始之前,让我们运行几个命令来准备好我们的系统。我们安装了 TensorFlow、TensorFlow 模型制作工具、Numpy 和熊猫。

pip3 install tensorflow
pip3 install tflite-model-maker
pip3 install numpy~=1.19.2
pip3 install pandas

然后我们打开一个python3解释器,运行下面的代码。

import os
import numpy as np
import pandas as pd
import tensorflow as tf
from tflite_model_maker import model_spec
from tflite_model_maker import text_classifier
from tflite_model_maker.config import ExportFormat
from tflite_model_maker.text_classifier import AverageWordVecSpec
from tflite_model_maker.text_classifier import DataLoader
# Get the data
data_dir = tf.keras.utils.get_file(
      fname='SST-2.zip',
      origin='[https://dl.fbaipublicfiles.com/glue/data/SST-2.zip'](https://dl.fbaipublicfiles.com/glue/data/SST-2.zip'),
      extract=True)
data_dir = os.path.join(os.path.dirname(data_dir), 'SST-2')

您可以在这里看到,作为该设置的一部分,我们正在从fbaipublicfiles.com下载一个公共数据集。我们需要去看看那些公共数据,因为它是我们理解如何创建我们自己的数据的关键。

如果我们打印data_dir,我们可以看到数据已经保存到我们的主目录中(在一个隐藏的.keras文件夹中)。

print(data_dir)
/Users/tpmccallum/.keras/datasets/SST-2

如果我们查看这些数据,我们可以看到数据集的格式不适合 TensorFlow Lite …还不适合!

我们可以解决这个问题:)

为了使该数据与 TensorFlow Lite 兼容,我们执行以下任务。

首先,我们将制表符分隔的数据文件dev.tsv转换为逗号分隔的文件,并替换标签(将0转换为单词negative,将1转换为单词positive,如下图所示)。

df = pd.read_csv('/Users/tpmccallum/.keras/datasets/SST-2/dev.tsv', sep='\t')
label_map = {0: 'negative', 1: 'positive'}
df.replace({'label': label_map}, inplace=True)
df.to_csv('/Users/tpmccallum/.keras/datasets/SST-2/dev.csv')
replace_label(os.path.join(os.path.join(data_dir, 'dev.tsv')), 'dev.csv')

我们也对train.tsv文件这样做

df = pd.read_csv('/Users/tpmccallum/.keras/datasets/SST-2/train.tsv', sep='\t')
label_map = {0: 'negative', 1: 'positive'}
df.replace({'label': label_map}, inplace=True)
df.to_csv('/Users/tpmccallum/.keras/datasets/SST-2/train.csv')
replace_label(os.path.join(os.path.join(data_dir, 'train.tsv')), 'train.csv')

最后,我们再次对test.tsv文件执行此操作。

df = pd.read_csv('/Users/tpmccallum/.keras/datasets/SST-2/test.tsv', sep='\t')
label_map = {0: 'negative', 1: 'positive'}
df.replace({'label': label_map}, inplace=True)
df.to_csv('/Users/tpmccallum/.keras/datasets/SST-2/test.csv')
replace_label(os.path.join(os.path.join(data_dir, 'test.tsv')), 'test.csv')

好的,太好了!现在我们有了一些有意义的 TensorFlow Lite 兼容数据,可以使用和复制(使用我们自己的句子和标签)。

3 个电子表格(dev.csvtrain.csvtest.csv)各有两列(句子和标签)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个句子不是肯定的就是否定的。例如,句子“坚定地黯淡和绝望”被正确地标注为否定的。

理解了这个大纲,你就可以开始创建你自己的训练和测试数据。你只需简单地添加句子,然后正确/准确地标记它们(然后存储你的定制文件来代替这些原始文件)。

培养

我们现在可以加载这些csv文件,然后执行训练。

spec = model_spec.get('average_word_vec')
train_data = DataLoader.from_csv(filename='train.csv', text_column='sentence', label_column='label', model_spec=spec, is_training=True)
test_data = DataLoader.from_csv(filename='dev.csv', text_column='sentence', label_column='label', model_spec=spec, is_training=False)
# Train
model = text_classifier.create(train_data, model_spec=spec, epochs=10)

培训过程将生成如下所示的输出。

Epoch 1/101/2104 [..............................]
2104/2104 [==============================] - 3s 1ms/step - loss: 0.6841 - accuracy: 0.5570// snip //Epoch 10/10
2104/2104 [==============================] - 2s 1ms/step - loss: 0.3340 - accuracy: 0.8647

我们现在可以对训练好的模型进行测试

# Test
loss, acc = model.evaluate(test_data)

培训的结果如下

28/28 [==============================] - 0s 1ms/step - loss: 0.5160 - accuracy: 0.8303

如果我们对这些结果满意,那么我们可以将训练好的模型导出为一个.tflite文件;然后我们可以在我们的应用程序中使用它(稍后将详细介绍如何创建应用程序)。

model.export(export_dir='average_word_vec')

如果我们在 netron app 中打开新创建的 TensorFlow Lite 兼容文件(model.tflite,可以看到输入输出规范。这些规范将帮助我们编写应用程序。

模型设定

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如我们所见,输入称为input_1,输出称为Identity

输入(称为 input_1)

模型属性中的描述描述了输入的数据格式。具体来说…

嵌入表示要分类的输入文本的向量。输入需要从原始文本转换为嵌入向量使用附加的字典文件。

本质上,这个输入希望文本(用户提供的)被转换成一个单独的 i32 整数数组,即[5043, 201023, ... , 29361, 3499]。因此,我们需要了解模型的创建者希望我们如何将单词映射到数字。

通过调查数据,我们了解到该模型的创建者使用了一个字典文件,该文件将单词/短语映射到数字。字典文件每行有一个唯一的整数(对应于文本)。

例如,在第 85,155 行,我们有单词“awesome”和整数 29361(如下所示)。

awesome|29361

因此,在我们的应用程序中,如果用户键入单词“awesome ”,我们需要将整数29361发送给模型(作为模型期望的i32数组中的许多元素之一)。

这取决于您是在客户端还是在服务器端这样做。编程语言是你自己的个人喜好;我在下面创建了一些 Rust 代码,展示了如何从本地文件系统中读取字典,然后从数据中创建一个 HashMap。然而,我们也可以通过网络阅读这个文件,而不是;请允许我在下一节解释。

从本地磁盘读取并解析字典文件

 // Create HashMap which stores String and Integer pairs
    let mut map_name: HashMap<String, i32> = HashMap::new();
    // Read the dictionary file 
    let filename = "src/dictionary.txt";
    let file = File::open(filename).unwrap();
    let reader = BufReader::new(file);
    // Process each line
    for (index, line) in reader.lines().enumerate() {
        let line = line.unwrap();
        // Create vector to store each line as split data
        let v: Vec<&str> = line.split(|c| c == '|').collect();
        // Place the split data into the HashMap
        map_name.insert(v[0].to_string(), v[1].parse::<i32>().unwrap());
    }
    // Create another vector to hold the input data
    let size = 256;
    let mut vecForModel: Vec<i32> = Vec::with_capacity(size);
    // Split this functions input by space
    let vInputString: Vec<&str> = input_string.split(|c| c == ' ').collect();
    // See if any words are in the HashMap
    for word in vInputString {
        if map_name.contains_key(word){
            // If so, add the appropriate integer
            vecForModel.push(*map_name.get(word).unwrap());
        }

通过网络读取和解析字典文件

为了向您展示如何为 web 创建 AI 应用**,让我们远程解析这个字典文件。**

WasmEdge 的 RESTful API 其实可以远程为我们取这个字典文件;类似于使用内容交付网络(CDN ),而不是在本地存储文件。这有几个好处。

首先,应用程序开发人员可以更新字典文件(在其远程位置),而用户无需做任何事情。

其次,文件的获取和读取现在 100%在服务器端完成(客户机不需要做任何这种高带宽的工作)。我们的 AI 应用程序的用户(在客户端)只上传他们的句子和指向字典文件的 URL 指针。我们必须记住,这个字典文件超过 20 万行(239,232),并且可能随着新单词/语言的添加而增长。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

上面屏幕截图显示这只是一个文本文件。

远程获取这种大型文本文件要快得多,繁重的工作更适合服务器端。下图说明了远程获取是如何工作的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Web 表单

让这个 AI 应用程序可用的最好方法是使用表单数据(即 web 表单)。让我们看看 web 表单会是什么样子。

除了几个输入框(在 HTML 中),我们将有一个 Javascript 函数,它接受输入,然后调用 WasmEdge 的 RESTful API。

这是 Javascript。本质上只是一个 AJAX 请求。

function callService() {
          setTimeout(function() {
            $('#process').prop('disabled', true);
          }, 0); var formData = new FormData();
          formData.append('input_1', $('#input_1').val());
          formData.append('fetch_input_2', $('#input_2').val());
          console.log("Running ...");
          $.ajax({
            url: "[https://rpc.ssvm.secondstate.io:8081/api/multipart/run/392/classify](https://rpc.ssvm.secondstate.io:8081/api/multipart/run/392/classify)",
            type: "post",
            cache: false,
            data: formData,
            contentType: false,
            processData: false,
            xhrFields: {
              responseType: "" // defaults to text
            },
            success: function(r_data) {
              console.log("Successfully ran the ajax");
              document.getElementById("result_box").innerHTML = r_data;
              $('#process').prop('disabled', false);
            },
            error: function(r_error) {
              console.log("Error running the ajax: " + r_error);
              alert("Rate limit exceeded");
              $('#process').prop('disabled', false);
            }
          });
          console.log("END");
          return false;
        }

只是提醒一下,WasmEdge 几乎可以在任何设备上运行。为了这篇文章,我们将使用网络,以便您可以看到它的行动。

从上面的 Javascript 代码可以看出,WasmEdge 有一个 API 端点,任何能够发出安全 HTTP 请求的设备都可以调用它。显然,对于汽车应用来说,这些程序将在本地硬件上运行,而不是通过网络。

然而,仅仅为了演示 WasmEdge 的多功能性,让我们仔细看看 WasmEdge 的 API 端点结构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

您会注意到这个 URL 以一个函数名结尾,在本例中是classify。这实际上是执行所有逻辑(执行张量流模型)的 Rust 函数的名称。出于演示的目的,Rust 函数已经被编写、编译成 Wasm 并部署在 wasm_id 392(如上面的 URL 所示)。不要担心,我们很快就会深入研究 Rust/Wasm。现在,让我们只关注应用程序的前端(客户端)。

以下简单的 curl 命令可用于执行我们预先编写的 Wasm 二进制文件。注意我们如何添加两个--form参数(让 curl 模拟一个填充的表单)。注意,第二个输入实际上是我们前面提到的大字典文件的远程获取。

提示:执行远程获取时,使用不经过重定向的 URL,即如果在 GitHub 中存储数据,则使用如下所示的raw.githubusercontent风格的 URL。

curl --location --request POST 'https://rpc.ssvm.secondstate.io:8081/api/multipart/run/392/classify' --form 'input_1="Awesome movie"' --form 'fetch_input_2="[https://**raw.githubusercontent**.com/tpmccallum/Tim2/main/dictionary_testing.txt](https://raw.githubusercontent.com/tpmccallum/Tim2/main/dictionary_testing.txt)"'

一旦 curl 工作了,我们就可以为我们的应用程序创建一个 HTML 表单了。我们之前准备的那个看起来像下图,你可以在这里访问 HTML 源代码

同样的页面也可以通过 GitHub pages 进行现场演示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们已经介绍了 HTML 和 Javascript,让我们看看我们实际上通过 WasmEdge API 调用的可执行代码。

这整个应用程序是由 Rust 函数驱动的,这里是我们之前准备的 Rust 源代码的链接。注意,这个函数叫做classify,它与上面的 API URL 相匹配。

我们使用一个命令将 Rust 源代码编译成 WebAssembly (Wasm)。

rustwasmc build

如上所述,WasmEdge 能够在多种模式下运行,即通过 NodeJS、在嵌入式设备上等等。然而,我们将继续使用 WasmEdge 的 API 进行演示,以便您可以试用。

让我们看看如何解释输出。

输出——“身份”

正如我们在模型的属性中看到的,输出被称为“身份”。Identity 是一个包含两个元素的数组(数据类型都是 float 32)。第一个是与负面情绪相关的指数0-1。例如,0.25 意味着它有 1/4 的负面含义,1 意味着它是一个完全负面的评论。

第二个因素代表积极的情绪。

数组中的 2 个元素的总和总是 1。例如,中性将是 0.5 负和 0.5 正。

让我们尝试一些句子,看看我们得到了什么。

…的句子

“绝顶的平淡,痛苦的缓慢。”

导致了:

  • 高负指数1
  • 0的低正指数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

相比之下……的句子

这部电影棒极了。伟大的演员,好的情节和娱乐性。

导致了:

  • 0.09839419的低负指数
  • 0.9016058的积极指数较高

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了更深入一点,在我们结束自然语言示例之前,我冒昧地粘贴了 WasmEdge 服务器端日志的输出。下面的输出显示了 Rust 源代码中所有的println!语句;本质上展示了我们如何远程获取字典,获取用户的输入,然后为模型创建一个 256 元素的数组,该数组包含任何单词/整数匹配的数字表示(在输入与字典文件的交叉引用期间)。

Input string: "This film was excellent. Great actors, good plot and entertaining"Processing word: "this"Processing word: "film"Processing word: "was"Processing word: "excellent."Processing word: "great"Processing word: "actors,"Processing word: "good"Processing word: "plot"Processing word: "and"Processing word: "entertaining"Processing loading the modelFinal Vec For Model: [2838, 976, 3070, 6874, 1092, 9754, 408, 6224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]Adding outputRunning sessionThe words you provided have a negative connotation index of 0.09839419, and a positive connotation index of 0.9016058.

第一个例子到此结束,现在我们来看另一个例子。物体检测。你可能在无人驾驶汽车演示中见过这种人工智能。物体检测有着广泛的用途,尤其是在工程和制造业。

目标检测

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

科学高清照片Unsplash

单发探测器(SSD)示例

和上面的自然语言例子一样,我们将首先安装一些依赖项

pip3 install testresources
pip3 install pycocotools
pip install grpcio==1.32
pip3 install tflite-model-maker

然后输入python3进入 Python 解释器。

import numpy as np
import os

from tflite_model_maker.config import ExportFormat
from tflite_model_maker import model_spec
from tflite_model_maker import object_detector

import tensorflow as tf
assert tf.__version__.startswith('2')

tf.get_logger().setLevel('ERROR')
from absl import logging
logging.set_verbosity(logging.ERROR)

对于这个特定的对象检测,我们将使用 GS://cloud-ml-data/img/open image/CSV/Salads _ ml _ use . CSV 中的沙拉数据集

前述的salads_ml_use.csv遵循特定的约定。以下是为培训目的创建自己的csv文件的条件。

目标是理解这个模型,这样你就可以在你喜欢的任何图像/物体上训练它;不仅仅是沙拉😊

数据格式

csv文件:

  • 必须是 UTF 8 编码的
  • 必须以.csv扩展名结尾
  • 集合中的每个边界框都有一行
  • 每行包含一幅图像**;具有多个边界框的图像将在与边界框一样多的行上重复**

标签

每个标签必须以字母开头,并且只能包含字母、数字和下划线。

边界框

图像中特定对象的每个边界框(在csv文件的那一行)可以用两种方式之一来表示。

  1. 只有两个顶点(由一组 x,y 坐标组成),如果它们是矩形的对角点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

例如:

(x_relative_min,
    y_relative_min,
    ,
    ,
    x_relative_max,
    y_relative_max,
    ,
)

2.所有 4 个顶点

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

例如

(x_relative_min,
    y_relative_min,
    x_relative_max,
    y_relative_min,
    x_relative_max,
    y_relative_max,
    x_relative_min,
y_relative_max)

从示例中可以看出,这些坐标必须是 0 到 1 范围内的浮点数,其中 0 表示最小的 x 或 y 值,1 表示最大的 x 或 y 值。

正如我们在本文开头提到的,理解数据非常重要,这样我们才能创建自己的训练数据。这些坐标可能会有点混乱,所以让我们来看一张图,这将使这一点更清楚。首先,正如你所看到的,最小值和最大值是从左上到右下排序的。因此,不要感到困惑,或者尝试将这与传统的数据绘图练习联系起来(这是不同的)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下图增加了一些细节;演示边界框的坐标位置。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

例如,x_min = 0,x_max = 1,y_min = 0,y_max = 1

创建您自己的数据集

我们马上就要使用一个现成的数据集,但是现在我们已经了解了这个数据是如何工作的,让我们来看看如何从头开始创建我们自己的数据集。

有许多应用程序允许你在自己的图像上手动创建带标签的边界框。其中一个应用叫做 labelImg

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们在本文中使用的另一个应用程序叫做 MakeML

下图显示了我们如何拍摄桌子的照片,然后识别笔记本电脑(通过绘制黄色边框并创建名为“laptop”的标签)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后我们识别笔记本电脑的键盘(通过画一个紫色的方框并创建一个名为“keyboard”的标签)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在每张图片上画出一个边界框(越多越好),然后点击左下角的“导出数据集”链接。

有几种不同的数据格式可供选择。我们来对比一下。

Turicreate

Turicreate 兼容数据如下。

[{'label':'keyboard','type':'rectangle','coordinates':{'x':298,'y':301,'width':397,'height':69}},{'label':'laptop','type':'rectangle','coordinates':{'x':294,'y':225,'width':508,'height':407}}]

椰子树

这个通用对象上下文(COCO)兼容数据集是一个 JSON 文件(如下所示)。

{
  "categories" : [
    {
      "id" : 1629415338,
      "name" : "laptop"
    },
    {
      "name" : "keyboard",
      "id" : 1629415413
    }
  ],
  "images" : [
    {
      "file_name" : "ssd10.png",
      "height" : 450,
      "id" : 0,
      "width" : 600
    }
  ],
  "annotations" : [
    {
      "id" : 0,
      "category_id" : 1629415413,
      "iscrowd" : 0,
      "bbox" : [
        101,
        268,
        498,
        114
      ],
      "segmentation" : [],
      "image_id" : 0,
      "area" : 27456
    },
    {
      "iscrowd" : 0,
      "id" : 1,
      "bbox" : [
        40,
        22,
        549,
        21
      ],
      "segmentation" : [],
      "area" : 207401,
      "image_id" : 0,
      "category_id" : 1629415338
    }
  ]
}

帕斯卡 VOC

Pascal VOC 数据集格式是一个 XML 文件(如下所示)

<annotation>
    <folder>images</folder>
    <filename>ssd10.png</filename>
    <size>
        <width>600</width>
        <height>450</height>
        <depth>3</depth>
    </size>
    <segmented>0</segmented>
    <object>
        <name>keyboard</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <occluded>0</occluded>
        <difficult>0</difficult>
        <bndbox>
            <xmin>101</xmin>
            <ymin>268</ymin>
            <xmax>498</xmax>
            <ymax>337</ymax>
        </bndbox>
    </object>
    <object>
        <name>laptop</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <occluded>0</occluded>
        <difficult>0</difficult>
        <bndbox>
            <xmin>40</xmin>
            <ymin>22</ymin>
            <xmax>549</xmax>
            <ymax>430</ymax>
        </bndbox>
    </object>
</annotation>

您可能还记得上面的内容,我们需要以特定的方式格式化数据,即电子表格的每一行都需要如下所示:

链接到图像、标签、边界框坐标,即

gs://folder/ssd10.png,笔记本电脑,x_min,y_min,x_max,y_min,x_max,y_max,x_min,y_max

gs://folder/ssd10.png,键盘,x_min,y_min,x_max,y_min,x_max,y_max,x_min,y_max

为了符合上面讨论的格式,我们需要将图像形状和框坐标转换为 0–1 值(作为 600 px x450 px 格式中的并列像素坐标)。

如果宽度(x 轴)是 600 像素,高度(y 轴)是 450 像素,那么我们将对笔记本电脑的边界框坐标执行以下转换。

40px(最小)/ 600px(宽度)= 0.06

549 像素(最大值)/600 像素(宽度)= 0.91

22px(最小)/ 450px(高度)= 0.04

430(最大)/450 像素(高度)= 0.95

因此,膝上型电脑边界框的单行条目如下

gs://folder/ssd10.png,笔记本电脑,0.06,0.04,0.91,0.04,0.91,0.95,0.06,0.95

用数据训练

准备好电子表格行和图像后,您可以继续运行以下命令。

spec = model_spec.get('efficientdet_lite0')train_data, validation_data, test_data = object_detector.DataLoader.from_csv('gs://cloud-ml-data/img/openimage/csv/salads_ml_use.csv')model = object_detector.create(train_data, model_spec=spec, batch_size=8, train_whole_model=**True**, validation_data=validation_data)model.evaluate(test_data)model.export(export_dir='.')

编写应用程序来执行对象检测

使用经过训练的模型来执行对象检测的应用程序需要提供正确的输入(数据类型),并且还知道如何解释模型的输出。

如果我们检查model.tflite文件(使用 netron 这样的应用程序。app),我们看到以下内容

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

投入

这个模型很好地描述了输入和输出(我们可以看到输入在 RGB 中是 320 x 320 像素)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们确保 Rust 源代码以 320x320 数组格式提供图像;平面阵列。

let mut resized = image::imageops::thumbnail(&img, 320, 320);
let mut flat_img: Vec<u8> = Vec::new();
for rgb in resized.pixels() {
    flat_img.push(rgb[0]);
    flat_img.push(rgb[1]);
    flat_img.push(rgb[2]);
}

输出

输出在模型规格中有详细说明,如下图所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们看一个使用前面提到的沙拉数据集的例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

弗兰霍根,CC BY-SA 4.0<https://creativecommons.org/licenses/by-sa/4.0>,通过维基共享

该模型本质上是采用它以前从未见过的新图像,然后以与我们在生成训练数据时手动创建边界框坐标几乎相同的方式返回边界框坐标。

有趣的是,这个模型以相同的0–1格式返回给我们边界框,并且与缩小的 320x320 图像尺寸相关。

当我们将原始图像返回给用户时,我们需要确保根据原始图像的大小来转换对象边界框。

这里有一个包围盒坐标的例子,我们称这个数据为res0

[0.8125, 0.72265625, 0.5859375, 0.45703125, 
...
0.4296875, 0.36328125, 0.36328125, 0.3203125]

处理盒子的逻辑如下(基于我们在每个盒子 4 个坐标的集合中工作的事实)

let mut iter = 0;
while (iter * 4) < res0.len() {
    // bounding box logic
    iter += 1;
}

边界框逻辑的具体实现(假定原始图像是 512 像素乘 512 像素)如下。

let image_height: f32 = img.height() as f32; //512
let image_width: f32 = img.width() as f32; //512
let x1 = res0[4 * iter + 1] * image_width;
let y1 = res0[4 * iter] * image_height;
let x2 = res0[4 * iter + 3] * image_width;
let y2 = res0[4 * iter + 2]  * image_height;

为训练和测试创建自己的数据集

我想用一个额外的工具来结束这篇文章,它可能有助于使这个数据训练过程更快和更健壮。

我们在上面提到了标签图像标签应用程序。这是一个开源产品,以 PASCAL VOC 格式的 XML 文件构建训练集。这是 ImageNet 使用的格式。

ImageNet 是一项正在进行的研究工作,旨在为世界各地的研究人员提供用于训练大规模对象识别模型的图像数据。

令人欣慰的是,labelImg 似乎有一个免费的转换工具,可以在GitHub 仓库获得,它可以将你的 XML 文件从 PASCAL VOC 格式转换成 TensorFlow 兼容格式,我们在本文中已经解包了这种格式;正式描述在谷歌的官方文档中。labelImg 还支持 YOLO 和 CreateML 格式。

使用 labelImg 将允许您创建自己的自定义图像和自定义标签。额外的转换工具将使您不必编写自己的转换工具。

一旦你的数据集被训练并导出为tflite文件,你就可以使用 WasmEdge 创建你自己的 AI 应用程序。

你会创造什么?

如果你有任何问题,请在下面留下评论。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此外,如果您想为 WasmEdge 做贡献,请访问官方 WasmEdge GitHub 页面。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://www.secondstate.io/

SecondState 团队是 WasmEdge 的最初创建者和当前维护者,所以请随时查看 SecondState 的网站、博客GitHub 库。

感谢阅读!

参考

[1]https://github.com/WasmEdge/WasmEdge#introduction

[2]https://www . ABC . net . au/news/2021-08-20/Toyota-slash-car-production-over-chip-short/100392630

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值