Skip to content

Refactored model.py to support image and LiDAR detection models. #308

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
296 changes: 261 additions & 35 deletions detectionmetrics/models/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
import detectionmetrics.utils.io as uio


class SegmentationModel(ABC):
"""Parent segmentation model class
class PerceptionModel(ABC):
"""Base class for all vision perception models (e.g., segmentation, detection).

:param model: Segmentation model object
:param model: Model object
:type model: Any
:param model_type: Model type (e.g. scripted, compiled, etc.)
:type model_type: str
Expand Down Expand Up @@ -52,41 +52,14 @@ def __init__(

@abstractmethod
def inference(
self, points: Union[np.ndarray, Image.Image]
) -> Union[np.ndarray, Image.Image]:
"""Perform inference for a single image or point cloud

:param image: Either a numpy array (LiDAR point cloud) or a PIL image
:type image: Union[np.ndarray, Image.Image]
:return: Segmenation result as a point cloud or image with label indices
:rtype: Union[np.ndarray, Image.Image]
"""
self, data: Union[np.ndarray, Image.Image]
) -> Union[np.ndarray, Image.Image, dict]:
"""Perform inference for a single image or point cloud."""
raise NotImplementedError

@abstractmethod
def eval(
self,
dataset: dm_dataset.SegmentationDataset,
split: str | List[str] = "test",
ontology_translation: Optional[str] = None,
predictions_outdir: Optional[str] = None,
results_per_sample: bool = False,
) -> pd.DataFrame:
"""Perform evaluation for an image segmentation dataset

:param dataset: Segmentation dataset for which the evaluation will be performed
:type dataset: ImageSegmentationDataset
:param split: Split or splits to be used from the dataset, defaults to "test"
:type split: str | List[str], optional
:param ontology_translation: JSON file containing translation between dataset and model output ontologies
:type ontology_translation: str, optional
:param predictions_outdir: Directory to save predictions per sample, defaults to None. If None, predictions are not saved.
:type predictions_outdir: Optional[str], optional
:param results_per_sample: Whether to store results per sample or not, defaults to False. If True, predictions_outdir must be provided.
:type results_per_sample: bool, optional
:return: DataFrame containing evaluation results
:rtype: pd.DataFrame
"""
def eval(self, *args, **kwargs) -> pd.DataFrame:
"""Evaluate the model on the given dataset."""
raise NotImplementedError

