Repository: catalyst-team/catalyst

Issue:
Lost parameters in logs_path/configs/_config.json
## 🐛 Bug Report
<!-- A clear and concise description of what the bug is. -->
After running a custom experiment - the parameters given in the config are not saved into /path/to/log/configs/_config.json which gives problems during model tracing using the function `trace_model_from_checkpoint`.

### How To Reproduce
Steps to reproduce the behavior:

1. Comment the line `from .experiment import Experiment` in `examples/cifar_simple/__init__.py` (otherwise you will get the error "AssertionError: Experiment is set both in code and config.")
2. `cd examples`
3. `catalyst-dl run --config ./cifar_simple/config_experiment.yml`
4. Then run `catalyst-dl trace ./logs/cifar_simple/` -> get error "TypeError: 'NoneType' object is not callable"
<!-- If you have a code sample, error messages, stack traces, please provide it here as well -->


<!--#### Code sample--> 
<!-- Ideally attach a minimal code sample to reproduce the decried issue. 
Minimal means having the shortest code but still preserving the bug. -->


#### Screenshots
<!-- If applicable, add screenshots to help explain your problem.  -->


### Expected behavior
<!-- A clear and concise description of what you expected to happen. -->
Tracing doesn't give an error; parameters are written to _config.

### Environment
Please copy and paste the output from our environment collection script
```bash
Catalyst version: 20.11
PyTorch version: 1.7.0
Is debug build: Yes
CUDA used to build PyTorch: 10.2
TensorFlow version: N/A
TensorBoard version: 2.4.0

OS: Linux Mint 19.3 Tricia
GCC version: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
CMake version: version 3.10.2

Python version: 3.8
Is CUDA available: Yes
CUDA runtime version: Could not collect
GPU models and configuration: GPU 0: GeForce RTX 2070 SUPER
Nvidia driver version: 450.80.02
cuDNN version: Could not collect

Versions of relevant libraries:
[pip3] catalyst==20.11
[pip3] catalyst-codestyle==20.6.1
[pip3] catalyst-sphinx-theme==1.1.2
[pip3] efficientnet-pytorch==0.6.3
[pip3] numpy==1.19.4
[pip3] segmentation-models-pytorch==0.1.2
[pip3] tensorboard==2.4.0
[pip3] tensorboard-plugin-wit==1.7.0
[pip3] tensorboardX==2.1
[pip3] torch==1.7.0
[pip3] torchvision==0.8.1
[conda] catalyst                  20.11                    pypi_0    pypi
[conda] catalyst-codestyle        20.6.1                   pypi_0    pypi
[conda] catalyst-sphinx-theme     1.1.2                    pypi_0    pypi
[conda] efficientnet-pytorch      0.6.3                    pypi_0    pypi
[conda] numpy                     1.19.4                   pypi_0    pypi
[conda] segmentation-models-pytorch 0.1.2                    pypi_0    pypi
[conda] tensorboard               2.4.0                    pypi_0    pypi
[conda] tensorboard-plugin-wit    1.7.0                    pypi_0    pypi
[conda] tensorboardx              2.1                      pypi_0    pypi
[conda] torch                     1.7.0                    pypi_0    pypi
[conda] torchvision               0.8.1                    pypi_0    pypi
```

PS
- [x] I know, that I could [join Catalyst slack (#__questions channel)](https://join.slack.com/t/catalyst-team-core/shared_invite/zt-d9miirnn-z86oKDzFMKlMG4fgFdZafw) for issue discussion.



Discussion:
Hi! Thank you for your contribution! Great first issue! Please [join our slack](https://join.slack.com/t/catalyst-team-core/shared_invite/zt-d9miirnn-z86oKDzFMKlMG4fgFdZafw) for issue discussion (#__questions channel).
Working on the hotfix.

Resolving patch:
diff --git a/catalyst/utils/scripts.py b/catalyst/utils/scripts.py
--- a/catalyst/utils/scripts.py
+++ b/catalyst/utils/scripts.py
@@ -1,4 +1,5 @@
 from typing import Callable, Dict, Union
+import copy
 from importlib.util import module_from_spec, spec_from_file_location
 import os
 import pathlib
@@ -56,13 +57,14 @@ def prepare_config_api_components(expdir: pathlib.Path, config: Dict):
     Returns:
         Experiment, Runner, Config for Config API usage.
     """
+    copy_config = copy.deepcopy(config)
     if not isinstance(expdir, pathlib.Path):
         expdir = pathlib.Path(expdir)
     m = import_module(expdir)
     experiment_fn = getattr(m, "Experiment", None)
     runner_fn = getattr(m, "Runner", None)
 
-    experiment_params = config.get("experiment_params", {})
+    experiment_params = copy_config.get("experiment_params", {})
     experiment_from_config = experiment_params.pop("experiment", None)
     assert any(
         x is None for x in (experiment_fn, experiment_from_config)
@@ -70,7 +72,7 @@ def prepare_config_api_components(expdir: pathlib.Path, config: Dict):
     if experiment_fn is None and experiment_from_config is not None:
         experiment_fn = EXPERIMENTS.get(experiment_from_config)
 
-    runner_params = config.get("runner_params", {})
+    runner_params = copy_config.get("runner_params", {})
     runner_from_config = runner_params.pop("runner", None)
     assert any(
         x is None for x in (runner_fn, runner_from_config)
@@ -78,7 +80,7 @@ def prepare_config_api_components(expdir: pathlib.Path, config: Dict):
     if runner_fn is None and runner_from_config is not None:
         runner_fn = RUNNERS.get(runner_from_config)
 
-    experiment = experiment_fn(config)
+    experiment = experiment_fn(copy_config)
     runner = runner_fn(**runner_params)
 
     return experiment, runner, config


Test patch: