@@ -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 ,
0 commit comments