Skip to content

Commit 9c1e688

Browse files
muellerzrsguggerpacman100
authored
Allow for kwargs to be passed to trackers (#542)
* Allow for kwarg passing to trackers Co-authored-by: Sylvain Gugger <35901082+sgugger@users.noreply.github.com> Co-authored-by: Sourab Mangrulkar <13534540+pacman100@users.noreply.github.com>
1 parent d6c72bd commit 9c1e688

3 files changed

Lines changed: 65 additions & 23 deletions

File tree

src/accelerate/accelerator.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,7 @@ def wait_for_everyone(self):
927927
"""
928928
wait_for_everyone()
929929

930-
def init_trackers(self, project_name: str, config: Optional[dict] = None):
930+
def init_trackers(self, project_name: str, config: Optional[dict] = None, init_kwargs: Optional[dict] = {}):
931931
"""
932932
Initializes a run for all trackers stored in `self.log_with`, potentially with starting configurations
933933
@@ -936,6 +936,12 @@ def init_trackers(self, project_name: str, config: Optional[dict] = None):
936936
The name of the project. All trackers will save their data based on this
937937
config (`dict`, *optional*):
938938
Optional starting configuration to be logged.
939+
init_kwargs (`dict`, *optional*):
940+
A nested dictionary of kwargs to be passed to a specific tracker's `__init__` function. Should be
941+
formatted like this:
942+
```python
943+
{"wandb": {"tags": ["tag_a", "tag_b"]}}
944+
```
939945
"""
940946
self.trackers = []
941947
for tracker in self.log_with:
@@ -946,14 +952,16 @@ def init_trackers(self, project_name: str, config: Optional[dict] = None):
946952
tracker_init = LOGGER_TYPE_TO_CLASS[str(tracker)]
947953
if getattr(tracker_init, "requires_logging_directory"):
948954
# We can skip this check since it was done in `__init__`
949-
self.trackers.append(tracker_init(project_name, self.logging_dir))
955+
self.trackers.append(
956+
tracker_init(project_name, self.logging_dir, **init_kwargs.get(str(tracker), {}))
957+
)
950958
else:
951-
self.trackers.append(tracker_init(project_name))
959+
self.trackers.append(tracker_init(project_name, **init_kwargs.get(str(tracker), {})))
952960
if config is not None:
953961
for tracker in self.trackers:
954962
tracker.store_init_configuration(config)
955963

956-
def log(self, values: dict, step: Optional[int] = None):
964+
def log(self, values: dict, step: Optional[int] = None, log_kwargs: Optional[dict] = {}):
957965
"""
958966
Logs `values` to all stored trackers in `self.trackers`.
959967
@@ -962,10 +970,16 @@ def log(self, values: dict, step: Optional[int] = None):
962970
Values should be a dictionary-like object containing only types `int`, `float`, or `str`.
963971
step (`int`, *optional*):
964972
The run step. If included, the log will be affiliated with this step.
973+
log_kwargs (`dict`, *optional*):
974+
A nested dictionary of kwargs to be passed to a specific tracker's `log` function. Should be formatted
975+
like this:
976+
```python
977+
{"wandb": {"tags": ["tag_a", "tag_b"]}}
978+
```
965979
"""
966980
if self.is_main_process:
967981
for tracker in self.trackers:
968-
tracker.log(values, step=step)
982+
tracker.log(values, step=step, **log_kwargs.get(tracker.name, {}))
969983

970984
def end_training(self):
971985
"""

src/accelerate/tracking.py

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,16 @@ def get_available_trackers():
5252
class GeneralTracker(object, metaclass=ABCMeta):
5353
"""
5454
A base Tracker class to be used for all logging integration implementations.
55+
56+
Each function should take in `**kwargs` that will automatically be passed in from a base dictionary provided to
57+
[`Accelerator`]
5558
"""
5659

60+
@abstractproperty
61+
def name(self):
62+
"String representation of the python class name"
63+
pass
64+
5765
@abstractproperty
5866
def requires_logging_directory(self):
5967
"""
@@ -75,7 +83,7 @@ def store_init_configuration(self, values: dict):
7583
pass
7684

7785
@abstractmethod
78-
def log(self, values: dict, step: Optional[int]):
86+
def log(self, values: dict, step: Optional[int], **kwargs):
7987
"""
8088
Logs `values` to the current run. Base `log` implementations of a tracking API should go in here, along with
8189
special behavior for the `step parameter.
@@ -105,14 +113,17 @@ class TensorBoardTracker(GeneralTracker):
105113
The name of the experiment run
106114
logging_dir (`str`, `os.PathLike`):
107115
Location for TensorBoard logs to be stored.
116+
kwargs:
117+
Additional key word arguments passed along to the `tensorboard.SummaryWriter.__init__` method.
108118
"""
109119

120+
name = "tensorboard"
110121
requires_logging_directory = True
111122

112-
def __init__(self, run_name: str, logging_dir: Optional[Union[str, os.PathLike]]):
123+
def __init__(self, run_name: str, logging_dir: Optional[Union[str, os.PathLike]], **kwargs):
113124
self.run_name = run_name
114125
self.logging_dir = os.path.join(logging_dir, run_name)
115-
self.writer = tensorboard.SummaryWriter(self.logging_dir)
126+
self.writer = tensorboard.SummaryWriter(self.logging_dir, **kwargs)
116127
logger.info(f"Initialized TensorBoard project {self.run_name} logging to {self.logging_dir}")
117128
logger.info(
118129
"Make sure to log any initial configurations with `self.store_init_configuration` before training!"
@@ -131,7 +142,7 @@ def store_init_configuration(self, values: dict):
131142
self.writer.flush()
132143
logger.info("Stored initial configuration hyperparameters to TensorBoard")
133144

134-
def log(self, values: dict, step: Optional[int] = None):
145+
def log(self, values: dict, step: Optional[int] = None, **kwargs):
135146
"""
136147
Logs `values` to the current run.
137148
@@ -141,14 +152,17 @@ def log(self, values: dict, step: Optional[int] = None):
141152
`str` to `float`/`int`.
142153
step (`int`, *optional*):
143154
The run step. If included, the log will be affiliated with this step.
155+
kwargs:
156+
Additional key word arguments passed along to either `SummaryWriter.add_scaler`,
157+
`SummaryWriter.add_text`, or `SummaryWriter.add_scalers` method based on the contents of `values`.
144158
"""
145159
for k, v in values.items():
146160
if isinstance(v, (int, float)):
147-
self.writer.add_scalar(k, v, global_step=step)
161+
self.writer.add_scalar(k, v, global_step=step, **kwargs)
148162
elif isinstance(v, str):
149-
self.writer.add_text(k, v, global_step=step)
163+
self.writer.add_text(k, v, global_step=step, **kwargs)
150164
elif isinstance(v, dict):
151-
self.writer.add_scalars(k, v, global_step=step)
165+
self.writer.add_scalars(k, v, global_step=step, **kwargs)
152166
self.writer.flush()
153167
logger.info("Successfully logged to TensorBoard")
154168

@@ -167,13 +181,16 @@ class WandBTracker(GeneralTracker):
167181
Args:
168182
run_name (`str`):
169183
The name of the experiment run.
184+
kwargs:
185+
Additional key word arguments passed along to the `wandb.init` method.
170186
"""
171187

188+
name = "wandb"
172189
requires_logging_directory = False
173190

174-
def __init__(self, run_name: str):
191+
def __init__(self, run_name: str, **kwargs):
175192
self.run_name = run_name
176-
self.run = wandb.init(project=self.run_name)
193+
self.run = wandb.init(project=self.run_name, **kwargs)
177194
logger.info(f"Initialized WandB project {self.run_name}")
178195
logger.info(
179196
"Make sure to log any initial configurations with `self.store_init_configuration` before training!"
@@ -191,7 +208,7 @@ def store_init_configuration(self, values: dict):
191208
wandb.config.update(values)
192209
logger.info("Stored initial configuration hyperparameters to WandB")
193210

194-
def log(self, values: dict, step: Optional[int] = None):
211+
def log(self, values: dict, step: Optional[int] = None, **kwargs):
195212
"""
196213
Logs `values` to the current run.
197214
@@ -201,8 +218,10 @@ def log(self, values: dict, step: Optional[int] = None):
201218
`str` to `float`/`int`.
202219
step (`int`, *optional*):
203220
The run step. If included, the log will be affiliated with this step.
221+
kwargs:
222+
Additional key word arguments passed along to the `wandb.log` method.
204223
"""
205-
self.run.log(values, step=step)
224+
self.run.log(values, step=step, **kwargs)
206225
logger.info("Successfully logged to WandB")
207226

208227
def finish(self):
@@ -222,13 +241,16 @@ class CometMLTracker(GeneralTracker):
222241
Args:
223242
run_name (`str`):
224243
The name of the experiment run.
244+
kwargs:
245+
Additional key word arguments passed along to the `Experiment.__init__` method.
225246
"""
226247

248+
name = "comet_ml"
227249
requires_logging_directory = False
228250

229-
def __init__(self, run_name: str):
251+
def __init__(self, run_name: str, **kwargs):
230252
self.run_name = run_name
231-
self.writer = Experiment(project_name=run_name)
253+
self.writer = Experiment(project_name=run_name, **kwargs)
232254
logger.info(f"Initialized CometML project {self.run_name}")
233255
logger.info(
234256
"Make sure to log any initial configurations with `self.store_init_configuration` before training!"
@@ -246,7 +268,7 @@ def store_init_configuration(self, values: dict):
246268
self.writer.log_parameters(values)
247269
logger.info("Stored initial configuration hyperparameters to CometML")
248270

249-
def log(self, values: dict, step: Optional[int] = None):
271+
def log(self, values: dict, step: Optional[int] = None, **kwargs):
250272
"""
251273
Logs `values` to the current run.
252274
@@ -256,16 +278,19 @@ def log(self, values: dict, step: Optional[int] = None):
256278
`str` to `float`/`int`.
257279
step (`int`, *optional*):
258280
The run step. If included, the log will be affiliated with this step.
281+
kwargs:
282+
Additional key word arguments passed along to either `Experiment.log_metric`, `Experiment.log_other`,
283+
or `Experiment.log_metrics` method based on the contents of `values`.
259284
"""
260285
if step is not None:
261286
self.writer.set_step(step)
262287
for k, v in values.items():
263288
if isinstance(v, (int, float)):
264-
self.writer.log_metric(k, v, step=step)
289+
self.writer.log_metric(k, v, step=step, **kwargs)
265290
elif isinstance(v, str):
266-
self.writer.log_other(k, v)
291+
self.writer.log_other(k, v, **kwargs)
267292
elif isinstance(v, dict):
268-
self.writer.log_metrics(v, step=step)
293+
self.writer.log_metrics(v, step=step, **kwargs)
269294
logger.info("Successfully logged to CometML")
270295

271296
def finish(self):

tests/test_tracking.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ def test_init_trackers(self):
100100
project_name = "test_project_with_config"
101101
accelerator = Accelerator(log_with="wandb")
102102
config = {"num_iterations": 12, "learning_rate": 1e-2, "some_boolean": False, "some_string": "some_value"}
103-
accelerator.init_trackers(project_name, config)
103+
kwargs = {"wandb": {"tags": ["my_tag"]}}
104+
accelerator.init_trackers(project_name, config, kwargs)
104105
accelerator.end_training()
105106
# The latest offline log is stored at wandb/latest-run/*.wandb
106107
for child in Path(f"{self.tmpdir}/wandb/latest-run").glob("*"):
@@ -116,6 +117,7 @@ def test_init_trackers(self):
116117
self.assertEqual(self.get_value_from_log("learning_rate", cleaned_log), "0.01")
117118
self.assertEqual(self.get_value_from_log("some_boolean", cleaned_log), "false")
118119
self.assertEqual(self.get_value_from_log("some_string", cleaned_log), "some_value")
120+
self.assertIn("my_tag", cleaned_log)
119121

120122
def test_log(self):
121123
project_name = "test_project_with_log"
@@ -214,6 +216,7 @@ class MyCustomTracker(GeneralTracker):
214216
"some_string",
215217
]
216218

219+
name = "my_custom_tracker"
217220
requires_logging_directory = False
218221

219222
def __init__(self, dir: str):

0 commit comments

Comments
 (0)