diff --git a/README.md b/README.md index 438c2493..6af5cb32 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,74 @@ - -# Datamint python API +# Datamint Python API ![Build Status](https://github.com/SonanceAI/datamint-python-api/actions/workflows/run_test.yaml/badge.svg) +[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/) + +A comprehensive Python SDK for interacting with the Datamint platform, providing seamless integration for medical imaging workflows, dataset management, and machine learning experiments. + +## 📋 Table of Contents + +- [Features](#-features) +- [Installation](#-installation) +- [Quick Setup](#-quick-setup) +- [Documentation](#-documentation) +- [Key Components](#-key-components) +- [Command Line Tools](#️-command-line-tools) +- [Examples](#-examples) +- [Support](#-support) + +## 🚀 Features + +- **Dataset Management**: Download, upload, and manage medical imaging datasets +- **Annotation Tools**: Create, upload, and manage annotations (segmentations, labels, measurements) +- **Experiment Tracking**: Integrated MLflow support for experiment management +- **PyTorch Lightning Integration**: Streamlined ML workflows with Lightning DataModules and callbacks +- **DICOM Support**: Native handling of DICOM files with anonymization capabilities +- **Multi-format Support**: PNG, JPEG, NIfTI, and other medical imaging formats See the full documentation at https://sonanceai.github.io/datamint-python-api/ -## Installation +## 📦 Installation + +> [!NOTE] +> We recommend using a virtual environment to avoid package conflicts. -Datamint requires Python 3.10+. -You can install/update Datamint and its dependencies using pip +### From PyPI + +To be released soon + +### From Source ```bash -pip install -U datamint +pip install git+https://github.com/SonanceAI/datamint-python-api ``` +### Virtual Environment Setup + +
+Click to expand virtual environment setup instructions + We recommend that you install Datamint in a dedicated virtual environment, to avoid conflicting with your system packages. -Create the enviroment once with `python3 -m venv datamint-env` and then activate it whenever you need it with: -- `source datamint-env/bin/activate` (Linux/MAC) -- `datamint-env\Scripts\activate.bat` (Windows CMD) -- `datamint-env\Scripts\Activate.ps1` (Windows PowerShell) +For instance, create the enviroment once with `python3 -m venv datamint-env` and then activate it whenever you need it with: + +1. **Create the environment** (one-time setup): + ```bash + python3 -m venv datamint-env + ``` + +2. **Activate the environment** (run whenever you need it): + + | Platform | Command | + |----------|---------| + | Linux/macOS | `source datamint-env/bin/activate` | + | Windows CMD | `datamint-env\Scripts\activate.bat` | + | Windows PowerShell | `datamint-env\Scripts\Activate.ps1` | +3. **Install the package**: + ```bash + pip install git+https://github.com/SonanceAI/datamint-python-api + ``` + +
## Setup API key @@ -45,29 +94,174 @@ import os os.environ["DATAMINT_API_KEY"] = "my_api_key" ``` -### Method 3: Api constructor +## 📚 Documentation + +| Resource | Description | +|----------|-------------| +| [🚀 Getting Started](docs/source/getting_started.rst) | Step-by-step setup and basic usage | +| [📖 API Reference](docs/source/client_api.rst) | Complete API documentation | +| [🔥 PyTorch Integration](docs/source/pytorch_integration.rst) | ML workflow integration | +| [💡 Examples](examples/) | Practical usage examples | + +## 🔗 Key Components + +### Dataset Management + +```python +from datamint import Dataset + +# Load dataset with annotations +dataset = Dataset( + project_name="medical-segmentation", +) + +# Access data +for sample in dataset: + image = sample['image'] # torch.Tensor + mask = sample['segmentation'] # torch.Tensor (if available) + metadata = sample['metainfo'] # dict +``` + + +### PyTorch Lightning Integration + +```python +import lightning as L +from datamint.lightning import DatamintDataModule +from datamint.mlflow.lightning.callbacks import MLFlowModelCheckpoint + +# Data module +datamodule = DatamintDataModule( + project_name="your-project", + batch_size=16, + train_split=0.8 +) + +# ML tracking callback +checkpoint_callback = MLFlowModelCheckpoint( + monitor="val_loss", + save_top_k=1, + register_model_name="best-model" +) + +# Trainer with MLflow logging +trainer = L.Trainer( + max_epochs=100, + callbacks=[checkpoint_callback], + logger=L.pytorch.loggers.MLFlowLogger( + experiment_name="medical-segmentation" + ) +) +``` + + +### Annotation Management -Specify API key in the Api constructor: ```python -from datamint import Api -api = Api(api_key='my_api_key') +# Upload segmentation masks +api.upload_segmentations( + resource_id="resource-123", + file_path="segmentation.nii.gz", + name="liver_segmentation", + frame_index=0 +) + +# Add categorical annotations +api.add_image_category_annotation( + resource_id="resource-123", + identifier="diagnosis", + value="positive" +) + +# Add geometric annotations +api.add_line_annotation( + point1=(10, 20), + point2=(50, 80), + resource_id="resource-123", + identifier="measurement", + frame_index=5 +) +``` + + +## 🛠️ Command Line Tools + +### Upload Resources + +**Upload DICOM files with anonymization:** +```bash +datamint-upload \ + --path /path/to/dicoms \ + --recursive \ + --channel "training-data" \ + --anonymize \ + --publish +``` + +**Upload with segmentation masks:** +```bash +datamint-upload \ + --path /path/to/images \ + --segmentation_path /path/to/masks \ + --segmentation_names segmentation_config.yaml ``` -## Tutorials +### Configuration Management +```bash +# Interactive setup +datamint-config + +# Set API key +datamint-config --api-key "your-key" +``` -You can find example notebooks in the `notebooks` folder: +## 🔍 Examples -- [Uploading your resources](notebooks/upload_data.ipynb) -- [Uploading model segmentations](notebooks/upload_model_segmentations.ipynb) +### Medical Image Segmentation Pipeline -and example scripts in [examples](examples) folder: +```python +import torch +import lightning as L +from datamint.lightning import DatamintDataModule +from datamint.mlflow.lightning.callbacks import MLFlowModelCheckpoint + +class SegmentationModel(L.LightningModule): + def __init__(self): + super().__init__() + # Model definition... + + def training_step(self, batch, batch_idx): + # Training logic... + pass + +# Setup data +datamodule = DatamintDataModule( + project_name="liver-segmentation", + batch_size=8, + train_split=0.8 +) + +# Setup model with MLflow tracking +model = SegmentationModel() +checkpoint_cb = MLFlowModelCheckpoint( + monitor="val_dice", + mode="max", + register_model_name="liver-segmentation-model" +) + +# Train +trainer = L.Trainer( + max_epochs=50, + callbacks=[checkpoint_cb], + logger=L.pytorch.loggers.MLFlowLogger() +) +trainer.fit(model, datamodule) +``` -- [API usage examples](examples/api_usage.ipynb) -- [Project and entity usage](examples/project_entity_usage.ipynb) -- [Channels example](examples/channels_example.ipynb) +## 🆘 Support -## Full documentation +[Full Documentation](https://datamint-python-api.readthedocs.io/) +[GitHub Issues](https://github.com/SonanceAI/datamint-python-api/issues) -See all functionalities in the full documentation at https://sonanceai.github.io/datamint-python-api/ diff --git a/datamint/api/base_api.py b/datamint/api/base_api.py index ddfff0de..fd953af3 100644 --- a/datamint/api/base_api.py +++ b/datamint/api/base_api.py @@ -61,22 +61,56 @@ def __init__(self, client: Optional HTTP client instance. If None, a new one will be created. """ self.config = config - self.client = client or self._create_client() + self._owns_client = client is None # Track if we created the client + self.client = client or BaseApi._create_client(config) self.semaphore = asyncio.Semaphore(20) self._api_instance: 'Api | None' = None # Injected by Api class - def _create_client(self) -> httpx.Client: - """Create and configure HTTP client with authentication and timeouts.""" - headers = None - if self.config.api_key: - headers = {"apikey": self.config.api_key} + @staticmethod + def _create_client(config: ApiConfig) -> httpx.Client: + """Create and configure HTTP client with authentication and timeouts. + + The client is designed to be long-lived and reused across multiple requests. + It maintains connection pooling for improved performance. + Default limits: max_keepalive_connections=20, max_connections=100 + """ + headers = {"apikey": config.api_key} if config.api_key else None return httpx.Client( - base_url=self.config.server_url, + base_url=config.server_url, headers=headers, - timeout=self.config.timeout + timeout=config.timeout, + limits=httpx.Limits( + max_keepalive_connections=5, # Increased from default 20 + max_connections=20, # Increased from default 100 + keepalive_expiry=8 + ) ) + def close(self) -> None: + """Close the HTTP client and release resources. + + Should be called when the API instance is no longer needed. + Only closes the client if it was created by this instance. + """ + if self._owns_client and self.client is not None: + self.client.close() + + def __enter__(self): + """Context manager entry.""" + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """Context manager exit - ensures client is closed.""" + self.close() + + def __del__(self): + """Destructor - ensures client is closed when instance is garbage collected.""" + try: + self.close() + except Exception: + pass # Ignore errors during cleanup + def _stream_request(self, method: str, endpoint: str, **kwargs): """Make streaming HTTP request with error handling. diff --git a/datamint/api/client.py b/datamint/api/client.py index 626df5ed..5a62bab0 100644 --- a/datamint/api/client.py +++ b/datamint/api/client.py @@ -68,6 +68,8 @@ def check_connection(self): f" Please check your api_key and/or other configurations. {e}") def _get_endpoint(self, name: str): + if self._client is None: + self._client = BaseApi._create_client(self.config) if name not in self._endpoints: api_class = self._API_MAP[name] endpoint = api_class(self.config, self._client) diff --git a/datamint/apihandler/base_api_handler.py b/datamint/apihandler/base_api_handler.py index 887311c0..392fc86c 100644 --- a/datamint/apihandler/base_api_handler.py +++ b/datamint/apihandler/base_api_handler.py @@ -30,7 +30,6 @@ _PAGE_LIMIT = 5000 - @deprecated(reason="Please use `from datamint import Api` instead.", version="2.0.0") class BaseAPIHandler: """ diff --git a/datamint/apihandler/dto/annotation_dto.py b/datamint/apihandler/dto/annotation_dto.py index 7c8311fc..2138a46e 100644 --- a/datamint/apihandler/dto/annotation_dto.py +++ b/datamint/apihandler/dto/annotation_dto.py @@ -178,6 +178,8 @@ def __init__(self, if model_id is not None: if is_model == False: raise ValueError("model_id==False while self.model_id is provided.") + if not isinstance(model_id, str): + raise ValueError("model_id must be a string if provided.") is_model = True self.is_model = is_model self.geometry = geometry diff --git a/datamint/dataset/base_dataset.py b/datamint/dataset/base_dataset.py index 8b75c912..71aaf133 100644 --- a/datamint/dataset/base_dataset.py +++ b/datamint/dataset/base_dataset.py @@ -307,6 +307,10 @@ def _setup_labels(self) -> None: self.image_lsets, self.image_lcodes = self._get_labels_set(framed=False) worklist_id = self.get_info()['worklist_id'] groups: dict[str, dict] = self.api.annotationsets.get_segmentation_group(worklist_id)['groups'] + if not groups: + self.seglabel_list = [] + self.seglabel2code = {} + return # order by 'index' key max_index = max([g['index'] for g in groups.values()]) self.seglabel_list : list[str] = ['UNKNOWN'] * max_index # 1-based diff --git a/datamint/lightning/__init__.py b/datamint/lightning/__init__.py new file mode 100644 index 00000000..2a3ba90a --- /dev/null +++ b/datamint/lightning/__init__.py @@ -0,0 +1 @@ +from .datamintdatamodule import DatamintDataModule \ No newline at end of file diff --git a/datamint/lightning/datamintdatamodule.py b/datamint/lightning/datamintdatamodule.py new file mode 100644 index 00000000..72f02622 --- /dev/null +++ b/datamint/lightning/datamintdatamodule.py @@ -0,0 +1,103 @@ +from torch.utils.data import DataLoader +from datamint import Dataset +import lightning as L +from typing import Any +from copy import copy +import numpy as np + + +class DatamintDataModule(L.LightningDataModule): + """ + LightningDataModule for Datamint datasets with train/val split. + TODO: Add support for test and predict dataloaders. + """ + + def __init__( + self, + project_name: str = "./", + batch_size: int = 32, + image_transform=None, + mask_transform=None, + alb_transform=None, + alb_train_transform=None, + alb_val_transform=None, + train_split: float = 0.9, + val_split: float = 0.1, + seed: int = 42, + num_workers: int = 4, + **dataset_kwargs: Any, + ): + super().__init__() + self.project_name = project_name + self.batch_size = batch_size + self.image_transform = image_transform + self.mask_transform = mask_transform + + if alb_transform is not None and (alb_train_transform is not None or alb_val_transform is not None): + raise ValueError("You cannot specify both `alb_transform` and `alb_train_transform`/`alb_val_transform`.") + + # Handle backward compatibility for alb_transform + if alb_transform is not None: + self.alb_train_transform = alb_transform + self.alb_val_transform = alb_transform + else: + self.alb_train_transform = alb_train_transform + self.alb_val_transform = alb_val_transform + + self.train_split = train_split + self.val_split = val_split + self.seed = seed + self.dataset_kwargs = dataset_kwargs + self.num_workers = num_workers + + self.dataset = None + + def prepare_data(self) -> None: + """Download or update data if needed.""" + Dataset( + project_name=self.project_name, + auto_update=True, + ) + + def setup(self, stage: str = None) -> None: + """Set up datasets and perform train/val split.""" + if self.dataset is None: + # Create base dataset for getting indices + self.dataset = Dataset( + return_as_semantic_segmentation=True, + semantic_seg_merge_strategy="union", + return_frame_by_frame=True, + include_unannotated=False, + project_name=self.project_name, + image_transform=self.image_transform, + mask_transform=self.mask_transform, + alb_transform=None, # No transform for base dataset + auto_update=False, + **self.dataset_kwargs, + ) + + indices = list(copy(self.dataset.subset_indices)) + rs = np.random.RandomState(self.seed) + rs.shuffle(indices) + train_end = int(self.train_split * len(indices)) + train_idx = indices[:train_end] + val_idx = indices[train_end:] + + self.train_dataset = copy(self.dataset).subset(train_idx) + self.train_dataset.alb_transform = self.alb_train_transform + self.val_dataset = copy(self.dataset).subset(val_idx) + self.val_dataset.alb_transform = self.alb_val_transform + + def train_dataloader(self) -> DataLoader: + return self.train_dataset.get_dataloader(batch_size=self.batch_size, num_workers=self.num_workers, shuffle=True) + + def val_dataloader(self) -> DataLoader: + return self.val_dataset.get_dataloader(batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False) + + def test_dataloader(self): + # Use the same dataloader as validation for testing, because we have so few samples + return self.val_dataset.get_dataloader(batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False) + + def predict_dataloader(self): + # Use the same dataloader as validation for testing, because we have so few samples + return self.val_dataset.get_dataloader(batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False) diff --git a/datamint/mlflow/__init__.py b/datamint/mlflow/__init__.py new file mode 100644 index 00000000..1c19141c --- /dev/null +++ b/datamint/mlflow/__init__.py @@ -0,0 +1,46 @@ +# Monkey patch mlflow.tracking._tracking_service.utils.get_tracking_uri +from .tracking.fluent import set_project +import mlflow.tracking._tracking_service.utils as mlflow_utils +from functools import wraps +import logging +from .env_utils import setup_mlflow_environment, ensure_mlflow_configured + +_LOGGER = logging.getLogger(__name__) + +# Store reference to original function +_original_get_tracking_uri = mlflow_utils.get_tracking_uri +_SETUP_CALLED_SUCCESSFULLY = False + + +@wraps(_original_get_tracking_uri) +def _patched_get_tracking_uri(*args, **kwargs): + """Patched version of get_tracking_uri that ensures MLflow environment is set up first. + + This wrapper ensures that setup_mlflow_environment is called before any tracking + URI operations, guaranteeing proper MLflow configuration. + + Args: + *args: Arguments passed to the original get_tracking_uri function. + **kwargs: Keyword arguments passed to the original get_tracking_uri function. + + Returns: + The result of the original get_tracking_uri function. + """ + global _SETUP_CALLED_SUCCESSFULLY + if _SETUP_CALLED_SUCCESSFULLY: + return _original_get_tracking_uri(*args, **kwargs) + try: + _SETUP_CALLED_SUCCESSFULLY = setup_mlflow_environment(set_mlflow=True) + except Exception as e: + _SETUP_CALLED_SUCCESSFULLY = False + _LOGGER.error("Failed to set up MLflow environment: %s", e) + ret = _original_get_tracking_uri(*args, **kwargs) + return ret + + +setup_mlflow_environment(set_mlflow=False) +# Replace the original function with our patched version +mlflow_utils.get_tracking_uri = _patched_get_tracking_uri + + +__all__ = ['set_project', 'setup_mlflow_environment', 'ensure_mlflow_configured'] diff --git a/datamint/mlflow/artifact/__init__.py b/datamint/mlflow/artifact/__init__.py new file mode 100644 index 00000000..6c0799a3 --- /dev/null +++ b/datamint/mlflow/artifact/__init__.py @@ -0,0 +1 @@ +from .datamint_artifacts_repo import DatamintArtifactsRepository \ No newline at end of file diff --git a/datamint/mlflow/artifact/datamint_artifacts_repo.py b/datamint/mlflow/artifact/datamint_artifacts_repo.py new file mode 100644 index 00000000..06760cc2 --- /dev/null +++ b/datamint/mlflow/artifact/datamint_artifacts_repo.py @@ -0,0 +1,8 @@ +from mlflow.store.artifact.mlflow_artifacts_repo import MlflowArtifactsRepository + + +class DatamintArtifactsRepository(MlflowArtifactsRepository): + @classmethod + def resolve_uri(cls, artifact_uri, tracking_uri): + tracking_uri = tracking_uri.split('datamint://', maxsplit=1)[-1] + return super().resolve_uri(artifact_uri, tracking_uri) diff --git a/datamint/mlflow/env_utils.py b/datamint/mlflow/env_utils.py new file mode 100644 index 00000000..eb58a52b --- /dev/null +++ b/datamint/mlflow/env_utils.py @@ -0,0 +1,109 @@ +""" +Utility functions for automatically configuring MLflow environment variables +based on Datamint configuration. +""" + +import os +import logging +from typing import Optional +from urllib.parse import urlparse +from datamint import configs + + +_LOGGER = logging.getLogger(__name__) + + +def get_datamint_api_url() -> Optional[str]: + """Get the Datamint API URL from configuration or environment variables.""" + # First check environment variable + api_url = os.getenv('DATAMINT_API_URL') + if api_url: + return api_url + + # Then check configuration + api_url = configs.get_value(configs.APIURL_KEY) + if api_url: + return api_url + + return None + + +def get_datamint_api_key() -> Optional[str]: + """Get the Datamint API key from configuration or environment variables.""" + # First check environment variable + api_key = os.getenv('DATAMINT_API_KEY') + if api_key: + return api_key + + # Then check configuration + api_key = configs.get_value(configs.APIKEY_KEY) + if api_key: + return api_key + + return None + + +def _get_mlflowdatamint_uri() -> Optional[str]: + api_url = get_datamint_api_url() + if not api_url: + return None + _LOGGER.debug(f"Retrieved Datamint API URL: {api_url}") + + # Remove trailing slash if present + api_url = api_url.rstrip('/') + # api_url samples: + # https://api.datamint.io + # http://localhost:3001 + + parsed_url = urlparse(api_url) + base_url = f"{parsed_url.scheme}://{parsed_url.hostname}" + _LOGGER.debug(f"Derived base URL for MLflow Datamint: {base_url}") + # FIXME: It should work with https or datamint-api server should forward https requests. + base_url = base_url.replace('https://', 'http://') + if len(base_url.replace('http:', '')) == 0: + return None + + mlflow_uri = f"{base_url}:5000" + return mlflow_uri + + +def setup_mlflow_environment(overwrite: bool = False, + set_mlflow: bool = True) -> bool: + """ + Automatically set up MLflow environment variables based on Datamint configuration. + + Returns: + bool: True if MLflow environment was successfully configured, False otherwise. + """ + _LOGGER.debug("Setting up MLflow environment variables from Datamint configuration") + api_key = get_datamint_api_key() + mlflow_uri = _get_mlflowdatamint_uri() + if not mlflow_uri or not api_key: + _LOGGER.warning("Datamint configuration incomplete, cannot auto-configure MLflow") + return False + + if overwrite or not os.getenv('MLFLOW_TRACKING_TOKEN'): + os.environ['MLFLOW_TRACKING_TOKEN'] = api_key + if overwrite or not os.getenv('MLFLOW_TRACKING_URI'): + os.environ['MLFLOW_TRACKING_URI'] = mlflow_uri + + if set_mlflow: + import mlflow + mlflow.set_tracking_uri(mlflow_uri) + + return True + + +def ensure_mlflow_configured() -> None: + """ + Ensure MLflow environment is properly configured. + Raises an exception if configuration is incomplete. + """ + if not setup_mlflow_environment(): + if not os.getenv('MLFLOW_TRACKING_URI') or not os.getenv('MLFLOW_TRACKING_TOKEN'): + raise ValueError( + "MLflow environment not configured. Please either:\n" + "1. Run 'datamint-config' to set up Datamint configuration, or\n" + "2. Set DATAMINT_API_URL and DATAMINT_API_KEY environment variables, or\n" + "3. Manually set MLFLOW_TRACKING_URI and MLFLOW_TRACKING_TOKEN environment variables" + ) diff --git a/datamint/mlflow/env_vars.py b/datamint/mlflow/env_vars.py new file mode 100644 index 00000000..6a47d97a --- /dev/null +++ b/datamint/mlflow/env_vars.py @@ -0,0 +1,5 @@ +from enum import Enum + +class EnvVars(Enum): + DATAMINT_PROJECT_ID = "DATAMINT_PROJECT_ID" + DATAMINT_PROJECT_NAME = "DATAMINT_PROJECT_NAME" diff --git a/datamint/mlflow/lightning/callbacks/__init__.py b/datamint/mlflow/lightning/callbacks/__init__.py new file mode 100644 index 00000000..b2c54ca0 --- /dev/null +++ b/datamint/mlflow/lightning/callbacks/__init__.py @@ -0,0 +1 @@ +from .modelcheckpoint import MLFlowModelCheckpoint \ No newline at end of file diff --git a/datamint/mlflow/lightning/callbacks/modelcheckpoint.py b/datamint/mlflow/lightning/callbacks/modelcheckpoint.py new file mode 100644 index 00000000..e695c2e2 --- /dev/null +++ b/datamint/mlflow/lightning/callbacks/modelcheckpoint.py @@ -0,0 +1,338 @@ +from lightning.pytorch.callbacks import ModelCheckpoint +from pathlib import Path +from weakref import proxy +from mlflow.store.artifact.artifact_repository_registry import get_artifact_repository +from typing import Literal, Any +import inspect +import torch +from torch import nn +import lightning.pytorch as L +from datamint.mlflow.models import log_model_metadata, _get_MLFlowLogger +from datamint.mlflow.env_utils import ensure_mlflow_configured +import mlflow +import logging +from lightning.pytorch.loggers import MLFlowLogger + +_LOGGER = logging.getLogger(__name__) + + +def help_infer_signature(x): + if isinstance(x, torch.Tensor): + return x.detach().cpu().numpy() + elif isinstance(x, dict): + return {k: v.detach().cpu().numpy() if isinstance(v, torch.Tensor) else v for k, v in x.items()} + elif isinstance(x, list): + return [v.detach().cpu().numpy() if isinstance(v, torch.Tensor) else v for v in x] + elif isinstance(x, tuple): + return tuple(v.detach().cpu().numpy() if isinstance(v, torch.Tensor) else v for v in x) + + return x + + +class MLFlowModelCheckpoint(ModelCheckpoint): + def __init__(self, *args, + register_model_name: str | None = None, + register_model_on: Literal["train", "val", "test", "predict"] | None = None, + code_paths: list[str] | None = None, + log_model_at_end_only: bool = True, + additional_metadata: dict[str, Any] | None = None, + extra_pip_requirements: list[str] | None = None, + **kwargs): + """ + MLFlowModelCheckpoint is a custom callback for PyTorch Lightning that integrates with MLFlow to log and register models. + + Args: + register_model_name (str | None): The name to register the model under in MLFlow. If None, the model will not be registered. + register_model_on (Literal["train", "val", "test", "predict"] | None): The stage at which to register the model. If None, the model will not be registered. + code_paths (list[str] | None): List of paths to Python files that should be included in the MLFlow model. + log_model_at_end_only (bool): If True, only log the model to MLFlow at the end of the training instead of after every checkpoint save. + additional_metadata (dict[str, Any] | None): Additional metadata to log with the model as a JSON file. + extra_pip_requirements (list[str] | None): Additional pip requirements to include with the MLFlow model. + **kwargs: Keyword arguments for ModelCheckpoint. + """ + # Ensure MLflow is configured when callback is initialized + ensure_mlflow_configured() + + super().__init__(*args, **kwargs) + if self.save_top_k > 1: + raise NotImplementedError("save_top_k > 1 is not supported. " + "Please use save_top_k=1 to save only the best model.") + if self.save_last is not None and self.save_top_k != 0 and self.monitor is not None: + raise NotImplementedError("save_last is not supported with monitor and save_top_k!=0. " + "Please use two separate callbacks: one for saving the last model " + "and another for saving the best model based on the monitor metric.") + + if register_model_name is not None and register_model_on is None: + raise ValueError("If you provide a register_model_name, you must also provide a register_model_on.") + if register_model_on is not None and register_model_name is None: + raise ValueError("If you provide a register_model_on, you must also provide a register_model_name.") + if register_model_on not in ["train", "val", "test", "predict", None]: + raise ValueError("register_model_on must be one of train, val, test or predict.") + + self.register_model_name = register_model_name + self.register_model_on = register_model_on + self.log_model_at_end_only = log_model_at_end_only + self._last_model_uri = None + self.last_saved_model_info = None + self._inferred_signature = None + self._input_example = None + self.code_paths = code_paths + self.additional_metadata = additional_metadata or {} + self.extra_pip_requirements = extra_pip_requirements or [] + + def _infer_params(self, model: nn.Module) -> tuple[dict, ...]: + """Extract metadata from the model's forward method signature. + + Returns: + A tuple of dicts, each containing parameter metadata ordered by position. + """ + forward_method = getattr(model.__class__, 'forward', None) + + if forward_method is None: + return () + + try: + sig = inspect.signature(forward_method) + params_list = [] + + for param_name, param in sig.parameters.items(): + if param_name == 'self': + continue + + param_info = { + 'name': param_name, + 'kind': param.kind.name, + 'annotation': param.annotation if param.annotation != inspect.Parameter.empty else None, + 'default': param.default if param.default != inspect.Parameter.empty else None, + } + params_list.append(param_info) + + # Add return annotation if available as the last element + return_annotation = sig.return_annotation + if return_annotation != inspect.Signature.empty: + return_info = {'_return_annotation': str(return_annotation)} + params_list.append(return_info) + + return tuple(params_list) + + except Exception as e: + _LOGGER.warning(f"Failed to infer forward method parameters: {e}") + return () + + def _save_checkpoint(self, trainer: L.Trainer, filepath: str) -> None: + _LOGGER.debug(f"Saving checkpoint to {filepath}...") + trainer.save_checkpoint(filepath, self.save_weights_only) + + self._last_global_step_saved = trainer.global_step + self._last_checkpoint_saved = filepath + + # notify loggers + if trainer.is_global_zero: + for logger in trainer.loggers: + logger.after_save_checkpoint(proxy(self)) + if isinstance(logger, MLFlowLogger) and not self.log_model_at_end_only: + _LOGGER.debug(f"_save_checkpoint: Logging model to MLFlow at {filepath}...") + self.log_model_to_mlflow(trainer.model, run_id=logger.run_id) + + def log_additional_metadata(self, logger: MLFlowLogger | L.Trainer, + additional_metadata: dict) -> None: + """Log additional metadata as a JSON file to the model artifact. + + Args: + logger: The MLFlowLogger or Lightning Trainer instance to use for logging. + additional_metadata: A dictionary containing additional metadata to log. + """ + self.additional_metadata = additional_metadata + if not self.additional_metadata: + return + + if self.last_saved_model_info is None: + _LOGGER.warning("No model has been saved yet. Cannot log additional metadata.") + return + + try: + log_model_metadata(metadata=self.additional_metadata, + logger=logger, + model_path=self.last_saved_model_info.artifact_path) + except Exception as e: + _LOGGER.warning(f"Failed to log additional metadata: {e}") + + def log_model_to_mlflow(self, + model: nn.Module, + run_id: str | MLFlowLogger + ) -> None: + """Log the model to MLflow.""" + if isinstance(run_id, MLFlowLogger): + logger = run_id + if logger.run_id is None: + raise ValueError("MLFlowLogger has no run_id. Cannot log model to MLFlow.") + run_id = logger.run_id + + if self._last_checkpoint_saved is None or self._last_checkpoint_saved == '': + _LOGGER.warning("No checkpoint saved yet. Cannot log model to MLFlow.") + return + + orig_device = next(model.parameters()).device + model = model.cpu() # Ensure the model is on CPU for logging + + requirements = list(self.extra_pip_requirements) + # check if lightning is in the requirements + if not any('lightning' in req.lower() for req in requirements): + requirements.append(f'lightning=={L.__version__}') + + _LOGGER.debug(f"log_model_to_mlflow: Logging model to MLFlow at {self._last_checkpoint_saved}...") + modelinfo = mlflow.pytorch.log_model( + pytorch_model=model, + artifact_path=f'model/{Path(self._last_checkpoint_saved).stem}', + signature=self._inferred_signature, + run_id=run_id, + extra_pip_requirements=requirements, + code_paths=self.code_paths + ) + + model.to(device=orig_device) # Move the model back to its original device + self._last_model_uri = modelinfo.model_uri + self.last_saved_model_info = modelinfo + + # Log additional metadata after the model is saved + log_model_metadata(self.additional_metadata, + model_path=modelinfo.artifact_path, + run_id=run_id) + + def _remove_checkpoint(self, trainer: L.Trainer, filepath: str) -> None: + super()._remove_checkpoint(trainer, filepath) + # remove the checkpoint from mlflow + if trainer.is_global_zero: + for logger in trainer.loggers: + if isinstance(logger, MLFlowLogger): + artifact_uri = logger.experiment.get_run(logger.run_id).info.artifact_uri + rep = get_artifact_repository(artifact_uri) + rep.delete_artifacts(f'model/{Path(filepath).stem}') + + def register_model(self, trainer=None): + """Register the model in MLFlow Model Registry.""" + # mlflow_client = _get_MLFlowLogger(trainer)._mlflow_client + return mlflow.register_model( + model_uri=self._last_model_uri, + name=self.register_model_name, + ) + + def _update_signature(self, trainer): + if self._inferred_signature is None: + _LOGGER.warning("No signature found. Cannot update signature.") + return + if self._last_model_uri is None: + _LOGGER.warning("No model URI found. Cannot update signature.") + return + + mllogger = _get_MLFlowLogger(trainer) + mlclient = mllogger._mlflow_client + + # check if the model exists + for artifact_info in mlclient.list_artifacts(run_id=mllogger.run_id): + if artifact_info.path.startswith('model'): + break + else: + _LOGGER.warning(f"Model URI {self._last_model_uri} does not exist. Cannot update signature.") + return + _LOGGER.debug(f"Updating signature for model URI: {self._last_model_uri}...") + # update the signature + mlflow.models.set_signature( + model_uri=self._last_model_uri, + signature=self._inferred_signature, + ) + + def __wrap_forward(self, pl_module: nn.Module): + original_forward = pl_module.forward + + def wrapped_forward(x, *args, **kwargs): + x0 = help_infer_signature(x) + infered_params = self._infer_params(pl_module) + if len(infered_params) > 1: + infered_params = {param['name']: param['default'] + for param in infered_params[1:] if 'name' in param} + else: + infered_params = None + + self._inferred_signature = mlflow.models.infer_signature(model_input=x0, + params=infered_params) + + + # run once and get back to the original forward + pl_module.forward = original_forward + method = getattr(pl_module, 'forward') + out = method(x, *args, **kwargs) + + output_sig = mlflow.models.infer_signature(model_output=help_infer_signature(out)) + self._inferred_signature.outputs = output_sig.outputs + + return out + + pl_module.forward = wrapped_forward + + def on_train_start(self, trainer, pl_module): + self.__wrap_forward(pl_module) + + def on_train_end(self, trainer: L.Trainer, pl_module: L.LightningModule) -> None: + super().on_train_end(trainer, pl_module) + + if self.log_model_at_end_only and trainer.is_global_zero: + logger = _get_MLFlowLogger(trainer) + if logger is None: + _LOGGER.warning("No MLFlowLogger found. Cannot log model to MLFlow.") + else: + self.log_model_to_mlflow(trainer.model, run_id=logger.run_id) + + self._update_signature(trainer) + + if self.register_model_on == 'train': + self.register_model(trainer) + + def _restore_model_uri(self, trainer: L.Trainer) -> None: + logger = _get_MLFlowLogger(trainer) + if logger is None: + _LOGGER.warning("No MLFlowLogger found. Cannot restore model URI.") + return + if trainer.ckpt_path is None: + return + extracted_run_id = Path(trainer.ckpt_path).parts[1] + if extracted_run_id != logger.run_id: + _LOGGER.warning(f"Run ID mismatch: {extracted_run_id} != {logger.run_id}." + + " Check `run_id` parameter in MLFlowLogger.") + self._last_model_uri = f'runs:/{logger.run_id}/model/{Path(trainer.ckpt_path).stem}' + try: + self.last_saved_model_info = mlflow.models.get_model_info(self._last_model_uri) + except mlflow.exceptions.MlflowException as e: + _LOGGER.warning(f"Failed to get model info for URI {self._last_model_uri}: {e}") + self.last_saved_model_info = None + + def on_test_start(self, trainer, pl_module): + self.__wrap_forward(pl_module) + self._restore_model_uri(trainer) + return super().on_test_start(trainer, pl_module) + + def on_predict_start(self, trainer, pl_module): + self.__wrap_forward(pl_module) + self._restore_model_uri(trainer) + return super().on_predict_start(trainer, pl_module) + + def on_test_end(self, trainer: L.Trainer, pl_module: L.LightningModule) -> None: + super().on_test_end(trainer, pl_module) + + if self.register_model_on == 'test': + self._update_signature(trainer) + self.register_model(trainer) + + def on_predict_end(self, trainer: L.Trainer, pl_module: L.LightningModule) -> None: + super().on_predict_end(trainer, pl_module) + + if self.register_model_on == 'predict': + self._update_signature(trainer) + self.register_model(trainer) + + def on_validation_end(self, trainer: L.Trainer, pl_module: L.LightningModule) -> None: + super().on_validation_end(trainer, pl_module) + + if self.register_model_on == 'val': + self._update_signature(trainer) + self.register_model(trainer) diff --git a/datamint/mlflow/models/__init__.py b/datamint/mlflow/models/__init__.py new file mode 100644 index 00000000..92a368db --- /dev/null +++ b/datamint/mlflow/models/__init__.py @@ -0,0 +1,94 @@ +import logging +import json +import lightning as L +from lightning.pytorch.loggers import MLFlowLogger +import mlflow +import os +from tempfile import TemporaryDirectory +from torch import nn + +_LOGGER = logging.getLogger(__name__) + + +def download_model_metadata(model_uri: str) -> dict: + from mlflow.tracking.artifact_utils import get_artifact_repository + + art_repo = get_artifact_repository(artifact_uri=model_uri) + try: + out_artifact_path = art_repo.download_artifacts(artifact_path='metadata.json') + except OSError as e: + _LOGGER.warning(f"Error downloading model metadata: {e}") + return {} + + with open(out_artifact_path, 'r') as f: + metadata = json.load(f) + return metadata + + +def _get_MLFlowLogger(trainer: L.Trainer) -> MLFlowLogger: + for logger in trainer.loggers: + if isinstance(logger, MLFlowLogger): + return logger + raise ValueError("No MLFlowLogger found in the trainer loggers.") + + +def log_model_metadata(metadata: dict, + mlflow_model: mlflow.models.Model | None = None, + logger: MLFlowLogger | L.Trainer | None = None, + model_path: str | None = None, + run_id: str | None = None, + ) -> None: + """ + Log additional metadata to the MLflow model. + It should be provided the one of the following combination of parameters: + 1. `mlflow_model` + 2. `logger` and `model_path` + 3. `run_id` and `model_path` + + Args: + self: The instance of the class where this method is called. + metadata (dict): The metadata to log. + mlflow_model (mlflow.models.Model, optional): The MLflow model object. Defaults to None. + logger (MLFlowLogger or L.Trainer, optional): The MLFlow logger or Lightning Trainer instance. Defaults to None. + model_path (str, optional): The path where the model is stored in MLflow. Defaults to None. + run_id (str, optional): The run ID of the MLflow run. Defaults to None. + """ + + # Validate inputs + if mlflow_model is None and (logger is None or model_path is None) and (run_id is None or model_path is None): + raise ValueError( + "You must provide either `mlflow_model`, or both `logger` and `model_path`, " + "or both `run_id` and `model_path`." + ) + # not both + if mlflow_model is not None and logger is not None: + raise ValueError("Only one of mlflow_model or logger can be provided.") + + if logger is not None and isinstance(logger, L.Trainer): + logger = _get_MLFlowLogger(logger) + if logger is None: + raise ValueError("MLFlowLogger not found in the Trainer's loggers.") + run_id = logger.run_id + artifact_path = model_path + mlfclient = logger.experiment + elif mlflow_model is not None: + run_id = mlflow_model.run_id + artifact_path = mlflow_model.artifact_path + mlfclient = mlflow.client.MlflowClient() + elif run_id is not None and model_path is not None: + mlfclient = mlflow.client.MlflowClient() + artifact_path = model_path + else: + raise ValueError("Invalid logger or mlflow_model provided.") + + with TemporaryDirectory() as tmpdir: + metadata_path = os.path.join(tmpdir, "metadata.json") + with open(metadata_path, "w") as f: + json.dump(metadata, f, indent=2) + + mlfclient.log_artifact( + run_id=run_id, + local_path=metadata_path, + artifact_path=artifact_path, + ) + _LOGGER.debug(f"Additional metadata logged to {artifact_path}/metadata.json") \ No newline at end of file diff --git a/datamint/mlflow/tracking/datamint_store.py b/datamint/mlflow/tracking/datamint_store.py new file mode 100644 index 00000000..f0413f47 --- /dev/null +++ b/datamint/mlflow/tracking/datamint_store.py @@ -0,0 +1,46 @@ +from mlflow.store.tracking.rest_store import RestStore +from functools import partial +from .fluent import get_active_project_id +import json + + +class DatamintStore(RestStore): + """ + DatamintStore is a subclass of RestStore that provides a tracking store + implementation for Datamint. + """ + + def __init__(self, store_uri: str, artifact_uri=None, force_valid=True): + # Ensure MLflow environment is configured when store is initialized + from datamint.mlflow.env_utils import setup_mlflow_environment + from mlflow.utils.credentials import get_default_host_creds + setup_mlflow_environment() + + if store_uri.startswith('datamint://') or 'datamint.io' in store_uri or force_valid: + self.invalid = False + else: + self.invalid = True + + store_uri = store_uri.split('datamint://', maxsplit=1)[-1] + get_host_creds = partial(get_default_host_creds, store_uri) + super().__init__(get_host_creds=get_host_creds) + + def create_experiment(self, name, artifact_location=None, tags=None, project_id: str = None) -> str: + from mlflow.protos.service_pb2 import CreateExperiment + from mlflow.utils.proto_json_utils import message_to_json + + if self.invalid: + return super().create_experiment(name, artifact_location, tags) + if project_id is None: + project_id = get_active_project_id() + tag_protos = [tag.to_proto() for tag in tags] if tags else [] + req_body = message_to_json( + CreateExperiment(name=name, artifact_location=artifact_location, tags=tag_protos) + ) + + req_body = json.loads(req_body) + req_body["project_id"] = project_id # FIXME: this should be in the proto + req_body = json.dumps(req_body) + + response_proto = self._call_endpoint(CreateExperiment, req_body) + return response_proto.experiment_id diff --git a/datamint/mlflow/tracking/default_experiment.py b/datamint/mlflow/tracking/default_experiment.py new file mode 100644 index 00000000..e40f4efb --- /dev/null +++ b/datamint/mlflow/tracking/default_experiment.py @@ -0,0 +1,27 @@ +import sys +import os +from mlflow.tracking.default_experiment.abstract_context import DefaultExperimentProvider + + +class DatamintExperimentProvider(DefaultExperimentProvider): + _experiment_id = None + + def in_context(self): + return True + + def get_experiment_id(self): + from mlflow.tracking.client import MlflowClient + + if DatamintExperimentProvider._experiment_id is not None: + return self._experiment_id + # Get the filename of the main source file + source_code_filename = os.path.basename(sys.argv[0]) + mlflowclient = MlflowClient() + exp = mlflowclient.get_experiment_by_name(source_code_filename) + if exp is None: + experiment_id = mlflowclient.create_experiment(source_code_filename) + else: + experiment_id = exp.experiment_id + DatamintExperimentProvider._experiment_id = experiment_id + + return experiment_id diff --git a/datamint/mlflow/tracking/fluent.py b/datamint/mlflow/tracking/fluent.py new file mode 100644 index 00000000..b39b1819 --- /dev/null +++ b/datamint/mlflow/tracking/fluent.py @@ -0,0 +1,78 @@ +from typing import Optional +import threading +import logging +from datamint import Api +from datamint.exceptions import DatamintException +import os +from datamint.mlflow.env_vars import EnvVars +from datamint.mlflow.env_utils import ensure_mlflow_configured + +_PROJECT_LOCK = threading.Lock() +_LOGGER = logging.getLogger(__name__) + +_ACTIVE_PROJECT_ID: Optional[str] = None + + +def get_active_project_id() -> str | None: + """ + Get the active project ID from the environment variable or the global variable. + """ + global _ACTIVE_PROJECT_ID + + if _ACTIVE_PROJECT_ID is not None: + return _ACTIVE_PROJECT_ID + # Check if the environment variable is set + project_id = os.getenv(EnvVars.DATAMINT_PROJECT_ID.value) + if project_id is not None: + _ACTIVE_PROJECT_ID = project_id + return project_id + project_name = os.getenv(EnvVars.DATAMINT_PROJECT_NAME.value) + if project_name is not None: + project = _find_project_by_name(project_name) + if project is not None: + _ACTIVE_PROJECT_ID = project['id'] + return _ACTIVE_PROJECT_ID + + return None + + +def _find_project_by_name(project_name: str): + dt_client = Api(check_connection=False) + project = dt_client.projects.get_by_name(project_name) + if project is None: + raise DatamintException(f"Project with name '{project_name}' does not exist.") + return project + + +def set_project(project_name: Optional[str] = None, project_id: Optional[str] = None): + from mlflow.exceptions import MlflowException + global _ACTIVE_PROJECT_ID + + # Ensure MLflow is properly configured before proceeding + ensure_mlflow_configured() + + if project_name is None and project_id is None: + raise MlflowException("You must specify either a project name or a project id") + + if project_name is not None and project_id is not None: + raise MlflowException("You cannot specify both a project name and a project id") + + with _PROJECT_LOCK: + dt_client = Api(check_connection=False) + if project_id is None: + project = dt_client.projects.get_by_name(project_name) + if project is None: + raise DatamintException(f"Project with name '{project_name}' does not exist.") + project_id = project.id + else: + project = dt_client.projects.get_by_id(project_id) + if project is None: + raise DatamintException(f"Project with id '{project_id}' does not exist.") + + _ACTIVE_PROJECT_ID = project_id + + # Set 'DATAMINT_PROJECT_ID' environment variable + # so that subprocess can inherit it. + os.environ[EnvVars.DATAMINT_PROJECT_ID.value] = project_id + + return project diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index c13064ef..e5f52716 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -1,3 +1,8 @@ +Getting Started with Datamint Python API +========================================= + +This guide will help you set up and start using the Datamint Python API for your medical imaging projects. + Installation =================================== @@ -18,10 +23,12 @@ You can do this by running: pip install -U datamint +.. include:: setup_api_key.rst Next Steps ------------ -- Setup your API key: :ref:`setup_api_key` -- Check out our command line tools: :ref:`command_line_tools` +Now that you have the basics set up, explore these advanced topics: + +- Master the command-line interface: :ref:`command_line_tools` - Check out our Python API documentation: :ref:`client_python_api` -- Our Pytorch integration: :ref:`pytorch_integration` \ No newline at end of file +- Our Pytorch, Lightning and MLflow integration: :ref:`pytorch_integration` \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index a709e1ba..3bbf3ef0 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -25,7 +25,6 @@ Datamint :caption: Contents getting_started - setup_api_key command_line_tools client_api pytorch_integration @@ -40,8 +39,38 @@ Datamint datamint.entities -Indices and tables -================== +Quick Start +----------- + +Install the package: + +.. code-block:: bash + + pip install datamint + +Configure your API access: + +.. code-block:: bash + + datamint-config + +Start using the API: + +.. code-block:: python + + from datamint import Api + + # Initialize API handler + api = Api() + all_projects = api.projects.get_all() + + +Community & Support +------------------- +`GitHub Issues `_ + +Indices and Tables +------------------ * :ref:`genindex` * :ref:`modindex` diff --git a/docs/source/pytorch_integration.rst b/docs/source/pytorch_integration.rst index d67f9fa3..1a955fab 100644 --- a/docs/source/pytorch_integration.rst +++ b/docs/source/pytorch_integration.rst @@ -1,28 +1,61 @@ .. _pytorch_integration: -Pytorch integration -=================== -Before continuing, you may want to check the :ref:`setup_api_key` section to easily set up your API key, if you haven't done so yet. +PyTorch & Lightning Integration +=============================== -Dataset -------- +The Datamint Python API provides seamless integration with PyTorch and PyTorch Lightning, enabling efficient machine learning workflows for medical imaging tasks. -Datamint provides a custom PyTorch dataset class that can be used to load data from the server in a PyTorch-friendly way. -To use it, import the |DatamintDatasetClass| class and create an instance of it, passing the necessary parameters. +Overview +-------- -.. code-block:: python +Key integration features: + +- **DatamintDataModule**: Lightning-compatible data module +- **MLFlowModelCheckpoint**: Advanced model checkpointing with MLflow integration +- **Automatic Experiment Tracking**: Seamless logging and model registration +- **Medical Image Optimizations**: Specialized handling for medical data formats - from datamint import Dataset +PyTorch Dataset Integration +--------------------------- - dataset = Dataset('../data', - project_name='MyProjectName', # Must exists in the server - # return_frame_by_frame=True, # Optional, if you want each item to be a frame instead of a video/3d-image - ) +Basic PyTorch Usage +~~~~~~~~~~~~~~~~~~~ -and then use it in your PyTorch code as usual. +.. code-block:: python -Here is a complete example that inherits |DatamintDatasetClass|: + import torch + from torch.utils.data import DataLoader + from datamint import Dataset + + # Load dataset. This is a PyTorch-compatible dataset that can be used directly. + dataset = Dataset( + project_name="liver-segmentation", + return_annotations=True, + return_frame_by_frame=True, + include_unannotated=False + ) + + # Create PyTorch DataLoader + dataloader = DataLoader( + dataset, + batch_size=16, + shuffle=True, + num_workers=4, + collate_fn=dataset.get_collate_fn() + ) + + # Training loop + for batch in dataloader: + images = batch['image'] # Shape: [B, C, H, W] + masks = batch['segmentation'] # Shape: [B, H, W] + metadata = batch['metainfo'] # List of dicts + # (...) + +Dataset Transforms +~~~~~~~~~~~~~~~~~~ + +Apply transforms for data augmentation and preprocessing: .. code-block:: python diff --git a/notebooks/mlflow_simple_training.ipynb b/notebooks/mlflow_simple_training.ipynb new file mode 100644 index 00000000..ed7756c6 --- /dev/null +++ b/notebooks/mlflow_simple_training.ipynb @@ -0,0 +1,593 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7ea9bc4f", + "metadata": {}, + "source": [ + "# MLflow Simple Training Tutorial\n", + "\n", + "This notebook demonstrates how to train a semantic segmentation model using Datamint's MLflow integration. You'll learn how to:\n", + "\n", + "- Set up your environment and configure MLflow\n", + "- Load and visualize data from Datamint\n", + "- Define data transformations for training\n", + "- Train a model with automatic MLflow logging\n", + "- Test the model and register it in the model registry\n", + "- Make predictions with the trained model\n", + "\n", + "## Prerequisites\n", + "\n", + "Before running this notebook, make sure you have:\n", + "1. Datamint Python API installed (`pip install git+https://github.com/Sonance/datamint-python-api.git`)\n", + "2. Your API key configured (run `datamint-config` in terminal)\n", + "3. Access to a project with segmentation data\n", + "4. Basic understanding of PyTorch and/or PyTorch Lightning\n", + "\n", + "## What is MLflow?\n", + "\n", + "MLflow is an open-source platform for managing machine learning workflows. It helps you:\n", + "- Track experiments (metrics, parameters, code versions)\n", + "- Package and reproduce models\n", + "- Deploy models to production\n", + "- Manage model versions in a central registry\n", + "\n", + "Datamint provides seamless MLflow integration, automatically configuring tracking and artifact storage." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07325547", + "metadata": {}, + "outputs": [], + "source": [ + "# STEP 1: Environment Setup\n", + "# ========================\n", + "\n", + "# Import datamint.mlflow to automatically configure MLflow environment\n", + "# This sets up MLflow tracking URI and authentication based on your Datamint configuration\n", + "import datamint.mlflow\n", + "from datamint import APIHandler\n", + "import logging\n", + "import rich.logging\n", + "\n", + "logging.getLogger().addHandler(rich.logging.RichHandler())\n", + "LOGGER = logging.getLogger(__name__)\n", + "LOGGER.setLevel(logging.INFO)\n", + "\n", + "\n", + "# Initialize Datamint API handler to verify connection\n", + "# This will use your configured API key (set via `datamint-config` command)\n", + "api = APIHandler()\n", + "LOGGER.info(\"✅ Datamint API connection established successfully!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c1ef3e5", + "metadata": {}, + "outputs": [], + "source": [ + "# STEP 2: Project Configuration\n", + "# =============================\n", + "\n", + "import lightning as L\n", + "from lightning.pytorch.loggers import MLFlowLogger\n", + "from datamint.mlflow import set_project\n", + "\n", + "# IMPORTANT: Replace 'BoneSeg' with your actual project name\n", + "PROJECT_NAME = 'BoneSeg' # you can retrieve project names using `api.get_projects()`\n", + "\n", + "# Set the active project for MLflow tracking\n", + "# This ensures all experiments are logged under the correct project\n", + "project_info = set_project(PROJECT_NAME)\n", + "LOGGER.info(f\"✅ Active project set to: {project_info['name']}\")\n", + "LOGGER.info(f\"Description: {project_info.get('description', 'No description')}\")" + ] + }, + { + "cell_type": "markdown", + "id": "b456d53e", + "metadata": {}, + "source": [ + "## Data Transformations\n", + "\n", + "Data augmentation is crucial for training robust models. We'll use Albumentations library to define transformations that:\n", + "\n", + "- **Resize and crop**: Standardize input size while maintaining aspect ratio\n", + "- **Symmetry**: Apply square symmetry for anatomical consistency \n", + "- **Color jitter**: Vary brightness/contrast to handle different imaging conditions\n", + "- **Gaussian noise**: Add robustness to image artifacts\n", + "\n", + "> 💡 **Tip**: Start with simple transformations and gradually add more complex ones. Monitor validation metrics to ensure augmentations help rather than hurt performance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f655f316", + "metadata": {}, + "outputs": [], + "source": [ + "# STEP 3: Define Data Transformations\n", + "# ===================================\n", + "\n", + "from datamintapi.utils.visualization import show, draw_masks\n", + "import albumentations as A\n", + "from datamint import Dataset\n", + "\n", + "# Define the target image size for training\n", + "# Smaller sizes train faster but may lose detail; larger sizes are more accurate but slower\n", + "IMAGE_SIZE = (512, 512)\n", + "\n", + "# Create augmentation pipeline using Albumentations\n", + "# Each transformation has a probability (p) of being applied\n", + "transf = A.Compose([\n", + " # Randomly crop and resize to target size (scale: 33%-100% of original)\n", + " A.RandomResizedCrop(size=IMAGE_SIZE, scale=(0.33, 1.0), ratio=(0.9, 1.1), p=1.0),\n", + " \n", + " # Apply square symmetry (useful for anatomical structures)\n", + " A.SquareSymmetry(p=0.5),\n", + " \n", + " # Vary image appearance (brightness, contrast) - no hue/saturation for medical images\n", + " A.ColorJitter(brightness=0.5, contrast=0.5, saturation=0.0, hue=0.0, p=0.5),\n", + " \n", + " # Add small amount of noise for robustness\n", + " A.GaussNoise(std_range=(0.01, 0.1), per_channel=False, p=0.2),\n", + "])\n", + "\n", + "# Load dataset for visualization\n", + "LOGGER.info(\"Loading dataset...\")\n", + "D = Dataset(\n", + " project_name=PROJECT_NAME,\n", + " return_as_semantic_segmentation=True, # Convert to pixel-level masks\n", + " semantic_seg_merge_strategy=\"union\", # Combine overlapping annotations\n", + " return_frame_by_frame=True, # Individual frames (not videos)\n", + " include_unannotated=False, # Only annotated data\n", + " auto_update=False, # Don't check for updates (faster)\n", + " alb_transform=transf, # Apply our transformations\n", + ")\n", + "\n", + "LOGGER.info(f\"✅ Dataset loaded: {len(D)} samples\")\n", + "LOGGER.info(f\"Available segmentation labels: {D.segmentation_labels_set}\")\n", + "\n", + "# Visualize a sample with transformations applied\n", + "item = D[0]\n", + "LOGGER.info(f\"Image shape: {item['image'].shape}\")\n", + "LOGGER.info(f\"Segmentation shape: {item['segmentations'].shape}\")\n", + "\n", + "# Display the image with overlay masks (excluding background at index 0)\n", + "show(draw_masks(item['image'], item['segmentations'][1:], alpha=0.5))" + ] + }, + { + "cell_type": "markdown", + "id": "92a7cf4c", + "metadata": {}, + "source": [ + "## Model Setup\n", + "\n", + "We'll now set up the training components:\n", + "\n", + "1. **DataModule**: Handles data loading and train/validation splits\n", + "2. **Model**: Custom segmentation model (DeepLabV3 with ResNet50 backbone)\n", + "3. **MLflow Integration**: Automatic experiment tracking and model versioning\n", + "\n", + "### Key Components Explained:\n", + "\n", + "- **DatamintDataModule**: Lightning-compatible data loader for Datamint datasets\n", + "- **MyModel**: Custom model with multiple loss functions (CrossEntropy + GIOU + Focal)\n", + "- **MLFlowModelCheckpoint**: Saves best models and logs them to MLflow automatically" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7032c22", + "metadata": {}, + "outputs": [], + "source": [ + "# STEP 4: Import Training Components\n", + "# =================================\n", + "\n", + "from datamint.lightning import DatamintDataModule # Lightning integration for Datamint\n", + "from my_custom_model import MyModel # Your custom segmentation model\n", + "from datamint.mlflow.lightning.callbacks import MLFlowModelCheckpoint # MLflow integration\n", + "\n", + "# Import torch for performance optimization\n", + "import torch\n", + "\n", + "LOGGER.info(\"✅ All training components imported successfully!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38b308ed", + "metadata": {}, + "outputs": [], + "source": [ + "# STEP 5: Configure Training Setup\n", + "# ===============================\n", + "\n", + "# Define metadata that will be saved with the model\n", + "# This helps with model deployment and inference later\n", + "model_metadata = {\n", + " \"task_type\": \"semantic_segmentation\",\n", + " \"labels\": [\"background\"] + D.segmentation_labels_set, # Include background as first label\n", + " \"need_gpu\": False, # Whether GPU is required for inference\n", + " \"automatic_preprocessing\": True # Whether preprocessing is handled automatically\n", + "}\n", + "\n", + "LOGGER.info(f\"Model will predict {len(model_metadata['labels'])} classes:\")\n", + "for i, label in enumerate(model_metadata['labels']):\n", + " LOGGER.info(f\" {i}: {label}\")\n", + "\n", + "# Configure model checkpointing with MLflow integration\n", + "checkcb = MLFlowModelCheckpoint(\n", + " monitor=\"val/loss\", # Metric to monitor for best model\n", + " mode=\"min\", # Save model when monitored metric decreases\n", + " save_top_k=1, # Keep only the best model\n", + " filename=\"best\", # Checkpoint filename\n", + " save_weights_only=True, # Save only model weights (not optimizer state)\n", + " register_model_name=PROJECT_NAME, # Name for model registry\n", + " register_model_on='test', # Register model after testing\n", + " code_paths=['my_custom_model.py'], # Include source code with model\n", + " log_model_at_end_only=True, # Log to MLflow only at the end (faster)\n", + " additional_metadata=model_metadata, # Include our metadata\n", + ")\n", + "\n", + "# Create MLflow logger for experiment tracking\n", + "mlflow_logger = MLFlowLogger(experiment_name=PROJECT_NAME)\n", + "LOGGER.info(f\"✅ MLflow experiment: {PROJECT_NAME}\")\n", + "\n", + "# Configure Lightning Trainer\n", + "trainer = L.Trainer(\n", + " max_epochs=10, # Number of training epochs\n", + " logger=mlflow_logger, # MLflow integration\n", + " precision='16-mixed', # Use mixed precision for faster training\n", + " enable_model_summary=True, # Show model architecture summary\n", + " enable_progress_bar=True, # Show training progress\n", + " callbacks=[checkcb], # Include our checkpoint callback\n", + " num_sanity_val_steps=0, # Skip validation sanity check\n", + ")\n", + "\n", + "# Initialize the model\n", + "# Note: num_classes should match the number of segmentation classes (excluding background)\n", + "num_classes = len(D.segmentation_labels_set)\n", + "model = MyModel(num_classes=num_classes, learning_rate=3e-4)\n", + "LOGGER.info(f\"✅ Model initialized for {num_classes} classes\")\n", + "\n", + "# Create data module with train/validation split\n", + "dm = DatamintDataModule(\n", + " PROJECT_NAME,\n", + " batch_size=8, # Adjust based on your GPU memory\n", + " alb_transform=transf, # Apply our transformations\n", + " num_workers=8, # Parallel data loading workers\n", + " # enable_video_cache=True, # Uncomment to cache video frames\n", + " include_segmentation_names=['fibula', 'tibia', 'patella', 'femur'] # Specify which labels to include\n", + ")\n", + "\n", + "LOGGER.info(\"✅ Training setup complete!\")\n", + "LOGGER.info(f\"Batch size: {dm.batch_size}\")\n", + "LOGGER.info(f\"Data workers: {dm.num_workers}\")" + ] + }, + { + "cell_type": "markdown", + "id": "947f4fa7", + "metadata": {}, + "source": [ + "## Training\n", + "\n", + "Now we'll start the actual training process. This will:\n", + "\n", + "1. Automatically split your data into training and validation sets\n", + "2. Train the model for the specified number of epochs\n", + "3. Track metrics (loss, IoU, etc.) in MLflow\n", + "4. Save the best model checkpoint based on validation loss\n", + "\n", + "### What to expect:\n", + "- Training progress bar with loss values\n", + "- Automatic logging of metrics to MLflow\n", + "- Model checkpointing when validation improves\n", + "\n", + "> ⚠️ **Note**: Training time depends on your data size, model complexity, and hardware. Start with fewer epochs for testing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48c174b6", + "metadata": {}, + "outputs": [], + "source": [ + "# STEP 6: Start Training\n", + "# =====================\n", + "\n", + "# Optimize matrix multiplication performance (PyTorch 2.0+)\n", + "torch.set_float32_matmul_precision('high')\n", + "\n", + "LOGGER.info(\"🚀 Starting training...\")\n", + "LOGGER.info(\"This will automatically:\")\n", + "LOGGER.info(\" - Split data into train/validation sets\")\n", + "LOGGER.info(\" - Track metrics in MLflow\")\n", + "LOGGER.info(\" - Save the best model checkpoint\")\n", + "LOGGER.info(\" - Log model artifacts\")\n", + "\n", + "# Start training!\n", + "trainer.fit(model, datamodule=dm)\n", + "\n", + "LOGGER.info(\"✅ Training completed!\")\n", + "LOGGER.info(f\"Best model saved at: {checkcb.best_model_path}\")\n", + "LOGGER.info(f\"MLflow run ID: {mlflow_logger.run_id}\")" + ] + }, + { + "cell_type": "markdown", + "id": "6d4362ab", + "metadata": {}, + "source": [ + "## Manual Model Logging (Optional)\n", + "\n", + "If you interrupted training or want to log the current model state manually, you can use the cell below. This is useful for:\n", + "\n", + "- Recovering from interrupted training sessions\n", + "- Logging intermediate model states\n", + "- Testing the logging functionality\n", + "\n", + "> 💡 **Tip**: This is only needed if automatic logging failed or was interrupted." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3cfeec66", + "metadata": {}, + "outputs": [], + "source": [ + "# STEP 7: Manual Model Logging (if needed)\n", + "# =======================================\n", + "\n", + "# Uncomment the following line if you cancelled training but want to log the model anyway:\n", + "# checkcb.log_model_to_mlflow(model, mlflow_logger.run_id)\n", + "\n", + "LOGGER.info(\"Manual logging skipped - model should have been logged automatically during training\")" + ] + }, + { + "cell_type": "markdown", + "id": "3935cedc", + "metadata": {}, + "source": [ + "## Update Model Metadata (Optional)\n", + "\n", + "You can add or update metadata after training is complete. This is useful for:\n", + "\n", + "- Adding deployment-specific information\n", + "- Updating model descriptions\n", + "- Including performance benchmarks\n", + "- Specifying hardware requirements\n", + "\n", + "The metadata is stored as a JSON file alongside your model in MLflow." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e9b009c", + "metadata": {}, + "outputs": [], + "source": [ + "# STEP 8: Update Model Metadata (Optional)\n", + "# ========================================\n", + "\n", + "# Define updated or additional metadata\n", + "model_metadata = {\n", + " \"task_type\": \"semantic_segmentation\",\n", + " \"labels\": [\"background\"] + D.segmentation_labels_set,\n", + " \"need_gpu\": False,\n", + " \"automatic_preprocessing\": True,\n", + "}\n", + "\n", + "LOGGER.info(\"Updating model metadata...\")\n", + "LOGGER.info(\"New metadata:\")\n", + "for key, value in model_metadata.items():\n", + " LOGGER.info(f\" {key}: {value}\")\n", + "\n", + "# Log the metadata (this will overwrite existing metadata)\n", + "checkcb.log_additional_metadata(\n", + " trainer, # Pass trainer (or mlflow_logger directly)\n", + " model_metadata # Updated metadata dictionary\n", + ")\n", + "\n", + "LOGGER.info(\"✅ Metadata updated successfully!\")" + ] + }, + { + "cell_type": "markdown", + "id": "9a762f14", + "metadata": {}, + "source": [ + "## Model Testing\n", + "\n", + "Now we'll evaluate the trained model on the test set. This will:\n", + "\n", + "1. Load the best model checkpoint (not the final training state)\n", + "2. Run inference on the test/validation data\n", + "3. Calculate final performance metrics\n", + "4. Automatically register the model in MLflow Model Registry\n", + "\n", + "> 📊 **Important**: We test on the best checkpoint (lowest validation loss) rather than the final model state to get the most reliable performance estimates." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "add45982", + "metadata": {}, + "outputs": [], + "source": [ + "# STEP 9: Test the Model\n", + "# =====================\n", + "\n", + "LOGGER.info(\"🧪 Starting model testing...\")\n", + "LOGGER.info(\"This will:\")\n", + "LOGGER.info(\" - Load the best model checkpoint\")\n", + "LOGGER.info(\" - Evaluate on test data\") \n", + "LOGGER.info(\" - Log final metrics to MLflow\")\n", + "LOGGER.info(\" - Register model in MLflow Model Registry\")\n", + "\n", + "# Test using the best model checkpoint\n", + "test_results = trainer.test(\n", + " model,\n", + " ckpt_path=checkcb.best_model_path, # Use best model, not last\n", + " datamodule=dm\n", + ")\n", + "\n", + "LOGGER.info(\"✅ Testing completed!\")\n", + "LOGGER.info(\"Final test metrics:\")\n", + "for metric_name, value in test_results[0].items():\n", + " LOGGER.info(f\" {metric_name}: {value:.4f}\")\n", + "\n", + "# Model registration happens automatically due to register_model_on='test'\n", + "LOGGER.info(f\"🏆 Model registered in MLflow Model Registry as '{PROJECT_NAME}'\")" + ] + }, + { + "cell_type": "markdown", + "id": "67727687", + "metadata": {}, + "source": [ + "# Making Predictions\n", + "\n", + "Now let's use our trained model to make predictions on new data. This section demonstrates:\n", + "\n", + "1. Loading the trained model\n", + "2. Setting up a prediction pipeline\n", + "3. Running inference on test data\n", + "4. Visualizing the results\n", + "\n", + "This is similar to how you would deploy the model in production.\n", + "\n", + "## Alternative Model Loading\n", + "\n", + "You can load models in several ways:\n", + "- From checkpoint file: `trainer.predict(model, ckpt_path=\"path/to/checkpoint\")`\n", + "- From MLflow registry: `mlflow.pytorch.load_model(\"models:/ModelName/Version\")`\n", + "- From MLflow run: `mlflow.pytorch.load_model(\"runs:/run_id/model/artifact_path\")`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bff8bab5", + "metadata": {}, + "outputs": [], + "source": [ + "# STEP 10: Make Predictions\n", + "# ========================\n", + "\n", + "LOGGER.info(\"🔮 Setting up prediction pipeline...\")\n", + "\n", + "# Create a new trainer for prediction (no training setup needed)\n", + "pred_trainer = L.Trainer(\n", + " enable_model_summary=True,\n", + " enable_progress_bar=True,\n", + ")\n", + "\n", + "# Set up data module for prediction (same as before)\n", + "pred_dm = DatamintDataModule(\n", + " PROJECT_NAME,\n", + " batch_size=8,\n", + " alb_transform=transf,\n", + " include_segmentation_names=['fibula', 'tibia', 'patella', 'femur']\n", + ")\n", + "\n", + "LOGGER.info(\"Running predictions...\")\n", + "LOGGER.info(\"Note: Using the model already in memory\")\n", + "LOGGER.info(\"Alternative: Load from MLflow registry with:\")\n", + "LOGGER.info(f\" model = mlflow.pytorch.load_model('models:/{PROJECT_NAME}/latest')\")\n", + "\n", + "# Option 1: Use model already in memory\n", + "preds = pred_trainer.predict(\n", + " model,\n", + " # ckpt_path=checkcb.best_model_path, # Uncomment to load from checkpoint\n", + " datamodule=pred_dm\n", + ")\n", + "\n", + "# Option 2: Load from MLflow Model Registry (commented out)\n", + "# registered_model = mlflow.pytorch.load_model(f'models:/{PROJECT_NAME}/latest')\n", + "# preds = pred_trainer.predict(registered_model, datamodule=pred_dm)\n", + "\n", + "LOGGER.info(f\"✅ Predictions completed!\")\n", + "LOGGER.info(f\"Generated {len(preds)} batches of predictions\")\n", + "LOGGER.info(f\"First batch shape: {preds[0].shape}\")" + ] + }, + { + "cell_type": "markdown", + "id": "d97b59db", + "metadata": {}, + "source": [ + "## Visualizing Results\n", + "\n", + "Let's visualize the model's predictions to see how well it's performing. We'll:\n", + "\n", + "1. Convert model outputs to binary masks\n", + "2. Load the corresponding input images\n", + "3. Overlay predicted masks on the original images\n", + "4. Display the results\n", + "\n", + "> 🎨 **Visualization Notes**: \n", + "> - We exclude the background class (index 0) from visualization\n", + "> - Different colors represent different anatomical structures\n", + "> - Transparency (alpha) allows you to see both image and predictions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18b01d97", + "metadata": {}, + "outputs": [], + "source": [ + "# STEP 11: Visualize Predictions\n", + "# ==============================\n", + "predicted_mask = preds[0] > 0\n", + "# plot mask\n", + "for batch in dm.predict_dataloader():\n", + " imgs = batch['image']\n", + " break\n", + "\n", + "imgs_with_mask = []\n", + "for im, pr in zip(imgs, predicted_mask):\n", + " imgs_with_mask.append(draw_masks(im, pr[1:])) # pr[0] is the background\n", + "show(imgs_with_mask, figsize=(16, 7))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/use_cases/fracatlas_classification.ipynb b/notebooks/use_cases/fracatlas_classification.ipynb new file mode 100644 index 00000000..1da2a825 --- /dev/null +++ b/notebooks/use_cases/fracatlas_classification.ipynb @@ -0,0 +1,668 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "64fddbde", + "metadata": {}, + "source": [ + "# Fracture Classification with Datamint and FracAtlas Dataset\n", + "\n", + "Train a binary classification model to detect fractures in musculoskeletal radiographs using the FracAtlas dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "734f7a66", + "metadata": {}, + "outputs": [], + "source": [ + "from datamint import Api\n", + "\n", + "PROJECT_NAME = \"FracAtlas\"\n", + "\n", + "api = Api()" + ] + }, + { + "cell_type": "markdown", + "id": "4450f467", + "metadata": {}, + "source": [ + "## Setup: Create Project and Upload Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "543295f2", + "metadata": {}, + "outputs": [], + "source": [ + "from datamint.mlflow import set_project\n", + "\n", + "proj = api.projects.get_by_name(PROJECT_NAME)\n", + "if not proj:\n", + " print(f\"Creating project '{PROJECT_NAME}'\")\n", + " proj = api.projects.create(name=PROJECT_NAME,\n", + " description=\"Project to train a segmentation model on FracAtlas dataset\")\n", + " \n", + "set_project(PROJECT_NAME)" + ] + }, + { + "cell_type": "markdown", + "id": "cdd506aa", + "metadata": {}, + "source": [ + "### Download FracAtlas Dataset\n", + "\n", + "Dataset source: [Figshare](https://doi.org/10.6084/m9.figshare.22363012)\n", + "\n", + "**Citation:** Abedeen, I., et al. (2023). FracAtlas: A Dataset for Fracture Classification, Localization and Segmentation of Musculoskeletal Radiographs. Scientific Data, 10(1). doi:10.1038/s41597-023-02432-4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62fa6238", + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "import zipfile\n", + "import os\n", + "\n", + "# Retrieve and download FracAtlas dataset from Figshare\n", + "# It might take a while depending on your internet connection. ~50 seconds on a 100Mbps connection\n", + "r = requests.get('https://api.figshare.com/v2/articles/22363012')\n", + "if r.status_code == 200:\n", + " file_metadata = r.json()['files'][0]\n", + " file_name = file_metadata['name']\n", + " print(f'Downloading {file_name}...')\n", + " \n", + " # Download and extract\n", + " r = requests.get(file_metadata['download_url'], allow_redirects=True)\n", + " with open(file_name, 'wb') as f:\n", + " f.write(r.content)\n", + " \n", + " print(f'Unzipping {file_name}...')\n", + " with zipfile.ZipFile(file_name, 'r') as zip_ref:\n", + " zip_ref.extractall(os.path.splitext(file_name)[0])\n", + "else:\n", + " print('Error:', r.text)" + ] + }, + { + "cell_type": "markdown", + "id": "ff63feee", + "metadata": {}, + "source": [ + "The dataset is structured as follows:\n", + "\n", + "```bash\n", + "FracAtlas/\n", + "├── images/\n", + "│ ├── Fractured/\n", + "│ │ ├── IMG0000110.jpg\n", + "│ │ └── ...\n", + "│ └── Non_fractured/\n", + "│ ├── IMG0002341.jpg\n", + "│ └── ...\n", + "├── Utilities/\n", + "└── ...\n", + "```\n", + "\n", + "We are going to use the `images` folder for our binary classification task." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2bdf58fd", + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "import os\n", + "\n", + "# get all non-fractured images\n", + "non_fractured_root_path = Path('FracAtlas/FracAtlas/images/Non_fractured/')\n", + "fractured_root_path = Path('FracAtlas/FracAtlas/images/Fractured/')\n", + "non_fractured_images_paths = [str(non_fractured_root_path / img) for img in os.listdir(non_fractured_root_path)]\n", + "fractured_images_paths = [str(fractured_root_path / img) for img in os.listdir(fractured_root_path)]\n", + "\n", + "print(f'Found {len(non_fractured_images_paths)} non-fractured images')\n", + "print(f'Found {len(fractured_images_paths)} fractured images')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "059b4a0b", + "metadata": {}, + "outputs": [], + "source": [ + "# Upload non-fractured images with tags for helping us later in the annotation creation\n", + "new_resources_list = api.resources.upload_resources(non_fractured_images_paths,\n", + " tags=['fracatlas', 'non-fractured'],\n", + " publish_to=proj, # associate the resources to the project\n", + " progress_bar=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c9aee35", + "metadata": {}, + "outputs": [], + "source": [ + "# Upload fractured images with tags for helping us later in the annotation creation\n", + "new_resources_list = api.resources.upload_resources(fractured_images_paths,\n", + " tags=['fracatlas', 'fractured'],\n", + " publish_to=proj, # associate the resources to the project\n", + " progress_bar=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4db69be", + "metadata": {}, + "outputs": [], + "source": [ + "from tqdm.auto import tqdm\n", + "\n", + "# Annotate non-fractured images with 'has_fracture: no'\n", + "nonfrac_resources_list = api.resources.get_list(project_name=PROJECT_NAME,\n", + " tags=['non-fractured'])\n", + "for res in tqdm(nonfrac_resources_list):\n", + " api.annotations.create_image_classification(resource=res,\n", + " identifier='has_fracture',\n", + " value='no')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ddc29f8", + "metadata": {}, + "outputs": [], + "source": [ + "# Annotate fractured images with 'has_fracture: yes'\n", + "frac_resources_list = api.resources.get_list(project_name=PROJECT_NAME,\n", + " tags=['fractured'])\n", + "for res in tqdm(frac_resources_list):\n", + " api.annotations.create_image_classification(resource=res,\n", + " identifier='has_fracture',\n", + " value='yes')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56b23d27", + "metadata": {}, + "outputs": [], + "source": [ + "# Verify annotation was created successfully\n", + "api.annotations.get_list(resource=frac_resources_list[0])[0].asdict()" + ] + }, + { + "cell_type": "markdown", + "id": "950ae0f4", + "metadata": {}, + "source": [ + "### Create Train/Val/Test Splits\n", + "\n", + "Split the dataset into 80% training, 10% validation, and 10% testing with class balance maintained across splits." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb794bc8", + "metadata": {}, + "outputs": [], + "source": [ + "# splitting\n", + "import random\n", + "\n", + "all_resources = list(api.resources.get_list(project_name=PROJECT_NAME,\n", + " tags=['fracatlas']))\n", + "# sort filename to ensure reproducibility\n", + "all_resources.sort(key=lambda r: r.filename)\n", + "random.seed(123)\n", + "random.shuffle(all_resources)\n", + "n_total = len(all_resources)\n", + "n_train = int(0.8 * n_total)\n", + "n_val = int(0.1 * n_total)\n", + "n_test = n_total - n_train - n_val\n", + "train_resources = all_resources[:n_train]\n", + "val_resources = all_resources[n_train:n_train + n_val]\n", + "test_resources = all_resources[n_train + n_val:]\n", + "\n", + "print(f'Total resources: {n_total}')\n", + "print(f'Training resources: {len(train_resources)}')\n", + "print(f'Validation resources: {len(val_resources)}')\n", + "print(f'Test resources: {len(test_resources)}')" + ] + }, + { + "cell_type": "markdown", + "id": "c3ab5bad", + "metadata": {}, + "source": [ + "Tag resources to identify their split assignment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e3aad459", + "metadata": {}, + "outputs": [], + "source": [ + "for res in train_resources:\n", + " api.resources.add_tags(res, ['split:train'])\n", + "for res in val_resources:\n", + " api.resources.add_tags(res, ['split:val'])\n", + "for res in test_resources:\n", + " api.resources.add_tags(res, ['split:test'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6a4b782", + "metadata": {}, + "outputs": [], + "source": [ + "# Verify split distribution and class balance\n", + "train_resources = api.resources.get_list(tags=['split:train'])\n", + "test_resources = api.resources.get_list(tags=['split:test'])\n", + "val_resources = api.resources.get_list(tags=['split:val'])\n", + "total_train = len(train_resources)\n", + "total_val = len(val_resources)\n", + "total_test = len(test_resources)\n", + "train_fractured_ratio = len([r for r in train_resources if 'fractured' in r.tags]) / total_train\n", + "val_fractured_ratio = len([r for r in val_resources if 'fractured' in r.tags]) / total_val\n", + "test_fractured_ratio = len([r for r in test_resources if 'fractured' in r.tags]) / total_test\n", + "\n", + "print('Training set: total={}, fractured ratio={:.0%}'.format(total_train, train_fractured_ratio))\n", + "print('Validation set: total={}, fractured ratio={:.0%}'.format(total_val, val_fractured_ratio))\n", + "print('Test set: total={}, fractured ratio={:.0%}'.format(total_test, test_fractured_ratio))\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "9f18e7a8", + "metadata": {}, + "source": [ + "## Dataset Preparation\n", + "\n", + "Define data transforms and create a PyTorch Dataset class for loading images and annotations from Datamint." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da4a5dde", + "metadata": {}, + "outputs": [], + "source": [ + "import albumentations as A\n", + "\n", + "train_transforms = A.Compose([\n", + " A.Resize(480, 480),\n", + " A.RandomBrightnessContrast(p=0.5), # data augmentation\n", + " A.HorizontalFlip(p=0.5), # data augmentation\n", + " A.ToRGB(), # ensure 3 channels\n", + " A.ToTensorV2(),\n", + "])\n", + "\n", + "test_transforms = A.Compose([\n", + " A.Resize(480, 480),\n", + " A.ToRGB(), # ensure 3 channels\n", + " A.ToTensorV2(),\n", + "])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb8eb723", + "metadata": {}, + "outputs": [], + "source": [ + "import torch.utils.data\n", + "import numpy as np\n", + "\n", + "\n", + "class FracAtlasDataset(torch.utils.data.Dataset):\n", + " \"\"\"Load FracAtlas images and annotations from Datamint for classification.\n", + " \n", + " Args:\n", + " project_name (str): Datamint project name\n", + " split (str | None): Filter by split tag ('train', 'val', 'test')\n", + " transforms: Albumentations transforms to apply\n", + " return_annotations (bool): Include class labels in output\n", + " \"\"\"\n", + " def __init__(self,\n", + " project_name: str,\n", + " split: str | None = None,\n", + " transforms=None,\n", + " return_annotations=True,\n", + " ):\n", + " \"\"\"\n", + " Args:\n", + " project_name (str): Name of the Datamint project containing the FracAtlas dataset.\n", + " split (str | None): If provided, filters resources by the specified split tag ('train', 'val', 'test').\n", + " transforms: Albumentations transforms to apply to the images. Optional.\n", + " return_annotations (bool): If True, returns class labels along with images.\n", + " \"\"\"\n", + " self.api = Api()\n", + " self.project = self.api.projects.get_by_name(project_name)\n", + " self.transforms = transforms\n", + " self.return_annotations = return_annotations\n", + "\n", + " if not self.project:\n", + " raise ValueError(f\"Project '{project_name}' not found.\")\n", + "\n", + " self.resources = self.project.fetch_resources()\n", + " if split:\n", + " self.resources = [res for res in self.resources if f'split:{split}' in res.tags]\n", + " if return_annotations:\n", + " self.category_annotations = []\n", + " for resource in self.resources:\n", + " annotations = resource.fetch_annotations(annotation_type='category')\n", + " self.category_annotations.append(annotations)\n", + "\n", + " def __len__(self):\n", + " return len(self.resources)\n", + "\n", + " def __getitem__(self, idx: int):\n", + " resource = self.resources[idx]\n", + "\n", + " # Download the image data\n", + " image_data = resource.fetch_file_data(auto_convert=True,\n", + " use_cache=True) # use_cache=True to avoid re-downloading. By default stored at \"~/.datamint/\"\n", + " # image_data is auto converted to a PIL Image (since it is a png image file).\n", + " image_data = image_data.convert('L') # convert to grayscale\n", + " # convert to numpy array float32\n", + " image_data = np.array(image_data, dtype=np.float32)\n", + " image_data /= 255.0 # normalize to [0, 1]\n", + " # apply transforms if any\n", + " if self.transforms:\n", + " image_data = self.transforms(image=image_data)['image']\n", + " # image_data.shape: torch.Size([3, 480, 480])\n", + "\n", + " if not self.return_annotations:\n", + " return image_data\n", + " \n", + " # Extract 'has_fracture' annotation\n", + " annotations = self.category_annotations[idx]\n", + " for ann in annotations:\n", + " if ann.identifier == 'has_fracture':\n", + " has_fracture = int(ann.value.lower() == 'yes')\n", + " return image_data, has_fracture\n", + " raise ValueError(f\"Annotation 'has_fracture' not found for '{resource.filename}'\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e6c8c36", + "metadata": {}, + "outputs": [], + "source": [ + "# dataloaders\n", + "from torch.utils.data import DataLoader\n", + "\n", + "train_dataset = FracAtlasDataset(project_name=PROJECT_NAME, split='train', transforms=train_transforms)\n", + "train_dataloader = DataLoader(train_dataset, batch_size=8, shuffle=True, num_workers=4)\n", + "\n", + "val_dataset = FracAtlasDataset(project_name=PROJECT_NAME, split='val', transforms=test_transforms)\n", + "val_dataloader = DataLoader(val_dataset, batch_size=8, shuffle=False, num_workers=4)\n", + "\n", + "test_dataset = FracAtlasDataset(project_name=PROJECT_NAME, split='test', transforms=test_transforms)\n", + "test_dataloader = DataLoader(test_dataset, batch_size=8, shuffle=False, num_workers=4)" + ] + }, + { + "cell_type": "markdown", + "id": "80abbae7", + "metadata": {}, + "source": [ + "## Train the model" + ] + }, + { + "cell_type": "markdown", + "id": "56844db7", + "metadata": {}, + "source": [ + "We define our model by extending `lightning.LightningModule` which extends PyTorch `nn.Module`, but handles the dirty work for us.\n", + "More details at https://lightning.ai/docs/pytorch/LTS/common/lightning_module.html" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecc640a0", + "metadata": {}, + "outputs": [], + "source": [ + "from torchvision.models import resnet18\n", + "import torch\n", + "import lightning as L\n", + "\n", + "class FracAtlasClassifier(L.LightningModule):\n", + " def __init__(self):\n", + " super().__init__()\n", + "\n", + " ## loading the backbone ResNet18 ##\n", + " self.model = resnet18(weights='DEFAULT')\n", + "\n", + " # Binary classification (fractured vs non-fractured)\n", + " # We change the final layer to output 2 classes\n", + " self.model.fc = torch.nn.Linear(self.model.fc.in_features, 2)\n", + "\n", + " # Our loss function\n", + " self.criterion = torch.nn.CrossEntropyLoss()\n", + "\n", + " def forward(self, x):\n", + " return self.model(x)\n", + "\n", + " def _run_step(self, batch):\n", + " \"\"\"Common step for training, validation, and testing.\"\"\"\n", + " x, y = batch\n", + " y_hat = self(x)\n", + " loss = self.criterion(y_hat, y)\n", + " return loss\n", + "\n", + " def training_step(self, batch, batch_idx):\n", + " loss = self._run_step(batch)\n", + " self.log(\"train/loss\", loss, on_step=True, on_epoch=True, prog_bar=True)\n", + " return loss\n", + "\n", + " def validation_step(self, batch, batch_idx):\n", + " loss = self._run_step(batch)\n", + " self.log(\"val/loss\", loss, on_step=False, on_epoch=True, prog_bar=True)\n", + "\n", + " def test_step(self, batch, batch_idx):\n", + " loss = self._run_step(batch)\n", + " self.log(\"test/loss\", loss, on_step=False, on_epoch=True, prog_bar=True)\n", + " return loss\n", + " \n", + " def configure_optimizers(self):\n", + " optimizer = torch.optim.Adam(self.parameters(), lr=1e-4)\n", + " return optimizer\n", + "\n", + "\n", + "model = FracAtlasClassifier()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "058f3633", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "from datamint.mlflow.lightning.callbacks import MLFlowModelCheckpoint\n", + "from lightning.pytorch.loggers import MLFlowLogger\n", + "\n", + "set_project(PROJECT_NAME) # Ensure the project is set\n", + "\n", + "# This callback will do the following:\n", + "# - Save the best model based on validation loss.\n", + "# - Register the best model in our server automatically.\n", + "checkcb = MLFlowModelCheckpoint(\n", + " monitor=\"val/loss\", # Metric to monitor for best model\n", + " mode=\"min\", # Save model when monitored metric decreases\n", + " save_top_k=1, # Keep only the best model\n", + " filename=\"best\", # Checkpoint filename\n", + " save_weights_only=True, # Save only model weights (not optimizer state)\n", + " register_model_name=PROJECT_NAME, # Name for model registry\n", + " register_model_on='test', # Register model after testing\n", + " # code_paths=['my_custom_model.py'], # Include source code with model\n", + " log_model_at_end_only=True, # Log to MLflow only at the end (faster)\n", + ")\n", + "\n", + "# Start Training\n", + "# ==============\n", + "\n", + "print(\"🚀 Starting training...\")\n", + "mlflow_logger = MLFlowLogger(experiment_name=PROJECT_NAME)\n", + "trainer = L.Trainer(\n", + " max_epochs=10, # Number of training epochs\n", + " logger=mlflow_logger, # MLflow integration\n", + " enable_model_summary=True, # Show model architecture summary\n", + " enable_progress_bar=True, # Show training progress\n", + " callbacks=[checkcb], # Include our checkpoint callback\n", + " num_sanity_val_steps=0, # Skip validation sanity check\n", + ")\n", + "trainer.fit(model,\n", + " train_dataloaders=train_dataloader,\n", + " val_dataloaders=val_dataloader)" + ] + }, + { + "attachments": { + "image-2.png": { + "image/png": "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csklt9xyi1Kp7OzsvOeee8rLy3/xi1+II5VimLV7924xyvzb3/422h6O9iRxdXV1EUJcLtdrx4i3MwwT2aawsFChUIh/G41G8Y/+/v4xjhIASEC8fgkhb775pnj9isvJo69fQkhRUdHI6/ekzdHhw4dHtpkxIgOvWVlZ4h9YGgUAiRgrehPju5gbtVpt5O9bbrmlt7d3xYoVra2tHo/nm9/8JpmAF198kWGYrKysb33rW3E3yM7OFle5tre3R248dOiQ+EdxcbFCofjd737X0tLy3//930VFRYFA4Oc///n+/ftzc3N37Njx6aefbtiwQa/XDw4Ofu973xttN0Z7kuhtgsFgdJubn58fExQ/+uijkY27u7sj29fX18d8HwCAXCIxU8xUCnFBUkRkoCD6+j1pcxR58sgyCACA1EZv2dnZYozyxhtv1NXVjfZgcdXCGWecMWvWrMHBwZjFVuMiCMKmTZsIIddee21kdnAMo9F4wQUXEEKqq6sfe+yxjo6O7du3i6tW8/PzzzrrrE8//bSmpqasrOzee++95557xEd1d3dv27ats7Nz5cqVTz311Ne//nVCiN1uH+037mhPEjks4i/1gwcPDg4OivvT19f3s5/9jGVZsSmPWdDa19e3cePGtra2TZs2icOyM2bMmDt37ikfKwBICvH6FbvnxV63gYGB3/72t5GfW6L/+q//Onjw4HvvvffII4+IP/D+4z/+46TN0TnnnCPOZnvuued++9vftrW11dfXR6bVAgBMSNzx1Keeemq0Nacvv/xyZLNzzjlHXG553nnnWa1WcVhBp9ONMe8t8k9xmDWyzErMUSIusI/ek5hVC3v37o38oo1Qq9XiKgFxDUFWVlZpaak4WFlVVeX1ei+99FJCiDVMfMg111wz2ljyaE8iCEJ9fX10Crrdu3fbbLbIWlSlUimuLzv77LOj37JWq42MnIpNv7huAwDkFQwGL7744ui2TvxDXDMeaXxi8o3feuut4sPHbo4EQXj++eejr/2Ra04jzem1114r3tLT0yPf8QCAtBG/7+2GG2647bbbCgoKdDrdaaedFncbQsjmzZsvuugig8Fw8ODB66+/PjJn/xQ8/fTThJALL7xwzpw5Y2w2f/78mpqaa6+9tqioSK1W5+bmXnrppR9//PFll11GCFmwYMGyZcsEQejp6SktLd2wYcOOHTsMBsOqVauqqqoGBwfdbvfChQt/9atfvfDCC6O9xGhPIt717LPPzpo1S6vVTp8+PSsrq6Cg4LPPPrvuuuuKi4uVSqXJZDrrrLNuvPHG6CecPn3673//+xkzZmi12kWLFr3++usTHGIGgKRQKBRvvfXWL37xi6qqKq1Wq1Kp5s2bt3Hjxpg85H/84x+XLFmi1Wpnzpz5y1/+8sknn0ykOSKEfO9733v33XcvvPDCjIwMnU5XWloauQsAYCIUI2e2Sa+zs7O0tDQQCLz++uuXX345mSwqKipaW1vLy8tbWlrk3hcAGJ/rrrvu+eefFzv+xVw/AACUoKIU1TPPPBMIBIqKisQhTmk8/PDDeSNcdNFFku0AAAAAQNLqnEqsqKjo/vvvX7p0qZg/SRq33HLLd77znZgbI+UQAAAAAOhERfQWU/tPGuYw6V8XAAAAIO3nvQEAAABAOs17AwAAAIAEIXoDAAAASCeI3gAAAADSCaI3AAAAgHSC6A0AAAAgnSB6AwAAAEgniN4AAAAA0gmiNwAAAIB0gugNAAAAIJ0gegMAAABIJ4jeAAAAANIJojcAAACAdILoDQAAACCdIHoDAAAASCeI3gAAAADSCaI3AAAAgHSC6A0AAAAgnajl3gEqvPLKKzt37oy58Stf+UpJSQkhpKKiIisrixBit9s7OjoIIRqNZuHCheJmBw4c8Hq9hJCioqLCwkJCiNfrPXDggHjvwoULHQ5HTk5Od3e33W4nhGRlZVVUVIj31tTUiH9M8CU0Gg0h5ODBgy6X66Qv0dfXd/jw4XG9xKJFi9Tq0KnS0dER8y56wgRBSN1LJPIuOI5zOp39/f2pe4kE3wXLsjzPDw4Opu4lYt6FxWIpLy8f+RKBQECv13s8npEvsX//foZhJv4SY7yL6JdQKBT5+fkqlWrMqxDSvq0TP/GBgYGUtnUsy3Z0dLjdbonbOqpeYryXcOreRWNjo9frFQRBxrYuKyvL6XS63e7e3t6p09YpxO9diPHCCy8oFIrvfve7Ez8ydXV1s2fPNhgMqT7Izc3N2dnZeXl5REI1NTWR8FFGbre7vb19/vz58u4GIcRms7EsW1paKveOhM6HnJyc3NxcuXeE1NbWnnbaaTqdTu4dgdS2dV1dXcFgcPr06Sk90E6n02azzZkzh8ihu7ub5/kZM2YQWXk8nkOHDi1YsEDe3ZDyC25s7e3ter3earVOnbYOI6cAAAAA6WSSjJxyHPf22293dXXdeuutJ934iSeeOHDgwG9+85sxAmSxNzUpzGazUilFlGw0GqXvA8vIyFAoFERuKpXKZDIRCmi1WkIHg8GQxNM4LS6BqcbhcLz66qvl5eWrV6+O3Njb27t169ampiae54uKilavXr1kyZIxniSJJ4lOpwsGgyTF1Gq10WgkMtHpdDRcVvS0eCaTiYarW6/X09D2StnWyX8WTtDAwMAnn3yyY8cOl8s1d+7ck25/IOykmxkMhmQFJZFB9FQrLi4mkps9ezahgMFgKCsrIxTIyckhdBBnMtGgsrJS7l2YbA4fPrxz587q6mqO42JamN///veFhYXXXXedWq3+97//vWnTpltvvXWMIbYktnXSTNswhxGZ0DAVQQxWZs2aRSgQmesmL6vcY6bSt3VpH729//77NTU1a9as2bt3L8/zY2/s9/u3bNkyd+7cRAI4AAA6vfzyy0ql8tZbb3366adj7vr2t789c+ZM8e/Zs2d3dnb+61//omGCFAAkUdpHb5dccsnll1+uUCj27dt30o3ffPNNs9l81llnIXoDgPR16623iovgRoqEbqFVaQqF1WodHByUcNcAQAryD1dLNu9q//79H3300Xe+851EtneFJWtJjricONWam5vFNc9Sqqmp8fv9RG5utzuR8F0CNputvb2dUKC5ubm/v59QoLa21ufzyb0Xk8pooVsMQRA6OjrGHkNPYlvX1dV15MgRkmJOp7OxsZHIpLu7W8wZIS+Px7N3715CAcm+4MbW3t5us9mmVFuX9tFbggYGBp5//vkrrriioKBA7n0BAJDC9u3b3W73xRdfjMMNMMmk/chpIjiOe/rpp+fNm3fuuefKvS8AACkXCATeeOONTz/9dMOGDRLngAQACUz+6E0QhBdeeIHn+SuvvFLs0hQXN/h8PpVKNdrab51Ol6x1WFarVZoV5rm5uXq9nkirqKiIhhz6Wq122rRphAJms1n6T4Ge8yGuwsJCGpIsTB12u/3ZZ5/VaDT33HPPSddIJrGty8jIIKmn1+tljEczMjIkyIqSRi1eQUGB7NnaSbhGAg2NjJRtnfzvNtUcDkdtbS0h5M4774y+/a677jrzzDPXr18f91FarTZZLZpkY7Wy5KoQa4/Ijp62TMZcBtTmLqFkMf8U0dPT8+tf//rs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CoXr168vLCyMi4s7fvx4c3PzqlWrpFIpIWTAgAGrV6/ev38/fdewiw3dcfLgEsg6ZN0tIesGuC3r0O7NxXg8nlgsZkaSox998ng8+tvJkyevWrVq3LhxHYea63pDNxEKhe+9994LL7wQEBDQ7iW9Xn/69OmZM2d2LN065e3tTX9x7dq12traWbNmEXcSiURMpUIIkUqlEonEZDLZr3P58uVLly7NmTOn3bYajcbLy6vjvcZbbug+Pj4+zl8XrbS0NDc3d+bMmbe7oUvs3r3by8uLfoxOs9lsly5dGjVqFJ1KhJDBgwd7eHhcvXqVEFJRURESEkKXbvQUw0OGDMnPz6coqusNoddC1iHr7gCybpSLsg733lwsPT393XffPXjwYHp6elNT044dO1JSUpjaiPnrdbsbugmHw3F0SoWFhWazWSQSrV69ury83NPTc9y4cVOmTLEvKI1Go0Kh2LVrV0JCQnJyMr3wypUrISEh+fn5GRkZDQ0N/v7+M2bMSElJceuFNDQ0aDQa+6nPmpubN23a9MQTT3SczVaj0eTn5588edLDwyMpKWnmzJmBgYHObOhaFotFqVSeOHFCq9VOmjTJyeti7N27d9CgQf3797/dDe9efn7+qVOn3njjjfLycvsjGo1G+2fQHA5HLpfX1dURQjw9PRsbGy0WC5//a+ZoNBq9Xq/VanU6XRcbQq+FrEPWOQlZp3dD1qF6c7F+/frNmzdv48aNO3fuJIQEBwc/88wzbt3QTaqrq/l8/jfffJOenj5r1qyioqK9e/fq9XrmmemSJUvoh78pKSlPP/00U9XV1NS0tLTs37//0UcflUql586d+/TTT1988UWmvHM5q9X63XffhYeHM4ewWq2fffZZQkLCqFGjWlpa2q0/f/58q9VqMpmqqqoOHTr09ttvv/HGG/Rj3643dKF169bl5+fTP/eXX37Z39/fmetilJeXX7169bXXXut0511sePeUSuUXX3wxZ86c4OBg++pNpVIRQtqVvBKJRKfT0Q9QMjMzP//88+nTp3t5eeXm5p47d46O9a43hF4LWYescway7px7sg7Vm4tduHBh06ZNDz/88ODBg9VqNd14fPny5WKx2E0buoler7dYLDNnzqRvm8XFxRmNxkOHDj366KP0Ka1YscJgMDQ2NmZmZr711luvvPIK/eROp9Nptdr//u//lslkhJCEhITa2tqDBw+6qXpTq9WfffaZRqN5+eWXmdvRW7ZsoZd0ugnz0ScuLm7o0KFvvfXWkSNHnn766Vtu6EJPPfWURqNpaWm5dOnSqlWrFixYkJqaesvrYhw/fjw8PDw2Nrbjnrve8C6ZTKYNGzYMHDgwLS2t3UtWq7W1KcZvj8hpQwjp37//woULf/jhh5UrVxJCwsLCJk6cuHv3brFY3PWG0Gsh65B1zkDWTXRP1qF6cyWTyfT9999PmDBhxowZ9JK4uLgVK1YcO3bskUcecceG7kM/4Ro0aBCzJCkp6cCBAwqFIjIykqmBYmNjU1NTV69evXXr1mXLltEbhoaG0qUbbeDAgYcOHXLHSRYUFHz55ZdDhw596aWXmPZ5x44dO3/+/PLly+lnu3TbL7PZbDKZOrbh8/Pzi42NraysvN0N71JgG0JIcnKyh4fHpk2bhg0bxty/7PS6GDqd7uLFi502y+t6w7tEt9G2WCxz5841Go30p0n6veLxeHRLzXYfIrVaLfP0PzU1dfjw4fX19RRFyeXyjIwMb29vsVh8yw2hF0LWIeuchKzLcE/WoXpzJYVCodfr7YdMk0gkwcHBxcXFbtrQfYKCguj/Z8xgH/Tng077W0RHR+fk5DAb3rhxo9067riPcvHixU2bNi1YsKDdlLXHjh0zGo3vvPOO/cJPP/1UJpP9/e9/77gfq9UqEAjuYENXiYuLO3bsWFNTE13PObouRk5OjsVi6fjqLTe8S01NTfRPuV3/9tdee2306NFPPvkkh8Oprq4eMGAAvZyiKIVCMWzYMGZNLpfL9KG+cuUKPcZecHDwLTeE3gZZh6y7A8g6juuyDtWb63vTFBYWMk/BWlpaFApFRESEmzZ0n6SkJB6PZz/kxOXLl6VSaXh4uNVqte+7YLPZiouLmQ6PgwcPPnPmTHFxcUxMDL0kLy+v3eB2d0+pVG7cuHHRokVDhw5t99ILL7xgNpuZb7Va7UcffTRr1izmF8ZeQ0NDUVHR5MmTb3fDu9HuDbxx44ZIJKIHZuviuhjZ2dmxsbHtups4s+Fd8vHxadfS7tq1a3v37l22bFlAQIBIJIqPj79w4cIDDzxAF+tXrlzR6/WdPjHPzc0tKSmhh9y7rQ2hl0DWIeucgazLdVvWoXpzJR8fn4kTJx49epTL5SYmJmo0msOHD/N4vClTprhpQ/eRSqUTJ07cs2ePzWaLjY29fv360aNHFyxYwOPxKioqvv/++7FjxwYFBWk0mpMnT9bU1DD3Y5KTk6Ojozds2DBr1ixfX98zZ85UV1c/99xzrj297OxsesSTdkOyDRgwoF03TLrzQUhICL28paXl008/TUtL8/f3VygU+/bt8/X1TU9Pp9tmdbGhC61ateq+++4LDw+nB8s4efLk448/Tj+q7uK66N92m81WWFj4u9/9zvk3xFU3Pvl8fruWdkqlkh7wj75BO3369DVr1mzcuDEtLa2pqenHH3+cMGECfRPXYrFs37594MCBIpEoPz//8OHDEydOZPbWxYbQOyHrkHXOQNYddlvWoXpzsVmzZgUHB586derMmTMeHh6xsbGLFy/utEehqzZ0nxkzZojF4lOnTmVkZAQFBS1evJi+r+Pv7y+Xy/fu3atWq729vWNiYuwnWuBwOEuXLt3Wxmg0xsTEvP766y7/S6xUKi0Wy9q1a9st//DDD+nHoI7QjQ9+/PFHvV7v7e09cuTIqVOnunwqiK4NHz48MzNTqVSKRKKwsLBXXnmFuTd5y+uqqqoymUwdC8o7fkNcKCYmZsmSJTt37ly7dq23t3d6evpDDz1Ev0Q/Lzh79qzVag0JCZk3b579WHFdbAi9FrIOWXdLyLp5bss6DkVRd7YlAAAAAHQ/zLUAAAAAwCao3gAAAADYBNUbAAAAAJugegMAAABgE1RvAAAAAGyC6g0AAACATVC9AQAAALAJqjcAAAAANkH1BgAAAMAmqN4AAAAA2ATVGwAAAACbYJZ66HVy2jQ0NJhMJolEMnz48PHjxxNCGhsbq6qqhgwZ0tMnCADgAsg6uGOo3qB3ycjIyM7OTk1NHTFihNVqbWxsVCqV9EuZmZkNDQ2o3gDgHoCsg7uB6g16EY1Gc/HixQkTJtA32wAA7knIOrhLqN6g1/Hw8Gi3pLm5ed26dfTXb731FiHkzTffJITYbLZTp07l5uZqNBp/f//09PSEhARCiE6ne++992bPnt3U1PTLL79oNBqZTDZhwoSkpKSeuCAAgE4g6+CO8VauXHnnWwO4lFAorKysvHz5cnBwsL+/P7NcIBAkJCRoNBoej/fUU0+lpKRIpVJCyI8//piXlzd+/PgxY8YYjcYjR47Ex8dLpVKz2Xz27Nna2lqZTDZ9+vQxY8bo9fqDBw9GRUX5+vrihwYAPQtZB3cJ1Rv0LgkJCUql8ujRoyUlJd7e3jKZrLVrNJcrlUqLi4uNRuP48ePp0q24uPj48eOzZ88eOnSor69vfHx8UVGRQqEYOHAgXb3169dv+vTpQqFQIBBER0eXlJSg0wMA9BLIOrgbGDEEeheRSDRjxowXXnhBIpF8++23P/zwg16v73TNwsJCT0/PxMREZklUVJRCoWC+jY+Pt18/MjLS/lUAgB6ErIO7gXZv0BvJ5fLHH3+8vLx8y5YtmzdvfvbZZzuuo9VqdTod3QyOwePxHLUp4fP5Op3OnWcNAHB7kHVwZ1C9Qe8VERHx4IMP7tmzR6FQyOXydq+KxWJvb+8nn3zSfiGHw2G+NplM9i8plUr6kSsAQK+CrIPbheoNehGj0cjn8+3vn5nNZuaOGo/Hs1gszEsRERHZ2dl8Pj8gIKDTvV27di05OZn+2mAwFBQUoM8pAPQGyDq4S+i1AL2IQqH46quvNBqNTqerr6+/cuVKZmZmTEzMqFGjCCFNTU15eXn+/v4qlUomkwUEBNy4ceOXX34RCoVWq7W6uvrcuXNmszkoKIjutWAymerq6sRicU1Nze7du41G4+zZs8VicU9fJQD0dcg6uEsciqLudh8ALqLX648cOXLz5s2WlhY+n+/r6zto0KDRo0fT995MJtP27dtLS0s9PT1feeUVZv3r16+bTCZvb++4uLi0tDSJREKP9zZz5syKioq8vDybzda/f/9JkyYFBgbiZwUAPQ5ZB3cJ1Rvcg+jqbc6cOXhUCgD3MGRdn4URQwAAAADYBNUbAAAAAJugegMAAABgE7R7AwAAAGAT3HsDAAAAYBNUbwAAAABsguoNAAAAgE1QvQEAAACwCao3AAAAADZB9QYAAADAJqjeAAAAANgE1RsAAAAAm6B6AwAAAGATVG8AAAAAbILqDQAAAIBNUL0BAAAAsAmqNwAAAAA2QfUGAAAAwCao3gAAAADYBNUbAAAAAJugegMAAABgE1RvAAAAAGyC6q33+sO5z//vyr472/b70nNTT7xPf12tb370xD/3V11y3+G62bprh549+1lPnwUAuMYH1w4/feZjC2W7g23zW6oeOPL3InWt81l3N4frZsg6cITv8BXoabHS4DBPv7vfjwdPEOcdLBN5dc/heqdZJ9cpTbp2C32FnjvHL2sLfeXnhScvNpaaKWt/ScBTUaPHBSUwq5Vq6j8pPHFZWU4IJ9U/aknCg8Fi726/AoB7VpinLMqo5nI43ZN1rjpc7/S3y7tO1BZ0XP7VmOf7SwL0VtNXxZknFAXNJl2wh8/DoUPmRo7ic369j6My6z8vOnmq9rreaoyVBi+Ke2CoX0S3XwE4BdVb7/X6oGku2Y+fUPKPlKe67XC908qhs8w2K/OtxWZ9O2/3lLChv756aWd/ScDrg6cJuYKD1ZfevLTjneTHxgTGEULKNA2Lf9440j9m5dBZOovpm5LTr178/osxC0Vc/O4AuMbsiNTZEandlnWuOlzv9Ez0/Y+EJ9sv+bLoJIdw+ksC2r4+VdBSvSj+gUCRNK+54sviky1m3YvxvyOEGG2WJRc2CbjcZQMmSQSijMrc//fL5o9GLYjxCuq5qwGH8BcI+oQhvv3sv91ensXn8OZFjaG//VPiQ4k+ofTXw2T9i9V1O8ov0tXbhhvHorwC30qexSWtn9ST/SLmnd5woOryjH7De+I6AAC6EuUVGEUCmW+L1LUFLdUfjvw9/W26POmPCQ/Sdx2H+kU0GbW7KrJfiE/nEs6O8ov1BtX3aX+UCSWEkJH+0UsubPqm5MzKITPxjvdCqN56r2fPfpYsi1g2YDIhZGnWN3KxzxuDH2VefSJz/fjgAfRnJkLI5eaKzwt/uq5SePAEk0MHe/HFzJotZt2Mn9atHDJzfPAAesklZfk3JWcKWqotlC3KK/Dt5NmBIqn94QghxZq6r4tPX1KW6yxGuYfvlLAhj0feR1cwXxSdPFh9+cdxS5lD/N+Vfa2PF+97lhBio6hvS88crr5SZ1B5Cz3mR4+dFj6si8vs9GRueb2EEIW+5YNrh3OVN3kc7ujA2JcSJnoLPJx5Yw1W87elZ+dFjfbkCeklTOlGSOsVRkj8G40a+ttCtWJiyCD6wumHrYN8w7MaS1C9AbjKumuHcpvKN455/pbxQgipNag+vnHsYmOphbKlyqIeCht8u1lnfzh6q6+KM8/UFTaZtD4Cj7FB8c/FjqfDJLupbHn2D9/ev5hpVXKw+vLqqxn701/1aEuPE7UFW8rOl2kaBFz++OCE5UlTurjMGn3zxuLMi40larMhWOyzLHHSCP/oW17v3WQdIeSzwp9GB8Yl+YR1zDpCSH+vALPNaqMoLodTqFL0lwTQpRttbFDcd6XnnDwQdDNUb92nwajZevPnm5oGmUgyLmjA6MBYV+05r7ni1YvfD/WLWDlkJp/L21GedU1V42jlE7UFb1/edX9g/BuDH/XgCS82lRqspnbrFLRUv3LxuySf0OVJD3sLPC42ln5RdLJG3/LnxIdueTIbbhw7WJ23bMCkEE/fSl2T1dZV02BnTqZTOqvp9dytD4UOfTLqviJ13WeFPzUaNc48NCGE7K78haIoRzUl1Vqx1Y70j6a/lQo8KrRN9iuozHqD1ezMgQD6JvdlncqsX3phE5/LW5Y4OVAkPVNf+H7+wbuJF7XFsOTnTVbK9ofYcWGefqWa+i+LMq82V20YtUDA5XV9MmfqC/92eddzseNfHjBJadJeVym6WLlC17Tk568DxF5/THhQLva5oVLoLG7PuuuqmguNJRtGLXC0wg2VItIrkG73JhV41BrKzDYrc+Eqs0FrMbaYdT4CT2cOB90J1Vs3Kdc2vvjzV7p/Z8fB6rxFcQ88GXmfS3b+8Y0TERL/d4c/QbfDTZFFvvDzxhp9c8c1DVbzP/MPPiBP/MvgGfSSYbL+HVf78PqRCIn/P1Kfou85DfWLkPBFnxSemNt/ZLinrOuTyVWWp8giHwwZSAgZ+O8PfJ1y8mQ6VWdQ/W/y7PsD4wkhg337Sfnid67sudpS1fURCSFmyrq17OdZEalinqDTFb4rPaM0ah/rP5L+9tHw4R9eP/Jt6ZmHQodaKdu2mxfKtA3+wls0iwbos9yadVtu/txs0n2X9mKgSEpHk8Vm3VmRfcfxsrn0fINR/e3YxQFtOxzs2y9OKv/jha8P1+Q9Evab1mMd5Tbd9BF4PP3vBhh0HDnyr2uHvQTij0YuoJNnkG+4u7OuLc3ODZP1H+Ad0vn5K8sPV+f9z+Dp9LePhA/NqMp5J2/Pc3HjpXzx2fpCuveufYth6D0wYogb5SrLmX8f3Tims5rS5Ulb0pbQDwS/KDr5S9NNZoU7PorWYsxvqZoSlsx0oeJyOPcFxHS68iVludpieCJydBc7VFsM+S3Vj4QlM48LCSGTQ4fQV3TL80n2izhbX7i9/CIT3444czKOePFF9lk5Lri1iyg9akDXflIUtJj1nd54s1C2D68f2VJ2YdWwOaEevvTCmREpT0WN/qr49JxT/3oic73C0DIhONGT/+sjVwC43axjmiXcgQsNJaMCY+jSjXZ/UPzdxMvPDcX3BcbSpRst0Sc0QuKf03TzlieTLOvfYtb/s+BgnUHV9Zo6qym7sWxmvxRHHxrdkXW1hpYzdTdm9kvp9NVD1Xmv52x9IT6decocL5W/MWh6rvLm7898MvPkum3lFx7vP4oQ4skX3e45QzfAvTc3+tPF79oteSpydJDY+0H5wC1lPxepa1/N/p556cTEFXd2lCaTlhAS4uFjv5Buk9ERnTJMadKp5rYdBomlv+3M5cnjcNRmwy3P54X4dC+BeFPJ6S+KTk7vN3x+9FgxT2CjqIeOvceskxac8JfB0505GUfs05YQIuTyxTxBS9uYIF+XnP6u5Czz0qej/xDZ1tmKtqsiOy0o3s+ubQetRt+88tJOAZf36X3PhtidEpdwno+dMD96bJVO6SUQB4qky7N/6Ce5xQ1IgD7ltrJuedLDt7yt5UiTUdPuFpqHg3rIyXhRmrTD/SPbLQwQeTmTdfcHxv118IyNxaf2VeamBSe8GJ8eLG7N4T9nf39FWUmv4yP0+HHc0kajxkao0DsakqmLrMtpuvlfv2xhXnppwIOPhv+nN9Weihw/kaTjHUGD1fx+wYHcpvL/TX5suOw31/6APHG8fEC1TkkRKtzT/7vSMzKhhGkfDL0Kqjc3sh8pp0zT0GLWVemVMdIgK2VT6Fvo2+BOjjkk4vKNNov9Ev2/m175CVtbJGgtRvtXVWZ9p/uRtH2KajJp6C865cVvbQ/bYFTbL2w26awURR9LxOMbre1O5j+32fgc7vzosU9G3nek5spH14/V6JpXDp3J5XCYNsKtgdt276qLk+niemntbuZrLAaD1UzH3Mx+KQ/KW5/b0oI8/jM2W7W+Ob+l+vHI1g+U9sq0DX+++N3DYUOfixnf6U9EyOVHebV249JZTXnNlS8lPOjgzQPoi24r6/y7HI+t63jxE0pcmHWtcScQNxh+k3WEkEajln7aSA8MZJ9F7YLoAXniBHnixcbSD68fWXrhm2/HLhZy+a8PmsZcAn3Vv55MZzcdu77errMuyTfMPld92/KZcUxxdVxQQrtA01lNr2Vv9uKLvhizUGrXuY3BJRymecyFhpJkp1uzQDdD9eZGa1PnMV//UHbu08Kf/nZ5V4xXULW+WWMxREj8PxjxtJO7ChJ7X22uYr69qW1gMsuLL5Z7+FxoKJkYMoheYiNUVmNJp/sZ6hfB43D3VOQscVx/+Ak9Y7yCMiovTQ0fxjw8PVxzhcfhpvhHtZ2Mj9piUJq09B0sM2UtaKludzdLyOU/EpZcqVPuq8yll3QcCriLk+niemk1+uYGo5r5VHpCUcAhJKXtM7S3wMNRh6yTtQVCLm9ogPiJAAAFY0lEQVSk/28eK9sI9bfLOyeGDHo+dgK5la+LM0Vc/gPyxFuuCdB3uDTruoqXOG/5L41lFsrGDDD7c0PxHWcdIWSEf1RG1SX7MLmhUtzUNsyPHksHUWv+aBqi2z68tfbu79B6hNO2kz/G/+6/c7ZW6JpivILa3S0jhMiEkkhJwL7K3EfCf9MixZk47SLrRFy+oyHWC1qqaw2qNLtRx2mf3DhBEWrVsDm8f7+BjpyrL8prrlzn9A8Ouhmqt24ys1/qleaqs/WFN9St/ZKCxN7O9N9k/C5k4IHqy5vLzs/ol1JraPlH/gH79hMLYtJWX9kX5x08JWyowWr+suiUozZn/iKvp6PGfF1yWm81TwgewOFwWhtGRKT2+21fhCUJD772y+ZXL34/O2KEVCDObir7vvTc76Pvp5ubjA6M9eQJ1xUcfiVxMtUaB8dNdp9N/3Jp+30BMZFegS0m3em6G0P8fjPQmpMn0/X1EkIEXN5bl3e9mviw3MPnYmPpp4U/zY4YQT+26MIvTTfjvUPa7apYXVeqaXg0fHh2U5n98lhpkI/As1Bdm9VQkugTaqFsR2quHKu5+ubQGfYDsgCAC7Ou63h5OmrM0Zorq6/sWxT/gCdPeLA6L6ux9G6ybl7UmJO115Ze+GZ+zNhwT1lrn9PiUymyyPHy1tZgQWLvwb7hX5VkRksDg8TeB6vz7Nv+fl500oMnSPIJ43I4uyqyZUJJmIfDZ6MvDZj4X79s/nNrqKb6CD2vNlfJxT4PyBO7vt67yLoyHocz0Ld9z4ZjiqsTghPbtWAOFnuHe8psFLX+xtGR/tFinuCXppuby87NjkhtN1Im9B6o3rqJmCd4J/kxrcVYrm2UiSS3/N2jh67gc37tuZ0ii/xT4uStNy9sLD4VIfFfHP+7965mMGtODhmst5h/vPnzZ4U/BYt9ZkSkhHvKvi/rfJyeBTFpQWLvbeVZh6ovS/jiZL8Inw53qobJ+q8b8fTGolOrruy12KyRXgGvDZwyOeTXcZWkfPHfh8/96PqxJzLX+wo96e6ZpZp6+tVwT9nXxafpj5Jjg+IXxnV1Q8vRyXR9vW3t/Hxn9Uv9y6XtCn1zgFj6ROSoJ6Nu0TyZIuRaS/Wk0P+MDkWrb2sfs+7a4XbLVyXPGR0YK+TyTtQWfF1yWsDlJfqE/nPEPMQZgIuzjiJ8LteZeAnz9Hsv5clPbhx/KvMjqUA8PnjAnxIfWp79wx1nnZ9Q8tGoBZ8X/vRJ4Qm12RAk9p4WPuyZqPuZO2T/M3j62muHXrqwiUM4D8gT50enrbt2iH4p0ivgm+Izm0pOi3nCIX791o6Y10WnhBRZ5D9T520szlx1ZS+XcGKlwfRNwa6v986yjr731l8SIPztlDA6q0lrMWZU5WZU/fpIhDa3/8jWoTQ5rXcZD1ZdtlC2SEnAsgGTH/73bDTQC3Eoiurpc4DOzT75wZz+I59wUU97AIDe6e283VqL8f+Gze3pEwFgDYwY0kvVGlRNJm20FBPMAcA97lpLNdOwDACcgSenvc6hmjx/odc3JWciJP4j/j3iPwDAPeZsfaEnX3RCkV9nUE13MCwZAHQK1Vuv80Pp+WqdcpBf+DvJjzk1mggAAAudbyg+UHUpzFP2v8mPBbf17gQAJ6HdGwAAAACboN0bAAAAAJugegMAAABgE1RvAAAAAGyC6g0AAACATVC9AQAAALAJqjcAAAAANkH1BgAAAMAmqN4AAAAA2ATVGwAAAACboHoDAAAAYBNUbwAAAABsguoNAAAAgE1QvQEAAACwCao3AAAAADZB9QYAAADAJqjeAAAAANgE1RsAAAAAm6B6AwAAACAs8v8BsLIbew3RTykAAAAASUVORK5CYII=" + }, + "image.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "4bbfbc81", + "metadata": {}, + "source": [ + "While running, \n", + "- you can check saved model locally with name \"best.ckpt\";\n", + "- And you can check experiment details on the Datamint platform:\n", + "\n", + "![image.png](attachment:image.png)\n", + "\n", + "![image-2.png](attachment:image-2.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "516bb580", + "metadata": {}, + "outputs": [], + "source": [ + "proj.show() # Display project details in Datamint platform" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "891e080f", + "metadata": {}, + "outputs": [], + "source": [ + "# Start Testing. Important to register the best model\n", + "trainer.test(dataloaders=test_dataloader)" + ] + }, + { + "cell_type": "markdown", + "id": "95e977c0", + "metadata": {}, + "source": [ + "# Predicting" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48591881", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a new trainer for prediction (no training setup needed)\n", + "import mlflow\n", + "import lightning as L\n", + "from torch.utils.data import DataLoader\n", + "\n", + "pred_trainer = L.Trainer(\n", + " enable_model_summary=True,\n", + " enable_progress_bar=True,\n", + ")\n", + "\n", + "registered_model = mlflow.pytorch.load_model(f'models:/{PROJECT_NAME}/latest')\n", + "\n", + "# Set up data module for prediction (same as before, but without annotations)\n", + "test_dataset = FracAtlasDataset(project_name=PROJECT_NAME, split='test',\n", + " transforms=test_transforms, return_annotations=False)\n", + "test_dataloader = DataLoader(test_dataset, batch_size=8, shuffle=False, num_workers=4)\n", + "\n", + "# Option 1: Use model already in memory\n", + "preds = pred_trainer.predict(\n", + " registered_model,\n", + " # ckpt_path=checkcb.best_model_path, # Uncomment to load from checkpoint\n", + " dataloaders=test_dataloader\n", + ")\n", + "\n", + "# Option 2: Load from MLflow Model Registry (commented out)\n", + "# registered_model = mlflow.pytorch.load_model(f'models:/{PROJECT_NAME}/latest')\n", + "# preds = pred_trainer.predict(registered_model, datamodule=pred_dm)\n", + "\n", + "\n", + "print(f\"✅ Predictions completed!\")\n", + "print(f\"First batch shape: {preds[0].shape}\")\n", + "print(f'First batch, class with max probability: {preds[0].argmax(dim=1)}')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pyproject.toml b/pyproject.toml index e68bb724..344ddfbd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,8 @@ Deprecated = ">=1.2.0" platformdirs = "^4.0.0" pandas = ">=2.0.0" matplotlib = "*" -lightning = "*" +lightning = ">=2.0.0, !=2.5.1, !=2.5.1.post0" +mlflow = "^2.0.0" albumentations = ">=2.0.0" lazy-loader = ">=0.3.0" medimgkit = ">=0.7.3" @@ -74,3 +75,16 @@ dev = ["pytest", "pytest-cov", "responses", "aioresponses"] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" +[tool.poetry.plugins."mlflow.tracking_store"] +datamint = "datamint.mlflow.tracking.datamint_store:DatamintStore" +http = "datamint.mlflow.tracking.datamint_store:DatamintStore" +https = "datamint.mlflow.tracking.datamint_store:DatamintStore" + +[tool.poetry.plugins."mlflow.artifact_repository"] +datamint = "datamint.mlflow.artifact.datamint_artifacts_repo:DatamintArtifactsRepository" +http = "datamint.mlflow.artifact.datamint_artifacts_repo:DatamintArtifactsRepository" +https = "datamint.mlflow.artifact.datamint_artifacts_repo:DatamintArtifactsRepository" +mlflow-artifacts = "datamint.mlflow.artifact.datamint_artifacts_repo:DatamintArtifactsRepository" + +[tool.poetry.plugins."mlflow.default_experiment_provider"] +datamint = "datamint.mlflow.tracking.default_experiment:DatamintExperimentProvider"