mirror of
https://github.com/wassname/pytorch-lightning.git
synced 2026-09-09 11:32:07 +08:00
Support hierarchical dict (#1152)
* Add support for hierarchical dict * Support nested Namespace * Add docstring * Migrate hparam flattening to each logger * Modify URLs in CHANGELOG * typo * Simplify the conditional branch about Namespace Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * Update CHANGELOG.md Co-Authored-By: Jirka Borovec <Borda@users.noreply.github.com> * added examples section to docstring * renamed _dict -> input_dict Co-authored-by: Jirka Borovec <Borda@users.noreply.github.com>
This commit is contained in:
co-authored by
Jirka Borovec
parent
22a7264e9a
commit
01b8991c5a
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for hierarchical `dict` ([#1152](https://github.com/PyTorchLightning/pytorch-lightning/pull/1152))
|
||||
- Added `TrainsLogger` class ([#1122](https://github.com/PyTorchLightning/pytorch-lightning/pull/1122))
|
||||
- Added type hints to `pytorch_lightning.core` ([#946](https://github.com/PyTorchLightning/pytorch-lightning/pull/946))
|
||||
- Added support for IterableDataset in validation and testing ([#1104](https://github.com/PyTorchLightning/pytorch-lightning/pull/1104))
|
||||
|
||||
@@ -53,6 +53,39 @@ class LightningLoggerBase(ABC):
|
||||
|
||||
return params
|
||||
|
||||
@staticmethod
|
||||
def _flatten_dict(params: Dict[str, Any], delimiter: str = '/') -> Dict[str, Any]:
|
||||
"""Flatten hierarchical dict e.g. {'a': {'b': 'c'}} -> {'a/b': 'c'}.
|
||||
|
||||
Args:
|
||||
params: Dictionary contains hparams
|
||||
delimiter: Delimiter to express the hierarchy. Defaults to '/'.
|
||||
|
||||
Returns:
|
||||
Flatten dict.
|
||||
|
||||
Examples:
|
||||
>>> LightningLoggerBase._flatten_dict({'a': {'b': 'c'}})
|
||||
{'a/b': 'c'}
|
||||
>>> LightningLoggerBase._flatten_dict({'a': {'b': 123}})
|
||||
{'a/b': 123}
|
||||
"""
|
||||
|
||||
def _dict_generator(input_dict, prefixes=None):
|
||||
prefixes = prefixes[:] if prefixes else []
|
||||
if isinstance(input_dict, dict):
|
||||
for key, value in input_dict.items():
|
||||
if isinstance(value, (dict, Namespace)):
|
||||
value = vars(value) if isinstance(value, Namespace) else value
|
||||
for d in _dict_generator(value, prefixes + [key]):
|
||||
yield d
|
||||
else:
|
||||
yield prefixes + [key, value if value is not None else str(None)]
|
||||
else:
|
||||
yield prefixes + [input_dict if input_dict is None else str(input_dict)]
|
||||
|
||||
return {delimiter.join(keys): val for *keys, val in _dict_generator(params)}
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_params(params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Returns params with non-primitvies converted to strings for logging
|
||||
|
||||
@@ -163,6 +163,7 @@ class CometLogger(LightningLoggerBase):
|
||||
@rank_zero_only
|
||||
def log_hyperparams(self, params: Union[Dict[str, Any], Namespace]) -> None:
|
||||
params = self._convert_params(params)
|
||||
params = self._flatten_dict(params)
|
||||
self.experiment.log_parameters(params)
|
||||
|
||||
@rank_zero_only
|
||||
|
||||
@@ -89,6 +89,7 @@ class MLFlowLogger(LightningLoggerBase):
|
||||
@rank_zero_only
|
||||
def log_hyperparams(self, params: Union[Dict[str, Any], Namespace]) -> None:
|
||||
params = self._convert_params(params)
|
||||
params = self._flatten_dict(params)
|
||||
for k, v in params.items():
|
||||
self.experiment.log_param(self.run_id, k, v)
|
||||
|
||||
|
||||
@@ -222,6 +222,7 @@ class NeptuneLogger(LightningLoggerBase):
|
||||
@rank_zero_only
|
||||
def log_hyperparams(self, params: Union[Dict[str, Any], Namespace]) -> None:
|
||||
params = self._convert_params(params)
|
||||
params = self._flatten_dict(params)
|
||||
for key, val in params.items():
|
||||
self.experiment.set_property(f'param__{key}', val)
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ class TensorBoardLogger(LightningLoggerBase):
|
||||
@rank_zero_only
|
||||
def log_hyperparams(self, params: Union[Dict[str, Any], Namespace]) -> None:
|
||||
params = self._convert_params(params)
|
||||
params = self._flatten_dict(params)
|
||||
sanitized_params = self._sanitize_params(params)
|
||||
|
||||
if parse_version(torch.__version__) < parse_version("1.3.0"):
|
||||
|
||||
@@ -96,6 +96,7 @@ class TestTubeLogger(LightningLoggerBase):
|
||||
# TODO: HACK figure out where this is being set to true
|
||||
self.experiment.debug = self.debug
|
||||
params = self._convert_params(params)
|
||||
params = self._flatten_dict(params)
|
||||
self.experiment.argparse(Namespace(**params))
|
||||
|
||||
@rank_zero_only
|
||||
|
||||
@@ -130,10 +130,10 @@ class TrainsLogger(LightningLoggerBase):
|
||||
return None
|
||||
if not params:
|
||||
return
|
||||
if isinstance(params, dict):
|
||||
self._trains.connect(params)
|
||||
else:
|
||||
self._trains.connect(vars(params))
|
||||
|
||||
params = self._convert_params(params)
|
||||
params = self._flatten_dict(params)
|
||||
self._trains.connect(params)
|
||||
|
||||
@rank_zero_only
|
||||
def log_metrics(self, metrics: Dict[str, float], step: Optional[int] = None) -> None:
|
||||
|
||||
@@ -108,8 +108,9 @@ def test_tensorboard_log_hyperparams(tmpdir):
|
||||
"int": 1,
|
||||
"string": "abc",
|
||||
"bool": True,
|
||||
"dict": {'a': {'b': 'c'}},
|
||||
"list": [1, 2, 3],
|
||||
"namespace": Namespace(foo=3),
|
||||
"namespace": Namespace(foo=Namespace(bar='buzz')),
|
||||
"layer": torch.nn.BatchNorm1d
|
||||
}
|
||||
logger.log_hyperparams(hparams)
|
||||
|
||||
Reference in New Issue
Block a user