Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
dbe3ec2
add get_clearml_task method and test cases
sallycaoyu Mar 22, 2023
b557a21
fix doc
sallycaoyu Mar 22, 2023
8f93dd2
fix doc
sallycaoyu Mar 22, 2023
f322dc2
remove local files
sallycaoyu Mar 22, 2023
7b7eca3
modified get_task and added point1
sallycaoyu Mar 22, 2023
d579afe
remove local files
sallycaoyu Mar 22, 2023
fe90e71
add get_task_bypass test
sallycaoyu Mar 23, 2023
7d1dd2b
modify docstring
sallycaoyu Mar 23, 2023
a782373
fix types
sallycaoyu Mar 23, 2023
0aadcba
add pytest warning context manager
sallycaoyu Mar 23, 2023
c628a28
change task in bypass mode from _Stub to an offline Task
sallycaoyu Mar 24, 2023
f5b87dd
change link docstring fmt
sallycaoyu Mar 24, 2023
47dca59
change docstring fmt
sallycaoyu Mar 24, 2023
be97cde
Merge branch 'master' into clearmllogger-task
vfdev-5 Mar 28, 2023
e972faa
Merge branch 'master' of github.com:pytorch/ignite into clearmllogger…
sallycaoyu Mar 28, 2023
3819618
delete return
sallycaoyu Mar 28, 2023
67ed056
Merge branch 'clearmllogger-task' of github.com:sallycaoyu/ignite int…
sallycaoyu Mar 28, 2023
bb5d49b
Merge branch 'master' into clearmllogger-task
vfdev-5 Mar 30, 2023
2c211d4
Merge branch 'master' into clearmllogger-task
vfdev-5 Mar 30, 2023
8ab771a
remove the mock projects of Task.current() from test_clearml_logger.py
sallycaoyu Mar 30, 2023
7aa7959
change previous mocked Task.current() to create real Task objects
sallycaoyu Mar 30, 2023
3d7b219
remove extra files
sallycaoyu Mar 30, 2023
67f38f9
changed Task.current() to magicmock in test_clearml_logger
sallycaoyu Mar 30, 2023
e0329c1
Merge branch 'master' into clearmllogger-task
vfdev-5 Mar 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 39 additions & 25 deletions ignite/contrib/handlers/clearml_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,29 +125,16 @@ def __init__(self, **kwargs: Any):
if self.bypass_mode():
warnings.warn("ClearMLSaver: running in bypass mode")

class _Stub(object):
def __call__(self, *_: Any, **__: Any) -> "_Stub":
return self

def __getattr__(self, attr: str) -> "_Stub":
if attr in ("name", "id"):
return "" # type: ignore[return-value]
return self

def __setattr__(self, attr: str, val: Any) -> None:
pass

self._task = _Stub()
else:
# Try to retrieve current the ClearML Task before trying to create a new one
self._task = Task.current_task()
if self._task is None:
self._task = Task.init(
project_name=kwargs.get("project_name"),
task_name=kwargs.get("task_name"),
task_type=kwargs.get("task_type", Task.TaskTypes.training),
**experiment_kwargs,
)
# Try to retrieve current the ClearML Task before trying to create a new one
self._task = Task.current_task()

if self._task is None:
self._task = Task.init(
project_name=kwargs.get("project_name"),
task_name=kwargs.get("task_name"),
task_type=kwargs.get("task_type", Task.TaskTypes.training),
**experiment_kwargs,
)

self.clearml_logger = self._task.get_logger()

Expand All @@ -156,13 +143,20 @@ def __setattr__(self, attr: str, val: Any) -> None:
@classmethod
def set_bypass_mode(cls, bypass: bool) -> None:
"""
Will bypass all outside communication, and will drop all logs.
Set ``clearml.Task`` to offline mode.
Will bypass all outside communication, and will save all data and logs to a local session folder.
Should only be used in "standalone mode", when there is no access to the *clearml-server*.

Args:
bypass: If ``True``, all outside communication is skipped.
Data and logs will be stored in a local session folder.
For more information, please refer to `ClearML docs
<https://clear.ml/docs/latest/docs/clearml_sdk/task_sdk/#offline-mode>`_.
"""
from clearml import Task

