We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
SupervisedWandbRunner logs wrong number of epochs to WandB
**Describe the bug**
Catalyst 20.02.4
`WandbRunner` is logging wrong number of epochs to WandB

**To Reproduce**
Steps to reproduce the behavior:
```
from catalyst import dl
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

class Projector(nn.Module):
    def __init__(self, input_size):
        super().__init__()
        self.linear = nn.Linear(input_size, 1)
        
    def forward(self, X):
        return self.linear(X).squeeze(-1)

X = torch.rand(16, 10)
y = torch.rand(X.shape[0])
model = Projector(X.shape[1])
dataset = TensorDataset(X, y)
loader = DataLoader(dataset, batch_size=8)
runner = dl.SupervisedWandbRunner()

runner.train(
    model=model,
    loaders={
        "train": loader,
        "valid": loader
    },
    criterion=nn.MSELoss(),
    optimizer=optim.Adam(model.parameters()),
    logdir="log_xxx_000",
    monitoring_params={
        "project": "wandb_wrong_epochs"
    },
    num_epochs=10
)
```

**Expected behavior**
In WandB I see two plots with `MSELoss` with exactly 10 epochs

**Actual behaviour**
In WandB I see two plots with `MSELoss` with 20 epochs (but each has exactly 10 dots)

**Screenshots**
Look on number of steps. It has 20 steps. But should have 10.
![image](https://user-images.githubusercontent.com/9883873/75762200-564c6900-5d4b-11ea-87e3-20ef0e840725.png)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `catalyst/contrib/dl/runner/wandb.py`
Content:
```
1 from typing import Dict, List  # isort:skip
2 from pathlib import Path
3 import shutil
4 
5 import wandb
6 
7 from catalyst.dl import utils
8 from catalyst.dl.core import Experiment, Runner
9 from catalyst.dl.experiment import ConfigExperiment
10 from catalyst.dl.runner import SupervisedRunner
11 
12 
13 class WandbRunner(Runner):
14     """
15     Runner wrapper with wandb integration hooks.
16     """
17     @staticmethod
18     def _log_metrics(metrics: Dict, mode: str, suffix: str = ""):
19         def key_locate(key: str):
20             """
21             Wandb uses first symbol _ for it service purposes
22             because of that fact, we can not send original metric names
23 
24             Args:
25                 key: metric name
26             Returns:
27                 formatted metric name
28             """
29             if key.startswith("_"):
30                 return key[1:]
31             return key
32 
33         metrics = {
34             f"{key_locate(key)}/{mode}{suffix}": value
35             for key, value in metrics.items()
36         }
37         wandb.log(metrics)
38 
39     def _init(
40         self,
41         log_on_batch_end: bool = False,
42         log_on_epoch_end: bool = True,
43         checkpoints_glob: List = None,
44     ):
45         super()._init()
46         self.log_on_batch_end = log_on_batch_end
47         self.log_on_epoch_end = log_on_epoch_end
48         self.checkpoints_glob = checkpoints_glob
49 
50         if (self.log_on_batch_end and not self.log_on_epoch_end) \
51                 or (not self.log_on_batch_end and self.log_on_epoch_end):
52             self.batch_log_suffix = ""
53             self.epoch_log_suffix = ""
54         else:
55             self.batch_log_suffix = "_batch"
56             self.epoch_log_suffix = "_epoch"
57 
58     def _pre_experiment_hook(self, experiment: Experiment):
59         monitoring_params = experiment.monitoring_params
60         monitoring_params["dir"] = str(Path(experiment.logdir).absolute())
61 
62         log_on_batch_end: bool = \
63             monitoring_params.pop("log_on_batch_end", False)
64         log_on_epoch_end: bool = \
65             monitoring_params.pop("log_on_epoch_end", True)
66         checkpoints_glob: List[str] = \
67             monitoring_params.pop("checkpoints_glob", [])
68         self._init(
69             log_on_batch_end=log_on_batch_end,
70             log_on_epoch_end=log_on_epoch_end,
71             checkpoints_glob=checkpoints_glob,
72         )
73         if isinstance(experiment, ConfigExperiment):
74             exp_config = utils.flatten_dict(experiment.stages_config)
75             wandb.init(**monitoring_params, config=exp_config)
76         else:
77             wandb.init(**monitoring_params)
78 
79     def _post_experiment_hook(self, experiment: Experiment):
80         # @TODO: add params for artefacts logging
81         logdir_src = Path(experiment.logdir)
82         # logdir_dst = wandb.run.dir
83         #
84         # exclude = ["wandb", "checkpoints"]
85         # logdir_files = list(logdir_src.glob("*"))
86         # logdir_files = list(
87         #     filter(
88         #         lambda x: all(z not in str(x) for z in exclude), logdir_files
89         #     )
90         # )
91         #
92         # for subdir in logdir_files:
93         #     if subdir.is_dir():
94         #         os.makedirs(f"{logdir_dst}/{subdir.name}", exist_ok=True)
95         #         shutil.rmtree(f"{logdir_dst}/{subdir.name}")
96         #         shutil.copytree(
97         #             f"{str(subdir.absolute())}",
98         #             f"{logdir_dst}/{subdir.name}"
99         #         )
100         #     else:
101         #         shutil.copy2(
102         #             f"{str(subdir.absolute())}",
103         #             f"{logdir_dst}/{subdir.name}"
104         #         )
105         #
106         checkpoints_src = logdir_src.joinpath("checkpoints")
107         checkpoints_dst = Path(wandb.run.dir).joinpath("checkpoints")
108         # os.makedirs(checkpoints_dst, exist_ok=True)
109 
110         checkpoint_paths = []
111         for glob in self.checkpoints_glob:
112             checkpoint_paths.extend(list(checkpoints_src.glob(glob)))
113         checkpoint_paths = list(set(checkpoint_paths))
114         for checkpoint_path in checkpoint_paths:
115             shutil.copy2(
116                 f"{str(checkpoint_path.absolute())}",
117                 f"{checkpoints_dst}/{checkpoint_path.name}"
118             )
119 
120     def _run_batch(self, batch):
121         super()._run_batch(batch=batch)
122         if self.log_on_batch_end:
123             mode = self.state.loader_name
124             metrics = self.state.batch_metrics
125             self._log_metrics(
126                 metrics=metrics, mode=mode, suffix=self.batch_log_suffix
127             )
128 
129     def _run_epoch(self, stage: str, epoch: int):
130         super()._run_epoch(stage=stage, epoch=epoch)
131         if self.log_on_epoch_end:
132             mode_metrics = utils.split_dict_to_subdicts(
133                 dct=self.state.epoch_metrics,
134                 prefixes=list(self.state.loaders.keys()),
135                 extra_key="_base",
136             )
137             for mode, metrics in mode_metrics.items():
138                 self._log_metrics(
139                     metrics=metrics, mode=mode, suffix=self.epoch_log_suffix
140                 )
141 
142     def run_experiment(self, experiment: Experiment):
143         self._pre_experiment_hook(experiment=experiment)
144         super().run_experiment(experiment=experiment)
145         self._post_experiment_hook(experiment=experiment)
146 
147 
148 class SupervisedWandbRunner(WandbRunner, SupervisedRunner):
149     pass
150 
151 
152 __all__ = ["WandbRunner", "SupervisedWandbRunner"]
153
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/catalyst/contrib/dl/runner/wandb.py b/catalyst/contrib/dl/runner/wandb.py
--- a/catalyst/contrib/dl/runner/wandb.py
+++ b/catalyst/contrib/dl/runner/wandb.py
@@ -15,7 +15,9 @@
     Runner wrapper with wandb integration hooks.
     """
     @staticmethod
-    def _log_metrics(metrics: Dict, mode: str, suffix: str = ""):
+    def _log_metrics(
+        metrics: Dict, mode: str, suffix: str = "", commit: bool = True
+    ):
         def key_locate(key: str):
             """
             Wandb uses first symbol _ for it service purposes
@@ -34,7 +36,7 @@
             f"{key_locate(key)}/{mode}{suffix}": value
             for key, value in metrics.items()
         }
-        wandb.log(metrics)
+        wandb.log(metrics, commit=commit)
 
     def _init(
         self,
@@ -123,7 +125,10 @@
             mode = self.state.loader_name
             metrics = self.state.batch_metrics
             self._log_metrics(
-                metrics=metrics, mode=mode, suffix=self.batch_log_suffix
+                metrics=metrics,
+                mode=mode,
+                suffix=self.batch_log_suffix,
+                commit=True
             )
 
     def _run_epoch(self, stage: str, epoch: int):
@@ -136,17 +141,26 @@
             )
             for mode, metrics in mode_metrics.items():
                 self._log_metrics(
-                    metrics=metrics, mode=mode, suffix=self.epoch_log_suffix
+                    metrics=metrics,
+                    mode=mode,
+                    suffix=self.epoch_log_suffix,
+                    commit=False
                 )
+            wandb.log(commit=True)
 
     def run_experiment(self, experiment: Experiment):
+        """Starts experiment
+
+        Args:
+            experiment (Experiment): experiment class
+        """
         self._pre_experiment_hook(experiment=experiment)
         super().run_experiment(experiment=experiment)
         self._post_experiment_hook(experiment=experiment)
 
 
 class SupervisedWandbRunner(WandbRunner, SupervisedRunner):
-    pass
+    """SupervisedRunner with WandB"""
 
 
 __all__ = ["WandbRunner", "SupervisedWandbRunner"]

{"golden_diff": "diff --git a/catalyst/contrib/dl/runner/wandb.py b/catalyst/contrib/dl/runner/wandb.py\n--- a/catalyst/contrib/dl/runner/wandb.py\n+++ b/catalyst/contrib/dl/runner/wandb.py\n@@ -15,7 +15,9 @@\n     Runner wrapper with wandb integration hooks.\n     \"\"\"\n     @staticmethod\n-    def _log_metrics(metrics: Dict, mode: str, suffix: str = \"\"):\n+    def _log_metrics(\n+        metrics: Dict, mode: str, suffix: str = \"\", commit: bool = True\n+    ):\n         def key_locate(key: str):\n             \"\"\"\n             Wandb uses first symbol _ for it service purposes\n@@ -34,7 +36,7 @@\n             f\"{key_locate(key)}/{mode}{suffix}\": value\n             for key, value in metrics.items()\n         }\n-        wandb.log(metrics)\n+        wandb.log(metrics, commit=commit)\n \n     def _init(\n         self,\n@@ -123,7 +125,10 @@\n             mode = self.state.loader_name\n             metrics = self.state.batch_metrics\n             self._log_metrics(\n-                metrics=metrics, mode=mode, suffix=self.batch_log_suffix\n+                metrics=metrics,\n+                mode=mode,\n+                suffix=self.batch_log_suffix,\n+                commit=True\n             )\n \n     def _run_epoch(self, stage: str, epoch: int):\n@@ -136,17 +141,26 @@\n             )\n             for mode, metrics in mode_metrics.items():\n                 self._log_metrics(\n-                    metrics=metrics, mode=mode, suffix=self.epoch_log_suffix\n+                    metrics=metrics,\n+                    mode=mode,\n+                    suffix=self.epoch_log_suffix,\n+                    commit=False\n                 )\n+            wandb.log(commit=True)\n \n     def run_experiment(self, experiment: Experiment):\n+        \"\"\"Starts experiment\n+\n+        Args:\n+            experiment (Experiment): experiment class\n+        \"\"\"\n         self._pre_experiment_hook(experiment=experiment)\n         super().run_experiment(experiment=experiment)\n         self._post_experiment_hook(experiment=experiment)\n \n \n class SupervisedWandbRunner(WandbRunner, SupervisedRunner):\n-    pass\n+    \"\"\"SupervisedRunner with WandB\"\"\"\n \n \n __all__ = [\"WandbRunner\", \"SupervisedWandbRunner\"]\n", "issue": "SupervisedWandbRunner logs wrong number of epochs to WandB\n**Describe the bug**\r\nCatalyst 20.02.4\r\n`WandbRunner` is logging wrong number of epochs to WandB\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n```\r\nfrom catalyst import dl\r\nimport torch\r\nimport torch.nn as nn\r\nimport torch.optim as optim\r\nfrom torch.utils.data import DataLoader, TensorDataset\r\n\r\nclass Projector(nn.Module):\r\n    def __init__(self, input_size):\r\n        super().__init__()\r\n        self.linear = nn.Linear(input_size, 1)\r\n        \r\n    def forward(self, X):\r\n        return self.linear(X).squeeze(-1)\r\n\r\nX = torch.rand(16, 10)\r\ny = torch.rand(X.shape[0])\r\nmodel = Projector(X.shape[1])\r\ndataset = TensorDataset(X, y)\r\nloader = DataLoader(dataset, batch_size=8)\r\nrunner = dl.SupervisedWandbRunner()\r\n\r\nrunner.train(\r\n    model=model,\r\n    loaders={\r\n        \"train\": loader,\r\n        \"valid\": loader\r\n    },\r\n    criterion=nn.MSELoss(),\r\n    optimizer=optim.Adam(model.parameters()),\r\n    logdir=\"log_xxx_000\",\r\n    monitoring_params={\r\n        \"project\": \"wandb_wrong_epochs\"\r\n    },\r\n    num_epochs=10\r\n)\r\n```\r\n\r\n**Expected behavior**\r\nIn WandB I see two plots with `MSELoss` with exactly 10 epochs\r\n\r\n**Actual behaviour**\r\nIn WandB I see two plots with `MSELoss` with 20 epochs (but each has exactly 10 dots)\r\n\r\n**Screenshots**\r\nLook on number of steps. It has 20 steps. But should have 10.\r\n![image](https://user-images.githubusercontent.com/9883873/75762200-564c6900-5d4b-11ea-87e3-20ef0e840725.png)\r\n\n", "before_files": [{"content": "from typing import Dict, List  # isort:skip\nfrom pathlib import Path\nimport shutil\n\nimport wandb\n\nfrom catalyst.dl import utils\nfrom catalyst.dl.core import Experiment, Runner\nfrom catalyst.dl.experiment import ConfigExperiment\nfrom catalyst.dl.runner import SupervisedRunner\n\n\nclass WandbRunner(Runner):\n    \"\"\"\n    Runner wrapper with wandb integration hooks.\n    \"\"\"\n    @staticmethod\n    def _log_metrics(metrics: Dict, mode: str, suffix: str = \"\"):\n        def key_locate(key: str):\n            \"\"\"\n            Wandb uses first symbol _ for it service purposes\n            because of that fact, we can not send original metric names\n\n            Args:\n                key: metric name\n            Returns:\n                formatted metric name\n            \"\"\"\n            if key.startswith(\"_\"):\n                return key[1:]\n            return key\n\n        metrics = {\n            f\"{key_locate(key)}/{mode}{suffix}\": value\n            for key, value in metrics.items()\n        }\n        wandb.log(metrics)\n\n    def _init(\n        self,\n        log_on_batch_end: bool = False,\n        log_on_epoch_end: bool = True,\n        checkpoints_glob: List = None,\n    ):\n        super()._init()\n        self.log_on_batch_end = log_on_batch_end\n        self.log_on_epoch_end = log_on_epoch_end\n        self.checkpoints_glob = checkpoints_glob\n\n        if (self.log_on_batch_end and not self.log_on_epoch_end) \\\n                or (not self.log_on_batch_end and self.log_on_epoch_end):\n            self.batch_log_suffix = \"\"\n            self.epoch_log_suffix = \"\"\n        else:\n            self.batch_log_suffix = \"_batch\"\n            self.epoch_log_suffix = \"_epoch\"\n\n    def _pre_experiment_hook(self, experiment: Experiment):\n        monitoring_params = experiment.monitoring_params\n        monitoring_params[\"dir\"] = str(Path(experiment.logdir).absolute())\n\n        log_on_batch_end: bool = \\\n            monitoring_params.pop(\"log_on_batch_end\", False)\n        log_on_epoch_end: bool = \\\n            monitoring_params.pop(\"log_on_epoch_end\", True)\n        checkpoints_glob: List[str] = \\\n            monitoring_params.pop(\"checkpoints_glob\", [])\n        self._init(\n            log_on_batch_end=log_on_batch_end,\n            log_on_epoch_end=log_on_epoch_end,\n            checkpoints_glob=checkpoints_glob,\n        )\n        if isinstance(experiment, ConfigExperiment):\n            exp_config = utils.flatten_dict(experiment.stages_config)\n            wandb.init(**monitoring_params, config=exp_config)\n        else:\n            wandb.init(**monitoring_params)\n\n    def _post_experiment_hook(self, experiment: Experiment):\n        # @TODO: add params for artefacts logging\n        logdir_src = Path(experiment.logdir)\n        # logdir_dst = wandb.run.dir\n        #\n        # exclude = [\"wandb\", \"checkpoints\"]\n        # logdir_files = list(logdir_src.glob(\"*\"))\n        # logdir_files = list(\n        #     filter(\n        #         lambda x: all(z not in str(x) for z in exclude), logdir_files\n        #     )\n        # )\n        #\n        # for subdir in logdir_files:\n        #     if subdir.is_dir():\n        #         os.makedirs(f\"{logdir_dst}/{subdir.name}\", exist_ok=True)\n        #         shutil.rmtree(f\"{logdir_dst}/{subdir.name}\")\n        #         shutil.copytree(\n        #             f\"{str(subdir.absolute())}\",\n        #             f\"{logdir_dst}/{subdir.name}\"\n        #         )\n        #     else:\n        #         shutil.copy2(\n        #             f\"{str(subdir.absolute())}\",\n        #             f\"{logdir_dst}/{subdir.name}\"\n        #         )\n        #\n        checkpoints_src = logdir_src.joinpath(\"checkpoints\")\n        checkpoints_dst = Path(wandb.run.dir).joinpath(\"checkpoints\")\n        # os.makedirs(checkpoints_dst, exist_ok=True)\n\n        checkpoint_paths = []\n        for glob in self.checkpoints_glob:\n            checkpoint_paths.extend(list(checkpoints_src.glob(glob)))\n        checkpoint_paths = list(set(checkpoint_paths))\n        for checkpoint_path in checkpoint_paths:\n            shutil.copy2(\n                f\"{str(checkpoint_path.absolute())}\",\n                f\"{checkpoints_dst}/{checkpoint_path.name}\"\n            )\n\n    def _run_batch(self, batch):\n        super()._run_batch(batch=batch)\n        if self.log_on_batch_end:\n            mode = self.state.loader_name\n            metrics = self.state.batch_metrics\n            self._log_metrics(\n                metrics=metrics, mode=mode, suffix=self.batch_log_suffix\n            )\n\n    def _run_epoch(self, stage: str, epoch: int):\n        super()._run_epoch(stage=stage, epoch=epoch)\n        if self.log_on_epoch_end:\n            mode_metrics = utils.split_dict_to_subdicts(\n                dct=self.state.epoch_metrics,\n                prefixes=list(self.state.loaders.keys()),\n                extra_key=\"_base\",\n            )\n            for mode, metrics in mode_metrics.items():\n                self._log_metrics(\n                    metrics=metrics, mode=mode, suffix=self.epoch_log_suffix\n                )\n\n    def run_experiment(self, experiment: Experiment):\n        self._pre_experiment_hook(experiment=experiment)\n        super().run_experiment(experiment=experiment)\n        self._post_experiment_hook(experiment=experiment)\n\n\nclass SupervisedWandbRunner(WandbRunner, SupervisedRunner):\n    pass\n\n\n__all__ = [\"WandbRunner\", \"SupervisedWandbRunner\"]\n", "path": "catalyst/contrib/dl/runner/wandb.py"}], "after_files": [{"content": "from typing import Dict, List  # isort:skip\nfrom pathlib import Path\nimport shutil\n\nimport wandb\n\nfrom catalyst.dl import utils\nfrom catalyst.dl.core import Experiment, Runner\nfrom catalyst.dl.experiment import ConfigExperiment\nfrom catalyst.dl.runner import SupervisedRunner\n\n\nclass WandbRunner(Runner):\n    \"\"\"\n    Runner wrapper with wandb integration hooks.\n    \"\"\"\n    @staticmethod\n    def _log_metrics(\n        metrics: Dict, mode: str, suffix: str = \"\", commit: bool = True\n    ):\n        def key_locate(key: str):\n            \"\"\"\n            Wandb uses first symbol _ for it service purposes\n            because of that fact, we can not send original metric names\n\n            Args:\n                key: metric name\n            Returns:\n                formatted metric name\n            \"\"\"\n            if key.startswith(\"_\"):\n                return key[1:]\n            return key\n\n        metrics = {\n            f\"{key_locate(key)}/{mode}{suffix}\": value\n            for key, value in metrics.items()\n        }\n        wandb.log(metrics, commit=commit)\n\n    def _init(\n        self,\n        log_on_batch_end: bool = False,\n        log_on_epoch_end: bool = True,\n        checkpoints_glob: List = None,\n    ):\n        super()._init()\n        self.log_on_batch_end = log_on_batch_end\n        self.log_on_epoch_end = log_on_epoch_end\n        self.checkpoints_glob = checkpoints_glob\n\n        if (self.log_on_batch_end and not self.log_on_epoch_end) \\\n                or (not self.log_on_batch_end and self.log_on_epoch_end):\n            self.batch_log_suffix = \"\"\n            self.epoch_log_suffix = \"\"\n        else:\n            self.batch_log_suffix = \"_batch\"\n            self.epoch_log_suffix = \"_epoch\"\n\n    def _pre_experiment_hook(self, experiment: Experiment):\n        monitoring_params = experiment.monitoring_params\n        monitoring_params[\"dir\"] = str(Path(experiment.logdir).absolute())\n\n        log_on_batch_end: bool = \\\n            monitoring_params.pop(\"log_on_batch_end\", False)\n        log_on_epoch_end: bool = \\\n            monitoring_params.pop(\"log_on_epoch_end\", True)\n        checkpoints_glob: List[str] = \\\n            monitoring_params.pop(\"checkpoints_glob\", [])\n        self._init(\n            log_on_batch_end=log_on_batch_end,\n            log_on_epoch_end=log_on_epoch_end,\n            checkpoints_glob=checkpoints_glob,\n        )\n        if isinstance(experiment, ConfigExperiment):\n            exp_config = utils.flatten_dict(experiment.stages_config)\n            wandb.init(**monitoring_params, config=exp_config)\n        else:\n            wandb.init(**monitoring_params)\n\n    def _post_experiment_hook(self, experiment: Experiment):\n        # @TODO: add params for artefacts logging\n        logdir_src = Path(experiment.logdir)\n        # logdir_dst = wandb.run.dir\n        #\n        # exclude = [\"wandb\", \"checkpoints\"]\n        # logdir_files = list(logdir_src.glob(\"*\"))\n        # logdir_files = list(\n        #     filter(\n        #         lambda x: all(z not in str(x) for z in exclude), logdir_files\n        #     )\n        # )\n        #\n        # for subdir in logdir_files:\n        #     if subdir.is_dir():\n        #         os.makedirs(f\"{logdir_dst}/{subdir.name}\", exist_ok=True)\n        #         shutil.rmtree(f\"{logdir_dst}/{subdir.name}\")\n        #         shutil.copytree(\n        #             f\"{str(subdir.absolute())}\",\n        #             f\"{logdir_dst}/{subdir.name}\"\n        #         )\n        #     else:\n        #         shutil.copy2(\n        #             f\"{str(subdir.absolute())}\",\n        #             f\"{logdir_dst}/{subdir.name}\"\n        #         )\n        #\n        checkpoints_src = logdir_src.joinpath(\"checkpoints\")\n        checkpoints_dst = Path(wandb.run.dir).joinpath(\"checkpoints\")\n        # os.makedirs(checkpoints_dst, exist_ok=True)\n\n        checkpoint_paths = []\n        for glob in self.checkpoints_glob:\n            checkpoint_paths.extend(list(checkpoints_src.glob(glob)))\n        checkpoint_paths = list(set(checkpoint_paths))\n        for checkpoint_path in checkpoint_paths:\n            shutil.copy2(\n                f\"{str(checkpoint_path.absolute())}\",\n                f\"{checkpoints_dst}/{checkpoint_path.name}\"\n            )\n\n    def _run_batch(self, batch):\n        super()._run_batch(batch=batch)\n        if self.log_on_batch_end:\n            mode = self.state.loader_name\n            metrics = self.state.batch_metrics\n            self._log_metrics(\n                metrics=metrics,\n                mode=mode,\n                suffix=self.batch_log_suffix,\n                commit=True\n            )\n\n    def _run_epoch(self, stage: str, epoch: int):\n        super()._run_epoch(stage=stage, epoch=epoch)\n        if self.log_on_epoch_end:\n            mode_metrics = utils.split_dict_to_subdicts(\n                dct=self.state.epoch_metrics,\n                prefixes=list(self.state.loaders.keys()),\n                extra_key=\"_base\",\n            )\n            for mode, metrics in mode_metrics.items():\n                self._log_metrics(\n                    metrics=metrics,\n                    mode=mode,\n                    suffix=self.epoch_log_suffix,\n                    commit=False\n                )\n            wandb.log(commit=True)\n\n    def run_experiment(self, experiment: Experiment):\n        \"\"\"Starts experiment\n\n        Args:\n            experiment (Experiment): experiment class\n        \"\"\"\n        self._pre_experiment_hook(experiment=experiment)\n        super().run_experiment(experiment=experiment)\n        self._post_experiment_hook(experiment=experiment)\n\n\nclass SupervisedWandbRunner(WandbRunner, SupervisedRunner):\n    \"\"\"SupervisedRunner with WandB\"\"\"\n\n\n__all__ = [\"WandbRunner\", \"SupervisedWandbRunner\"]\n", "path": "catalyst/contrib/dl/runner/wandb.py"}]}