config.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. # !/usr/bin/env python3
  2. # -*- coding: UTF-8 -*-
  3. ################################################################################
  4. #
  5. # Copyright (c) 2024 Baidu.com, Inc. All Rights Reserved
  6. #
  7. ################################################################################
  8. """
  9. Author: PaddlePaddle Authors
  10. """
  11. import abc
  12. import collections.abc
  13. from collections import OrderedDict
  14. from .register import get_registered_model_info, get_registered_suite_info
  15. from ...utils.errors import UnsupportedParamError
  16. __all__ = ['Config', 'BaseConfig']
  17. def _create_config(model_name, config_path=None):
  18. """ _create_config """
  19. # Build config from model name
  20. try:
  21. model_info = get_registered_model_info(model_name)
  22. except KeyError as e:
  23. raise UnsupportedParamError(
  24. f"{repr(model_name)} is not a registered model name.") from e
  25. suite_name = model_info['suite']
  26. suite_info = get_registered_suite_info(suite_name)
  27. config_cls = suite_info['config']
  28. config_obj = config_cls(model_name=model_name, config_path=config_path)
  29. return config_obj
  30. Config = _create_config
  31. class _Config(object):
  32. """ _Config """
  33. _DICT_TYPE_ = OrderedDict
  34. def __init__(self, cfg=None):
  35. super().__init__()
  36. self._dict = self._DICT_TYPE_()
  37. if cfg is not None:
  38. # Manipulate the internal `_dict` such that we avoid an extra copy
  39. self.reset_from_dict(cfg._dict)
  40. @property
  41. def dict(self):
  42. """ dict """
  43. return dict(self._dict)
  44. def __getattr__(self, key):
  45. try:
  46. val = self._dict[key]
  47. return val
  48. except KeyError:
  49. raise AttributeError
  50. def set_val(self, key, val):
  51. """ set_val """
  52. self._dict[key] = val
  53. def __getitem__(self, key):
  54. return self._dict[key]
  55. def __setitem__(self, key, val):
  56. self._dict[key] = val
  57. def __contains__(self, key):
  58. return key in self._dict
  59. def new_config(self, **kwargs):
  60. """ new_config """
  61. cfg = self.copy()
  62. cfg.update(kwargs)
  63. def copy(self):
  64. """ copy """
  65. return type(self)(cfg=self)
  66. def pop(self, key):
  67. """ pop """
  68. self._dict.pop(key)
  69. def __repr__(self):
  70. return format_cfg(self, indent=0)
  71. def reset_from_dict(self, dict_like_obj):
  72. """ reset_from_dict """
  73. self._dict.clear()
  74. self._dict.update(dict_like_obj)
  75. class BaseConfig(_Config, metaclass=abc.ABCMeta):
  76. """
  77. Abstract base class of Config.
  78. Config provides the funtionality to load, parse, or dump to a configuration
  79. file with a specific format. Also, it provides APIs to update configurations
  80. of several important hyperparameters and model components.
  81. """
  82. def __init__(self, model_name, config_path=None, cfg=None):
  83. """
  84. Initialize the instance.
  85. Args:
  86. model_name (str): A registered model name.
  87. config_path (str|None): Path of a configuration file. Default: None.
  88. cfg (BaseConfig|None): `BaseConfig` object to initialize from.
  89. Default: None.
  90. """
  91. super().__init__(cfg=cfg)
  92. self.model_name = model_name
  93. if cfg is None:
  94. # Initialize from file if no `cfg` is specified to initialize from
  95. if config_path is None:
  96. model_info = get_registered_model_info(self.model_name)
  97. config_path = model_info['config_path']
  98. self.load(config_path)
  99. @abc.abstractmethod
  100. def load(self, config_path):
  101. """Load configurations from a file."""
  102. raise NotImplementedError
  103. @abc.abstractmethod
  104. def dump(self, config_path):
  105. """Dump configurations to a file."""
  106. raise NotImplementedError
  107. @abc.abstractmethod
  108. def update(self, dict_like_obj):
  109. """Update configurations from a dict-like object."""
  110. raise NotImplementedError
  111. @abc.abstractmethod
  112. def update_dataset(self, dataset_dir, dataset_type=None):
  113. """Update configurations of dataset."""
  114. raise NotImplementedError
  115. @abc.abstractmethod
  116. def update_learning_rate(self, learning_rate):
  117. """Update learning rate."""
  118. raise NotImplementedError
  119. @abc.abstractmethod
  120. def update_batch_size(self, batch_size, mode='train'):
  121. """
  122. Update batch size.
  123. By default this method modifies the training batch size.
  124. """
  125. raise NotImplementedError
  126. @abc.abstractmethod
  127. def update_pretrained_weights(self, weight_path, is_backbone=False):
  128. """
  129. Update path to pretrained weights.
  130. By default this method modifies the weight path for the entire model.
  131. """
  132. raise NotImplementedError
  133. def get_epochs_iters(self):
  134. """Get total number of epochs or iterations in training."""
  135. raise NotImplementedError
  136. def get_learning_rate(self):
  137. """Get learning rate used in training."""
  138. raise NotImplementedError
  139. def get_batch_size(self, mode='train'):
  140. """
  141. Get batch size.
  142. By default this method returns the training batch size.
  143. """
  144. raise NotImplementedError
  145. def get_qat_epochs_iters(self):
  146. """Get total number of epochs or iterations in QAT."""
  147. raise NotImplementedError
  148. def get_qat_learning_rate(self):
  149. """Get learning rate used in QAT."""
  150. raise NotImplementedError
  151. def copy(self):
  152. """ copy """
  153. return type(self)(model_name=self.model_name, cfg=self)
  154. def format_cfg(cfg, indent=0):
  155. """ format_cfg """
  156. MAP_TYPES = (collections.abc.Mapping, )
  157. SEQ_TYPES = (list, tuple)
  158. NESTED_TYPES = (*MAP_TYPES, *SEQ_TYPES)
  159. s = ' ' * indent
  160. if isinstance(cfg, _Config):
  161. cfg = cfg.dict
  162. if isinstance(cfg, MAP_TYPES):
  163. for i, (k, v) in enumerate(sorted(cfg.items())):
  164. s += str(k) + ': '
  165. if isinstance(v, NESTED_TYPES):
  166. s += '\n' + format_cfg(v, indent=indent + 1)
  167. else:
  168. s += str(v)
  169. if i != len(cfg) - 1:
  170. s += '\n'
  171. elif isinstance(cfg, SEQ_TYPES):
  172. for i, v in enumerate(cfg):
  173. s += '- '
  174. if isinstance(v, NESTED_TYPES):
  175. s += '\n' + format_cfg(v, indent=indent + 1)
  176. else:
  177. s += str(v)
  178. if i != len(cfg) - 1:
  179. s += '\n'
  180. else:
  181. s += str(cfg)
  182. return s