Skip to content

Commit

Permalink
Update imports and requirements (#50)
Browse files Browse the repository at this point in the history
* update requirements

* simplify imports

* set macos version due to error in ci (try with 12.3)

* temporarily remove macos due to code-unreleated issues in ci

* Update NeptuneCallback docstring (#51)

* update NeptuneCallback docstring

- Update for neptune 1.0
- Streamline description and examples
- Rm extra links

* tweak arg description

* phrasing

* fix imports and tests

* simplify retrieve_fit_index

---------

Co-authored-by: Sabine <[email protected]>
  • Loading branch information
AleksanderWWW and normandy7 authored Mar 16, 2023
1 parent 0eb7be6 commit c5953ff
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 66 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest] #, windows-latest]
os: [ubuntu-latest] #, macos-12.3] #, windows-latest]
python-version: [3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## neptune-fastai 1.1.0

### Changes
- Updated integration for compatibility with `neptune 1.X`
- Removed `neptune` and `neptune-client` from base requirements - installation is checked at runtime
- Functions outside the callback accept `Handler` as well

## neptune-fastai 1.0.0

### Changes
Expand Down
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ style = "semver"
pattern = "default-unprefixed"

[tool.poetry.dependencies]
python = "^3.6"
python = "^3.7"

# Python lack of functionalities from future versions
importlib-metadata = { version = "*", python = "<3.8" }

# Base requirements
neptune-client = ">=0.16.17"
fastai = ">=2.4"

# dev
Expand All @@ -24,6 +23,7 @@ pytest = { version = ">=5.0", optional = true }
pytest-tap = { version = "3.2", optional = true }
pytest-cov = { version = "2.10.1", optional = true }
pytest-xdist = { version = "2.2.0", optional = true }
neptune = { version = ">=1.0.0", optional = true }

[tool.poetry.extras]
dev = [
Expand All @@ -32,6 +32,7 @@ dev = [
"pytest-cov",
"pytest-tap",
"pytest-xdist",
"neptune",
]

[tool.poetry]
Expand Down
83 changes: 34 additions & 49 deletions src/neptune_fastai/impl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,18 @@
trainable_params,
)

from neptune_fastai.impl.version import __version__

try:
# neptune-client=0.9.0+ package structure
import neptune.new as neptune
from neptune import Run
from neptune.handler import Handler
from neptune.integrations.utils import (
expect_not_an_experiment,
verify_type,
)
from neptune.types import File
from neptune.utils import stringify_unsupported
except ImportError:
from neptune.new import Run
from neptune.new.handler import Handler
from neptune.new.integrations.utils import (
Expand All @@ -50,16 +59,6 @@
)
from neptune.new.types import File
from neptune.new.utils import stringify_unsupported
except ImportError:
# neptune-client>=1.0.0 package structure
import neptune # isort:skip
from neptune.integrations.utils import expect_not_an_experiment, verify_type
from neptune.handler import Handler
from neptune import Run
from neptune.types import File # isort:skip
from neptune.utils import stringify_unsupported

from neptune_fastai.impl.version import __version__

INTEGRATION_VERSION_KEY = "source_code/integrations/neptune-fastai"

Expand All @@ -70,30 +69,14 @@ class NeptuneCallback(Callback):
The callback logs paramaters, metrics, losses, model configuration,
optimizer configuration, and info about the dataset: path, number of samples, and hash value.
Metrics and losses are logged separately for every `learner.fit()` call.
For example, when you call `learner.fit(n)` the first time, it will create
a folder named fit_0 under the folder metrics that contains optimizer hyperparameters,
batch, and loader-level metrics.
metrics
|--> fit_0
|--> batch
|--> loader
|--> optimizer hyperparameters
|--> ...
|--> fit_n
Note: To try the integration without registering, you can use the public API token
`neptune.ANONYMOUS_API_TOKEN` and set the `project` argument to "common/fastai-integration".
Args:
run: Neptune `Run` or namespace `Handler` object. A run is a representation of all metadata
that you log to Neptune.
base_namespace: Root namespace inside which all metadata will be logged.
run: Neptune run object. 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.
base_namespace: Root namespace where all metadata logged by the callback is stored.
If omitted, the metadata is logged without a common root namespace.
upload_saved_models: Which model checkpoints to upload.
- `"all"` (default): uploads all model checkpoints created by `SaveModelCallback()`.
- `"last"`: uploads the last model checkpoint created by `SaveModelCallback()`.
upload_saved_models: Which model checkpoints created by `SaveModelCallback()`
to upload: 'all' or 'last'.
Examples:
Expand All @@ -102,8 +85,8 @@ class NeptuneCallback(Callback):
from fastai.callback.all import SaveModelCallback
from fastai.vision.all import (untar_data, ImageDataLoaders, ...)
import neptune.new as neptune
from neptune.new.integrations.fastai import NeptuneCallback
import neptune
from neptune.integrations.fastai import NeptuneCallback
run = neptune.init_run()
Expand All @@ -119,10 +102,10 @@ class NeptuneCallback(Callback):
n = 2
learn = vision_learner(
...
...,
cbs=[
SaveModelCallback(every_epoch=n),
NeptuneCallback(run=run, base_namespace="experiment_2", upload_saved_models="all"),
NeptuneCallback(run=run, base_namespace="experiment_2"),
],
)
Expand All @@ -131,9 +114,6 @@ class NeptuneCallback(Callback):
For more, see the docs:
Tutorial: https://docs.neptune.ai/integrations/fastai
API reference: https://docs.neptune.ai/api/integrations/fastai
Example scripts:
https://github.com/neptune-ai/examples/tree/main/integrations-and-supported-tools/fastai/scripts
"""

order = SaveModelCallback.order + 1
Expand All @@ -148,7 +128,7 @@ def __init__(
super().__init__(**kwargs)

expect_not_an_experiment(run)
verify_type("run", run, (neptune.Run, neptune.handler.Handler))
verify_type("run", run, (Run, Handler))
verify_type("base_namespace", base_namespace, str)
verify_type("upload_saved_models", upload_saved_models, (str, type(None)))

Expand All @@ -158,7 +138,7 @@ def __init__(
self.fit_index = retrieve_fit_index(run, f"{base_namespace}/metrics/")

root_obj = run
if isinstance(root_obj, neptune.handler.Handler):
if isinstance(root_obj, Handler):
root_obj = run.get_root_object()
root_obj[INTEGRATION_VERSION_KEY] = __version__

Expand Down Expand Up @@ -343,7 +323,7 @@ def after_fit(self):
self.fit_index += 1


def _log_model_architecture(run: neptune.Run, base_namespace: str, learn: Learner):
def _log_model_architecture(run: Union[Run, Handler], base_namespace: str, learn: Learner):
if hasattr(learn, "arch"):
run[f"{base_namespace}/config/model/architecture_name"] = getattr(learn.arch, "__name__", "")

Expand All @@ -353,7 +333,7 @@ def _log_model_architecture(run: neptune.Run, base_namespace: str, learn: Learne
run[f"{base_namespace}/io_files/artifacts/model_architecture"].upload(model_architecture)


def _log_dataset_metadata(run: neptune.Run, base_namespace: str, learn: Learner):
def _log_dataset_metadata(run: Union[Run, Handler], base_namespace: str, learn: Learner):
sha = hashlib.sha1(str(learn.dls.path).encode())

run[f"{base_namespace}/io_files/resources/dataset"] = stringify_unsupported(
Expand All @@ -365,17 +345,22 @@ def _log_dataset_metadata(run: neptune.Run, base_namespace: str, learn: Learner)
)


def _log_or_assign_metric(run: neptune.Run, number_of_epochs: int, metric: str, value):
def _log_or_assign_metric(run: Union[Run, Handler], number_of_epochs: int, metric: str, value):
if number_of_epochs > 1:
run[metric].append(value)
else:
run[metric] = value


def retrieve_fit_index(run: neptune.Run, path: str) -> int:
return len(run.get_attribute(path) or [])
def retrieve_fit_index(run: Union[Run, Handler], path: str) -> int:
root = run

if isinstance(run, Handler):
root = run.get_root_object()

return len(root.get_attribute(path) or [])


def _log_optimizer_hyperparams(run: neptune.Run, prefix: str, optimizer_hyperparams: dict, n_epoch: int):
def _log_optimizer_hyperparams(run: Union[Run, Handler], prefix: str, optimizer_hyperparams: dict, n_epoch: int):
for param, value in optimizer_hyperparams.items():
_log_or_assign_metric(run, n_epoch, f"{prefix}/{param}", value)
9 changes: 9 additions & 0 deletions src/neptune_fastai/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-fastai")
except PackageNotFoundError:
Expand Down
8 changes: 1 addition & 7 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
import neptune
import pytest
from fastai.basics import (
URLs,
Expand All @@ -25,13 +26,6 @@
TabularDataLoaders,
)

try:
# neptune-client=0.9.0 package structure
from neptune import new as neptune
except ImportError:
# neptune-client=1.0.0 package structure
import neptune


@pytest.fixture()
def run():
Expand Down
20 changes: 13 additions & 7 deletions tests/neptune_fastai/test_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#
from itertools import islice

import neptune.new as neptune
from fastai.basics import (
URLs,
accuracy,
Expand All @@ -37,7 +36,13 @@
get_image_files,
squeezenet1_0,
)
from neptune.new.integrations.fastai import NeptuneCallback

try:
from neptune import init_run
from neptune.integrations.fastai import NeptuneCallback
except ImportError:
from neptune.new import init_run
from neptune.new.integrations.fastai import NeptuneCallback

import neptune_fastai

Expand All @@ -47,9 +52,10 @@ def is_cat(x):


class TestE2E:
def test_vision_classification(self):
def test_vision_classification_with_handler(self):
# given (Subject)
run = neptune.init_run(name="Integration fastai (vision classification)")
run = init_run(name="Integration fastai (vision classification)")["test"]
root_obj = run.get_root_object()

path = untar_data(URLs.PETS) / "images"

Expand All @@ -71,11 +77,11 @@ def test_vision_classification(self):
)

learn.fit(1)
run.sync()
root_obj.sync()

# then
# correct integration version is logged
logged_version = run["source_code/integrations/neptune-fastai"].fetch()
logged_version = root_obj["source_code/integrations/neptune-fastai"].fetch()
assert logged_version == neptune_fastai.__version__

# and
Expand All @@ -96,7 +102,7 @@ def test_vision_classification(self):

def test_tabular_model(self):
# given (Subject)
run = neptune.init_run(name="Integration fastai (tabular model)")
run = init_run(name="Integration fastai (tabular model)")

path = untar_data(URLs.ADULT_SAMPLE)

Expand Down

0 comments on commit c5953ff

Please sign in to comment.