HumanSignal / label-studio-ml-backend

Configs and boilerplates for Label Studio's Machine Learning backend
Apache License 2.0
585 stars 261 forks source link

Suggestions don't show in label studio gui. #613

Closed prichinatryaski closed 3 months ago

prichinatryaski commented 3 months ago

Hello, I've tried to write my own ml backend using yolo, however, label-studio doesn't show any boxes on screen. Here's my code:

def predict(self, tasks: List[Dict], context: Optional[Dict] = None, **kwargs) -> ModelResponse:
        """ Write your inference logic here
            :param tasks: [Label Studio tasks in JSON format](https://labelstud.io/guide/task_format.html)
            :param context: [Label Studio context in JSON format](https://labelstud.io/guide/ml_create#Implement-prediction-logic)
            :return model_response
                ModelResponse(predictions=predictions) with
                predictions: [Predictions array in JSON format](https://labelstud.io/guide/export.html#Label-Studio-JSON-format-of-annotated-tasks)
        """
        print(f'''\
        Run prediction on {tasks}
        Received context: {context}
        Project ID: {self.project_id}
        Label config: {self.label_config}
        Parsed JSON Label config: {self.parsed_label_config}
        Extra params: {self.extra_params}''')

        task = tasks[0]

        # Getting URL of the image
        image_url = task['data'][self.value]
        full_url = image_url if "://" in image_url else f"{LS_URL}{image_url}"
        print("FULL URL: ", full_url)

        # Header to get request
        header = {
            "Authorization": "Token " + LS_API_TOKEN
        }

        # Getting URL and loading image
        image = Image.open(BytesIO(requests.get(full_url, headers=header).content))
        # Height and width of image
        original_width, original_height = image.size

        # Creating list for predictions and variable for scores
        predictions = []
        score = 0
        i = 0

        def extract_coordinates(boxes):
            coordinates = []
            for box in boxes.boxes.xyxy:
                x1, y1, x2, y2 = box.to('cpu').tolist()
                coordinates.append([(x1, y1), (x2, y1), (x2, y2), (x1, y2)])
            return coordinates

        # Getting predictions from all models
        for model_info in self.models:
            model = model_info["model"]
            labels = model_info["labels"]

            # Getting prediction using model
            results = model.predict(image)[0]
            #print(results)

            for result in results:  # Iterate over the list of results
                if result.boxes.cls.tolist() and results.boxes.xywh.tolist()[0]:
                    print(result.boxes.xywh.tolist())
                    print(type(results.boxes.xywh.tolist()))
                    x = results.boxes.xywh.tolist()[0][0]
                    y = results.boxes.xywh.tolist()[0][1]
                    w = results.boxes.xywh.tolist()[0][2]
                    h = results.boxes.xywh.tolist()[0][3]

                    predictions.append({
                        "from_name": 'label',
                        "to_name": 'image',
                        "type": "rectanglelabels",
                        "score": result.boxes.conf.item(),
                        "original_width": original_width,
                        "original_height": original_height,
                        "image_rotation": 0,
                        "value": {
                            "rectanglelabels": [labels[int(result.boxes.cls)]],
                            "x": x,
                            "y": y,
                            "w": w,
                            "h": h,
                        }
                    })

                    score += result.boxes.conf
                    i += 1

        average_score = score / i if i > 0 else 0
        print(f"Prediction Score is {average_score}.")

        # Dict with final dicts with predictions
        final_prediction = [{
            "result": predictions,
            "score": average_score.item(),
            "model_version": "v8s"
        }]
        print(final_prediction)
        return ModelResponse(predictions=final_prediction)
    And here are logs:
      0: 384x640 (no detections), 97.9ms
Speed: 2.4ms preprocess, 97.9ms inference, 0.5ms postprocess per image at shape (1, 3, 384, 640)
Prediction Score is tensor([0.5800]).
[{'result': [{'from_name': 'label', 'to_name': 'image', 'type': 'rectanglelabels', 'score': 0.8434253931045532, 'original_width': 1920, 'original_height': 1128, 'image_rotation': 0, 'value': {'rectanglelabels': ['class1'], 'x': 1717.0357666015625, 'y': 630.5845947265625, 'w': 98.889404296875, 'h': 110.57818603515625}}, {'from_name': 'label', 'to_name': 'image', 'type': 'rectanglelabels', 'score': 0.6622791886329651, 'original_width': 1920, 'original_height': 1128, 'image_rotation': 0, 'value': {'rectanglelabels': ['class2'], 'x': 1717.0357666015625, 'y': 630.5845947265625, 'w': 98.889404296875, 'h': 110.57818603515625}}, {'from_name': 'label', 'to_name': 'image', 'type': 'rectanglelabels', 'score': 0.6021055579185486, 'original_width': 1920, 'original_height': 1128, 'image_rotation': 0, 'value': {'rectanglelabels': ['class2'], 'x': 1717.0357666015625, 'y': 630.5845947265625, 'w': 98.889404296875, 'h': 110.57818603515625}}, {'from_name': 'label', 'to_name': 'image', 'type': 'rectanglelabels', 'score': 0.47654151916503906, 'original_width': 1920, 'original_height': 1128, 'image_rotation': 0, 'value': {'rectanglelabels': ['class1'], 'x': 1717.0357666015625, 'y': 630.5845947265625, 'w': 98.889404296875, 'h': 110.57818603515625}}, {'from_name': 'label', 'to_name': 'image', 'type': 'rectanglelabels', 'score': 0.29415565729141235, 'original_width': 1920, 'original_height': 1128, 'image_rotation': 0, 'value': {'rectanglelabels': ['class2'], 'x': 1717.0357666015625, 'y': 630.5845947265625, 'w': 98.889404296875, 'h': 110.57818603515625}}, {'from_name': 'label', 'to_name': 'image', 'type': 'rectanglelabels', 'score': 0.2602131962776184, 'original_width': 1920, 'original_height': 1128, 'image_rotation': 0, 'value': {'rectanglelabels': ['class2'], 'x': 1717.0357666015625, 'y': 630.5845947265625, 'w': 98.889404296875, 'h': 110.57818603515625}}, {'from_name': 'label', 'to_name': 'image', 'type': 'rectanglelabels', 'score': 0.9213833212852478, 'original_width': 1920, 'original_height': 1128, 'image_rotation': 0, 'value': {'rectanglelabels': ['class3'], 'x': 468.77606201171875, 'y': 623.5928344726562, 'w': 523.1099853515625, 'h': 899.0106201171875}}], 'score': 0.5800148248672485, 'model_version': 'v8s'}]
[2024-08-22 11:42:14,544] [INFO] [werkzeug::_log::97] 127.0.0.1 - - [22/Aug/2024 11:42:14] "POST /predict HTTP/1.1" 200 -

So no real error is present, yet no boxes appear in the gui, even though those are present in logs

prichinatryaski commented 3 months ago

Fixed, issue with 'w' and 'h', should've wrote 'width' and 'height' instead. The measurment should've been in percent too. And iteration through objects in my code is wrong.