CHANfiG¶
介绍¶
CHANfiG 希望能让你的配置更加简单。
训练一个机器学习模型有无数个可调节的参数。
为了调节所有参数,研究员们常常需要撰写巨大的配置文件,有时甚至长达数千行。
大多数参数只是方法默认参数的简单重复,这导致了很多不必要的声明。
此外,调节这些参数同样很繁琐,需要定位并打开配置文件,作出修改,然后保存关闭。
这个过程浪费了无数的宝贵时间 这无疑是一种犯罪 。
使用argparse
可以在一定程度上缓解调参的不变,但是,要让他和配置文件适配依然需要很多工作,并且缺乏嵌套也限制了他的潜力。
CHANfiG 旨在带来改变。
你只需要在命令行中输入你的修改,然后把剩下的交给 CHANfiG。
CHANfiG 很大程度上启发自YACS。
不同于 YACS 的范式(代码 + 实验E的YACS配置文件 (+ 外部依赖 + 硬件 + 其他令人讨厌的术语 ...) = 可重复的实验E
),
CHANfiG 的范式是:
代码 + 命令行参数 (+ 可选的CHANfiG配置文件 + 外部依赖 + 硬件 + 其他令人讨厌的术语 ...) = 可重复的实验E (+ 可选的CHANfiG配置文件)
组件¶
一个配置文件可以被看作一个嵌套的字典结构。
但是,默认的 Python 字典十分难以操作。
访问字典成员的唯一方式是dict['name']
,这无疑是极其繁琐的。
更糟糕的,如果这个字典和配置一样是一个嵌套结构,访问成员将会变成类似于dict['parent']['children']['name']
的样子。
够了就是够了,是时候做出改变了。
我们需要属性方式的访问,并且我们现在就需要。
dict.name
和dict.parent.children.name
是所有你需要的。
尽管此前已经有工作来实现类似的对字典成员的属性方式访问。但是他们的 Config 对象要么使用一个独立的字典来存储属性方式访问的信息(EasyDict),而这可能导致属性方式访问和字典方式访问的不一致;要么重新使用既有的__dict__
然后对字典方式访问进行重定向(ml_collections),而这可能导致属性和字典成员存在冲突。
为了解决上述限制,我们继承了 Python 内置的dict
来创建FlatDict
、DefaultDict
、NestedDict
、Config
和Registry
。
我们同时介绍了Variable
来在多个位置共享值,和ConfigParser
来解析命令行参数。
FlatDict¶
FlatDict
在三个方面对默认的dict
做出改进。
字典操作¶
FlatDict
支持变量插值。
将一个成员的值设置为${}
包裹的另一个成员名,然后调用interpolate
方法。
这个成员的值将会自动替换为另一个成员的值。
Python 的dict
自 Python 3.7 之后就是有序的,但是并没有一个内置的方法来帮助你对一个dict
进行排序。FlatDict
支持sort
来帮助你管理你的字典。
FlatDict
包括了一个merge
方法,他使你能将一个Mapping
、Iterable
或者一个路径合并进入一个FlatDict
。
与update
方法不同,merge
方法是赋值而不是替换,这使得他能更好的与DefaultDict
配合使用。
此外,FlatDict
引入了difference
和intersect
,这些使其可以非常简单的将FlatDict
和其他Mapping
、Iterable
或者一个路径进行对比。
机器学习操作¶
FlatDict
支持与 Pytorch Tensor 类似的to
方法。
你可以很简单的通过相同的方式将所有FlatDict
的成员值转换为某种类型或者转移到某个设备上。
FlatDict
同时集成了cpu
、gpu
(cuda
)、tpu
(xla
)方法来提供更便捷的访问。
IO 操作¶
FlatDict
支持json
、jsons
、yaml
和yamls
方法来将FlatDict
存储到文件或者转换成字符串。
它还提供了from_json
、from_jsons
、from_yaml
和from_yamls
来从一个字符串或者文件中构建FlatDict
。
FlatDict
也包括了dump
和load
方法,他们可以从文件扩展名中自动推断类型然后将FlatDict
存储到文件中/从文件中加载FlatDict
。
DefaultDict¶
为了满足默认值的需要,我们包括了一个DefaultDict
,他接受default_factory
参数,并和collections.defaultdict
一样工作。
NestedDict¶
由于大多数配置都是一个嵌套的结构,我们进一步提出了NestedDict
。
基于DefaultDict
,NestedDict
提供了all_keys
、all_values
、all_items
方法来允许一次性遍历整个嵌套结构。
NestedDict
同时提供了apply
和apply_
方法,它可以使操纵嵌套结构更加容易。
Config¶
Config
通过两个方面来进一步提升功能性:
支持freeze
来冻结和defrost
解冻字典和
加入内置的ConfigParser
来解析命令行语句。
注意Config
默认设置default_factory=Config()
来提供便利。
Registry¶
Registry
继承自NestedDict
,并且提供register
、lookup
和build
来帮助你注册构造函数并从Config
来创建对象。
Variable¶
有一个值在多个地方以多个名字出现?我们给你提供掩护。
只要将值以Variable
包装,然后每处更改都会在处处体现。
Variable
同时支持type
、choices
、validator
、required
来确保值的正确性。
为了更加简单,Variable
还支持help
来在使用ConfigParser
时提供描述。
ConfigParser¶
ConfigParser
在ArgumentParser
的基础之上,提供了parse
和parse_config
来解析命令行参数并创建/更新Config
。
使用¶
CHANfiG 有着强大的前向兼容能力,能够良好的兼容以往基于 yaml 和 json 的配置文件。
如果你此前使用 yacs,只需简单将CfgNode
替换为Config
便可以享受所有 CHANfiG 所提供的便利。
更进一步的,如果你发现Config
中的名字对于命令行来说过长,你可以简单的调用self.add_argument
并设置恰当的dest
来在命令行中使用更短的名字,正如argparse
所做的那样。
所有你需要做的仅仅是运行一行:
Bash | |
---|---|
当然,你也可以读取一个默认配置文件然后在他基础上修改:
注意,你必须指定config.parse(default_config='config')
来正确读取默认配置文件。
Bash | |
---|---|
如果你保存了配置文件,那他应该看起来像这样:
YAML | |
---|---|
JSON | |
---|---|
在方法中定义默认参数,在命令行中修改,然后将剩下的交给 CHANfiG。
安装¶
安装 pypi 上最近的稳定版本:
Bash | |
---|---|
从源码安装最新的版本:
Bash | |
---|---|
他本该如此工作。
授权¶
CHANfiG 依据下列许可证进行多重授权:
- The Unlicense
- GNU Affero General Public License v3.0 or later
- GNU General Public License v2.0 or later
- BSD 4-Clause “Original” or “Old” License
- MIT License
- Apache License 2.0
如果你使用本工作,你可以从中任选(一个或者多个)许可证。
SPDX-License-Identifier: Unlicense OR AGPL-3.0-or-later OR GPL-2.0-or-later OR BSD-4-Clause OR MIT OR Apache-2.0