https://www.leiphone.com/news/202002/xkY9d1hhWJH1MoJs.htmlhtml
本文做者是 Omry Yadan,他是 Facebook 人工智能软件工程师,建立了 Hydra。git
Hydra 是最近发布的一个开源 Python 框架,由 Facebook AI 开发,可以简化科研和其余复杂应用程序的开发。这个新框架功能强大,能够从命令行和配置文件中组合和重写配置。做为 PyTorch 生态系统的一部分,Hydra 帮助 PyTorch 的研究人员和开发人员更容易地管理复杂的机器学习项目。Hydra 是通用的,能够应用于机器学习之外的领域。github
这篇文章分为两部分,第一部分描述开发机器学习软件时出现的常见问题,第二部分主要是 Hydra 如何解决这些问题。app
part1.你的代码比你想象的更加复杂框架
命令行是每一个软件开发人员最早了解的知识之一。命令行的核心是一个字符串列表,这些字符串一般被分解为标志(例如,-verbose)和参数(例如,-port=80)。这对于许多简单的应用程序来讲已经足够了,你可能只须要在命令行界面(CLI)解析库中定义 2 到 3 个命令行参数就足够了。iphone
当人们开始使用你的应用程序时,他们将不可避免地发现缺乏的功能。很快,你将添加更多功能,致使更多的命令行标志。这在机器学习中尤为常见。机器学习
上面的图片来自 PyTorch ImageNet 训练示例。尽管是一个很小的例子,可是命令行标志的数量已经很高了。其中一些标志在逻辑上描述了相同的组件,它们在理想状况下应该被分红一组(例如,与分布式训练相关的标志),可是没有一种简单的方法能够将这些标志分组并使用。分布式
在此示例的基础上,你可能但愿添加新功能,支持须要附加命令行标志的新模型、数据集或优化器。你能够想象在这个例子,随着你的扩展支持新的想法是如何作到的。函数
这种样式的另外一个微妙问题是,全部东西都须要解析的 args 对象。这会鼓励耦合,并使单个组件更难在不一样的项目中重用。学习
配置文件
一个常见的解决方案是切换到配置文件。配置文件能够是分层的,而且能够帮助减小定义命令行参数的代码的复杂性。不幸的是,配置文件中也会面临挑战,你将在下一节中看到。
配置文件很难更改
在尝试时,你须要使用不一样的配置选项运行应用程序。起初,你可能只是在每次运行以前更改配置文件,但你很快就会意识到跟踪与每次运行相关联的更改是很是困难的。
试图解决该问题的方法多是复制配置文件,在实验后命名,并对新文件进行更改。这种方法也不是很完美,由于它建立了一个很长的配置文件进行跟踪,这个文件将很快就不能与代码同步,变得毫无用处。此外,经过查看实验配置文件很难判断你要作什么,由于它与其余配置文件 99% 相同。
最后,对于常常更改的内容,你可能会返回到命令行标志,以容许从命令行更改它们。这是乏味的,而且会让命令行代码再次变得复杂。理想状况下,你能够从命令行重写配置中的全部内容,而没必要为每种状况单独编写代码。
配置文件变得单一
当开发人员编写代码时,他们喜欢将事情分解成很小的部分(模块、函数)。这能够帮助他们保存代码模型,并使代码更易于维护。它还支持函数重用——调用一个函数比复制它容易。
配置文件不提供相似的功能。若是但愿应用程序使用不一样的配置选项,例如一个用于 ImageNet 数据集,一个用于 CIFAR-10 数据集,则有两个选择:
维护两个配置文件
将这两个选项放在一个配置文件中,并在运行时以某种方式使用所需的内容
第一种方法彷佛很好,但后面你会意识到,随着你增长更多的选项,事情很快就会崩溃。例如,除了两个数据集选择以外,你可能还想尝试三种不一样的模型体系结构(AlexNet、ResNet50 和一些新的、使人兴奋的、你称之为 BestNet 的东西)。你还能够在两个损失函数之间进行选择。这使组合总数达到 12 个!你确实但愿避免维护 12 个相似的配置文件。
第二种方法最初的效果更好。你只需获得一个大的配置文件,该文件知道所选的两个数据集、三个体系结构和两个损失函数。可是,等等,当你在 AlexNet 和 ResNet50 上进行训练时,你的学习速率须要有所不一样,并且你须要在单个配置文件中表达出来。
这种复杂性也会泄漏到代码中,如今须要找出在运行时使用的学习速率!在设计、运行和调试实验时,大部分未使用的大型配置会产生显著的认知负载。因为 90% 的配置未使用,很难判断每次运行最重要 10% 在哪里。
经过添加从命令行重写配置中全部内容的功能来组合配置,能够为这些问题提供一个强大的解决方案。因为这个缘由,许多日益复杂的项目最终到达了开发 Hydra 所提供的功能子集的必要位置。这种功能每每与单个项目的需求紧密结合,所以很难重用,迫使开发人员不断地在每一个新项目中从新发明轮子。
不幸的是,在许多开发人员意识到这一点的时候,他们已经有了一个复杂且不灵活的代码库,具备高耦合、硬编码的配置。理想状况下,你但愿像编写代码同样编写配置。这使你能够扩大项目的复杂性。
part2.像使用 Hydra 编写代码同样编写配置
若是你走到了这一步,你必定会想,对于我在第 1 部分中描述的那些软件工程的问题,有什么神奇的解决方案?你可能会猜到它就是 Hydra。
Hydra 是 Facebook AI Research 开发的一个开源 Python 框架,它经过容许你组合传递给应用程序的配置来解决不少问题,包括第 1 部分中概述的问题。合成能够经过配置文件或命令行进行,合成配置中的全部内容也能够经过命令行重写。
基本示例
下面示例的源代码在这里能够找到:https://github.com/omry/hydra-article-code。
假设你的数据集的配置以下:
config.yaml
如下是加载此配置的简单 Hydra 应用程序:
my_app.py
这里最有趣的一行是 @hydra.main()修饰器。它采用一个 config_ 路径,提到了上面的 config.yaml 文件。
程序很好地打印了它获得的配置对象。毫无疑问,config 对象包含 ImageNet 数据集配置:
my_app 的常规输出
咱们如今能够从命令行重写此配置文件中的任何内容:
重写 dataset.path 时的输出
构成示例
有时,你可能但愿在两个不一样的数据集之间进行替换,每一个数据集都有本身的配置。要支持此功能,请为数据集引入一个配置组,并在其中放置单个配置文件,每一个选项一个:
你还能够在 config.yaml 中添加「defaults」部分,告诉 Hydra 如何编写配置。在这种状况下,咱们只想默认加载 cifar10 的配置,由于在它上面训练更快:
config.yaml
这个应用看起来几乎相同,惟一的区别是配置路径如今指向 conf/config.yaml。运行应用程序时,会加载预期的 cifar10 配置:
但咱们也能够很容易地选择使用 imagenet:
你能够拥有多个配置组,让咱们在优化器中添加一个:
默认状况下,还能够更新 config.yaml 以加载 adam:
config.yaml
运行应用程序时,咱们会获得一个包含 cifar10 和 adam 的联合配置:
这里还有不少能够谈的,但如今,让咱们转到下一个激动人心的特性。
Multirun
Multirun 是 Hydra 的一种功能,它能够屡次运行你的函数,每次都组成一个不一样的配置对象。这是一个天然的扩展,能够轻松地组合复杂的配置,而且很是方便地进行参数扫描,而无需编写冗长的脚本。
例如,咱们能够扫描全部 4 个组合(2 个数据集 X 2 个优化器):
基本的内置启动程序是串行运行,可是其余启动程序插件能够并行运行代码,甚至远程运行代码。这些插件尚未公开,但在社区的帮助下,我但愿很快能看到它们。
自动工做目录
若是仔细观察上面的输出,你会注意到 sweep 输出目录是根据我运行命令的时间生成的。人们在作研究时常常遇到的一个问题是如何保存输出。典型的解决方案是传入一个指定输出目录的命令行标志,但这很快会变得乏味。当你但愿同时运行多项任务,而且必须为每一个任务传递不一样的输出目录时,这尤为使人恼火。
Hydra 经过为每次运行生成输出目录并在运行代码以前更改当前工做目录来解决此问题。使用 --multirun 执行扫描时,会为每一个任务生成一个附加子目录。
这样能够很好地未来自同一 sweep 的任务分组在一块儿,同时保持每一个任务与其余任务的输出分离。
你仍然能够经过 Hydra 中的 API 访问原始工做目录。
original_cwd
从 /home/omry/dev/hydra 运行时的输出:
生成的工做目录能够彻底自定义,这包括让它做为路径的一部分,包含命令行参数或配置中的任何其余内容。
写在最后
本文中包含的只是 Hydra 提供的特性之一。其余功能包括动态选项卡完成、Python 日志记录子系统的自动配置、库和应用程序打包配置支持等等。
在 Facebook AI 中,咱们使用 Hydra 从命令行直接向内部集群发送代码。在社区的帮助下,我但愿 Hydra 可以成长为支持 AWS 和 GCP,并为 Facebook AI 以外的研究人员提供相似的功能。另外一个感兴趣的领域是命令行驱动的超参数优化。第一个这样的插件,Ax 正在开发中。
Hydra 是新的,咱们刚刚开始了解它是如何改变事物的。
我期待着看到社区在将来几年如何使用 Hydra。
要了解有关 Hydra 的更多信息,请参阅 Hydra 网站上的教程和文档:https://hydra.cc/ 。
雷锋网(公众号:雷锋网)雷锋网雷锋网
雷锋网版权文章,未经受权禁止转载。详情见转载须知。