diff --git a/frigate/api/event.py b/frigate/api/event.py index b1c98bb19..c716bba13 100644 --- a/frigate/api/event.py +++ b/frigate/api/event.py @@ -481,20 +481,15 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends()) else: search_types = search_type.split(",") - # only normalize multi-modal searches - apply_normalization = ( - "thumbnail" in search_types and "description" in search_types - ) + # only save stats for multi-modal searches + save_stats = "thumbnail" in search_types and "description" in search_types if "thumbnail" in search_types: thumb_result = context.search_thumbnail(query) - if apply_normalization: - thumb_distances = context.thumb_stats.normalize( - [result[1] for result in thumb_result] - ) - else: - thumb_distances = [result[1] for result in thumb_result] + thumb_distances = context.thumb_stats.normalize( + [result[1] for result in thumb_result], save_stats + ) thumb_ids = dict( zip([result[0] for result in thumb_result], thumb_distances) @@ -508,14 +503,10 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends()) if "description" in search_types: desc_result = context.search_description(query) - if apply_normalization: - desc_distances = context.desc_stats.normalize( - [result[1] for result in desc_result] - ) - else: - desc_distances = [ - result[1] for result in desc_result - ] # Use raw distances + + desc_distances = context.desc_stats.normalize( + [result[1] for result in desc_result], save_stats + ) desc_ids = dict(zip([result[0] for result in desc_result], desc_distances)) diff --git a/frigate/embeddings/util.py b/frigate/embeddings/util.py index 3d7605057..bc1a952ec 100644 --- a/frigate/embeddings/util.py +++ b/frigate/embeddings/util.py @@ -22,8 +22,9 @@ class ZScoreNormalization: def stddev(self): return math.sqrt(self.variance) if self.variance > 0 else 0.0 - def normalize(self, distances: list[float]): - self._update(distances) + def normalize(self, distances: list[float], save_stats: bool): + if save_stats: + self._update(distances) if self.stddev == 0: return distances return [ diff --git a/web/src/views/search/SearchView.tsx b/web/src/views/search/SearchView.tsx index de1da0746..4c33f7dc8 100644 --- a/web/src/views/search/SearchView.tsx +++ b/web/src/views/search/SearchView.tsx @@ -190,17 +190,13 @@ export default function SearchView({ // confidence score const zScoreToConfidence = (score: number) => { - // Normalizing is needed for multi-modal searches only + // Normalizing is not needed for similarity searches // Sigmoid function for normalized: 1 / (1 + e^x) - // Cosine for non-normalized + // Cosine for similarity if (searchFilter) { - const normalized = - !searchFilter.search_type || - (Array.isArray(searchFilter.search_type) && - searchFilter.search_type.length === 2 && - searchFilter.search_type.includes("thumbnail") && - searchFilter.search_type.includes("description")); - const confidence = normalized ? 1 / (1 + Math.exp(score)) : 1 - score; + const notNormalized = searchFilter?.search_type?.includes("similarity"); + + const confidence = notNormalized ? 1 - score : 1 / (1 + Math.exp(score)); return Math.round(confidence * 100); }