序:学习YACS 1 是在github上看到一个深度学习模板项目的一个部分,准备研究一下,顺便消磨时间。
YACS 是作为一个轻量级库创建的,用于定义和管理系统配置,例如在为科学实验设计的软件中常见的配置。这些“配置”通常涵盖诸如用于训练机器学习模型的超参数或可配置模型超参数之类的概念,例如卷积神经网络的深度。由于您从事科学工作,因此可重复性至关重要,因此您需要一种可靠的方法来序列化实验配置。YACS 使用 YAML 作为一种简单的、人类可读的序列化格式。范式是:your code + a YACS config for experiment E (+ external dependencies + hardware + other nuisance terms ...) = reproducible experiment E
. 虽然您可能无法控制一切,但至少您可以控制您的代码和实验配置。YACS 在这里为您提供帮助。
YACS源自 py-faster-rcnn和 Detectron中使用的实验性配置系统。
YACS主要有两种使用方式:
作者建议使用局部变量。
创建一个项目配置文件,通常为config.py
或default.py
。该文件是所有可配置选项的一站式参考点。它应该有很好的文档记录,并未所有选项提供合理的默认值。
# my_project/config.py
from yacs.config import CfgNode as CN
_C = CN()
_C.SYSTEM = CN()
# 设置实验中GPU的数量
_C.SYSTEM.NUM_GPUS = 8
# 设置训练时的线程数
_C.SYSTEM.NUM_WORKERS = 4
_C.TRAIN = CN()
# 一个非常重要的超参数,不知道干啥的
_C.TRAIN.HYPERPARAMETER_1 = 0.1
# 非常重要的尺度
_C.TRAIN.SCALES = (2, 4, 8, 16)
def get_cfg_defaults():
"""Get a yacs CfgNode object with default values for my_project."""
# Return a clone so that the defaults will not be altered
# This is for the "local variable" use pattern
return _C.clone()
# Alternatively, provide a way to import the defaults as
# a global singleton:
# cfg = _C # users can `from config import cfg`
创建YAML配置文件,通常情况下应该为每个实验创建一个,每个配置文件只覆盖
一次会在实验中改变的选项参数。
# my_project/experiment.yaml
SYSTEM:
NUM_GPUS: 2
TRAIN:
SCALES: (1, 2)
在实际项目中使用配置文件。在初始化参数设置之后,最好是将其冻结,以防在后续的操作中程序调用freeze()
方法修改参数。如下面的代码所示,设置系统参数可以通过导入cfg
,并直接通过它使用全局变量的方法来设置,或者cfg
作为参数进行复制和传递。
# my_project/main.py
import my_project
from config import get_cfg_defaults # 局部变量使用方式, or:
# from config import cfg # 全局变量使用方式
if __name__ == "__main__":
# `cfg`作为局部变量访问的例子
cfg = get_cfg_defaults()
cfg.merge_from_file("experiment.yaml")
cfg.freeze()
print(cfg)
# `cfg`作为全局变量访问的例子
if cfg.SYSTEM.NUM_GPUS > 0:
my_project.setup_multi_gpu_support()
model = my_project.create_model(cfg)
可以使用完全限定的键值对列表来更新CfgNode
。这使得从命令行进行覆盖选项变得很容易,如下代码所示:
cfg.merge_from_file("experiment.yaml")
# 现在开始从列表中进行覆盖 (opts could come from the command line)
opts = ["SYSTEM.NUM_GPUS", 8, "TRAIN.SCALES", "(1, 2, 3, 4)"]
cfg.merge_from_list(opts)
建议采用以下原则。“配置同一事物只有一种方法”。这个原则意味着,如果一个选项在YACS配置对象中被定义,那么你的程序应该使用cfg.merge_from_list(opts)
来设置该配置选项,而不是通过定义,例如,--train-scales
作为一个命令行参数是用来设置cfg.TRAIN.SCALES
这个对象的。
yacs>= 0.1.4
支持从 Python 源文件加载 CfgNode
对象。习惯上,Pyhon源文件必须导出一个名为cfg
的模块变量,其类型为dict
或CfgNode
。请参阅使用CfgNode
和dict
的示例以及单元测试中的用法。
1、使用_C()
作为创建的配置文件
2、clone()
返回配置文件的副本,且不改变默认值。
def get_cfg_defaults():
return __C.clone()
3、clear()
清空配置文件,得到一个None
作为结果
_c().clear()
print(_c)
4、merge_from_file()
merge_from_file()
这个方法,该函数会比较每个experiments特有的config和默认参数的区别,会将默认参数与特定参数不同的部分,用特定参数覆盖。__C.merge_from_file("./test_config.yaml")
from yacs.config import CfgNode as CN
# default cfgs
__C = CN()
__C.name = 'test'
__C.model = CN()
__C.model.backbone = 'resnet'
__C.model.depth = 18
# yaml cfgs
# 不报错的情况1:参数和default中一样多,并且层级关系一致
name: test
model:
backbone: resnet
depth: 18
# 不报错的情况2:参数可以比default中少,以下例子就不包含name和model.backbone
model:
depth: 34
# 报错的情况1:以下多了model.batch_normalization这个额外的key,这在default中是不存在的
name: test
model:
backbone: resnet
depth: 29
batch_normalization: True
# 报错的情况2:关键词不一致,这里的关键词是na_me,而default中是name
na_me: test
5、merge_from_list()
可以使用list
修改默认参数,其格式为: [参数名,修改后的变量值]。其它使用方式与merge_from_file()
相同。
from yacs.config import CfgNode as CN
__C = CN()
__C.name = 'test'
__C.model = CN()
__C.model.backbone = 'resnet'
__C.model.depth = 18
print(__C)
'''
model:
backbone: resnet
depth: 18
name: test
'''
opts = ["name", 'test_name', "model.backbone", "vgg"]
__C.merge_from_list(opts)
print(__C)
'''
model:
backbone: vgg
depth: 18
name: test_name
'''
6、merge_from_other_cfg()
使用方式与功能与merge_from_file()
和merge_from_list()
相同,其不同点在于融合文件是一个CfgNode
的一个类。
7、freeze()
冻结参数,在执行完该操作后不能改变参数的值。
from yacs.config import CfgNode as CN
__C = CN()
__C.name = 'test'
__C.model = CN()
__C.model.backbone = 'resnet'
__C.model.depth = 18
# freeze the config
__C.freeze()
# try to change the name's value, raise an error
__C.name = 'test2' # error
8、defrost()
解冻参数,在freeze()
后使用。
from yacs.config import CfgNode as CN
__C = CN()
__C.name = 'test'
__C.model = CN()
__C.model.backbone = 'resnet'
__C.model.depth = 18
# freeze the config
__C.freeze()
# try to change the name's value, raise an error
__C.name = 'test2' # error
__C.defrost() # not freeze cfgs, after this operation you can change the value
__C.name = 'test2' # work
[1] YACS项目地址
[2] yacs的使用小记