[docs]defextract_hparams(locals_dict:Dict[str,Any])->Dict[str,Any]:"""Takes in local symbol table and recursively grabs any hyperparameter. Args: locals_dict (Dict[str, Any]): The local symbol table returned when calling locals(), which maps any free local variables' names to their values. Returns: Dict[str, Any]: A nested dictionary with every element of locals_dict mapped to its value or to another sub_dict. """hparams={}fork,vinlocals_dict.items():ifk.startswith('_')ork=='self':continuehparams_to_add=_grab_hparams(v)hparams[k]=hparams_to_addreturnhparams
def_grab_hparams(obj)->Any:"""Helper function parses objects for their hyperparameters going only one level deep."""# If the object has already grabbed its hyperparameters (it calls extract_hparams inside __init__)# then parse hparams attribute (which is a dict) and name those sub-hyperparametersifhasattr(obj,'local_hparams'):return{obj.__class__.__name__:obj.local_hparams}elifisinstance(obj,List)orisinstance(obj,Tuple):return[_get_obj_repr(sub_obj)forsub_objinobj]elifisinstance(obj,Dict):return{k:_get_obj_repr(sub_obj)fork,sub_objinobj.items()}else:return_get_obj_repr(obj)def_get_obj_repr(obj:Any):"""Returns best representation of object. Args: obj (Any): the object. Returns: obj if obj is None or it is a int, float, str, bool type. Otherwise returns obj.__class__.__name__. """ifany([isinstance(obj,type_)fortype_in[int,float,str,bool]])orobjisNone:returnobjelse:returnobj.__class__.__name__
[docs]defconvert_nested_dict_to_flat_dict(nested_dict:Dict,prefix='')->Dict:"""Takes in a nested dict converts it to a flat dict with keys separated by slashes. Args: nested_dict (Dict): A dictionary containing at least one other dictionary. prefix (str, optional): A prefix to left append to the keys in the dictionary. 'Defaults to ''. Returns: Dict: A flat dictionary representation of the nested one (contains no other dictionaries inside of it) """flat_dict={}fork,vinnested_dict.items():key=prefix+'/'+kifprefix!=''elsek# Recursively crawl sub-dictionary.ifisinstance(v,dict):sub_flat_dict=convert_nested_dict_to_flat_dict(prefix=key,nested_dict=v)flat_dict.update(sub_flat_dict)else:flat_dict[key]=vreturnflat_dict
[docs]defconvert_flat_dict_to_nested_dict(flat_dict:Dict)->Dict:"""Converts flat dictionary separated by slashes to nested dictionary. Args: flat_dict (Dict): flat dictionary containing no sub-dictionary with keys separated by slashes. e.g. {'a':1, 'b/c':2} Returns: Dict: a nested dict. """nested_dict={}fork,vinflat_dict.items():# Initially sub_dict is the main nested_dict, but we will continually update it to be the# sub-dictionary of sub_dict.sub_dict=nested_dictsub_keys=k.split('/')forsub_keyinsub_keys[:-1]:ifsub_keynotinsub_dict:# Create a new sub-dictionary inside of sub_dict.sub_dict[sub_key]={}# Change the sub_dict reference to be the sub-dictionary of sub_dict (i.e. go one level deeper).sub_dict=sub_dict[sub_key]# The last key in sub_keys does not map to a dict. It just maps to v.sub_dict[sub_keys[-1]]=v# Changes to sub_dict will be reflected in nested_dict, so we can just return nested_dict.returnnested_dict