Skip to content

Commit 7f928bd

Browse files
test: add unit tests and docs for Trackio monitor
- Add TestTrackio covering config defaults, enabled config, and write_events() logging behavior (mocks the optional trackio dependency) - Add TestMonitorMasterTrackioWiring covering MonitorMaster registration when trackio is enabled/disabled - Update docs/_tutorials/monitor.md with Trackio overview, config example, and Custom Monitoring API reference Addresses Codex review feedback on PR #8065 Signed-off-by: Pranav Chanduri <preethivardhanc@gmail.com>
1 parent 486c102 commit 7f928bd

2 files changed

Lines changed: 93 additions & 3 deletions

File tree

docs/_tutorials/monitor.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ In this tutorial, we introduce the DeepSpeed Monitor and provide examples of its
1111

1212
## Overview
1313

14-
Monitoring model and system metrics during training is vital to ensure hardware resources are fully utilized. The DeepSpeed Monitor enables live logging of metrics through one or more monitoring backends such as PyTorch's [TensorBoard](https://pytorch.org/docs/1.8.0/tensorboard.html), [WandB](https://docs.wandb.ai/quickstart), [Comet](https://www.comet.com/site/?utm_source=deepseed&utm_medium=docs&utm_content=tutorial) and simple CSV files.
14+
Monitoring model and system metrics during training is vital to ensure hardware resources are fully utilized. The DeepSpeed Monitor enables live logging of metrics through one or more monitoring backends such as PyTorch's [TensorBoard](https://pytorch.org/docs/1.8.0/tensorboard.html), [WandB](https://docs.wandb.ai/quickstart), [Comet](https://www.comet.com/site/?utm_source=deepseed&utm_medium=docs&utm_content=tutorial), [Trackio](https://github.com/huggingface/trackio) and simple CSV files.
1515

1616
Below is a live monitoring view for TensorBoard:
1717

@@ -25,6 +25,8 @@ Below is a live monitoring view for Comet:
2525

2626
![CometML Example Output](/assets/images/comet_monitor.png){: .align-center}
2727