setattr(cls, "_bypass", bypass)
return Task.set_offline(offline_mode=bypass)

@classmethod
def bypass_mode(cls) -> bool:
Expand All @@ -172,12 +166,32 @@ def bypass_mode(cls) -> bool:
Note:
`GITHUB_ACTIONS` env will automatically set bypass_mode to ``True``
unless overridden specifically with ``ClearMLLogger.set_bypass_mode(False)``.
For more information, please refer to `ClearML docs
<https://clear.ml/docs/latest/docs/clearml_sdk/task_sdk/#offline-mode>`_.

Return:
If True, all outside communication is skipped.
If True, ``clearml.Task`` is on offline mode, and all outside communication is skipped.
"""
return getattr(cls, "_bypass", bool(os.environ.get("CI")))

def __getattr__(self, attr: Any) -> Any:
"""
Calls the corresponding method of ``clearml.Logger``.

Args:
attr: methods of the ``clearml.Logger`` class.
"""
return getattr(self.clearml_logger, attr)

def get_task(self) -> Any:
"""
Returns the task context that the logger is reporting.

Return:
Returns the current task, equivalent to ``clearml.Task.current_task()``.
"""
return self._task

def close(self) -> None:
self.clearml_logger.flush()

Expand Down
39 changes: 37 additions & 2 deletions tests/ignite/contrib/handlers/test_clearml_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,8 @@ def update_fn(engine, batch):

def dummy_handler(engine, logger, event_name):
global_step = engine.state.get_event_attrib_value(event_name)
logger.clearml_logger.report_scalar(title="", series="", value="test_value", iteration=global_step)
test_value = 0.3 # example
logger.clearml_logger.report_scalar(title="", series="", value=test_value, iteration=global_step)

logger.attach(trainer, log_handler=dummy_handler, event_name=Events.EPOCH_COMPLETED)

Expand All @@ -745,13 +746,47 @@ def update_fn(engine, batch):

def dummy_handler(engine, logger, event_name):
global_step = engine.state.get_event_attrib_value(event_name)
logger.clearml_logger.report_scalar(title="", series="", value="test_value", iteration=global_step)
test_value = 0.3 # example
logger.clearml_logger.report_scalar(title="", series="", value=test_value, iteration=global_step)

clearml_logger.attach(trainer, log_handler=dummy_handler, event_name=Events.EPOCH_COMPLETED)

trainer.run(data, max_epochs=n_epochs)


def test_clearml_logger_getattr_method(dirname):

with pytest.warns(UserWarning, match="ClearMLSaver: running in bypass mode"):
ClearMLLogger.set_bypass_mode(True)

logger = ClearMLLogger(output_uri=dirname)

# Create a mock clearml.Logger() object
mock_logger = MagicMock()
logger.clearml_logger = mock_logger

# Test a method called by __getattr__ calls the corresponding method of the mock project.
logger.report_single_value("accuracy", 0.72)
mock_logger.report_single_value.assert_called_once_with("accuracy", 0.72)

# Test a method called by __getattr__ calls the corresponding classmethod of the mock project's class.
logger.current_logger()
mock_logger.current_logger.assert_called_once()

logger.close()


def test_clearml_logger_get_task_bypass(dirname):

with pytest.warns(UserWarning, match="ClearMLSaver: running in bypass mode"):
ClearMLLogger.set_bypass_mode(True)

with ClearMLLogger(output_uri=dirname) as clearml_logger:
task = clearml_logger.get_task()
assert isinstance(task, clearml.Task)
assert task == clearml.Task.current_task()


def test_clearml_disk_saver_integration():
model = torch.nn.Module()
to_save_serializable = {"model": model}
Expand Down