跳转到主要内容

Python最甜蜜的配置系统

项目描述

Confection:Python最甜蜜的配置系统

confection :candy: 是一个轻量级库,提供了一个 配置系统,让您方便地描述任意对象树。

配置对于机器学习代码来说是一个巨大的挑战,因为您可能希望将任何函数的几乎所有细节都作为超参数公开。您想公开的设置可能位于您的调用堆栈中的任意位置,因此可能需要通过CLI或REST API,通过任意数量的中间函数传递,从而影响沿途的一切接口。然后一旦这些设置被添加,它们就很难在以后删除。默认值也很难更改,否则会破坏向后兼容性。

为了解决这个问题,confection提供了一个配置系统,允许您轻松地描述任意对象的树形结构。对象可以通过使用简单装饰器语法注册的函数调用创建。您甚至可以为创建的函数版本化,这样您就可以在不破坏向后兼容性的情况下进行改进。我们所知道的与它最相似的配置系统是Gin,它使用类似的语法,并允许您使用装饰器将配置系统链接到代码中的函数。confection的配置系统更简单,通过Gin功能的一个子集强调了不同的工作流程。

tests Current Release Version pypi Version conda Version Code style: black

⏳ 安装

pip install confection
conda install -c conda-forge confection

👩‍💻 使用方法

配置系统解析一个.cfg文件,例如

[training]
patience = 10
dropout = 0.2
use_vectors = false

[training.logging]
level = "INFO"

[nlp]
# This uses the value of training.use_vectors
use_vectors = ${training.use_vectors}
lang = "en"

并将其解析为Dict

{
  "training": {
    "patience": 10,
    "dropout": 0.2,
    "use_vectors": false,
    "logging": {
      "level": "INFO"
    }
  },
  "nlp": {
    "use_vectors": false,
    "lang": "en"
  }
}

配置被分为几个部分,部分名称用方括号括起来 - 例如,[训练]。在部分内部,可以使用=将配置值赋给键。值也可以使用点表示法和由美元符号和花括号指示的占位符从其他部分引用。例如,${training.use_vectors}将接收训练块中use_vectors的值。这对于在组件之间共享的设置很有用。

配置格式与Python内置的configparser有三个主要区别

  1. JSON格式的值。confection将所有值通过json.loads传递来解释它们。您可以使用原子值,如字符串、浮点数、整数或布尔值,或者可以使用复杂对象,如列表或映射。
  2. 结构化部分。confection使用点表示法构建嵌套部分。如果您有一个名为[部分.子部分]的部分,confection将将其解析为嵌套结构,将子部分放在部分内部。
  3. 对注册函数的引用。如果一个键以@开头,confection将将其值解释为函数注册表的名称,加载为该名称注册的函数,并将其余部分作为参数传递。如果函数有类型提示,参数值(以及函数的返回值)将与其进行验证。这允许您表达复杂的配置,例如一个训练流程,其中batch_size由一个生成浮点数的函数填充。

没有预定义的方案需要遵循;您如何设置顶层部分由您自己决定。最后,您将收到一个字典,其中包含您可以在脚本中使用的值 - 无论是完全初始化的函数还是仅基本设置。

例如,假设您想定义一个新的优化器。您可以在config.cfg中这样定义它的参数

[optimizer]
@optimizers = "my_cool_optimizer.v1"
learn_rate = 0.001
gamma = 1e-8

