Skip to content

Commit 93b0eee

Browse files
Revert "Support optimal confidence from model-eval (#2206)" (#2241)
This reverts commit 5f1026e.
1 parent 5f1026e commit 93b0eee

File tree

78 files changed

+259
-1902
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+259
-1902
lines changed

inference/core/entities/requests/inference.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from pydantic import BaseModel, ConfigDict, Field, validator
55

66
from inference.core.entities.common import ApiKey, ModelID, ModelType
7-
from inference_sdk.http.entities import Confidence
87

98

109
class BaseRequest(BaseModel):
@@ -146,13 +145,10 @@ class ObjectDetectionInferenceRequest(CVInferenceRequest):
146145
examples=[["class-1", "class-2", "class-n"]],
147146
description="If provided, only predictions for the listed classes will be returned",
148147
)
149-
confidence: Confidence = Field(
148+
confidence: Optional[float] = Field(
150149
default=0.4,
151-
examples=[0.5, "best", "default"],
152-
description=(
153-
'Confidence threshold. "best" uses model-eval thresholds, '
154-
'"default" uses the model built-in, or pass a float.'
155-
),
150+
examples=[0.5],
151+
description="The confidence threshold used to filter out predictions",
156152
)
157153
fix_batch_size: Optional[bool] = Field(
158154
default=False,
@@ -249,13 +245,10 @@ def __init__(self, **kwargs):
249245
kwargs["model_type"] = "classification"
250246
super().__init__(**kwargs)
251247

252-
confidence: Confidence = Field(
248+
confidence: Optional[float] = Field(
253249
default=0.4,
254-
examples=[0.5, "best", "default"],
255-
description=(
256-
'Confidence threshold. "best" uses model-eval thresholds, '
257-
'"default" uses the model built-in, or pass a float.'
258-
),
250+
examples=[0.5],
251+
description="The confidence threshold used to filter out predictions",
259252
)
260253
visualization_stroke_width: Optional[int] = Field(
261254
default=1,

inference/core/models/base.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,7 @@ def infer_from_request(
139139
is also included in the response.
140140
"""
141141
t1 = perf_counter()
142-
kwargs = request.dict()
143-
confidence = kwargs.get("confidence")
144-
if isinstance(confidence, str):
145-
logger.warning(
146-
"Legacy inference does not support confidence=%r, "
147-
"using model default",
148-
confidence,
149-
)
150-
kwargs.pop("confidence")
151-
responses = self.infer(**kwargs, return_image_dims=False)
142+
responses = self.infer(**request.dict(), return_image_dims=False)
152143
for response in responses:
153144
response.time = perf_counter() - t1
154145
logger.debug(f"model infer time: {response.time * 1000.0} ms")

inference/core/models/inference_models_adapters.py

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -677,29 +677,25 @@ def postprocess(
677677
List[ClassificationInferenceResponse],
678678
]:
679679
mapped_kwargs = self.map_inference_kwargs(kwargs)
680-
if isinstance(self._model, MultiLabelClassificationModel):
681-
post_processed_predictions = self._model.post_process(
682-
predictions, **mapped_kwargs
683-
)
680+
post_processed_predictions = self._model.post_process(
681+
predictions, **mapped_kwargs
682+
)
683+
if isinstance(post_processed_predictions, list):
684+
# multi-label classification
684685
return prepare_multi_label_classification_response(
685686
post_processed_predictions,
686687
image_sizes=returned_metadata,
687688
class_names=self.class_names,
689+
confidence_threshold=kwargs.get("confidence", 0.5),
690+
)
691+
else:
692+
# single-label classification
693+
return prepare_classification_response(
694+
post_processed_predictions,
695+
image_sizes=returned_metadata,
696+
class_names=self.class_names,
697+
confidence_threshold=kwargs.get("confidence", 0.5),
688698
)
689-
# Single-label classification: top-1 always wins regardless of
690-
# confidence, so per-class refinement isn't meaningful here. The base
691-
# class deliberately opts out of recommendedParameters entirely. The
692-
# response builder still uses kwargs.get("confidence", 0.5) for the
693-
# cutoff that decides which alternative classes show up.
694-
post_processed_predictions = self._model.post_process(
695-
predictions, **mapped_kwargs
696-
)
697-
return prepare_classification_response(
698-
post_processed_predictions,
699-
image_sizes=returned_metadata,
700-
class_names=self.class_names,
701-
confidence_threshold=kwargs.get("confidence") or 0.5,
702-
)
703699

704700
def clear_cache(self, delete_from_disk: bool = True) -> None:
705701
"""Clears any cache if necessary. TODO: Implement this to delete the cache from the experimental model.
@@ -751,27 +747,20 @@ def prepare_multi_label_classification_response(
751747
post_processed_predictions: List[MultiLabelClassificationPrediction],
752748
image_sizes: List[Tuple[int, int]],
753749
class_names: List[str],
750+
confidence_threshold: float,
754751
) -> List[MultiLabelClassificationInferenceResponse]:
755-
"""Build the API response from a model's post-processed predictions.
756-
757-
`prediction.class_ids` is the authoritative list of "passed" classes —
758-
the model's `post_process` already applied the
759-
full priority chain (user → per-class → global → default), so the
760-
response builder doesn't re-threshold here. The full per-class score
761-
vector is still emitted in `image_predictions_dict` for UI display.
762-
"""
763752
results = []
764753
for prediction, image_size in zip(post_processed_predictions, image_sizes):
765-
image_predictions_dict = {
766-
class_names[class_id]: {
754+
image_predictions_dict = dict()
755+
predicted_classes = []
756+
for class_id, confidence in enumerate(prediction.confidence.cpu().tolist()):
757+
cls_name = class_names[class_id]
758+
image_predictions_dict[cls_name] = {
767759
"confidence": confidence,
768760
"class_id": class_id,
769761
}
770-
for class_id, confidence in enumerate(prediction.confidence.cpu().tolist())
771-
}
772-
predicted_classes = [
773-
class_names[class_id] for class_id in prediction.class_ids.tolist()
774-
]
762+
if confidence > confidence_threshold:
763+
predicted_classes.append(cls_name)
775764
results.append(
776765
MultiLabelClassificationInferenceResponse(
777766
predictions=image_predictions_dict,

inference_models/docs/changelog.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,5 @@
11
# Changelog
22

3-
## `0.25.0`
4-
5-
### Added
6-
7-
- `post_process(...)` on object detection, instance segmentation, keypoint detection, classification, and semantic
8-
segmentation models now accepts `confidence` as `"best"` (use per-class or global thresholds from
9-
`RecommendedParameters` when available), `"default"` (model's built-in default), or a float override. Shared NMS
10-
helpers accept a per-class `torch.Tensor` for single-pass per-class filtering.
11-
12-
---
13-
143
## `0.24.4`
154

165
### Changed

inference_models/inference_models/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
if os.environ.get("TOKENIZERS_PARALLELISM") is None:
2929
os.environ["TOKENIZERS_PARALLELISM"] = "false"
3030

31-
from inference_models.entities import ColorFormat, Confidence
31+
from inference_models.entities import ColorFormat
3232
from inference_models.model_pipelines.auto_loaders.core import AutoModelPipeline
3333
from inference_models.models.auto_loaders.core import AutoModel
3434
from inference_models.models.auto_loaders.entities import (
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from collections import namedtuple
2-
from typing import Literal, Union
2+
from typing import Literal
33

44
ImageDimensions = namedtuple("ImageDimensions", ["height", "width"])
55
ColorFormat = Literal["rgb", "bgr"]
6-
Confidence = Union[float, Literal["best", "default"]]

inference_models/inference_models/models/auto_loaders/auto_resolution_cache.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@
1717
TaskType,
1818
)
1919
from inference_models.utils.file_system import dump_json, read_json
20-
from inference_models.weights_providers.entities import (
21-
ModelDependency,
22-
RecommendedParameters,
23-
)
20+
from inference_models.weights_providers.entities import ModelDependency
2421

2522

2623
class AutoResolutionCacheEntry(BaseModel):
@@ -33,7 +30,6 @@ class AutoResolutionCacheEntry(BaseModel):
3330
model_dependencies: Optional[List[ModelDependency]] = Field(default=None)
3431
created_at: datetime
3532
model_features: Optional[dict] = Field(default=None)
36-
recommended_parameters: Optional[RecommendedParameters] = Field(default=None)
3733

3834

3935
class AutoResolutionCache(ABC):

inference_models/inference_models/models/auto_loaders/core.py

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@
8181
ModelDependency,
8282
ModelPackageMetadata,
8383
Quantization,
84-
RecommendedParameters,
8584
)
8685

8786
MODEL_TYPES_TO_LOAD_FROM_CHECKPOINT = {
@@ -927,7 +926,6 @@ def model_directory_pointer(model_dir: str) -> None:
927926
model_dependencies=model_metadata.model_dependencies,
928927
model_dependencies_instances=model_dependencies_instances,
929928
model_dependencies_directories=model_dependencies_directories,
930-
recommended_parameters=model_metadata.recommended_parameters,
931929
max_package_loading_attempts=max_package_loading_attempts,
932930
model_download_file_lock_acquire_timeout=model_download_file_lock_acquire_timeout,
933931
verify_hash_while_download=verify_hash_while_download,
@@ -1080,10 +1078,6 @@ def attempt_loading_model_with_auto_load_cache(
10801078
package_id=cache_entry.model_package_id,
10811079
)
10821080
model_init_kwargs[MODEL_DEPENDENCIES_KEY] = model_dependencies_instances
1083-
# Cache stores the already-resolved (package-vs-model) value written
1084-
# in initialize_model — no need to re-run resolve_recommended_parameters.
1085-
if cache_entry.recommended_parameters is not None:
1086-
model_init_kwargs["recommended_parameters"] = cache_entry.recommended_parameters
10871081
model = model_class.from_pretrained(
10881082
model_package_cache_dir, **model_init_kwargs
10891083
)
@@ -1119,7 +1113,6 @@ def attempt_loading_matching_model_packages(
11191113
model_dependencies: Optional[List[ModelDependency]],
11201114
model_dependencies_instances: Dict[str, AnyModel],
11211115
model_dependencies_directories: Dict[str, str],
1122-
recommended_parameters: Optional[RecommendedParameters] = None,
11231116
max_package_loading_attempts: Optional[int] = None,
11241117
model_download_file_lock_acquire_timeout: int = FILE_LOCK_ACQUIRE_TIMEOUT,
11251118
verbose: bool = True,
@@ -1160,7 +1153,6 @@ def attempt_loading_matching_model_packages(
11601153
model_dependencies=model_dependencies,
11611154
model_dependencies_instances=model_dependencies_instances,
11621155
model_dependencies_directories=model_dependencies_directories,
1163-
recommended_parameters=recommended_parameters,
11641156
verify_hash_while_download=verify_hash_while_download,
11651157
download_files_without_hash=download_files_without_hash,
11661158
on_file_created=partial(
@@ -1226,7 +1218,6 @@ def initialize_model(
12261218
model_dependencies: Optional[List[ModelDependency]],
12271219
model_dependencies_instances: Dict[str, AnyModel],
12281220
model_dependencies_directories: Dict[str, str],
1229-
recommended_parameters: Optional[RecommendedParameters] = None,
12301221
model_download_file_lock_acquire_timeout: int = FILE_LOCK_ACQUIRE_TIMEOUT,
12311222
verify_hash_while_download: bool = True,
12321223
download_files_without_hash: bool = False,
@@ -1316,12 +1307,6 @@ def initialize_model(
13161307
)
13171308
resolved_files.update(dependencies_resolved_files)
13181309
model_init_kwargs[MODEL_DEPENDENCIES_KEY] = model_dependencies_instances
1319-
resolved_recommended_parameters = resolve_recommended_parameters(
1320-
package_level=model_package.recommended_parameters,
1321-
model_level=recommended_parameters,
1322-
)
1323-
if resolved_recommended_parameters is not None:
1324-
model_init_kwargs["recommended_parameters"] = resolved_recommended_parameters
13251310
model = model_class.from_pretrained(model_package_cache_dir, **model_init_kwargs)
13261311
dump_auto_resolution_cache(
13271312
use_auto_resolution_cache=use_auto_resolution_cache,
@@ -1335,7 +1320,6 @@ def initialize_model(
13351320
resolved_files=resolved_files,
13361321
model_dependencies=model_dependencies,
13371322
model_features=model_package.model_features,
1338-
recommended_parameters=resolved_recommended_parameters,
13391323
)
13401324
return model, model_package_cache_dir
13411325

@@ -1500,7 +1484,6 @@ def dump_auto_resolution_cache(
15001484
resolved_files: Set[str],
15011485
model_dependencies: Optional[List[ModelDependency]],
15021486
model_features: Optional[dict],
1503-
recommended_parameters: Optional[RecommendedParameters] = None,
15041487
) -> None:
15051488
if not use_auto_resolution_cache:
15061489
return None
@@ -1514,7 +1497,6 @@ def dump_auto_resolution_cache(
15141497
created_at=datetime.now(),
15151498
model_dependencies=model_dependencies,
15161499
model_features=model_features,
1517-
recommended_parameters=recommended_parameters,
15181500
)
15191501
auto_resolution_cache.register(
15201502
auto_negotiation_hash=auto_negotiation_hash, cache_entry=cache_content
@@ -1830,11 +1812,3 @@ def load_class_from_path(module_path: str, class_name: str) -> AnyModel:
18301812
help_url="https://inference-models.roboflow.com/errors/model-loading/#corruptedmodelpackageerror",
18311813
)
18321814
return getattr(module, class_name)
1833-
1834-
1835-
def resolve_recommended_parameters(
1836-
package_level: Optional[RecommendedParameters],
1837-
model_level: Optional[RecommendedParameters],
1838-
) -> Optional[RecommendedParameters]:
1839-
"""Package-level recommended_parameters take priority over model-level."""
1840-
return package_level if package_level is not None else model_level

inference_models/inference_models/models/base/classification.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ class ClassificationPrediction:
1717

1818
class ClassificationModel(ABC, Generic[PreprocessedInputs, RawPrediction]):
1919

20-
# Single-label classification deliberately opts out of recommendedParameters.
21-
# Top-1 always wins regardless of confidence, so per-class refinement isn't
22-
# a meaningful semantic for this task type. (Multi-label classification opts
23-
# in below — that's where per-class thresholds actually filter the result.)
24-
2520
@classmethod
2621
@abstractmethod
2722
def from_pretrained(

0 commit comments

Comments
 (0)