PaddleClas/ppcls/utils/config.py
2020-04-09 02:16:30 +08:00

202 lines
5.4 KiB
Python

#copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
#
#Licensed under the Apache License, Version 2.0 (the "License");
#you may not use this file except in compliance with the License.
#You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#Unless required by applicable law or agreed to in writing, software
#distributed under the License is distributed on an "AS IS" BASIS,
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#See the License for the specific language governing permissions and
#limitations under the License.
import os
import yaml
from ppcls.utils import check
from ppcls.utils import logger
__all__ = ['get_config']
CONFIG_SECS = ['TRAIN', 'VALID', 'OPTIMIZER', 'LEARNING_RATE']
class AttrDict(dict):
def __getattr__(self, key):
return self[key]
def __setattr__(self, key, value):
if key in self.__dict__:
self.__dict__[key] = value
else:
self[key] = value
def create_attr_dict(yaml_config):
from ast import literal_eval
for key, value in yaml_config.items():
if type(value) is dict:
yaml_config[key] = value = AttrDict(value)
if isinstance(value, str):
try:
value = literal_eval(value)
except BaseException:
pass
if isinstance(value, AttrDict):
create_attr_dict(yaml_config[key])
else:
yaml_config[key] = value
return
def parse_config(cfg_file):
"""Load a config file into AttrDict"""
with open(cfg_file, 'r') as fopen:
yaml_config = AttrDict(yaml.load(fopen, Loader=yaml.FullLoader))
create_attr_dict(yaml_config)
return yaml_config
def print_dict(d, delimiter=0):
"""
Recursively visualize a dict and
indenting acrrording by the relationship of keys.
"""
for k, v in d.items():
if k in CONFIG_SECS:
logger.info("-" * 60)
if isinstance(v, dict):
logger.info("{}{} : ".format(delimiter * " ", k))
print_dict(v, delimiter + 4)
elif isinstance(v, list) and len(v) >= 1 and isinstance(v[0], dict):
logger.info("{}{} : ".format(delimiter * " ", k))
for value in v:
print_dict(value, delimiter + 4)
else:
logger.info("{}{} : {}".format(delimiter * " ", k, v))
if k in CONFIG_SECS:
logger.info("-" * 60)
def print_config(config):
"""
visualize configs
Arguments:
config: configs
"""
copyright = "PaddleCLS is powered by PaddlePaddle"
ad = "https://github.com/PaddlePaddle/PaddleCLS"
logger.info("\n" * 2)
logger.info(copyright)
logger.info(ad)
print_dict(config)
logger.info("-" * 60)
def check_config(config):
"""
Check config
"""
check.check_version()
mode = config.get('mode', 'train')
check.check_gpu()
architecture = config.get('architecture')
check.check_architecture(architecture)
use_mix = config.get('use_mix')
check.check_mix(architecture, use_mix)
classes_num = config.get('classes_num')
check.check_classes_num(classes_num)
if mode.lower() == 'train':
check.check_function_params(config, 'LEARNING_RATE')
check.check_function_params(config, 'OPTIMIZER')
def override(dl, ks, v):
"""
Recursively replace dict of list
Args:
dl(dict or list): dict or list to be replaced
ks(list): list of keys
v(str): value to be replaced
"""
def str2num(v):
try:
return eval(v)
except Exception:
return v
assert isinstance(dl, (list, dict)), ("{} should be a list or a dict")
assert len(ks) > 0, ('lenght of keys should larger than 0')
if isinstance(dl, list):
k = str2num(ks[0])
if len(ks) == 1:
assert k < len(dl), ('index({}) out of range({})'.format(k, dl))
dl[k] = str2num(v)
else:
override(dl[k], ks[1:], v)
else:
if len(ks) == 1:
assert ks[0] in dl, ('{} is not exist in {}'.format(ks[0], dl))
dl[ks[0]] = str2num(v)
else:
override(dl[ks[0]], ks[1:], v)
def override_config(config, options=[]):
"""
Recursively override the config
Args:
config(dict): dict to be replaced
options(list): list of pairs(key0.key1.idx.key2=value)
such as: [
'topk=2',
'VALID.transforms.1.ResizeImage.resize_short=300'
]
Returns:
config(dict): replaced config
"""
for opt in options:
assert isinstance(opt, str), \
("option({}) should be a str".format(opt))
assert "=" in opt, ("option({}) should contain " \
"a = to distinguish between key and value".format(opt))
pair = opt.split('=')
assert len(pair) == 2, ("there can be only a = in the option")
key, value = pair
keys = key.split('.')
override(config, keys, value)
return config
def get_config(fname, overrides=[], show=True):
"""
Read config from file
"""
assert os.path.exists(fname), \
('config file({}) is not exist'.format(fname))
config = parse_config(fname)
if show: print_config(config)
if len(overrides) > 0:
override_config(config, overrides)
print_config(config)
check_config(config)
return config