diff --git a/.github/markdown-links-config.json b/.github/markdown-links-config.json
index 6383904f96..88919c56a3 100644
--- a/.github/markdown-links-config.json
+++ b/.github/markdown-links-config.json
@@ -8,12 +8,6 @@
},
{
"pattern": "^https://codecov.io/gh/Lightning-AI/pytorch-lightning/graph/badge.svg"
- },
- {
- "pattern": "^https://app.neptune.ai"
- },
- {
- "pattern": "^https://www.neptune.ai/"
}
],
"httpHeaders": [
diff --git a/.gitignore b/.gitignore
index 42c36e534d..e334befd2b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -169,7 +169,6 @@ wandb
.forked/
*.prof
*.tar.gz
-.neptune/
# dataset generated from bolts in examples.
cifar-10-batches-py
diff --git a/README.md b/README.md
index 10118ee3a4..9f91e0eae1 100644
--- a/README.md
+++ b/README.md
@@ -292,9 +292,6 @@ trainer = Trainer(logger=loggers.CometLogger())
# mlflow
trainer = Trainer(logger=loggers.MLFlowLogger())
-# neptune
-trainer = Trainer(logger=loggers.NeptuneLogger())
-
# ... and dozens more
```
diff --git a/docs/source-pytorch/api_references.rst b/docs/source-pytorch/api_references.rst
index e7c7feb198..c73f1e1eb2 100644
--- a/docs/source-pytorch/api_references.rst
+++ b/docs/source-pytorch/api_references.rst
@@ -99,7 +99,6 @@ loggers
comet
csv_logs
mlflow
- neptune
tensorboard
wandb
diff --git a/docs/source-pytorch/conf.py b/docs/source-pytorch/conf.py
index ad2619dfba..11f9861d28 100644
--- a/docs/source-pytorch/conf.py
+++ b/docs/source-pytorch/conf.py
@@ -351,7 +351,6 @@ intersphinx_mapping = {
"lightning.fabric": ("https://lightning.ai/docs/fabric/stable/", None),
# TODO: these are missing objects.inv
# "comet_ml": ("https://www.comet.com/docs/v2/", None),
- # "neptune": ("https://docs.neptune.ai/", None),
# "wandb": ("https://docs.wandb.ai//", None),
}
nitpicky = True
@@ -457,8 +456,6 @@ nitpick_ignore = [
("py:class", "mlflow.tracking.MlflowClient"),
("py:attr", "model"),
("py:meth", "move_data_to_device"),
- ("py:class", "neptune.Run"),
- ("py:class", "neptune.handler.Handler"),
("py:meth", "on_after_batch_transfer"),
("py:meth", "on_before_batch_transfer"),
("py:meth", "on_save_checkpoint"),
@@ -605,7 +602,6 @@ from lightning.pytorch.callbacks import Callback
from lightning.pytorch.cli import _JSONARGPARSE_SIGNATURES_AVAILABLE as _JSONARGPARSE_AVAILABLE
from lightning.pytorch.utilities.imports import _TORCHVISION_AVAILABLE
from lightning.fabric.loggers.tensorboard import _TENSORBOARD_AVAILABLE, _TENSORBOARDX_AVAILABLE
-from lightning.pytorch.loggers.neptune import _NEPTUNE_AVAILABLE
from lightning.pytorch.loggers.comet import _COMET_AVAILABLE
from lightning.pytorch.loggers.mlflow import _MLFLOW_AVAILABLE
from lightning.pytorch.loggers.wandb import _WANDB_AVAILABLE
@@ -638,7 +634,4 @@ linkcheck_ignore = [
"https://openai.com/blog/.*",
"https://openai.com/index/*",
"https://tinyurl.com/.*", # has a human verification check on redirect
- "https://docs.neptune.ai/.*", # TODO: remove after dropping Neptune support
- "https://app.neptune.ai/*",
- "https://www.neptune.ai/*"
]
diff --git a/docs/source-pytorch/extensions/logging.rst b/docs/source-pytorch/extensions/logging.rst
index 94b86721cb..66c3d3d8d1 100644
--- a/docs/source-pytorch/extensions/logging.rst
+++ b/docs/source-pytorch/extensions/logging.rst
@@ -31,7 +31,6 @@ The following are loggers we support:
CometLogger
CSVLogger
MLFlowLogger
- NeptuneLogger
TensorBoardLogger
WandbLogger
@@ -69,7 +68,7 @@ You can also pass a custom Logger to the :class:`~lightning.pytorch.trainer.trai
tb_logger = pl_loggers.TensorBoardLogger(save_dir="logs/")
trainer = Trainer(logger=tb_logger)
-Choose from any of the others such as MLflow, Comet, Neptune, WandB, etc.
+Choose from any of the others such as LitLogger, MLflow, Comet, WandB, etc.
.. code-block:: python
diff --git a/docs/source-pytorch/visualize/supported_exp_managers.rst b/docs/source-pytorch/visualize/supported_exp_managers.rst
index c279125640..3f8726b7a7 100644
--- a/docs/source-pytorch/visualize/supported_exp_managers.rst
+++ b/docs/source-pytorch/visualize/supported_exp_managers.rst
@@ -88,47 +88,6 @@ Here's the full documentation for the :class:`~lightning.pytorch.loggers.MLFlowL
----
-Neptune.ai
-==========
-To use `Neptune.ai `_ first install the neptune package:
-
-.. code-block:: bash
-
- pip install neptune
-
-or with conda:
-
-.. code-block:: bash
-
- conda install -c conda-forge neptune
-
-Configure the logger and pass it to the :class:`~lightning.pytorch.trainer.trainer.Trainer`:
-
-.. testcode::
- :skipif: not _NEPTUNE_AVAILABLE
-
- import neptune
- from lightning.pytorch.loggers import NeptuneLogger
-
- neptune_logger = NeptuneLogger(
- api_key=neptune.ANONYMOUS_API_TOKEN, # replace with your own
- project="common/pytorch-lightning-integration", # format ""
- )
- trainer = Trainer(logger=neptune_logger)
-
-Access the neptune logger from any function (except the LightningModule *init*) to use its API for tracking advanced artifacts
-
-.. code-block:: python
-
- class LitModel(LightningModule):
- def any_lightning_module_function_or_hook(self):
- neptune_logger = self.logger.experiment["your/metadata/structure"]
- neptune_logger.append(metadata)
-
-Here's the full documentation for the :class:`~lightning.pytorch.loggers.NeptuneLogger`.
-
-----
-
Tensorboard
===========
`TensorBoard `_ can be installed with:
diff --git a/requirements/pytorch/loggers.info b/requirements/pytorch/loggers.info
index 1c01893cda..ad8cf6c4c5 100644
--- a/requirements/pytorch/loggers.info
+++ b/requirements/pytorch/loggers.info
@@ -1,7 +1,6 @@
# all supported loggers. this list is here as a reference, but they are not installed in CI
litlogger >= 2026.03.17
-neptune >=1.0.0
comet-ml >=3.31.0
mlflow >=1.0.0
wandb >=0.12.10
diff --git a/src/lightning/pytorch/CHANGELOG.md b/src/lightning/pytorch/CHANGELOG.md
index 22bb7db477..2bf4fd8495 100644
--- a/src/lightning/pytorch/CHANGELOG.md
+++ b/src/lightning/pytorch/CHANGELOG.md
@@ -15,7 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
### Removed
--
+- Removed support for Neptune logger ([#21572](https://github.com/Lightning-AI/pytorch-lightning/pull/21572))
### Changed
@@ -27,6 +27,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Fixed `val_check_interval` raising `ValueError` when `limit_val_batches=0` and interval exceeds training batches ([#21560](https://github.com/Lightning-AI/pytorch-lightning/pull/21560))
+- Fixed pkg-resources deprecation issue ([#21538](https://github.com/Lightning-AI/pytorch-lightning/pull/21538))
+
- Fixed FSDP mixed precision (`bf16-mixed`, `16-mixed`) initializing model parameters in half precision instead of fp32 ([#21586](https://github.com/Lightning-AI/pytorch-lightning/pull/21586))
- Fixed `device_mesh` type hint in `FSDPStrategy` to accept a 2-element tuple via the CLI ([#21581](https://github.com/Lightning-AI/pytorch-lightning/pull/21581))
diff --git a/src/lightning/pytorch/callbacks/model_checkpoint.py b/src/lightning/pytorch/callbacks/model_checkpoint.py
index 34dca4232a..081b187536 100644
--- a/src/lightning/pytorch/callbacks/model_checkpoint.py
+++ b/src/lightning/pytorch/callbacks/model_checkpoint.py
@@ -229,7 +229,7 @@ class ModelCheckpoint(Checkpoint):
... )
# save epoch and val_loss in name, but specify the formatting yourself (e.g. to avoid problems with Tensorboard
- # or Neptune, due to the presence of characters like '=' or '/')
+ # or other loggers, due to the presence of characters like '=' or '/')
# saves a file like: my/path/sample-mnist-epoch02-val_loss0.32.ckpt
>>> checkpoint_callback = ModelCheckpoint(
... monitor='val/loss',
diff --git a/src/lightning/pytorch/loggers/__init__.py b/src/lightning/pytorch/loggers/__init__.py
index 2ac2780e92..b6117ece65 100644
--- a/src/lightning/pytorch/loggers/__init__.py
+++ b/src/lightning/pytorch/loggers/__init__.py
@@ -16,7 +16,6 @@ from lightning.pytorch.loggers.csv_logs import CSVLogger
from lightning.pytorch.loggers.litlogger import LitLogger
from lightning.pytorch.loggers.logger import Logger
from lightning.pytorch.loggers.mlflow import MLFlowLogger
-from lightning.pytorch.loggers.neptune import NeptuneLogger
from lightning.pytorch.loggers.tensorboard import TensorBoardLogger
from lightning.pytorch.loggers.wandb import WandbLogger
@@ -28,5 +27,4 @@ __all__ = [
"MLFlowLogger",
"TensorBoardLogger",
"WandbLogger",
- "NeptuneLogger",
]
diff --git a/src/lightning/pytorch/loggers/neptune.py b/src/lightning/pytorch/loggers/neptune.py
index bf9669c824..90680a9100 100644
--- a/src/lightning/pytorch/loggers/neptune.py
+++ b/src/lightning/pytorch/loggers/neptune.py
@@ -12,583 +12,34 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""
-Neptune Logger
---------------
+Neptune Logger (Deprecated)
+---------------------------
+
+Neptune has been sunset. Please migrate to LitLogger.
"""
-import contextlib
-import logging
-import os
-from argparse import Namespace
-from collections.abc import Generator
-from functools import wraps
-from typing import TYPE_CHECKING, Any, Callable, Optional, Union
-
-from lightning_utilities.core.imports import RequirementCache
-from torch import Tensor
-from typing_extensions import override
-
-import lightning.pytorch as pl
-from lightning.fabric.utilities.logger import _add_prefix, _convert_params, _sanitize_callable_params
-from lightning.pytorch.callbacks import Checkpoint
-from lightning.pytorch.loggers.logger import Logger, rank_zero_experiment
-from lightning.pytorch.utilities.model_summary import ModelSummary
-from lightning.pytorch.utilities.rank_zero import rank_zero_only
-
-if TYPE_CHECKING:
- from neptune import Run
- from neptune.handler import Handler
-
-log = logging.getLogger(__name__)
-
-# Neptune is available with two names on PyPI : `neptune` and `neptune-client`
-# `neptune` was introduced as a name transition of neptune-client and the long-term target is to get
-# rid of Neptune-client package completely someday. It was introduced as a part of breaking-changes with a release
-# of neptune-client==1.0. neptune-client>=1.0 is just an alias of neptune package and have some breaking-changes
-# in compare to neptune-client<1.0.0.
-_NEPTUNE_AVAILABLE = RequirementCache("neptune>=1.0")
-_INTEGRATION_VERSION_KEY = "source_code/integrations/pytorch-lightning"
+from typing import Any
-# Neptune client throws `InactiveRunException` when trying to log to an inactive run.
-# This may happen when the run was stopped through the UI and the logger is still trying to log to it.
-def _catch_inactive(func: Callable) -> Callable:
- @wraps(func)
- def wrapper(*args: Any, **kwargs: Any) -> Any:
- from neptune.exceptions import InactiveRunException
+class NeptuneLogger:
+ """
+ .. deprecated:: Use :class:`LitLogger` instead.
- with contextlib.suppress(InactiveRunException):
- return func(*args, **kwargs)
+ Neptune has been sunset and this logger is no longer maintained.
+ Please migrate to **LitLogger**, the recommended logging solution for
+ tracking AI experiments, metrics, inputs, outputs, and artifacts.
- return wrapper
-
-
-class NeptuneLogger(Logger):
- r"""Log using `Neptune `_.
-
- Install it with pip:
-
- .. code-block:: bash
-
- pip install neptune
-
- or conda:
-
- .. code-block:: bash
-
- conda install -c conda-forge neptune-client
-
- **Quickstart**
-
- Pass a NeptuneLogger instance to the Trainer to log metadata with Neptune:
-
- .. code-block:: python
-
-
- from lightning.pytorch import Trainer
- from lightning.pytorch.loggers import NeptuneLogger
- import neptune
-
- neptune_logger = NeptuneLogger(
- api_key=neptune.ANONYMOUS_API_TOKEN, # replace with your own
- project="common/pytorch-lightning-integration", # format "workspace-name/project-name"
- tags=["training", "resnet"], # optional
- )
- trainer = Trainer(max_epochs=10, logger=neptune_logger)
-
- **How to use NeptuneLogger?**
-
- Use the logger anywhere in your :class:`~lightning.pytorch.core.LightningModule` as follows:
-
- .. code-block:: python
-
- from neptune.types import File
- from lightning.pytorch import LightningModule
-
-
- class LitModel(LightningModule):
- def training_step(self, batch, batch_idx):
- # log metrics
- acc = ...
- self.append("train/loss", loss)
-
- def any_lightning_module_function_or_hook(self):
- # log images
- img = ...
- self.logger.experiment["train/misclassified_images"].append(File.as_image(img))
-
- # generic recipe
- metadata = ...
- self.logger.experiment["your/metadata/structure"] = metadata
-
- Note that the syntax ``self.logger.experiment["your/metadata/structure"].append(metadata)`` is specific to
- Neptune and extends the logger capabilities. It lets you log various types of metadata, such as
- scores, files, images, interactive visuals, and CSVs.
- Refer to the `Neptune docs `_
- for details.
- You can also use the regular logger methods ``log_metrics()``, and ``log_hyperparams()`` with NeptuneLogger.
-
- **Log after fitting or testing is finished**
-
- You can log objects after the fitting or testing methods are finished:
-
- .. code-block:: python
-
- neptune_logger = NeptuneLogger(project="common/pytorch-lightning-integration")
-
- trainer = pl.Trainer(logger=neptune_logger)
- model = ...
- datamodule = ...
- trainer.fit(model, datamodule=datamodule)
- trainer.test(model, datamodule=datamodule)
-
- # Log objects after `fit` or `test` methods
- # model summary
- neptune_logger.log_model_summary(model=model, max_depth=-1)
-
- # generic recipe
- metadata = ...
- neptune_logger.experiment["your/metadata/structure"] = metadata
-
- **Log model checkpoints**
-
- If you have :class:`~lightning.pytorch.callbacks.ModelCheckpoint` configured,
- the Neptune logger automatically logs model checkpoints.
- Model weights will be uploaded to the "model/checkpoints" namespace in the Neptune run.
- You can disable this option with:
-
- .. code-block:: python
-
- neptune_logger = NeptuneLogger(log_model_checkpoints=False)
-
- **Pass additional parameters to the Neptune run**
-
- You can also pass ``neptune_run_kwargs`` to add details to the run, like ``tags`` or ``description``:
-
- .. testcode::
- :skipif: not _NEPTUNE_AVAILABLE
-
- from lightning.pytorch import Trainer
- from lightning.pytorch.loggers import NeptuneLogger
-
- neptune_logger = NeptuneLogger(
- project="common/pytorch-lightning-integration",
- name="lightning-run",
- description="mlp quick run with pytorch-lightning",
- tags=["mlp", "quick-run"],
- )
- trainer = Trainer(max_epochs=3, logger=neptune_logger)
-
- Check `run documentation `_
- for more info about additional run parameters.
-
- **Details about Neptune run structure**
-
- Runs can be viewed as nested dictionary-like structures that you can define in your code.
- Thanks to this you can easily organize your metadata in a way that is most convenient for you.
-
- The hierarchical structure that you apply to your metadata is reflected in the Neptune web app.
-
- See also:
- - Read about
- `what objects you can log to Neptune `_.
- - Check out an `example run `_
- with multiple types of metadata logged.
- - For more detailed examples, see the
- `user guide `_.
-
- Args:
- api_key: Optional.
- Neptune API token, found on https://www.neptune.ai upon registration.
- You should save your token to the `NEPTUNE_API_TOKEN`
- environment variable and leave the api_key argument out of your code.
- Instructions: `Setting your API token `_.
- project: Optional.
- Name of a project in the form "workspace-name/project-name", for example "tom/mask-rcnn".
- If ``None``, the value of `NEPTUNE_PROJECT` environment variable is used.
- You need to create the project on https://www.neptune.ai first.
- name: Optional. Editable name of the run.
- The run name is displayed in the Neptune web app.
- run: Optional. Default is ``None``. A Neptune ``Run`` object.
- If specified, this existing run will be used for logging, instead of a new run being created.
- You can also pass a namespace handler object; for example, ``run["test"]``, in which case all
- metadata is logged under the "test" namespace inside the run.
- log_model_checkpoints: Optional. Default is ``True``. Log model checkpoint to Neptune.
- Works only if ``ModelCheckpoint`` is passed to the ``Trainer``.
- prefix: Optional. Default is ``"training"``. Root namespace for all metadata logging.
- \**neptune_run_kwargs: Additional arguments like ``tags``, ``description``, ``capture_stdout``, etc.
- used when a run is created.
+ See: https://github.com/Lightning-AI/LitLogger
Raises:
- ModuleNotFoundError:
- If the required Neptune package is not installed.
- ValueError:
- If an argument passed to the logger's constructor is incorrect.
-
+ RuntimeError: Always raised when attempting to instantiate this logger.
"""
- LOGGER_JOIN_CHAR = "/"
- PARAMETERS_KEY = "hyperparams"
- ARTIFACTS_KEY = "artifacts"
-
- def __init__(
- self,
- *, # force users to call `NeptuneLogger` initializer with `kwargs`
- api_key: Optional[str] = None,
- project: Optional[str] = None,
- name: Optional[str] = None,
- run: Optional[Union["Run", "Handler"]] = None,
- log_model_checkpoints: Optional[bool] = True,
- prefix: str = "training",
- **neptune_run_kwargs: Any,
- ):
- if not _NEPTUNE_AVAILABLE:
- raise ModuleNotFoundError(str(_NEPTUNE_AVAILABLE))
-
- # verify if user passed proper init arguments
- self._verify_input_arguments(api_key, project, name, run, neptune_run_kwargs)
- super().__init__()
- self._log_model_checkpoints = log_model_checkpoints
- self._prefix = prefix
- self._run_name = name
- self._project_name = project
- self._api_key = api_key
- self._run_instance = run
- self._neptune_run_kwargs = neptune_run_kwargs
- self._run_short_id: Optional[str] = None
-
- if self._run_instance is not None:
- self._retrieve_run_data()
-
- from neptune.handler import Handler
-
- # make sure that we've log integration version for outside `Run` instances
- root_obj = self._run_instance
- if isinstance(root_obj, Handler):
- root_obj = root_obj.get_root_object()
-
- root_obj[_INTEGRATION_VERSION_KEY] = pl.__version__
-
- def _retrieve_run_data(self) -> None:
- from neptune.handler import Handler
-
- assert self._run_instance is not None
- root_obj = self._run_instance
- if isinstance(root_obj, Handler):
- root_obj = root_obj.get_root_object()
-
- root_obj.wait()
-
- if root_obj.exists("sys/id"):
- self._run_short_id = root_obj["sys/id"].fetch()
- self._run_name = root_obj["sys/name"].fetch()
- else:
- self._run_short_id = "OFFLINE"
- self._run_name = "offline-name"
-
- @property
- def _neptune_init_args(self) -> dict:
- args: dict = {}
- # Backward compatibility in case of previous version retrieval
- with contextlib.suppress(AttributeError):
- args = self._neptune_run_kwargs
-
- if self._project_name is not None:
- args["project"] = self._project_name
-
- if self._api_key is not None:
- args["api_token"] = self._api_key
-
- if self._run_short_id is not None:
- args["run"] = self._run_short_id
-
- # Backward compatibility in case of previous version retrieval
- with contextlib.suppress(AttributeError):
- if self._run_name is not None:
- args["name"] = self._run_name
-
- return args
-
- def _construct_path_with_prefix(self, *keys: str) -> str:
- """Return sequence of keys joined by `LOGGER_JOIN_CHAR`, started with `_prefix` if defined."""
- if self._prefix:
- return self.LOGGER_JOIN_CHAR.join([self._prefix, *keys])
- return self.LOGGER_JOIN_CHAR.join(keys)
-
- @staticmethod
- def _verify_input_arguments(
- api_key: Optional[str],
- project: Optional[str],
- name: Optional[str],
- run: Optional[Union["Run", "Handler"]],
- neptune_run_kwargs: dict,
- ) -> None:
- from neptune import Run
- from neptune.handler import Handler
-
- # check if user passed the client `Run`/`Handler` object
- if run is not None and not isinstance(run, (Run, Handler)):
- raise ValueError("Run parameter expected to be of type `neptune.Run`, or `neptune.handler.Handler`.")
-
- # check if user passed redundant neptune.init_run arguments when passed run
- any_neptune_init_arg_passed = any(arg is not None for arg in [api_key, project, name]) or neptune_run_kwargs
- if run is not None and any_neptune_init_arg_passed:
- raise ValueError(
- "When an already initialized run object is provided, you can't provide other `neptune.init_run()`"
- " parameters."
- )
-
- def __getstate__(self) -> dict[str, Any]:
- state = self.__dict__.copy()
- # Run instance can't be pickled
- state["_run_instance"] = None
- return state
-
- def __setstate__(self, state: dict[str, Any]) -> None:
- import neptune
-
- self.__dict__ = state
- self._run_instance = neptune.init_run(**self._neptune_init_args)
-
- @property
- @rank_zero_experiment
- def experiment(self) -> "Run":
- r"""Actual Neptune run object. Allows you to use neptune logging features in your
- :class:`~lightning.pytorch.core.LightningModule`.
-
- Example::
-
- class LitModel(LightningModule):
- def training_step(self, batch, batch_idx):
- # log metrics
- acc = ...
- self.logger.experiment["train/acc"].append(acc)
-
- # log images
- img = ...
- self.logger.experiment["train/misclassified_images"].append(File.as_image(img))
-
- Note that the syntax ``self.logger.experiment["your/metadata/structure"].append(metadata)``
- is specific to Neptune and extends the logger capabilities.
- It lets you log various types of metadata, such as scores, files,
- images, interactive visuals, and CSVs. Refer to the
- `Neptune docs `_
- for more detailed explanations.
- You can also use the regular logger methods ``log_metrics()``, and ``log_hyperparams()``
- with NeptuneLogger.
-
- """
- return self.run
-
- @property
- @rank_zero_experiment
- def run(self) -> "Run":
- import neptune
-
- if not self._run_instance:
- self._run_instance = neptune.init_run(**self._neptune_init_args)
- self._retrieve_run_data()
- # make sure that we've log integration version for newly created
- self._run_instance[_INTEGRATION_VERSION_KEY] = pl.__version__
-
- return self._run_instance
-
- @override
- @rank_zero_only
- @_catch_inactive
- def log_hyperparams(self, params: Union[dict[str, Any], Namespace]) -> None:
- r"""Log hyperparameters to the run.
-
- Hyperparameters will be logged under the "/hyperparams" namespace.
-
- Note:
-
- You can also log parameters by directly using the logger instance:
- ``neptune_logger.experiment["model/hyper-parameters"] = params_dict``.
-
- In this way you can keep hierarchical structure of the parameters.
-
- Args:
- params: `dict`.
- Python dictionary structure with parameters.
-
- Example::
-
- from lightning.pytorch.loggers import NeptuneLogger
- import neptune
-
- PARAMS = {
- "batch_size": 64,
- "lr": 0.07,
- "decay_factor": 0.97,
- }
-
- neptune_logger = NeptuneLogger(
- api_key=neptune.ANONYMOUS_API_TOKEN,
- project="common/pytorch-lightning-integration"
- )
-
- neptune_logger.log_hyperparams(PARAMS)
-
- """
- from neptune.utils import stringify_unsupported
-
- params = _convert_params(params)
- params = _sanitize_callable_params(params)
-
- parameters_key = self.PARAMETERS_KEY
- parameters_key = self._construct_path_with_prefix(parameters_key)
-
- self.run[parameters_key] = stringify_unsupported(params)
-
- @override
- @rank_zero_only
- @_catch_inactive
- def log_metrics(self, metrics: dict[str, Union[Tensor, float]], step: Optional[int] = None) -> None:
- """Log metrics (numeric values) in Neptune runs.
-
- Args:
- metrics: Dictionary with metric names as keys and measured quantities as values.
- step: Step number at which the metrics should be recorded
-
- """
- if rank_zero_only.rank != 0:
- raise ValueError("run tried to log from global_rank != 0")
-
- metrics = _add_prefix(metrics, self._prefix, self.LOGGER_JOIN_CHAR)
-
- for key, val in metrics.items():
- self.run[key].append(val, step=step)
-
- @override
- @rank_zero_only
- @_catch_inactive
- def finalize(self, status: str) -> None:
- if not self._run_instance:
- # When using multiprocessing, finalize() should be a no-op on the main process, as no experiment has been
- # initialized there
- return
- if status:
- self.run[self._construct_path_with_prefix("status")] = status
-
- super().finalize(status)
-
- @property
- @override
- def save_dir(self) -> Optional[str]:
- """Gets the save directory of the experiment which in this case is ``None`` because Neptune does not save
- locally.
-
- Returns:
- the root directory where experiment logs get saved
-
- """
- return os.path.join(os.getcwd(), ".neptune")
-
- @rank_zero_only
- @_catch_inactive
- def log_model_summary(self, model: "pl.LightningModule", max_depth: int = -1) -> None:
- from neptune.types import File
-
- model_str = str(ModelSummary(model=model, max_depth=max_depth))
- self.run[self._construct_path_with_prefix("model/summary")] = File.from_content(
- content=model_str, extension="txt"
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
+ """Raise an error indicating Neptune logger is no longer supported."""
+ raise RuntimeError(
+ "NeptuneLogger is no longer supported. Neptune has been sunset.\n"
+ "\n"
+ "Please migrate to LitLogger, the recommended logger for AI experiments.\n"
+ "See: https://github.com/lightning-ai/litlogger\n"
)
-
- @override
- @rank_zero_only
- @_catch_inactive
- def after_save_checkpoint(self, checkpoint_callback: Checkpoint) -> None:
- """Automatically log checkpointed model. Called after model checkpoint callback saves a new checkpoint.
-
- Args:
- checkpoint_callback: the model checkpoint callback instance
-
- """
- if not self._log_model_checkpoints:
- return
-
- file_names = set()
- checkpoints_namespace = self._construct_path_with_prefix("model/checkpoints")
-
- # save last model
- if hasattr(checkpoint_callback, "last_model_path") and checkpoint_callback.last_model_path:
- model_last_name = self._get_full_model_name(checkpoint_callback.last_model_path, checkpoint_callback)
- file_names.add(model_last_name)
- self.run[f"{checkpoints_namespace}/{model_last_name}"].upload(checkpoint_callback.last_model_path)
-
- # save best k models
- if hasattr(checkpoint_callback, "best_k_models"):
- for key in checkpoint_callback.best_k_models:
- model_name = self._get_full_model_name(key, checkpoint_callback)
- file_names.add(model_name)
- self.run[f"{checkpoints_namespace}/{model_name}"].upload(key)
-
- # log best model path and checkpoint
- if hasattr(checkpoint_callback, "best_model_path") and checkpoint_callback.best_model_path:
- self.run[self._construct_path_with_prefix("model/best_model_path")] = checkpoint_callback.best_model_path
-
- model_name = self._get_full_model_name(checkpoint_callback.best_model_path, checkpoint_callback)
- file_names.add(model_name)
- self.run[f"{checkpoints_namespace}/{model_name}"].upload(checkpoint_callback.best_model_path)
-
- # remove old models logged to experiment if they are not part of best k models at this point
- if self.run.exists(checkpoints_namespace):
- exp_structure = self.run.get_structure()
- uploaded_model_names = self._get_full_model_names_from_exp_structure(exp_structure, checkpoints_namespace)
-
- for file_to_drop in list(uploaded_model_names - file_names):
- del self.run[f"{checkpoints_namespace}/{file_to_drop}"]
-
- # log best model score
- if hasattr(checkpoint_callback, "best_model_score") and checkpoint_callback.best_model_score:
- self.run[self._construct_path_with_prefix("model/best_model_score")] = (
- checkpoint_callback.best_model_score.cpu().detach().numpy()
- )
-
- @staticmethod
- def _get_full_model_name(model_path: str, checkpoint_callback: Checkpoint) -> str:
- """Returns model name which is string `model_path` appended to `checkpoint_callback.dirpath`."""
- if hasattr(checkpoint_callback, "dirpath"):
- model_path = os.path.normpath(model_path)
- expected_model_path = os.path.normpath(checkpoint_callback.dirpath)
- if not model_path.startswith(expected_model_path):
- raise ValueError(f"{model_path} was expected to start with {expected_model_path}.")
- # Remove extension from filepath
- filepath, _ = os.path.splitext(model_path[len(expected_model_path) + 1 :])
- return filepath.replace(os.sep, "/")
- return model_path.replace(os.sep, "/")
-
- @classmethod
- def _get_full_model_names_from_exp_structure(cls, exp_structure: dict[str, Any], namespace: str) -> set[str]:
- """Returns all paths to properties which were already logged in `namespace`"""
- structure_keys: list[str] = namespace.split(cls.LOGGER_JOIN_CHAR)
- for key in structure_keys:
- exp_structure = exp_structure[key]
- uploaded_models_dict = exp_structure
- return set(cls._dict_paths(uploaded_models_dict))
-
- @classmethod
- def _dict_paths(cls, d: dict[str, Any], path_in_build: Optional[str] = None) -> Generator:
- for k, v in d.items():
- path = f"{path_in_build}/{k}" if path_in_build is not None else k
- if not isinstance(v, dict):
- yield path
- else:
- yield from cls._dict_paths(v, path)
-
- @property
- @override
- def name(self) -> Optional[str]:
- """Return the experiment name or 'offline-name' when exp is run in offline mode."""
- return self._run_name
-
- @property
- @override
- def version(self) -> Optional[str]:
- """Return the experiment version.
-
- It's Neptune Run's short_id
-
- """
- return self._run_short_id
diff --git a/src/pytorch_lightning/README.md b/src/pytorch_lightning/README.md
index 86176359f6..5b7f8798f4 100644
--- a/src/pytorch_lightning/README.md
+++ b/src/pytorch_lightning/README.md
@@ -251,9 +251,6 @@ trainer = Trainer(logger=loggers.CometLogger())
# mlflow
trainer = Trainer(logger=loggers.MLFlowLogger())
-# neptune
-trainer = Trainer(logger=loggers.NeptuneLogger())
-
# ... and dozens more
```
diff --git a/tests/tests_pytorch/loggers/conftest.py b/tests/tests_pytorch/loggers/conftest.py
index 241374e619..8f24db4024 100644
--- a/tests/tests_pytorch/loggers/conftest.py
+++ b/tests/tests_pytorch/loggers/conftest.py
@@ -113,50 +113,6 @@ def comet_mock(monkeypatch):
return comet
-@pytest.fixture
-def neptune_mock(monkeypatch):
- class RunType: # to make isinstance checks pass
- def get_root_object(self):
- pass
-
- def __getitem__(self, item):
- pass
-
- def __setitem__(self, key, value):
- pass
-
- run_mock = MagicMock(spec=RunType, exists=Mock(return_value=False), wait=Mock(), get_structure=MagicMock())
- run_mock.get_root_object.return_value = run_mock
-
- neptune = ModuleType("neptune")
- neptune.init_run = Mock(return_value=run_mock)
- neptune.Run = RunType
- monkeypatch.setitem(sys.modules, "neptune", neptune)
-
- neptune_handler = ModuleType("handler")
- neptune_handler.Handler = RunType
- monkeypatch.setitem(sys.modules, "neptune.handler", neptune_handler)
-
- neptune_types = ModuleType("types")
- neptune_types.File = Mock()
- monkeypatch.setitem(sys.modules, "neptune.types", neptune_types)
-
- neptune_utils = ModuleType("utils")
- neptune_utils.stringify_unsupported = Mock()
- monkeypatch.setitem(sys.modules, "neptune.utils", neptune_utils)
-
- neptune_exceptions = ModuleType("exceptions")
- neptune_exceptions.InactiveRunException = Exception
- monkeypatch.setitem(sys.modules, "neptune.exceptions", neptune_exceptions)
-
- neptune.handler = neptune_handler
- neptune.types = neptune_types
- neptune.utils = neptune_utils
-
- monkeypatch.setattr("lightning.pytorch.loggers.neptune._NEPTUNE_AVAILABLE", True)
- return neptune
-
-
@pytest.fixture
def litlogger_mock(monkeypatch):
"""Mock litlogger module for unit testing LightningLogger."""
diff --git a/tests/tests_pytorch/loggers/test_all.py b/tests/tests_pytorch/loggers/test_all.py
index a9cf9af791..be4ff4e14e 100644
--- a/tests/tests_pytorch/loggers/test_all.py
+++ b/tests/tests_pytorch/loggers/test_all.py
@@ -26,7 +26,6 @@ from lightning.pytorch.loggers import (
CometLogger,
CSVLogger,
MLFlowLogger,
- NeptuneLogger,
TensorBoardLogger,
WandbLogger,
)
@@ -41,11 +40,9 @@ ALL_LOGGER_CLASSES = (
CometLogger,
CSVLogger,
MLFlowLogger,
- NeptuneLogger,
TensorBoardLogger,
WandbLogger,
)
-ALL_LOGGER_CLASSES_WO_NEPTUNE = tuple(filter(lambda cls: cls is not NeptuneLogger, ALL_LOGGER_CLASSES))
def _get_logger_args(logger_class, save_dir):
@@ -56,8 +53,6 @@ def _get_logger_args(logger_class, save_dir):
logger_args.update(offline_mode=True)
if "offline" in inspect.getfullargspec(logger_class).args:
logger_args.update(offline=True)
- if issubclass(logger_class, NeptuneLogger):
- logger_args.update(mode="offline")
if issubclass(logger_class, CometLogger):
logger_args.update(online=False)
return logger_args
@@ -72,7 +67,7 @@ def _instantiate_logger(logger_class, save_dir, **override_kwargs):
@mock.patch.dict(os.environ, {})
@mock.patch("lightning.pytorch.loggers.mlflow._get_resolve_tags", Mock())
@pytest.mark.parametrize("logger_class", ALL_LOGGER_CLASSES)
-def test_loggers_fit_test_all(logger_class, mlflow_mock, wandb_mock, comet_mock, neptune_mock, tmp_path, monkeypatch):
+def test_loggers_fit_test_all(logger_class, mlflow_mock, wandb_mock, comet_mock, tmp_path, monkeypatch):
"""Verify that basic functionality of all loggers."""
monkeypatch.chdir(tmp_path)
@@ -111,11 +106,6 @@ def test_loggers_fit_test_all(logger_class, mlflow_mock, wandb_mock, comet_mock,
logger._project_name = "bar"
logger.experiment.get_key.return_value = "SOME_KEY"
- if logger_class == NeptuneLogger:
- logger._retrieve_run_data = Mock()
- logger._run_short_id = "foo"
- logger._run_name = "bar"
-
if logger_class == MLFlowLogger:
logger = mock_mlflow_run_creation(logger, experiment_id="foo", run_id="bar")
@@ -149,9 +139,7 @@ def test_loggers_fit_test_all(logger_class, mlflow_mock, wandb_mock, comet_mock,
@mock.patch.dict(os.environ, {})
-@pytest.mark.parametrize(
- "logger_class", ALL_LOGGER_CLASSES_WO_NEPTUNE
-) # WandbLogger and NeptuneLogger get tested separately
+@pytest.mark.parametrize("logger_class", ALL_LOGGER_CLASSES) # WandbLogger gets tested separately
def test_loggers_pickle_all(tmp_path, monkeypatch, logger_class):
"""Test that the logger objects can be pickled.
@@ -222,8 +210,6 @@ class LazyInitExperimentCheck(Callback):
return
if isinstance(trainer.logger, MLFlowLogger):
assert trainer.logger._mlflow_client
- elif isinstance(trainer.logger, NeptuneLogger):
- assert trainer.logger._run_instance
elif hasattr(trainer.logger, "_experiment"):
assert trainer.logger._experiment
@@ -255,7 +241,7 @@ class CustomLoggerWithoutExperiment(Logger):
@mock.patch.dict(os.environ, {})
-@pytest.mark.parametrize("logger_class", [*ALL_LOGGER_CLASSES_WO_NEPTUNE, CustomLoggerWithoutExperiment])
+@pytest.mark.parametrize("logger_class", [*ALL_LOGGER_CLASSES, CustomLoggerWithoutExperiment])
@RunIf(skip_windows=True)
def test_logger_initialization(tmp_path, monkeypatch, logger_class):
"""Test that loggers get replaced by dummy loggers on global rank > 0 and that the experiment object is available
@@ -288,7 +274,7 @@ def _test_logger_initialization(tmp_path, logger_class):
@mock.patch.dict(os.environ, {})
@mock.patch("lightning.pytorch.loggers.mlflow._get_resolve_tags", Mock())
-def test_logger_with_prefix_all(mlflow_mock, wandb_mock, comet_mock, neptune_mock, monkeypatch, tmp_path):
+def test_logger_with_prefix_all(mlflow_mock, wandb_mock, comet_mock, monkeypatch, tmp_path):
"""Test that prefix is added at the beginning of the metric keys."""
prefix = "tmp"
@@ -308,14 +294,6 @@ def test_logger_with_prefix_all(mlflow_mock, wandb_mock, comet_mock, neptune_moc
run_id=ANY, metrics=[Metric(key="tmp-test", value=1.0, timestamp=ANY, step=0)]
)
- # Neptune
- logger = _instantiate_logger(NeptuneLogger, api_key="test", project="project", save_dir=tmp_path, prefix=prefix)
- assert logger.experiment.__getitem__.call_count == 0
- logger.log_metrics({"test": 1.0}, step=0)
- assert logger.experiment.__getitem__.call_count == 1
- logger.experiment.__getitem__.assert_called_with("tmp/test")
- logger.experiment.__getitem__().append.assert_called_once_with(1.0, step=0)
-
# TensorBoard
if _TENSORBOARD_AVAILABLE:
import torch.utils.tensorboard as tb
diff --git a/tests/tests_pytorch/loggers/test_litlogger.py b/tests/tests_pytorch/loggers/test_litlogger.py
index 6ffbf510fd..1fb4760ae8 100644
--- a/tests/tests_pytorch/loggers/test_litlogger.py
+++ b/tests/tests_pytorch/loggers/test_litlogger.py
@@ -21,6 +21,7 @@ import torch
from lightning.pytorch import Trainer
from lightning.pytorch.demos.boring_classes import BoringModel
from lightning.pytorch.loggers.litlogger import LitLogger
+from lightning.pytorch.loggers.neptune import NeptuneLogger
def test_litlogger_init(litlogger_mock, tmp_path):
@@ -360,3 +361,8 @@ def test_litlogger_save_logs_option(litlogger_mock, tmp_path):
call_kwargs = litlogger_mock.Experiment.call_args[1]
assert call_kwargs["save_logs"] is True
+
+
+def test_neptune_logger_raises_runtime_error():
+ with pytest.raises(RuntimeError, match="NeptuneLogger is no longer supported"):
+ NeptuneLogger()
diff --git a/tests/tests_pytorch/loggers/test_neptune.py b/tests/tests_pytorch/loggers/test_neptune.py
deleted file mode 100644
index 572b85715d..0000000000
--- a/tests/tests_pytorch/loggers/test_neptune.py
+++ /dev/null
@@ -1,318 +0,0 @@
-# Copyright The Lightning AI team.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-import os
-import pickle
-from collections import namedtuple
-from unittest import mock
-from unittest.mock import MagicMock, call
-
-import pytest
-import torch
-
-import lightning.pytorch as pl
-from lightning.pytorch import Trainer
-from lightning.pytorch.demos.boring_classes import BoringModel
-from lightning.pytorch.loggers import NeptuneLogger
-
-
-def _fetchable_paths(value):
- if value == "sys/id":
- return MagicMock(fetch=MagicMock(return_value="TEST-1"))
- if value == "sys/name":
- return MagicMock(fetch=MagicMock(return_value="Run test name"))
- return MagicMock()
-
-
-def _fit_and_test(logger, model, tmp_path):
- trainer = Trainer(default_root_dir=tmp_path, max_epochs=1, limit_train_batches=0.05, logger=logger)
- assert trainer.log_dir == os.path.join(os.getcwd(), ".neptune")
- trainer.fit(model)
- trainer.test(model)
- assert trainer.log_dir == os.path.join(os.getcwd(), ".neptune")
-
-
-def _get_logger_with_mocks(**kwargs):
- logger = NeptuneLogger(**kwargs)
- run_instance_mock = MagicMock()
- logger._run_instance = run_instance_mock
- logger._run_instance.__getitem__.return_value.fetch.return_value = "exp-name"
- run_attr_mock = MagicMock()
- logger._run_instance.__getitem__.return_value = run_attr_mock
-
- return logger, run_instance_mock, run_attr_mock
-
-
-def test_neptune_online(neptune_mock):
- neptune_mock.init_run.return_value.exists.return_value = True
- neptune_mock.init_run.return_value.__getitem__.side_effect = _fetchable_paths
-
- logger = NeptuneLogger(api_key="test", project="project")
- created_run_mock = logger.run
-
- assert logger._run_instance == created_run_mock
- created_run_mock.exists.assert_called_once_with("sys/id")
- assert logger.name == "Run test name"
- assert logger.version == "TEST-1"
- assert neptune_mock.init_run.call_count == 1
- assert created_run_mock.__getitem__.call_count == 2
- assert created_run_mock.__setitem__.call_count == 1
- created_run_mock.__getitem__.assert_has_calls([call("sys/id"), call("sys/name")], any_order=True)
- created_run_mock.__setitem__.assert_called_once_with("source_code/integrations/pytorch-lightning", pl.__version__)
-
-
-def test_neptune_offline(neptune_mock):
- neptune_mock.init_run.return_value.exists.return_value = False
-
- logger = NeptuneLogger(mode="offline")
- created_run_mock = logger.run
- logger.experiment["foo"] = "bar"
-
- created_run_mock.exists.assert_called_once_with("sys/id")
- assert logger._run_short_id == "OFFLINE"
- assert logger._run_name == "offline-name"
-
-
-def test_online_with_custom_run(neptune_mock):
- neptune_mock.init_run.return_value.exists.return_value = True
- neptune_mock.init_run.return_value.__getitem__.side_effect = _fetchable_paths
-
- created_run = neptune_mock.init_run()
- neptune_mock.init_run.reset_mock()
-
- logger = NeptuneLogger(run=created_run)
- assert logger._run_instance == created_run
- assert logger._run_instance == created_run
- assert logger.version == "TEST-1"
- assert neptune_mock.init_run.call_count == 0
-
-
-def test_neptune_pickling(neptune_mock):
- neptune_mock.init_run.return_value.exists.return_value = True
- neptune_mock.init_run.return_value.__getitem__.side_effect = _fetchable_paths
-
- unpickleable_run = neptune_mock.init_run()
- with pytest.raises(pickle.PicklingError):
- pickle.dumps(unpickleable_run)
- neptune_mock.init_run.reset_mock()
-
- logger = NeptuneLogger(run=unpickleable_run)
- assert neptune_mock.init_run.call_count == 0
-
- pickled_logger = pickle.dumps(logger)
- unpickled = pickle.loads(pickled_logger)
-
- neptune_mock.init_run.assert_called_once_with(name="Run test name", run="TEST-1")
- assert unpickled.experiment is not None
-
-
-def test_online_with_wrong_kwargs(neptune_mock):
- """Tests combinations of kwargs together with `run` kwarg which makes some of other parameters unavailable in
- init."""
- run = neptune_mock.init_run()
-
- with pytest.raises(ValueError, match="Run parameter expected to be of type `neptune.Run`*"):
- NeptuneLogger(run="some string")
-
- with pytest.raises(ValueError, match="When an already initialized run object is provided*"):
- NeptuneLogger(run=run, project="redundant project")
-
- with pytest.raises(ValueError, match="When an already initialized run object is provided*"):
- NeptuneLogger(run=run, api_key="redundant api key")
-
- with pytest.raises(ValueError, match="When an already initialized run object is provided*"):
- NeptuneLogger(run=run, name="redundant api name")
-
- with pytest.raises(ValueError, match="When an already initialized run object is provided*"):
- NeptuneLogger(run=run, foo="random **kwarg")
-
- # this should work
- NeptuneLogger(run=run)
- NeptuneLogger(project="foo")
- NeptuneLogger(foo="bar")
-
-
-def test_neptune_additional_methods(neptune_mock):
- logger, run_instance_mock, _ = _get_logger_with_mocks(api_key="test", project="project")
-
- logger.experiment["key1"].log(torch.ones(1))
- run_instance_mock.__getitem__.assert_called_once_with("key1")
- run_instance_mock.__getitem__().log.assert_called_once_with(torch.ones(1))
-
-
-def test_neptune_leave_open_experiment_after_fit(neptune_mock, tmp_path, monkeypatch):
- """Verify that neptune experiment was NOT closed after training."""
- monkeypatch.chdir(tmp_path)
- logger, run_instance_mock, _ = _get_logger_with_mocks(api_key="test", project="project")
- _fit_and_test(logger=logger, model=BoringModel(), tmp_path=tmp_path)
- assert run_instance_mock.stop.call_count == 0
-
-
-def test_neptune_log_metrics_on_trained_model(neptune_mock, tmp_path, monkeypatch):
- """Verify that trained models do log data."""
- monkeypatch.chdir(tmp_path)
-
- class LoggingModel(BoringModel):
- def on_validation_epoch_end(self):
- self.log("some/key", 42)
-
- logger, run_instance_mock, _ = _get_logger_with_mocks(api_key="test", project="project")
- _fit_and_test(logger=logger, model=LoggingModel(), tmp_path=tmp_path)
- run_instance_mock.__getitem__.assert_any_call("training/some/key")
- run_instance_mock.__getitem__.return_value.append.assert_has_calls([call(42, step=2)])
-
-
-def test_log_hyperparams(neptune_mock):
- neptune_mock.utils.stringify_unsupported = lambda x: x
-
- params = {"foo": "bar", "nested_foo": {"bar": 42}}
- test_variants = [
- ({}, "training/hyperparams"),
- ({"prefix": "custom_prefix"}, "custom_prefix/hyperparams"),
- ({"prefix": "custom/nested/prefix"}, "custom/nested/prefix/hyperparams"),
- ]
- for prefix, hyperparams_key in test_variants:
- logger, run_instance_mock, _ = _get_logger_with_mocks(api_key="test", project="project", **prefix)
- logger.log_hyperparams(params)
- assert run_instance_mock.__setitem__.call_count == 1
- assert run_instance_mock.__getitem__.call_count == 0
- run_instance_mock.__setitem__.assert_called_once_with(hyperparams_key, params)
-
-
-def test_log_metrics(neptune_mock):
- metrics = {
- "foo": 42,
- "bar": 555,
- }
- test_variants = [
- ({}, ("training/foo", "training/bar")),
- ({"prefix": "custom_prefix"}, ("custom_prefix/foo", "custom_prefix/bar")),
- ({"prefix": "custom/nested/prefix"}, ("custom/nested/prefix/foo", "custom/nested/prefix/bar")),
- ]
-
- for prefix, (metrics_foo_key, metrics_bar_key) in test_variants:
- logger, run_instance_mock, run_attr_mock = _get_logger_with_mocks(api_key="test", project="project", **prefix)
- logger.log_metrics(metrics)
- assert run_instance_mock.__setitem__.call_count == 0
- assert run_instance_mock.__getitem__.call_count == 2
- run_instance_mock.__getitem__.assert_any_call(metrics_foo_key)
- run_instance_mock.__getitem__.assert_any_call(metrics_bar_key)
- run_attr_mock.append.assert_has_calls([call(42, step=None), call(555, step=None)])
-
-
-def test_log_model_summary(neptune_mock):
- model = BoringModel()
- test_variants = [
- ({}, "training/model/summary"),
- ({"prefix": "custom_prefix"}, "custom_prefix/model/summary"),
- ({"prefix": "custom/nested/prefix"}, "custom/nested/prefix/model/summary"),
- ]
-
- for prefix, model_summary_key in test_variants:
- logger, run_instance_mock, _ = _get_logger_with_mocks(api_key="test", project="project", **prefix)
- file_from_content_mock = neptune_mock.types.File.from_content()
-
- logger.log_model_summary(model)
-
- assert run_instance_mock.__setitem__.call_count == 1
- assert run_instance_mock.__getitem__.call_count == 0
- run_instance_mock.__setitem__.assert_called_once_with(model_summary_key, file_from_content_mock)
-
-
-@mock.patch("builtins.open", mock.mock_open(read_data="test"))
-def test_after_save_checkpoint(neptune_mock):
- test_variants = [
- ({}, "training/model"),
- ({"prefix": "custom_prefix"}, "custom_prefix/model"),
- ({"prefix": "custom/nested/prefix"}, "custom/nested/prefix/model"),
- ]
-
- for prefix, model_key_prefix in test_variants:
- logger, run_instance_mock, run_attr_mock = _get_logger_with_mocks(api_key="test", project="project", **prefix)
- models_root_dir = os.path.join("path", "to", "models")
- cb_mock = MagicMock(
- dirpath=models_root_dir,
- last_model_path=os.path.join(models_root_dir, "last"),
- best_k_models={
- f"{os.path.join(models_root_dir, 'model1')}": None,
- f"{os.path.join(models_root_dir, 'model2/with/slashes')}": None,
- },
- best_model_path=os.path.join(models_root_dir, "best_model"),
- best_model_score=None,
- )
-
- mock_file = neptune_mock.types.File
- mock_file.reset_mock()
- mock_file.side_effect = mock.Mock()
- logger.after_save_checkpoint(cb_mock)
-
- assert run_instance_mock.__setitem__.call_count == 1 # best_model_path
- assert run_instance_mock.__getitem__.call_count == 4 # last_model_path, best_k_models, best_model_path
- assert run_attr_mock.upload.call_count == 4 # last_model_path, best_k_models, best_model_path
- assert mock_file.from_stream.call_count == 0
-
- run_instance_mock.__getitem__.assert_any_call(f"{model_key_prefix}/checkpoints/model1")
- run_instance_mock.__getitem__.assert_any_call(f"{model_key_prefix}/checkpoints/model2/with/slashes")
-
- run_attr_mock.upload.assert_has_calls([
- call(os.path.join(models_root_dir, "model1")),
- call(os.path.join(models_root_dir, "model2/with/slashes")),
- ])
-
-
-def test_save_dir(neptune_mock):
- logger = NeptuneLogger(api_key="test", project="project")
- assert logger.save_dir == os.path.join(os.getcwd(), ".neptune")
-
-
-def test_get_full_model_name():
- SimpleCheckpoint = namedtuple("SimpleCheckpoint", ["dirpath"])
- test_input_data = [
- ("key", os.path.join("foo", "bar", "key.ext"), SimpleCheckpoint(dirpath=os.path.join("foo", "bar"))),
- (
- "key/in/parts",
- os.path.join("foo", "bar", "key/in/parts.ext"),
- SimpleCheckpoint(dirpath=os.path.join("foo", "bar")),
- ),
- ("key", os.path.join("../foo", "bar", "key.ext"), SimpleCheckpoint(dirpath=os.path.join("../foo", "bar"))),
- ("key", os.path.join("foo", "key.ext"), SimpleCheckpoint(dirpath=os.path.join("./foo", "bar/../"))),
- ]
-
- for expected_model_name, model_path, checkpoint in test_input_data:
- assert NeptuneLogger._get_full_model_name(model_path, checkpoint) == expected_model_name
-
-
-def test_get_full_model_names_from_exp_structure():
- input_dict = {
- "foo": {
- "bar": {
- "lvl1_1": {"lvl2": {"lvl3_1": "some non important value", "lvl3_2": "some non important value"}},
- "lvl1_2": "some non important value",
- },
- "other_non_important": {"val100": 100},
- },
- "other_non_important": {"val42": 42},
- }
- expected_keys = {"lvl1_1/lvl2/lvl3_1", "lvl1_1/lvl2/lvl3_2", "lvl1_2"}
- assert NeptuneLogger._get_full_model_names_from_exp_structure(input_dict, "foo/bar") == expected_keys
-
-
-def test_inactive_run(neptune_mock, tmp_path, monkeypatch):
- from neptune.exceptions import InactiveRunException
-
- monkeypatch.chdir(tmp_path)
- logger, run_instance_mock, _ = _get_logger_with_mocks(api_key="test", project="project")
- run_instance_mock.__setitem__.side_effect = InactiveRunException
-
- # this should work without any exceptions
- _fit_and_test(logger=logger, model=BoringModel(), tmp_path=tmp_path)
diff --git a/tests/tests_pytorch/test_cli.py b/tests/tests_pytorch/test_cli.py
index 094a21a5b9..50e3356e6b 100644
--- a/tests/tests_pytorch/test_cli.py
+++ b/tests/tests_pytorch/test_cli.py
@@ -1802,21 +1802,6 @@ def test_comet_logger_init_args():
)
-@pytest.mark.xfail(
- # Only on Windows: TypeError: 'NoneType' object is not subscriptable
- raises=TypeError,
- condition=(sys.platform == "win32"),
- strict=False,
- reason="TypeError on Windows when parsing",
-)
-def test_neptune_logger_init_args():
- _test_logger_init_args(
- "NeptuneLogger",
- init={"name": "neptune"}, # Resolve from NeptuneLogger.__init__
- unresolved={"description": "neptune"}, # Unsupported resolving from neptune.internal.init.run.init_run
- )
-
-
def test_tensorboard_logger_init_args():
_test_logger_init_args(
"TensorBoardLogger",
diff --git a/tests/tests_pytorch/utilities/test_imports.py b/tests/tests_pytorch/utilities/test_imports.py
index b33f236b51..0852178166 100644
--- a/tests/tests_pytorch/utilities/test_imports.py
+++ b/tests/tests_pytorch/utilities/test_imports.py
@@ -85,12 +85,6 @@ def clean_import():
pytest.param(
"torch.distributed.is_available", _shortcut_patch(is_available, ()), "lightning.pytorch", id="ProcessGroup"
),
- pytest.param(
- "lightning_utilities.core.imports.RequirementCache.__bool__",
- _shortcut_patch(RequirementCache.__bool__, ("neptune",), ("requirement",)),
- "lightning.pytorch.loggers.neptune",
- id="neptune",
- ),
pytest.param(
"lightning_utilities.core.imports.RequirementCache.__bool__",
_shortcut_patch(RequirementCache.__bool__, ("jsonargparse[signatures]>=4.12.0",), ("requirement",)),