具有argparse集成的全局作用域配置
项目描述
Effortless Config
具有argparse集成的全局作用域配置。
安装
pip install effortless-config
理由
- 在构建机器学习模型时,我经常遇到一个名为
config.py
的文件,其中包含许多我在整个代码库中引用的全局变量。 - 随着工作的进展,我最终会有 组 的特定配置设置,这些设置与特定的实验相对应。
- 我想在启动实验时能够在命令行中选取配置组。
- 并且我想能够在命令行中覆盖实验中的某些设置。
基本用法
首先,定义一个扩展 effortless_config.Config
的类,并在其中指定默认配置值
from effortless_config import Config
class config(Config): # lowercase "c" optional
SOME_INTEGER_SETTING = 10
FLOAT_SETTING = 0.5
A_BOOLEAN = False
MY_STRING_SETTING = 'foo'
然后您可以在代码库的任何地方引用这些设置
def main():
print(f'SOME_INTEGER_SETTING is {config.SOME_INTEGER_SETTING}')
print(f'FLOAT_SETTING is {config.FLOAT_SETTING}')
print(f'A_BOOLEAN is {config.A_BOOLEAN}')
print(f'MY_STRING_SETTING is {config.MY_STRING_SETTING}')
函数 config.parse_args()
从您的配置创建了一个 argparse 解析器。如果我们把前面的两个代码片段放入一个名为 basic_example.py
的文件中,并完成它,那么
if __name__ == '__main__':
config.parse_args()
main()
...我们可以使用 -h/--help
查看可用的设置
$ python basic_example.py --help
usage: basic_example.py [-h] [--some-integer-setting SOME_INTEGER_SETTING]
[--float-setting FLOAT_SETTING] [--a-boolean {true,false}]
[--my-string-setting MY_STRING_SETTING]
optional arguments:
-h, --help show this help message and exit
--some-integer-setting SOME_INTEGER_SETTING
--float-setting FLOAT_SETTING
--a-boolean {true,false}
--my-string-setting MY_STRING_SETTING
然后我们可以从命令行覆盖配置设置
$ python basic_example.py
SOME_INTEGER_SETTING is 10
FLOAT_SETTING is 0.5
A_BOOLEAN is False
MY_STRING_SETTING is foo
$ python basic_example.py --some-integer-setting 1000
SOME_INTEGER_SETTING is 1000
FLOAT_SETTING is 0.5
A_BOOLEAN is False
MY_STRING_SETTING is foo
列表和字典类型设置可以通过从命令行传递JSON字符串来覆盖,例如
$ python lists_and_dicts.py --my-list='[1, 2, 3]' --my-dict='{"foo": 10, "bar": 20}'
使用 组
配置 组 是您希望一起绑定的设置系列。例如,您可能有一些机器学习问题,对于这个问题您有一个大模型和小模型,您想轻松地在两个模型之间切换,而无需每次都在命令行中指定所有参数。
要指定组,请使用 settings(...)
函数
from effortless_config import Config, setting
class config(Config):
groups = ['large', 'small']
NUM_LAYERS = setting(default=5, large=10, small=3)
NUM_UNITS = setting(default=128, large=512, small=32)
USE_SKIP_CONNECTIONS = setting(default=True, small=False)
LEARNING_RATE = 0.1
OPTIMIZER = 'adam'
setting(...)
的签名是
def setting(default: T, **kwargs: T) -> T
...其中 T
是 Union[int, float, str, bool, list, dict, NoneType]
,而 kwargs
是从组名到值的映射。通过值指定参数是具有无组的 setting
的缩写,即 SOME_KEY = 'value'
等同于 SOME_KEY = setting(default='value')
。
当使用组时,您必须首先使用 config.groups
列定义组名。
然后在您的代码中,您可以使用这些设置,如下面的基本示例所示
def main():
print(f'NUM_LAYERS is {config.NUM_LAYERS}')
print(f'NUM_UNITS is {config.NUM_UNITS}')
print(f'USE_SKIP_CONNECTIONS is {config.USE_SKIP_CONNECTIONS}')
print(f'LEARNING_RATE is {config.LEARNING_RATE}')
print(f'OPTIMIZER is {config.OPTIMIZER}')
if __name__ == '__main__':
config.parse_args()
main()
现在,当我们请求 --help
时,我们看到一个额外的 --configuration
选项
$ python group_example.py --help
usage: group_example.py [-h] [--configuration {default,large,small}]
[--num-layers NUM_LAYERS] [--num-units NUM_UNITS]
[--use-skip-connections {true,false}]
[--learning-rate LEARNING_RATE] [--optimizer OPTIMIZER]
optional arguments:
-h, --help show this help message and exit
--configuration {default,large,small}, -c {default,large,small}
--num-layers NUM_LAYERS
--num-units NUM_UNITS
--use-skip-connections {true,false}
--learning-rate LEARNING_RATE
--optimizer OPTIMIZER
--configuration
选项指定配置组,如果省略则默认为 default
。
例如
$ python group_example.py
NUM_LAYERS is 5
NUM_UNITS is 128
USE_SKIP_CONNECTIONS is True
LEARNING_RATE is 0.1
OPTIMIZER is adam
$ python group_example.py --configuration large
NUM_LAYERS is 10
NUM_UNITS is 512
USE_SKIP_CONNECTIONS is True
LEARNING_RATE is 0.1
OPTIMIZER is adam
$ python group_example.py --configuration small
NUM_LAYERS is 3
NUM_UNITS is 32
USE_SKIP_CONNECTIONS is False
LEARNING_RATE is 0.1
OPTIMIZER is adam
我们还可以与组结合覆盖单个设置。单个设置优先于组设置
$ python group_example.py --configuration large --num-units 768
NUM_LAYERS is 10
NUM_UNITS is 768
USE_SKIP_CONNECTIONS is True
LEARNING_RATE is 0.1
OPTIMIZER is adam
测试
在编写测试时,您可以使用 config.override
上下文管理器来覆盖单个设置
import pytest
from .config import config
def test_with_context_manager():
with config.override(FLOAT_SETTING=0.8, A_BOOLEAN=True):
assert config.FLOAT_SETTING * config.SOME_INTEGER_SETTING == 8
assert config.A_BOOLEAN is True
config.override
方法也可以与 config.reset_to_defaults
结合使用而不进行上下文管理
def test_with_manual_reset():
config.override(FLOAT_SETTING=0.8, A_BOOLEAN=True)
assert config.FLOAT_SETTING * config.SOME_INTEGER_SETTING == 8
assert config.A_BOOLEAN is True
config.reset_to_defaults()
顺便说一句,这与 Chef 的 Effortless Config 项目无关,我在将其放在 PyPI 上之前忘记谷歌其名称,现在我猜我得继续使用它了。