Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update integration #12

Merged
merged 4 commits into from
Mar 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 6 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,25 @@ python = "^3.7"
# Python lack of functionalities from future versions
importlib-metadata = { version = "*", python = "<3.8" }

neptune = ">=1.0.0"
numpy = "<1.24.0"
fvcore = "<0.1.5.post20221220"

# dev
pre-commit = { version = "*", optional = true }
pytest = { version = ">=5.0", optional = true }
pytest-cov = { version = "2.10.1", optional = true }
torch = "^1.13.0"
torchvision = "^0.14.0"
torch = { version = "^1.13.0", optional = true }
torchvision = { version = "^0.14.0", optional = true }
neptune = { version = ">=1.0.0", optional = true }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think detectron2 should also be an optional dependency. Wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not that easy, as it is only installed from GitHub repo, not PyPI and I've been having issued with adding that to poetry (that's why there is a seperate step just to install detectron2 in out CI)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense.


[tool.poetry.extras]
dev = [
"pre-commit",
"pytest",
"pytest-cov",
"torch",
"torchvision",
"neptune",
]

[tool.poetry]
Expand Down
51 changes: 31 additions & 20 deletions src/neptune_detectron2/impl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,24 @@
import detectron2
from detectron2.checkpoint import Checkpointer
from detectron2.engine import hooks
from neptune import Run
from neptune.handler import Handler
from neptune.internal.utils import verify_type
from neptune.types import File
from neptune.utils import stringify_unsupported
from torch.nn import Module

from neptune_detectron2.impl.version import __version__

try:
from neptune import Run
from neptune.handler import Handler
from neptune.internal.utils import verify_type
from neptune.types import File
from neptune.utils import stringify_unsupported
except ImportError:
from neptune.new.metadata_containers import Run
from neptune.new.handler import Handler
from neptune.new.internal.utils import verify_type
from neptune.new.types import File
from neptune.new.utils import stringify_unsupported

from torch.nn import Module

INTEGRATION_VERSION_KEY = "source_code/integrations/detectron2"


Expand All @@ -51,9 +60,9 @@ class NeptuneHook(hooks.HookBase):
for example, run["test"], in which case all metadata is logged under
the "test" namespace inside the run.
base_namespace: Root namespace where all metadata logged by the hook is stored.
smoothing_window_size: How often NeptuneHook should log metrics (and checkpoints, if
metrics_update_freq: How often NeptuneHook should log metrics (and checkpoints, if
log_checkpoints is set to True). The value must be greater than zero.
Example: Setting smoothing_window_size=10 will log metrics on every 10th epoch.
Example: Setting metrics_update_freq=10 will log metrics on every 10th epoch.
log_model: Whether to upload the final model checkpoint, whenever it is saved by the Trainer.
Expects CheckpointHook to be present.
log_checkpoints: Whether to upload checkpoints whenever they are saved by the Trainer.
Expand All @@ -65,9 +74,9 @@ class NeptuneHook(hooks.HookBase):
neptune_hook = NeptuneHook(
run=neptune_run,
log_checkpoints=True, # Log model checkpoints
smoothing_window_size=10, # Upload metrics and checkpoints every 10th epoch
metrics_update_freq=10, # Upload metrics and checkpoints every 10th epoch
)

For more, see the docs:
Tutorial: https://docs.neptune.ai/integrations/detectron2/
API reference: https://docs.neptune.ai/api/integrations/detectron2/
Expand All @@ -78,19 +87,19 @@ def __init__(
run: Run | Handler,
*,
base_namespace: str = "training",
smoothing_window_size: int = 20,
metrics_update_freq: int = 20,
log_model: bool = False,
log_checkpoints: bool = False,
):
verify_type("run", run, (Run, Handler))

self._run = run

self._window_size = smoothing_window_size
self._metrics_update_freq = metrics_update_freq
self.log_model = log_model
self.log_checkpoints = log_checkpoints

self._verify_window_size()
self._verify_metrics_update_freq()

if base_namespace.endswith("/"):
base_namespace = base_namespace[:-1]
Expand All @@ -99,11 +108,13 @@ def __init__(

self._root_object = self._run.get_root_object() if isinstance(self._run, Handler) else self._run

def _verify_window_size(self) -> None:
if self._window_size <= 0:
raise ValueError(f"Update freq should be greater than 0. Got {self._window_size}.")
if not isinstance(self._window_size, int):
raise TypeError(f"Smoothing window size should be of type int. Got {type(self._window_size)} instead.")
def _verify_metrics_update_freq(self) -> None:
if not isinstance(self._metrics_update_freq, int):
raise TypeError(
f"metrics_update_freq should be of type int. Got {type(self._metrics_update_freq)} instead."
)
if self._metrics_update_freq <= 0:
raise ValueError(f"metrics_update_freq should be greater than 0. Got {self._metrics_update_freq}.")

def _log_integration_version(self) -> None:
self._root_object[INTEGRATION_VERSION_KEY] = detectron2.__version__
Expand Down Expand Up @@ -134,14 +145,14 @@ def _log_checkpoint(self, final: bool = False) -> None:

def _log_metrics(self) -> None:
storage = detectron2.utils.events.get_event_storage()
for k, (v, _) in storage.latest_with_smoothing_hint(self._window_size).items():
for k, (v, _) in storage.latest_with_smoothing_hint(self._metrics_update_freq).items():
self.base_handler[f"metrics/{k}"].append(v)

def _can_save_checkpoint(self) -> bool:
return hasattr(self.trainer, "checkpointer") and isinstance(self.trainer.checkpointer, Checkpointer)

def _should_perform_after_step(self) -> bool:
return self.trainer.iter % self._window_size == 0
return self.trainer.iter % self._metrics_update_freq == 0

def before_train(self) -> None:
"""Logs detectron2 version used, the config that the trainer uses, and the underlying model summary."""
Expand Down
9 changes: 9 additions & 0 deletions src/neptune_detectron2/impl/version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
__all__ = ["__version__"]

import sys
from importlib.util import find_spec

if sys.version_info >= (3, 8):
from importlib.metadata import (
Expand All @@ -13,6 +14,14 @@
version,
)

if not (find_spec("neptune") or find_spec("neptune-client")):
msg = """
The Neptune client library was not found.
Install the neptune package with
`pip install neptune`
Need help? -> https://docs.neptune.ai/setup/installation/"""
raise PackageNotFoundError(msg)

try:
__version__ = version("neptune-detectron2")
except PackageNotFoundError:
Expand Down
5 changes: 4 additions & 1 deletion tests/test_e2e.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import os

from neptune import init_run
try:
from neptune import init_run
except ImportError:
from neptune.new import init_run

from src.neptune_detectron2 import NeptuneHook
from tests.utils import get_images
Expand Down