Skip to content

Commit 33ea1b0

Browse files
committed
squash commit
1 parent 859f6af commit 33ea1b0

File tree

75 files changed

+2330
-61
lines changed

Some content is hidden

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

75 files changed

+2330
-61
lines changed

.github/workflows/integration_tests_workflows_x86.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,7 @@ jobs:
6363
python -m pip install --upgrade pip
6464
pip install --upgrade setuptools
6565
pip install --extra-index-url https://download.pytorch.org/whl/cpu -r requirements/_requirements.txt -r requirements/requirements.sam.txt -r requirements/requirements.cpu.txt -r requirements/requirements.http.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.doctr.txt -r requirements/requirements.yolo_world.txt -r requirements/requirements.transformers.txt -r requirements/requirements.sdk.http.txt -r requirements/requirements.easyocr.txt
66+
# Test against source build of inference_models, not pinned PyPI version
67+
pip install --force-reinstall --no-deps ./inference_models
6668
- name: 🧪 Integration Tests of Workflows
6769
run: USE_INFERENCE_MODELS=${{ matrix.use-inference-models }} ROBOFLOW_API_KEY=${{ secrets.API_KEY }} MODAL_TOKEN_ID=${{ secrets.MODAL_TOKEN_ID }} MODAL_TOKEN_SECRET=${{ secrets.MODAL_TOKEN_SECRET }} MODAL_ALLOW_ANONYMOUS_EXECUTION=True MODAL_ANONYMOUS_WORKSPACE_NAME=github-test MODAL_SKIP_FLORENCE2_TEST=FALSE LOAD_ENTERPRISE_BLOCKS=TRUE python -m pytest tests/workflows/integration_tests

