文章目录
一、yaml(Yet Another Markup Language)
1.1、yaml 简介
- 深度学习调参过程中会遇到很多参数,为了 完整保存一个项目的所有配置,推荐使用
yaml
工具进行配置(pip install pyyaml
)yaml
是一种人类可读的数据序列化语言,支持三种基本数据类型:标量(例如字符串,整数、浮点数、布尔值和空值),列表和关联数组(字典)
yaml
的基本语法特点为:
- 缩进表示层级关系,不允许使用 tab,只允许使用空格,缩进的空格数不重要,只要相同层级的元素左对齐即可
- 列表通过
"-"
表示,字典通过":"
表示- 在同一个
yaml
文件中,可以用"---"
来分段,这样可以将多个文档写在一个文件中- 大小写敏感;注释使用
"#"
- 读取:
yaml.load(f, Loader=yaml.FullLoader)
;写入:yaml.dump(data=config, stream=f, allow_unicode=True)
- Note: 字典的 key 不要使用 number,要不然会报错(
TypeError: sequence item 2: expected str instance, int found
)
1.2、读取 yaml
文件
- yolov5l.yaml 示例(部分):
# parameters
nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
# anchors
anchors:
- [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16
- [116,90, 156,198, 373,326] # P5/32
# 或者写成这种
# [[10, 13, 16, 30, 33, 23],
# [30, 61, 62, 45, 59, 119],
# [116, 90, 156, 198, 373, 326]]
# YOLOv5 backbone
backbone:
# [from, number, module, args]
[[-1, 1, Focus, [64, 3]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
]
# YOLOv5 head
head:
[[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[-1, 1, Conv, [256, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
]
names:
0: aeroplane
1: bicycle
2: bird
3: boat
- 代码
import yaml
with open("configs/yolov5l.yaml", encoding='utf-8') as f:
d = yaml.load(f, Loader=yaml.FullLoader)
print(d) # d 为字典
# 输出如下
{
'nc': 80,
'depth_multiple': 1.0,
'width_multiple': 1.0,
'anchors':
[
[10, 13, 16, 30, 33, 23],
[30, 61, 62, 45, 59, 119],
[116, 90, 156, 198, 373, 326]
],
'backbone':
[
[-1, 1, 'Focus', [64, 3]],
[-1, 1, 'Conv', [128, 3, 2]]
],
'head':
[
[-1, 1, 'Conv', [512, 1, 1]],
[-1, 1, 'nn.Upsample', ['None', 2, 'nearest']],
[-1, 1, 'Conv', [256, 1, 1]],
[-1, 1, 'nn.Upsample', ['None', 2, 'nearest']]
]
'names': {0: 'aeroplane', 1: 'bicycle', 2: 'bird', 3: 'boat'}
}
1.3、将内容存储到 yaml
文件中
import yaml
config = {
"test_dataRoot": "./dataset/test",
"epoch": 200,
"batch_size": 12,
"anchors": [10, 12, 24, 19, 37, 50]
}
with open('configs/data.yaml', encoding='utf-8', mode='w') as f:
yaml.dump(data=config, stream=f, allow_unicode=True) # 该示例将词典列表写入 data.yaml 文件
# 写入的内容如下
anchors:
- 10
- 12
- 24
- 19
- 37
- 50
batch_size: 12
epoch: 200
test_dataRoot: ./dataset/test
二、yacs(Yet Another Configuration System)
2.1、yacs 简介
yacs
是一个用于定义和管理系统配置的开源库,常用于深度学习模型参数的配置它包含了所有可配置的参数,并为每个参数设置了默认值,它是一个类似字典的容器
,允许用户用基于属性的方式.
使用键(key
)来访问值(eg:cfg.SYSTEM.NUM_GPUS)
,也允许用户基于字典的方式访问值cfg["SYSTEM"]["NUM_GPUS"]
yacs
安装:pip install yacs
yacs
的基本语法特点:
cfg.merge_from_file("config.yaml")
:Load a yaml config file and merge it this CfgNodecfg.merge_from_list(args.opts)
:Merge config (keys, values) in a list (e.g.,from command line
) into this CfgNodecfg.freeze()
:Make this CfgNode and all of its children immutable- 在
_C
中申明过后的变量才能被赋值和修改,如果_C
中没有某个变量,而yaml
中有,那就会报错,因为该变量未能事先申明(Note:如果事先merge
了yaml
中的新增变量也不会报错)_C.DATASETS = CN(new_allowed=True)
申明父类的变量,允许子类新建
2.2、config.py 及 exp1.yaml 示例
# config.py 示例(存放一些默认的参数)
from yacs.config import CfgNode as CN
_C = CN(new_allowed=True) # whether adding new key is allowed when merging with other configs
_C.SYSTEM = CN(new_allowed=True)
_C.SYSTEM.NUM_GPUS = 8 # Number of GPUS to use in the experiment
_C.SYSTEM.NUM_WORKERS = 4 # Number of workers for doing things
_C.TRAIN = CN(new_allowed=True)
_C.TRAIN.HYPERPARAMETER_1 = 0.1 # A very important hyperparameter
_C.TRAIN.SCALES = (2, 4, 8, 16) # The all important scales for the stuff
_C.DATASETS = CN(new_allowed=True)
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`,可使用 cfg[SYSTEM][NUM_GPUS] 这种方式来访问相应的 value
# exp1.yaml 示例
# 存放本次实验的配置,无需更改的默认参数不用列出
SYSTEM:
NUM_GPUS: 2 # 需要更改的默认参数在此列出(注意:在 _C 中申明过后的变量才能被赋值和修改)
TRAIN:
SCALES: (1, 2) # 需要更改的默认参数在此列出(注意:在 _C 中申明过后的变量才能被赋值和修改)
DATASETS:
train_2017: # 需要新增的参数在此列出(注意:需要父类节点允许子类新建,即 new_allowed=True)
t17: 1
t18: 1
2.3、yacs&yaml&argparse 混合使用示例
整个主代码定义一个变量
cfg
,代码中的所有参数都包含在里面,进行实验时通过 yaml 配置文件 和 命令行参数 可以很方便地修改各个参数
import yaml
import argparse
from config import cfg
if __name__ == "__main__":
# 1、yaml 用法
with open("yolov5l.yaml", encoding='utf-8') as f:
d = yaml.load(f, Loader=yaml.FullLoader)
print(d) # d 为字典
# 2、yacs 联合 yaml 和 argparse 命令行的用法
# python 2-yaml-yacs.py -cfg_file exp1.yaml -opts "SYSTEM.NUM_GPUS" 12 "TRAIN.SCALES" "(1, 2, 3, 4)"
parser = argparse.ArgumentParser()
parser.add_argument("--cfg_file", default="exp1.yaml", help="to specify the config file")
parser.add_argument("--opts", default="", help="Modify config options using the command-line",
nargs=argparse.REMAINDER)
args = parser.parse_args()
print(args)
if args.cfg_file != "":
cfg.merge_from_file(args.cfg_file) # Load a yaml config file and merge it this CfgNode
if args.opts != "":
cfg.merge_from_list(args.opts) # Merge config in a list (from command line) into this CfgNode
cfg.freeze() # Make this CfgNode and all of its children immutable
print("this exp config is:\n{}".format(cfg))
# 访问方式:可以使用属性的方式访问,也可以使用字典的方式访问
print(cfg.SYSTEM.NUM_GPUS)
print(cfg["SYSTEM"]["NUM_GPUS"])
# 命令行调用(一般不需要额外的参数设置 opts,opts 后面的参数会转换为字符串后组合成列表)
python 2-yaml-yacs.py --cfg_file exp1.yaml --opts "SYSTEM.NUM_GPUS" 12 "TRAIN.SCALES" "(1, 2, 3, 4)"
# 输出如下所示:
Namespace(cfg_file='config.yaml', opts=['SYSTEM.NUM_GPUS', '12', 'TRAIN.SCALES', '(1, 2, 3, 4)'])
this exp config is:
DATASETS:
train_2017: # yaml 中新增参数
17: 1
18: 1
SYSTEM:
NUM_GPUS: 12 # 默认为 8,yaml 中为 2,通过命令行方式更改为 12
NUM_WORKERS: 4
TRAIN:
HYPERPARAMETER_1: 0.1
SCALES: (1, 2, 3, 4) # 默认为 (2, 4, 8, 16),yaml 中为 (1, 2),通过命令行方式更改为 (1, 2, 3, 4)
12
12
三、参考资料
1、Python Yaml配置工具
2、https://github.com/rbgirshick/yacs
3、How to use argparse and yaml module on jupyter at the same time
4、detectron2 的 LazyConfig之前的参数配置是基于 yaml 和 yacs