Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix/methods #85

Merged
merged 5 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions oodeel/extractor/feature_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def predict(
self,
dataset: Union[ItemType, DatasetType],
postproc_fns: Optional[List[Callable]] = None,
verbose: bool = False,
**kwargs,
) -> Tuple[List[TensorType], dict]:
"""Get the projection of the dataset in the feature space of self.model
Expand All @@ -122,6 +123,7 @@ def predict(
dataset (Union[ItemType, DatasetType]): input dataset
postproc_fns (Optional[Callable]): postprocessing function to apply to each
feature immediately after forward. Default to None.
verbose (bool): if True, display a progress bar. Defaults to False.
kwargs (dict): additional arguments not considered for prediction

Returns:
Expand Down
5 changes: 4 additions & 1 deletion oodeel/extractor/keras_feature_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from typing import Optional

import tensorflow as tf
from tqdm import tqdm

from ..datasets.tf_data_handler import TFDataHandler
from ..types import Callable
Expand Down Expand Up @@ -190,6 +191,7 @@ def predict(
self,
dataset: Union[ItemType, tf.data.Dataset],
postproc_fns: Optional[List[Callable]] = None,
verbose: bool = False,
**kwargs,
) -> Tuple[List[tf.Tensor], dict]:
"""Get the projection of the dataset in the feature space of self.model
Expand All @@ -198,6 +200,7 @@ def predict(
dataset (Union[ItemType, tf.data.Dataset]): input dataset
postproc_fns (Optional[Callable]): postprocessing function to apply to each
feature immediately after forward. Default to None.
verbose (bool): if True, display a progress bar. Defaults to False.
kwargs (dict): additional arguments not considered for prediction

Returns:
Expand All @@ -218,7 +221,7 @@ def predict(
features = [None for i in range(len(self.feature_layers_id))]
logits = None
contains_labels = TFDataHandler.get_item_length(dataset) > 1
for elem in dataset:
for elem in tqdm(dataset, desc="Predicting", disable=not verbose):
tensor = TFDataHandler.get_input_from_dataset_item(elem)
features_batch, logits_batch = self.predict_tensor(tensor, postproc_fns)

Expand Down
5 changes: 4 additions & 1 deletion oodeel/extractor/torch_feature_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import torch
from torch import nn
from torch.utils.data import DataLoader
from tqdm import tqdm

from ..datasets.torch_data_handler import TorchDataHandler
from ..types import Callable
Expand Down Expand Up @@ -226,6 +227,7 @@ def predict(
dataset: Union[DataLoader, ItemType],
postproc_fns: Optional[List[Callable]] = None,
detach: bool = True,
verbose: bool = False,
**kwargs,
) -> Tuple[List[torch.Tensor], dict]:
"""Get the projection of the dataset in the feature space of self.model
Expand All @@ -236,6 +238,7 @@ def predict(
each feature immediately after forward. Default to None.
detach (bool): if True, return features detached from the computational
graph. Defaults to True.
verbose (bool): if True, display a progress bar. Defaults to False.
kwargs (dict): additional arguments not considered for prediction

Returns:
Expand All @@ -257,7 +260,7 @@ def predict(
logits = None
batch = next(iter(dataset))
contains_labels = isinstance(batch, (list, tuple)) and len(batch) > 1
for elem in dataset:
for elem in tqdm(dataset, desc="Predicting", disable=not verbose):
tensor = TorchDataHandler.get_input_from_dataset_item(elem)
features_batch, logits_batch = self.predict_tensor(
tensor, postproc_fns, detach=detach
Expand Down
20 changes: 16 additions & 4 deletions oodeel/methods/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import inspect
from abc import ABC
from abc import abstractmethod
from typing import get_args

import numpy as np
from tqdm import tqdm

from ..extractor.feature_extractor import FeatureExtractor
from ..types import Callable
Expand Down Expand Up @@ -104,6 +106,7 @@ def fit(
fit_dataset: Optional[Union[ItemType, DatasetType]] = None,
feature_layers_id: List[Union[int, str]] = [],
input_layer_id: Optional[Union[int, str]] = None,
verbose: bool = False,
**kwargs,
) -> None:
"""Prepare the detector for scoring:
Expand All @@ -122,6 +125,7 @@ def fit(
layer of the feature extractor.
If int, the rank of the layer in the layer list
If str, the name of the layer. Defaults to None.
verbose (bool): if True, display a progress bar. Defaults to False.
"""
(
self.backend,
Expand All @@ -144,7 +148,7 @@ def fit(
" provided to compute react activation threshold"
)
else:
self.compute_react_threshold(model, fit_dataset)
self.compute_react_threshold(model, fit_dataset, verbose=verbose)

if (feature_layers_id == []) and (self.requires_internal_features):
raise ValueError(
Expand All @@ -160,6 +164,8 @@ def fit(
)

if fit_dataset is not None:
if "verbose" in inspect.signature(self._fit_to_dataset).parameters.keys():
kwargs.update({"verbose": verbose})
Comment on lines +167 to +168
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know what is the best practice but I think it's more clear to make verbose a real argument of _fit_to_dataset(), not in kwargs. Otherwise, we should make it clear in the docstring of _fit_to_dataset() (and in the tutorial "implement your own baseline") that verbose is a supported argument.

self._fit_to_dataset(fit_dataset, **kwargs)

def _load_feature_extractor(
Expand Down Expand Up @@ -207,12 +213,14 @@ def _fit_to_dataset(self, fit_dataset: DatasetType) -> None:
def score(
self,
dataset: Union[ItemType, DatasetType],
verbose: bool = False,
) -> np.ndarray:
"""
Computes an OOD score for input samples "inputs".

Args:
dataset (Union[ItemType, DatasetType]): dataset or tensors to score
verbose (bool): if True, display a progress bar. Defaults to False.

Returns:
tuple: scores or list of scores (depending on the input) and a dictionary
Expand All @@ -236,7 +244,7 @@ def score(
scores = np.array([])
logits = None

for item in dataset:
for item in tqdm(dataset, desc="Scoring", disable=not verbose):
tensor = self.data_handler.get_input_from_dataset_item(item)
score_batch = self._score_tensor(tensor)
logits_batch = self.op.convert_to_numpy(
Expand Down Expand Up @@ -267,9 +275,13 @@ def score(
info = dict(labels=labels, logits=logits)
return scores, info

def compute_react_threshold(self, model: Callable, fit_dataset: DatasetType):
def compute_react_threshold(
self, model: Callable, fit_dataset: DatasetType, verbose: bool = False
):
penult_feat_extractor = self._load_feature_extractor(model, [-2])
unclipped_features, _ = penult_feat_extractor.predict(fit_dataset)
unclipped_features, _ = penult_feat_extractor.predict(
fit_dataset, verbose=verbose
)
self.react_threshold = self.op.quantile(
unclipped_features[0], self.react_quantile
)
Expand Down