@abstractmethod
Expand Down Expand Up @@ -124,6 +97,71 @@ def get_lut_ontology(
return lut_ontology


class SegmentationModel(PerceptionModel):
"""Parent segmentation model class

:param model: Segmentation model object
:type model: Any
:param model_type: Model type (e.g. scripted, compiled, etc.)
:type model_type: str
:param model_cfg: JSON file containing model configuration
:type model_cfg: str
:param ontology_fname: JSON file containing model output ontology
:type ontology_fname: str
:param model_fname: Model file or directory, defaults to None
:type model_fname: Optional[str], optional
"""

def __init__(
self,
model: Any,
model_type: str,
model_cfg: str,
ontology_fname: str,
model_fname: Optional[str] = None,
):
super().__init__(model, model_type, model_cfg, ontology_fname, model_fname)

@abstractmethod
def inference(
self, points: Union[np.ndarray, Image.Image]
) -> Union[np.ndarray, Image.Image]:
"""Perform inference for a single image or point cloud

:param image: Either a numpy array (LiDAR point cloud) or a PIL image
:type image: Union[np.ndarray, Image.Image]
:return: Segmenation result as a point cloud or image with label indices
:rtype: Union[np.ndarray, Image.Image]
"""
raise NotImplementedError

@abstractmethod
def eval(
self,
dataset: dm_dataset.SegmentationDataset,
split: str | List[str] = "test",
ontology_translation: Optional[str] = None,
predictions_outdir: Optional[str] = None,
results_per_sample: bool = False,
) -> pd.DataFrame:
"""Perform evaluation for an image segmentation dataset

:param dataset: Segmentation dataset for which the evaluation will be performed
:type dataset: ImageSegmentationDataset
:param split: Split or splits to be used from the dataset, defaults to "test"
:type split: str | List[str], optional
:param ontology_translation: JSON file containing translation between dataset and model output ontologies
:type ontology_translation: str, optional
:param predictions_outdir: Directory to save predictions per sample, defaults to None. If None, predictions are not saved.
:type predictions_outdir: Optional[str], optional
:param results_per_sample: Whether to store results per sample or not, defaults to False. If True, predictions_outdir must be provided.
:type results_per_sample: bool, optional
:return: DataFrame containing evaluation results
:rtype: pd.DataFrame
"""
raise NotImplementedError


class ImageSegmentationModel(SegmentationModel):
"""Parent image segmentation model class

Expand Down Expand Up @@ -248,3 +286,191 @@ def eval(
:rtype: pd.DataFrame
"""
raise NotImplementedError

class DetectionModel(PerceptionModel):
"""Parent detection model class

:param model: Detection model object
:type model: Any
:param model_type: Model type (e.g. scripted, compiled, etc.)
:type model_type: str
:param model_cfg: JSON file containing model configuration
:type model_cfg: str
:param ontology_fname: JSON file containing model output ontology
:type ontology_fname: str
:param model_fname: Model file or directory, defaults to None
:type model_fname: Optional[str], optional
"""

def __init__(
self,
model: Any,
model_type: str,
model_cfg: str,
ontology_fname: str,
model_fname: Optional[str] = None,
):
super().__init__(model, model_type, model_cfg, ontology_fname, model_fname)

@abstractmethod
def inference(
self, data: Union[np.ndarray, Image.Image]
) -> List[dict]:
"""Perform inference for a single input (image or point cloud)

:param data: Input image or LiDAR point cloud
:type data: Union[np.ndarray, Image.Image]
:return: List of detection results (each a dict with bbox, confidence, class)
:rtype: List[dict]
"""
raise NotImplementedError

@abstractmethod
def eval(
self,
dataset: dm_dataset.DetectionDataset,
split: Union[str, List[str]] = "test",
ontology_translation: Optional[str] = None,
predictions_outdir: Optional[str] = None,
results_per_sample: bool = False,
) -> pd.DataFrame:
"""Perform evaluation for a detection dataset

:param dataset: Detection dataset for which evaluation will be performed
:type dataset: ImageDetecctionDataset
:param split: Split(s) to use, defaults to "test"
:type split: Union[str, List[str]]
:param ontology_translation: JSON file containing translation between dataset and model output ontologies
:type ontology_translation: Optional[str]
:param predictions_outdir: Directory to save predictions per sample, defaults to None. If None, predictions are not saved.
:type predictions_outdir: Optional[str]
:param results_per_sample: Whether to store results per sample or not, defaults to False. If True, predictions_outdir must be provided.
:type results_per_sample: bool
:return: DataFrame containing evaluation metrics
:rtype: pd.DataFrame
"""
raise NotImplementedError

class ImageDetectionModel(DetectionModel):
"""Parent image detection model class

:param model: Detection model object
:type model: Any
:param model_type: Model type (e.g. scripted, compiled, etc.)
:type model_type: str
:param model_cfg: JSON file containing model configuration (e.g. image size or normalization parameters)
:type model_cfg: str
:param ontology_fname: JSON file containing model output ontology
:type ontology_fname: str
:param model_fname: Model file or directory, defaults to None
:type model_fname: Optional[str], optional
"""

def __init__(
self,
model: Any,
model_type: str,
model_cfg: str,
ontology_fname: str,
model_fname: Optional[str] = None,
):
super().__init__(model, model_type, model_cfg, ontology_fname, model_fname)

@abstractmethod
def inference(self, image: Image.Image) -> List[dict]:
"""Perform inference for a single image

:param image: PIL image
:type image: Image.Image
:return: List of detection results
:rtype: List[dict]
"""
raise NotImplementedError

@abstractmethod
def eval(
self,
dataset: dm_dataset.ImageDetectionDataset,
split: Union[str, List[str]] = "test",
ontology_translation: Optional[str] = None,
predictions_outdir: Optional[str] = None,
results_per_sample: bool = False,
) -> pd.DataFrame:
"""Evaluate the image detection model

:param dataset: Image detection dataset for which the evaluation will be performed
:type dataset: ImageDetectionDataset
:param split: Split(s) to use, defaults to "test"
:type split: Union[str, List[str]]
:param ontology_translation: JSON file containing translation between dataset and model output ontologies
:type ontology_translation: Optional[str]
:param predictions_outdir: Directory to save predictions per sample, defaults to None. If None, predictions are not saved.
:type predictions_outdir: Optional[str]
:param results_per_sample: Whether to store results per sample or not, defaults to False. If True, predictions_outdir must be provided.
:type results_per_sample: bool
:return: DataFrame containing evaluation metrics
:rtype: pd.DataFrame
"""
raise NotImplementedError

class LiDARDetectionModel(DetectionModel):
"""Parent LiDAR detection model class

:param model: Detection model object
:type model: Any
:param model_type: Model type (e.g. scripted, compiled, etc.)
:type model_type: str
:param model_cfg: JSON file with model configuration
:type model_cfg: str
:param ontology_fname: JSON file containing model output ontology
:type ontology_fname: str
:param model_fname: Model file or directory, defaults to None
:type model_fname: Optional[str], optional
"""

def __init__(
self,
model: Any,
model_type: str,
model_cfg: str,
ontology_fname: str,
model_fname: Optional[str] = None,
):
super().__init__(model, model_type, model_cfg, ontology_fname, model_fname)

@abstractmethod
def inference(self, points: np.ndarray) -> List[dict]:
"""Perform inference for a single LiDAR point cloud

:param points: N x 3 or N x 4 point cloud array
:type points: np.ndarray
:return: List of detection results
:rtype: List[dict]
"""
raise NotImplementedError

@abstractmethod
def eval(
self,
dataset: dm_dataset.LiDARDetectionDataset,
split: Union[str, List[str]] = "test",
ontology_translation: Optional[str] = None,
predictions_outdir: Optional[str] = None,
results_per_sample: bool = False,
) -> pd.DataFrame:
"""Perform evaluation for a LiDAR detection dataset

:param dataset: LiDAR detection dataset for which the evaluation will be performed
:type dataset: LiDARDetectionDataset
:param split: Split or splits to be used from the dataset, defaults to "test"
:type split: Union[str, List[str]]
:param ontology_translation: JSON file containing translation between dataset and model output ontologies
:type ontology_translation: Optional[str]
:param predictions_outdir: Directory to save predictions per sample, defaults to None. If None, predictions are not saved.
:type predictions_outdir: Optional[str]
:param results_per_sample: Whether to store results per sample or not, defaults to False. If True, predictions_outdir must be provided.
:type results_per_sample: bool, optional
:return: DataFrame containing evaluation metrics
:rtype: pd.DataFrame
"""
raise NotImplementedError
28 changes: 6 additions & 22 deletions docs/py_docs/_build/html/detectionmetrics.cli.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,30 +74,14 @@ <h1>detectionmetrics.cli package<a class="headerlink" href="#detectionmetrics-cl
<section id="submodules">
<h2>Submodules<a class="headerlink" href="#submodules" title="Link to this heading"></a></h2>
</section>
<section id="module-detectionmetrics.cli.batch">
<span id="detectionmetrics-cli-batch-module"></span><h2>detectionmetrics.cli.batch module<a class="headerlink" href="#module-detectionmetrics.cli.batch" title="Link to this heading"></a></h2>
<section id="detectionmetrics-cli-batch-module">
<h2>detectionmetrics.cli.batch module<a class="headerlink" href="#detectionmetrics-cli-batch-module" title="Link to this heading"></a></h2>
</section>
<section id="module-detectionmetrics.cli.evaluate">
<span id="detectionmetrics-cli-evaluate-module"></span><h2>detectionmetrics.cli.evaluate module<a class="headerlink" href="#module-detectionmetrics.cli.evaluate" title="Link to this heading"></a></h2>
<dl class="py function">
<dt class="sig sig-object py" id="detectionmetrics.cli.evaluate.parse_split">
<span class="sig-prename descclassname"><span class="pre">detectionmetrics.cli.evaluate.</span></span><span class="sig-name descname"><span class="pre">parse_split</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">ctx</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">param</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">value</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#detectionmetrics.cli.evaluate.parse_split" title="Link to this definition"></a></dt>
<dd><p>Parse split argument</p>
</dd></dl>

<section id="detectionmetrics-cli-evaluate-module">
<h2>detectionmetrics.cli.evaluate module<a class="headerlink" href="#detectionmetrics-cli-evaluate-module" title="Link to this heading"></a></h2>
</section>
<section id="module-detectionmetrics.cli">
<span id="module-contents"></span><h2>Module contents<a class="headerlink" href="#module-detectionmetrics.cli" title="Link to this heading"></a></h2>
<dl class="py function">
<dt class="sig sig-object py" id="detectionmetrics.cli.get_dataset">
<span class="sig-prename descclassname"><span class="pre">detectionmetrics.cli.</span></span><span class="sig-name descname"><span class="pre">get_dataset</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">task</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">input_type</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">dataset_format</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">dataset_fname</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">dataset_dir</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">split_dir</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">train_dataset_dir</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">val_dataset_dir</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">test_dataset_dir</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">images_dir</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">labels_dir</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">data_suffix</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">label_suffix</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">ontology</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">split</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#detectionmetrics.cli.get_dataset" title="Link to this definition"></a></dt>
<dd></dd></dl>

<dl class="py function">
<dt class="sig sig-object py" id="detectionmetrics.cli.get_model">
<span class="sig-prename descclassname"><span class="pre">detectionmetrics.cli.</span></span><span class="sig-name descname"><span class="pre">get_model</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">task</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">input_type</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">model_format</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">model</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">ontology</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">model_cfg</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#detectionmetrics.cli.get_model" title="Link to this definition"></a></dt>
<dd></dd></dl>

<section id="module-contents">
<h2>Module contents<a class="headerlink" href="#module-contents" title="Link to this heading"></a></h2>
</section>
</section>

Expand Down
Loading