28+
[Trackio](https://github.com/huggingface/trackio) is a lightweight, offline-first experiment tracking library from Hugging Face with a WandB-compatible API. Runs can be visualized as an HF Space or dataset on the HF Hub.
29+
2830
## Usage
2931

3032
The DeepSpeed Monitor is configured within the deepspeed [configuration file](/docs/config-json/#monitoring-module). DeepSpeed will automatically monitor key training metrics, including those tracked with the `wall_clock_breakdown` configuration option. In addition, users can log their own custom events and metrics.
@@ -54,6 +56,10 @@ When using DeepSpeed for model training, the Monitor can be configured in the De
5456
"project": "my_project",
5557
"experiment_name": "my_experiment"
5658
}
59+
"trackio": {
60+
"enabled": true,
61+
"project": "my_project"
62+
}
5763
"csv_monitor": {
5864
"enabled": true,
5965
"output_path": "output/ds_logs/",
@@ -69,7 +75,7 @@ DeepSpeed will automatically log to all available and enabled monitoring backend
6975
In addition to automatic monitoring, users can log their own custom metrics in client scripts. Currently, there are two ways to initialize Monitor objects:
7076

7177
1. (Recommended) - Create a `MonitorMaster(ds_config.monitor_config)` object, which automatically initializes all monitor backends present in the DeepSpeed configuration
72-
2. Create a specific `TensorBoardMonitor(ds_config.monitor_config)`, `WandbMonitor(ds_config.monitor_config)`, `csvMonitor(ds_config.monitor_config)` object which will only initialize a specific monitor backend present in the DeepSpeed configuration
78+
2. Create a specific `TensorBoardMonitor(ds_config.monitor_config)`, `WandbMonitor(ds_config.monitor_config)`, `TrackioMonitor(ds_config.monitor_config)`, `csvMonitor(ds_config.monitor_config)` object which will only initialize a specific monitor backend present in the DeepSpeed configuration
7379

7480

7581
The steps to create a custom monitor are as follows:

tests/unit/monitor/test_monitor.py

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@
33

44
# DeepSpeed Team
55

6+
import sys
7+
68
from deepspeed.monitor.tensorboard import TensorBoardMonitor
79
from deepspeed.monitor.wandb import WandbMonitor
810
from deepspeed.monitor.csv_monitor import csvMonitor
911
from deepspeed.monitor.config import DeepSpeedMonitorConfig
1012
from deepspeed.monitor.comet import CometMonitor
13+
from deepspeed.monitor.trackio import TrackioMonitor
14+
from deepspeed.monitor.monitor import MonitorMaster
1115

1216
from unit.common import DistributedTest
13-
from unittest.mock import Mock, patch
17+
from unittest.mock import Mock, MagicMock, patch
1418
from deepspeed.runtime.config import DeepSpeedConfig
1519

1620
import deepspeed.comm as dist
@@ -164,3 +168,83 @@ def test_empty_comet(self):
164168
assert comet_monitor.enabled == defaults.enabled
165169
assert comet_monitor.samples_log_interval == defaults.samples_log_interval
166170
mock_start.assert_not_called()
171+
172+
173+
class TestTrackio(DistributedTest):
174+
world_size = 2
175+
176+
def test_trackio(self):
177+
# trackio is an optional dependency, so we stub the module rather
178+
# than requiring it to be installed for CI.
179+
mock_trackio = MagicMock()
180+
181+
config_dict = {"train_batch_size": 2, "trackio": {"enabled": True, "project": "my_project"}}
182+
ds_config = DeepSpeedConfig(config_dict)
183+
184+
with patch.dict(sys.modules, {"trackio": mock_trackio}):
185+
trackio_monitor = TrackioMonitor(ds_config.monitor_config.trackio)
186+
187+
assert trackio_monitor.enabled == True
188+
assert trackio_monitor.project == "my_project"
189+
190+
# trackio.init should only be called on rank 0
191+
if dist.get_rank() == 0:
192+
mock_trackio.init.assert_called_once_with(project="my_project")
193+
else:
194+
mock_trackio.init.assert_not_called()
195+
196+
def test_empty_trackio(self):
197+
mock_trackio = MagicMock()
198+
199+
config_dict = {"train_batch_size": 2, "trackio": {}}
200+
ds_config = DeepSpeedConfig(config_dict)
201+
202+
with patch.dict(sys.modules, {"trackio": mock_trackio}):
203+
trackio_monitor = TrackioMonitor(ds_config.monitor_config.trackio)
204+
205+
defaults = DeepSpeedMonitorConfig().trackio
206+
assert trackio_monitor.enabled == defaults.enabled
207+
assert trackio_monitor.project == defaults.project
208+
209+
def test_trackio_write_events(self):
210+
# Verifies write_events() correctly converts 3-tuples into
211+
# trackio.log() calls with the right step value.
212+
mock_trackio = MagicMock()
213+
214+
config_dict = {"train_batch_size": 2, "trackio": {"enabled": True, "project": "my_project"}}
215+
ds_config = DeepSpeedConfig(config_dict)
216+
217+
with patch.dict(sys.modules, {"trackio": mock_trackio}):
218+
trackio_monitor = TrackioMonitor(ds_config.monitor_config.trackio)
219+
events = [("Train/Loss", 0.5, 100)]
220+
trackio_monitor.write_events(events)
221+
222+
if dist.get_rank() == 0:
223+
mock_trackio.log.assert_called_once_with({"Train/Loss": 0.5}, step=100)
224+
else:
225+
mock_trackio.log.assert_not_called()
226+
227+
228+
class TestMonitorMasterTrackioWiring(DistributedTest):
229+
world_size = 2
230+
231+
def test_trackio_enabled_creates_monitor(self):
232+
mock_trackio = MagicMock()
233+
234+
config_dict = {"train_batch_size": 2, "trackio": {"enabled": True, "project": "my_project"}}
235+
ds_config = DeepSpeedConfig(config_dict)
236+
237+
with patch.dict(sys.modules, {"trackio": mock_trackio}):
238+
monitor_master = MonitorMaster(ds_config.monitor_config)
239+
240+
if dist.get_rank() == 0:
241+
assert monitor_master.trackio_monitor is not None
242+
assert isinstance(monitor_master.trackio_monitor, TrackioMonitor)
243+
else:
244+
assert monitor_master.trackio_monitor is None
245+
246+
def test_trackio_disabled_skips_monitor(self):
247+
config_dict = {"train_batch_size": 2, "trackio": {"enabled": False}}
248+
ds_config = DeepSpeedConfig(config_dict)
249+
monitor_master = MonitorMaster(ds_config.monitor_config)
250+
assert monitor_master.trackio_monitor is None

0 commit comments

Comments
 (0)