使用catalogue注册表加载和解析此配置(单独安装catalogue

import dataclasses
from typing import Union, Iterable
import catalogue
from confection import registry, Config

# Create a new registry.
registry.optimizers = catalogue.create("confection", "optimizers", entry_points=False)


# Define a dummy optimizer class.
@dataclasses.dataclass
class MyCoolOptimizer:
    learn_rate: float
    gamma: float


@registry.optimizers.register("my_cool_optimizer.v1")
def make_my_optimizer(learn_rate: Union[float, Iterable[float]], gamma: float):
    return MyCoolOptimizer(learn_rate, gamma)


# Load the config file from disk, resolve it and fetch the instantiated optimizer object.
config = Config().from_disk("./config.cfg")
resolved = registry.resolve(config)
optimizer = resolved["optimizer"]  # MyCoolOptimizer(learn_rate=0.001, gamma=1e-08)

⚠️ 注意:类型检查器(如mypy)会将以这种方式添加新属性到registry - 即registry.new_attr = ... - 标记为错误。这是因为新属性是在类初始化之后添加到类中的。如果您使用类型检查器,您可以选择忽略它(例如,对于mypy使用# type: ignore)或使用类型安全的替代方案:而不是使用registry.new_attr = ...,使用setattr(registry, "new_attr", ...)

在底层,confection将在"optimizers"注册表中查找"my_cool_optimizer.v1"函数,然后使用learn_rategamma作为参数调用它。如果函数有类型注解,它也会验证输入。例如,如果learn_rate被注解为浮点数,而配置定义了一个字符串,confection将引发错误。

Thinc文档提供了有关配置系统的更多信息

🎛 API

Config

此类包含模型和训练 配置,可以从字符串、文件或字节中加载和保存 INI 风格的配置格式。 Config 类是 dict 的子类,并在内部使用 Python 的 ConfigParser

方法 Config.__init__

使用可选数据初始化一个新的 Config 对象。

from confection import Config
config = Config({"training": {"patience": 10, "dropout": 0.2}})
参数 类型 描述
data Optional[Union[Dict[str, Any], Config]] 用于初始化配置的可选数据。
section_order Optional[List[str]] 顶层节点的名称,按顺序排列,用于排序保存和加载的配置。所有其他节点都将按字母顺序排序。
is_interpolated Optional[bool] 配置是否插值或是否包含变量。如果它是 Config 的实例,则从 data 中读取;否则默认为 True

方法 Config.from_str

从字符串中加载配置。

from confection import Config

config_str = """
[training]
patience = 10
dropout = 0.2
"""
config = Config().from_str(config_str)
print(config["training"])  # {'patience': 10, 'dropout': 0.2}}
参数 类型 描述
text str 要加载的字符串配置。
interpolate bool 是否插值变量,如 ${section.key}。默认为 True
overrides Dict[str, Any] 值和节点的覆盖。键以点表示法提供,例如 "training.dropout" 映射到值。
返回 Config 加载的配置。

方法 Config.to_str

从字符串中加载配置。

from confection import Config

config = Config({"training": {"patience": 10, "dropout": 0.2}})
print(config.to_str()) # '[training]\npatience = 10\n\ndropout = 0.2'
参数 类型 描述
interpolate bool 是否插值变量,如 ${section.key}。默认为 True
返回 str 字符串配置。

方法 Config.to_bytes

将配置序列化为字节字符串。

from confection import Config

config = Config({"training": {"patience": 10, "dropout": 0.2}})
config_bytes = config.to_bytes()
print(config_bytes)  # b'[training]\npatience = 10\n\ndropout = 0.2'
参数 类型 描述
interpolate bool 是否插值变量,如 ${section.key}。默认为 True
overrides Dict[str, Any] 值和节点的覆盖。键以点表示法提供,例如 "training.dropout" 映射到值。
返回 str 序列化的配置。

方法 Config.from_bytes

从字节字符串中加载配置。

from confection import Config

config = Config({"training": {"patience": 10, "dropout": 0.2}})
config_bytes = config.to_bytes()
new_config = Config().from_bytes(config_bytes)
参数 类型 描述
bytes_data bool 要加载的数据。
interpolate bool 是否插值变量,如 ${section.key}。默认为 True
返回 Config 加载的配置。

方法 Config.to_disk

将配置序列化为文件。

from confection import Config

config = Config({"training": {"patience": 10, "dropout": 0.2}})
config.to_disk("./config.cfg")
参数 类型 描述
path Union[Path, str] 文件路径。
interpolate bool 是否插值变量,如 ${section.key}。默认为 True

方法 Config.from_disk

从文件中加载配置。

from confection import Config

config = Config({"training": {"patience": 10, "dropout": 0.2}})
config.to_disk("./config.cfg")
new_config = Config().from_disk("./config.cfg")
参数 类型 描述
path Union[Path, str] 文件路径。
interpolate bool 是否插值变量,如 ${section.key}。默认为 True
overrides Dict[str, Any] 值和节点的覆盖。键以点表示法提供,例如 "training.dropout" 映射到值。
返回 Config 加载的配置。

方法 Config.copy

深度复制配置。

参数 类型 描述
返回 Config 复制的配置。

方法 Config.interpolate

插值变量,如 ${section.value}${section.subsection},并返回包含插值值的配置副本。如果配置是通过 Config.from_strinterpolate=False 加载的,则可以使用此方法。

from confection import Config

config_str = """
[hyper_params]
dropout = 0.2

[training]
dropout = ${hyper_params.dropout}
"""
config = Config().from_str(config_str, interpolate=False)
print(config["training"])  # {'dropout': '${hyper_params.dropout}'}}
config = config.interpolate()
print(config["training"])  # {'dropout': 0.2}}
参数 类型 描述
返回 Config 包含插值值的配置副本。
方法 Config.merge

深度合并两个配置对象,使用当前配置作为默认配置。仅合并节点和字典,不合并其他值,如列表。在更新中提供的值将覆盖基本配置中的值,并将添加任何新的值或节点。如果配置值是变量,如 ${section.key}(例如,如果配置是通过 interpolate=False 加载的),则即使更新提供了不同的值,也将优先选择变量。这确保变量引用不会被合并所破坏。

:warning: 注意,使用 @ 语法引用已注册函数的块仅在它们引用同一函数时才合并。否则,合并可能会轻松产生无效的配置,因为不同的函数可以接受不同的参数。如果块引用不同的函数,则会被覆盖。

from confection import Config

base_config_str = """
[training]
patience = 10
dropout = 0.2
"""
update_config_str = """
[training]
dropout = 0.1
max_epochs = 2000
"""

base_config = Config().from_str(base_config_str)
update_config = Config().from_str(update_config_str)
merged = Config(base_config).merge(update_config)
print(merged["training"])  # {'patience': 10, 'dropout': 0.1, 'max_epochs': 2000}
参数 类型 描述
overrides Union[Dict[str, Any], Config] 要合并到配置中的更新。
返回 Config 包含合并配置的新配置实例。

配置属性

参数 类型 描述
is_interpolated bool 配置值是否已被插值。默认为 True,如果配置是通过 interpolate=False 加载的,例如使用 Config.from_str,则设置为 False

项目详情


下载文件

下载您平台对应的文件。如果您不确定该选择哪个,请了解有关安装包的更多信息。

源代码发行版

confection-0.1.5.tar.gz (38.9 kB 查看哈希值)

上传时间 源代码

构建发行版

confection-0.1.5-py3-none-any.whl (35.5 kB 查看哈希值)

上传时间 Python 3

由以下支持