Arulkumar03/Wheat_HEAD_Detection_Counting_ComputerVision_Model
0
1# -*- coding: utf-8 -*-2# Copyright (c) Facebook, Inc. and its affiliates.3 4import functools5import inspect6import logging7from fvcore.common.config import CfgNode as _CfgNode8 9from detectron2.utils.file_io import PathManager10 11 12class CfgNode(_CfgNode):13 """14 The same as `fvcore.common.config.CfgNode`, but different in:15 16 1. Use unsafe yaml loading by default.17 Note that this may lead to arbitrary code execution: you must not18 load a config file from untrusted sources before manually inspecting19 the content of the file.20 2. Support config versioning.21 When attempting to merge an old config, it will convert the old config automatically.22 23 .. automethod:: clone24 .. automethod:: freeze25 .. automethod:: defrost26 .. automethod:: is_frozen27 .. automethod:: load_yaml_with_base28 .. automethod:: merge_from_list29 .. automethod:: merge_from_other_cfg30 """31 32 @classmethod33 def _open_cfg(cls, filename):34 return PathManager.open(filename, "r")35 36 # Note that the default value of allow_unsafe is changed to True37 def merge_from_file(self, cfg_filename: str, allow_unsafe: bool = True) -> None:38 """39 Load content from the given config file and merge it into self.40 41 Args:42 cfg_filename: config filename43 allow_unsafe: allow unsafe yaml syntax44 """45 assert PathManager.isfile(cfg_filename), f"Config file '{cfg_filename}' does not exist!"46 loaded_cfg = self.load_yaml_with_base(cfg_filename, allow_unsafe=allow_unsafe)47 loaded_cfg = type(self)(loaded_cfg)48 49 # defaults.py needs to import CfgNode50 from .defaults import _C51 52 latest_ver = _C.VERSION53 assert (54 latest_ver == self.VERSION55 ), "CfgNode.merge_from_file is only allowed on a config object of latest version!"56 57 logger = logging.getLogger(__name__)58 59 loaded_ver = loaded_cfg.get("VERSION", None)60 if loaded_ver is None:61 from .compat import guess_version62 63 loaded_ver = guess_version(loaded_cfg, cfg_filename)64 assert loaded_ver <= self.VERSION, "Cannot merge a v{} config into a v{} config.".format(65 loaded_ver, self.VERSION66 )67 68 if loaded_ver == self.VERSION:69 self.merge_from_other_cfg(loaded_cfg)70 else:71 # compat.py needs to import CfgNode72 from .compat import upgrade_config, downgrade_config73 74 logger.warning(75 "Loading an old v{} config file '{}' by automatically upgrading to v{}. "76 "See docs/CHANGELOG.md for instructions to update your files.".format(77 loaded_ver, cfg_filename, self.VERSION78 )79 )80 # To convert, first obtain a full config at an old version81 old_self = downgrade_config(self, to_version=loaded_ver)82 old_self.merge_from_other_cfg(loaded_cfg)83 new_config = upgrade_config(old_self)84 self.clear()85 self.update(new_config)86 87 def dump(self, *args, **kwargs):88 """89 Returns:90 str: a yaml string representation of the config91 """92 # to make it show up in docs93 return super().dump(*args, **kwargs)94 95 96global_cfg = CfgNode()97 98 99def get_cfg() -> CfgNode:100 """101 Get a copy of the default config.102 103 Returns:104 a detectron2 CfgNode instance.105 """106 from .defaults import _C107 108 return _C.clone()109 110 111def set_global_cfg(cfg: CfgNode) -> None:112 """113 Let the global config point to the given cfg.114 115 Assume that the given "cfg" has the key "KEY", after calling116 `set_global_cfg(cfg)`, the key can be accessed by:117 ::118 from detectron2.config import global_cfg119 print(global_cfg.KEY)120 121 By using a hacky global config, you can access these configs anywhere,122 without having to pass the config object or the values deep into the code.123 This is a hacky feature introduced for quick prototyping / research exploration.124 """125 global global_cfg126 global_cfg.clear()127 global_cfg.update(cfg)128 129 130def configurable(init_func=None, *, from_config=None):131 """132 Decorate a function or a class's __init__ method so that it can be called133 with a :class:`CfgNode` object using a :func:`from_config` function that translates134 :class:`CfgNode` to arguments.135 136 Examples:137 ::138 # Usage 1: Decorator on __init__:139 class A:140 @configurable141 def __init__(self, a, b=2, c=3):142 pass143 144 @classmethod145 def from_config(cls, cfg): # 'cfg' must be the first argument146 # Returns kwargs to be passed to __init__147 return {"a": cfg.A, "b": cfg.B}148 149 a1 = A(a=1, b=2) # regular construction150 a2 = A(cfg) # construct with a cfg151 a3 = A(cfg, b=3, c=4) # construct with extra overwrite152 153 # Usage 2: Decorator on any function. Needs an extra from_config argument:154 @configurable(from_config=lambda cfg: {"a: cfg.A, "b": cfg.B})155 def a_func(a, b=2, c=3):156 pass157 158 a1 = a_func(a=1, b=2) # regular call159 a2 = a_func(cfg) # call with a cfg160 a3 = a_func(cfg, b=3, c=4) # call with extra overwrite161 162 Args:163 init_func (callable): a class's ``__init__`` method in usage 1. The164 class must have a ``from_config`` classmethod which takes `cfg` as165 the first argument.166 from_config (callable): the from_config function in usage 2. It must take `cfg`167 as its first argument.168 """169 170 if init_func is not None:171 assert (172 inspect.isfunction(init_func)173 and from_config is None174 and init_func.__name__ == "__init__"175 ), "Incorrect use of @configurable. Check API documentation for examples."176 177 @functools.wraps(init_func)178 def wrapped(self, *args, **kwargs):179 try:180 from_config_func = type(self).from_config181 except AttributeError as e:182 raise AttributeError(183 "Class with @configurable must have a 'from_config' classmethod."184 ) from e185 if not inspect.ismethod(from_config_func):186 raise TypeError("Class with @configurable must have a 'from_config' classmethod.")187 188 if _called_with_cfg(*args, **kwargs):189 explicit_args = _get_args_from_config(from_config_func, *args, **kwargs)190 init_func(self, **explicit_args)191 else:192 init_func(self, *args, **kwargs)193 194 return wrapped195 196 else:197 if from_config is None:198 return configurable # @configurable() is made equivalent to @configurable199 assert inspect.isfunction(200 from_config201 ), "from_config argument of configurable must be a function!"202 203 def wrapper(orig_func):204 @functools.wraps(orig_func)205 def wrapped(*args, **kwargs):206 if _called_with_cfg(*args, **kwargs):207 explicit_args = _get_args_from_config(from_config, *args, **kwargs)208 return orig_func(**explicit_args)209 else:210 return orig_func(*args, **kwargs)211 212 wrapped.from_config = from_config213 return wrapped214 215 return wrapper216 217 218def _get_args_from_config(from_config_func, *args, **kwargs):219 """220 Use `from_config` to obtain explicit arguments.221 222 Returns:223 dict: arguments to be used for cls.__init__224 """225 signature = inspect.signature(from_config_func)226 if list(signature.parameters.keys())[0] != "cfg":227 if inspect.isfunction(from_config_func):228 name = from_config_func.__name__229 else:230 name = f"{from_config_func.__self__}.from_config"231 raise TypeError(f"{name} must take 'cfg' as the first argument!")232 support_var_arg = any(233 param.kind in [param.VAR_POSITIONAL, param.VAR_KEYWORD]234 for param in signature.parameters.values()235 )236 if support_var_arg: # forward all arguments to from_config, if from_config accepts them237 ret = from_config_func(*args, **kwargs)238 else:239 # forward supported arguments to from_config240 supported_arg_names = set(signature.parameters.keys())241 extra_kwargs = {}242 for name in list(kwargs.keys()):243 if name not in supported_arg_names:244 extra_kwargs[name] = kwargs.pop(name)245 ret = from_config_func(*args, **kwargs)246 # forward the other arguments to __init__247 ret.update(extra_kwargs)248 return ret249 250 251def _called_with_cfg(*args, **kwargs):252 """253 Returns:254 bool: whether the arguments contain CfgNode and should be considered255 forwarded to from_config.256 """257 from omegaconf import DictConfig258 259 if len(args) and isinstance(args[0], (_CfgNode, DictConfig)):260 return True261 if isinstance(kwargs.pop("cfg", None), (_CfgNode, DictConfig)):262 return True263 # `from_config`'s first argument is forced to be "cfg".264 # So the above check covers all cases.265 return False266 