inference/core/entities/requests/inference.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,14 @@ class ObjectDetectionInferenceRequest(CVInferenceRequest):
146146
description="If provided, only predictions for the listed classes will be returned",
147147
)
148148
confidence: Optional[float] = Field(
149-
default=0.4,
149+
default=None,
150150
examples=[0.5],
151-
description="The confidence threshold used to filter out predictions",
151+
description=(
152+
"The confidence threshold used to filter out predictions. If omitted, "
153+
"the server uses the model's F1-optimal threshold from model evaluation "
154+
"when available, otherwise falls back to 0.4. Pass an explicit value to "
155+
"override both."
156+
),
152157
)
153158
fix_batch_size: Optional[bool] = Field(
154159
default=False,

inference/core/models/classification_base.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from io import BytesIO
22
from time import perf_counter
3-
from typing import Any, List, Tuple, Union
3+
from typing import Any, List, Optional, Tuple, Union
44

55
import numpy as np
66

@@ -299,7 +299,7 @@ def make_response(
299299
self,
300300
predictions,
301301
img_dims,
302-
confidence: float = 0.5,
302+
confidence: Optional[float] = 0.5,
303303
**kwargs,
304304
) -> Union[ClassificationInferenceResponse, List[ClassificationInferenceResponse]]:
305305
"""
@@ -320,6 +320,8 @@ def make_response(
320320
- Predictions below the confidence threshold are filtered out.
321321
"""
322322
responses = []
323+
if confidence is None:
324+
confidence = 0.5
323325
confidence_threshold = float(confidence)
324326
for ind, prediction in enumerate(predictions):
325327
if self.multiclass:

inference/core/models/inference_models_adapters.py

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -677,25 +677,29 @@ def postprocess(
677677
List[ClassificationInferenceResponse],
678678
]:
679679
mapped_kwargs = self.map_inference_kwargs(kwargs)
680-
post_processed_predictions = self._model.post_process(
681-
predictions, **mapped_kwargs
682-
)
683-
if isinstance(post_processed_predictions, list):
684-
# multi-label classification
685-
return prepare_multi_label_classification_response(
686-
post_processed_predictions,
687-
image_sizes=returned_metadata,
688-
class_names=self.class_names,
689-
confidence_threshold=kwargs.get("confidence", 0.5),
680+
if isinstance(self._model, MultiLabelClassificationModel):
681+
post_processed_predictions = self._model.post_process(
682+
predictions, **mapped_kwargs
690683
)
691-
else:
692-
# single-label classification
693-
return prepare_classification_response(
684+
return prepare_multi_label_classification_response(
694685
post_processed_predictions,
695686
image_sizes=returned_metadata,
696687
class_names=self.class_names,
697-
confidence_threshold=kwargs.get("confidence", 0.5),
698688
)
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", 0.5),
702+
)
699703

700704
def clear_cache(self, delete_from_disk: bool = True) -> None:
701705
"""Clears any cache if necessary. TODO: Implement this to delete the cache from the experimental model.
@@ -747,20 +751,27 @@ def prepare_multi_label_classification_response(
747751
post_processed_predictions: List[MultiLabelClassificationPrediction],
748752
image_sizes: List[Tuple[int, int]],
749753
class_names: List[str],
750-
confidence_threshold: float,
751754
) -> 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+
"""
752763
results = []
753764
for prediction, image_size in zip(post_processed_predictions, image_sizes):
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] = {
765+
image_predictions_dict = {
766+
class_names[class_id]: {
759767
"confidence": confidence,
760768
"class_id": class_id,
761769
}
762-
if confidence > confidence_threshold:
763-
predicted_classes.append(cls_name)
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+
]
764775
results.append(
765776
MultiLabelClassificationInferenceResponse(
766777
predictions=image_predictions_dict,

inference/core/models/instance_segmentation_base.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, List, Tuple, Union
1+
from typing import Any, List, Optional, Tuple, Union
22

33
import numpy as np
44

@@ -49,7 +49,7 @@ def infer(
4949
self,
5050
image: Any,
5151
class_agnostic_nms: bool = False,
52-
confidence: float = DEFAULT_CONFIDENCE,
52+
confidence: Optional[float] = DEFAULT_CONFIDENCE,
5353
disable_preproc_auto_orient: bool = False,
5454
disable_preproc_contrast: bool = False,
5555
disable_preproc_grayscale: bool = False,
@@ -94,6 +94,8 @@ def infer(
9494
- Applies non-maximum suppression to the predictions.
9595
- Decodes the masks according to the specified mode.
9696
"""
97+
if confidence is None:
98+
confidence = DEFAULT_CONFIDENCE
9799
return super().infer(
98100
image,
99101
class_agnostic_nms=class_agnostic_nms,

inference/core/models/object_detection_base.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def infer(
4343
self,
4444
image: Any,
4545
class_agnostic_nms: bool = DEFAULT_CLASS_AGNOSTIC_NMS,
46-
confidence: float = DEFAULT_CONFIDENCE,
46+
confidence: Optional[float] = DEFAULT_CONFIDENCE,
4747
disable_preproc_auto_orient: bool = False,
4848
disable_preproc_contrast: bool = False,
4949
disable_preproc_grayscale: bool = False,
@@ -81,6 +81,8 @@ def infer(
8181
Raises:
8282
ValueError: If batching is not enabled for the model and more than one image is passed for processing.
8383
"""
84+
if confidence is None:
85+
confidence = DEFAULT_CONFIDENCE
8486
return super().infer(
8587
image,
8688
class_agnostic_nms=class_agnostic_nms,

inference/core/workflows/core_steps/models/roboflow/instance_segmentation/v2.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,15 @@ class BlockManifest(WorkflowBlockManifest):
8585
images: Selector(kind=[IMAGE_KIND]) = ImageInputField
8686
model_id: Union[Selector(kind=[ROBOFLOW_MODEL_ID_KIND]), str] = RoboflowModelField
8787
confidence: Union[
88-
FloatZeroToOne,
88+
Optional[FloatZeroToOne],
8989
Selector(kind=[FLOAT_ZERO_TO_ONE_KIND]),
9090
] = Field(
91-
default=0.4,
92-
description="Confidence threshold for predictions.",
91+
default=None,
92+
description=(
93+
"Confidence threshold for predictions. If omitted, the inference "
94+
"server uses the model's F1-optimal threshold from model evaluation "
95+
"when available, otherwise falls back to 0.4."
96+
),
9397
examples=[0.3, "$inputs.confidence_threshold"],
9498
)
9599
class_filter: Union[Optional[List[str]], Selector(kind=[LIST_OF_VALUES_KIND])] = (

inference/core/workflows/core_steps/models/roboflow/keypoint_detection/v2.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,15 @@ class BlockManifest(WorkflowBlockManifest):
8484
images: Selector(kind=[IMAGE_KIND]) = ImageInputField
8585
model_id: Union[Selector(kind=[ROBOFLOW_MODEL_ID_KIND]), str] = RoboflowModelField
8686
confidence: Union[
87-
FloatZeroToOne,
87+
Optional[FloatZeroToOne],
8888
Selector(kind=[FLOAT_ZERO_TO_ONE_KIND]),
8989
] = Field(
90-
default=0.4,
91-
description="Confidence threshold for predictions.",
90+
default=None,
91+
description=(
92+
"Confidence threshold for predictions. If omitted, the inference "
93+
"server uses the model's F1-optimal threshold from model evaluation "
94+
"when available, otherwise falls back to 0.4."
95+
),
9296
examples=[0.3, "$inputs.confidence_threshold"],
9397
)
9498
keypoint_confidence: Union[

inference/core/workflows/core_steps/models/roboflow/multi_class_classification/v2.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,15 @@ class BlockManifest(WorkflowBlockManifest):
7878
images: Selector(kind=[IMAGE_KIND]) = ImageInputField
7979
model_id: Union[Selector(kind=[ROBOFLOW_MODEL_ID_KIND]), str] = RoboflowModelField
8080
confidence: Union[
81-
FloatZeroToOne,
81+
Optional[FloatZeroToOne],
8282
Selector(kind=[FLOAT_ZERO_TO_ONE_KIND]),
8383
] = Field(
84-
default=0.4,
85-
description="Confidence threshold for predictions.",
84+
default=None,
85+
description=(
86+
"Confidence threshold for predictions. If omitted, the inference "
87+
"server uses the model's F1-optimal threshold from model evaluation "
88+
"when available, otherwise falls back to 0.5."
89+
),
8690
examples=[0.3, "$inputs.confidence_threshold"],
8791
)
8892
disable_active_learning: Union[bool, Selector(kind=[BOOLEAN_KIND])] = Field(

inference/core/workflows/core_steps/models/roboflow/multi_label_classification/v2.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,15 @@ class BlockManifest(WorkflowBlockManifest):
7777
images: Selector(kind=[IMAGE_KIND]) = ImageInputField
7878
model_id: Union[Selector(kind=[ROBOFLOW_MODEL_ID_KIND]), str] = RoboflowModelField
7979
confidence: Union[
80-
FloatZeroToOne,
80+
Optional[FloatZeroToOne],
8181
Selector(kind=[FLOAT_ZERO_TO_ONE_KIND]),
8282
] = Field(
83-
default=0.4,
84-
description="Confidence threshold for predictions.",
83+
default=None,
84+
description=(
85+
"Confidence threshold for predictions. If omitted, the inference "
86+
"server uses the model's F1-optimal threshold from model evaluation "
87+
"when available, otherwise falls back to 0.5."
88+
),
8589
examples=[0.3, "$inputs.confidence_threshold"],
8690
)
8791
disable_active_learning: Union[bool, Selector(kind=[BOOLEAN_KIND])] = Field(

0 commit comments

Comments
 (0)