Skip to content

⚡️ Speed up function process_transformers_detection_result by 223% #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from

Conversation

codeflash-ai[bot]
Copy link

@codeflash-ai codeflash-ai bot commented Feb 3, 2025

📄 223% (2.23x) speedup for process_transformers_detection_result in supervision/detection/tools/transformers.py

⏱️ Runtime : 2.12 milliseconds 656 microseconds (best of 171 runs)

📝 Explanation and details

o3-mini
I made several improvements to reduce overhead by minimizing repeated tensor operations and by vectorizing the conversion of class IDs to class names. In particular, the .cpu().detach().numpy() operations are now only done once per key, and when id2label is provided the mapping is performed via a preconstructed lookup array rather than a Python list‐comprehension, which can be appreciably faster when there are many detections.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 19 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 88.9%
🌀 Generated Regression Tests Details
from typing import Any, Dict, Optional

import numpy as np
# imports
import pytest  # used for our unit tests
# function to test
from supervision.config import CLASS_NAME_DATA_FIELD
from supervision.detection.tools.transformers import \
    process_transformers_detection_result

# unit tests

# Helper function to create dummy detection results
def create_dummy_detection_result(labels, boxes, scores):
    class DummyTensor:
        def __init__(self, data):
            self.data = data

        def cpu(self):
            return self

        def detach(self):
            return self

        def numpy(self):
            return np.array(self.data)

    return {
        "labels": DummyTensor(labels),
        "boxes": DummyTensor(boxes),
        "scores": DummyTensor(scores)
    }

# Basic Functionality
def test_basic_functionality():
    detection_result = create_dummy_detection_result([1, 2], [[0, 0, 1, 1], [1, 1, 2, 2]], [0.9, 0.8])
    id2label = {1: "cat", 2: "dog"}
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

# Edge Cases
def test_empty_detection_result():
    detection_result = create_dummy_detection_result([], [], [])
    id2label = {1: "cat", 2: "dog"}
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

def test_single_detection():
    detection_result = create_dummy_detection_result([1], [[0, 0, 1, 1]], [0.9])
    id2label = {1: "cat"}
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

def test_no_class_labels_provided():
    detection_result = create_dummy_detection_result([1, 2], [[0, 0, 1, 1], [1, 1, 2, 2]], [0.9, 0.8])
    codeflash_output = process_transformers_detection_result(detection_result, None)

# Invalid Inputs
def test_invalid_data_types():
    detection_result = {"labels": [1, 2], "boxes": [[0, 0, 1, 1], [1, 1, 2, 2]], "scores": [0.9, 0.8]}
    id2label = {1: "cat", 2: "dog"}
    with pytest.raises(AttributeError):
        process_transformers_detection_result(detection_result, id2label)



def test_large_number_of_detections():
    labels = list(range(1000))
    boxes = [[i, i, i+1, i+1] for i in range(1000)]
    scores = [0.9] * 10000
    id2label = {i: f"label_{i}" for i in range(1000)}
    detection_result = create_dummy_detection_result(labels, boxes, scores)
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

# Special Cases
def test_negative_class_ids():
    detection_result = create_dummy_detection_result([-1, -2], [[0, 0, 1, 1], [1, 1, 2, 2]], [0.9, 0.8])
    id2label = {-1: "unknown", -2: "unknown"}
    codeflash_output = process_transformers_detection_result(detection_result, id2label)


def test_class_ids_at_maximum_integer_value():
    detection_result = create_dummy_detection_result([2147483647], [[0, 0, 1, 1]], [0.9])
    id2label = {2147483647: "max_int"}
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

def test_class_ids_at_minimum_integer_value():
    detection_result = create_dummy_detection_result([-2147483648], [[0, 0, 1, 1]], [0.9])
    id2label = {-2147483648: "min_int"}
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

# Real-world Scenarios

def test_high_confidence_scores():
    detection_result = create_dummy_detection_result([1, 2], [[0, 0, 1, 1], [1, 1, 2, 2]], [0.999, 0.998])
    id2label = {1: "cat", 2: "dog"}
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

def test_low_confidence_scores():
    detection_result = create_dummy_detection_result([1, 2], [[0, 0, 1, 1], [1, 1, 2, 2]], [0.001, 0.002])
    id2label = {1: "cat", 2: "dog"}
    codeflash_output = process_transformers_detection_result(detection_result, id2label)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

from typing import Any, Dict, Optional

import numpy as np
# imports
import pytest  # used for our unit tests
# function to test
from supervision.config import CLASS_NAME_DATA_FIELD
from supervision.detection.tools.transformers import \
    process_transformers_detection_result

# unit tests

# Test cases for basic functionality
def test_basic_functionality_with_id2label():
    # Example detection result
    detection_result = {
        "boxes": np.array([[10, 20, 30, 40], [50, 60, 70, 80]]),
        "labels": np.array([1, 2]),
        "scores": np.array([0.9, 0.8])
    }
    id2label = {1: "cat", 2: "dog"}
    
    # Mocking the .cpu().detach().numpy() method chain
    for key in detection_result:
        detection_result[key] = MockTensor(detection_result[key])
    
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

def test_basic_functionality_without_id2label():
    # Example detection result
    detection_result = {
        "boxes": np.array([[10, 20, 30, 40], [50, 60, 70, 80]]),
        "labels": np.array([1, 2]),
        "scores": np.array([0.9, 0.8])
    }
    id2label = None
    
    # Mocking the .cpu().detach().numpy() method chain
    for key in detection_result:
        detection_result[key] = MockTensor(detection_result[key])
    
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

# Test cases for edge cases
def test_empty_detection_results():
    detection_result = {
        "boxes": np.array([]),
        "labels": np.array([]),
        "scores": np.array([])
    }
    id2label = {1: "cat", 2: "dog"}
    
    # Mocking the .cpu().detach().numpy() method chain
    for key in detection_result:
        detection_result[key] = MockTensor(detection_result[key])
    
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

def test_single_detection_result():
    detection_result = {
        "boxes": np.array([[10, 20, 30, 40]]),
        "labels": np.array([1]),
        "scores": np.array([0.9])
    }
    id2label = {1: "cat"}
    
    # Mocking the .cpu().detach().numpy() method chain
    for key in detection_result:
        detection_result[key] = MockTensor(detection_result[key])
    
    codeflash_output = process_transformers_detection_result(detection_result, id2label)


def test_missing_keys_in_detection_results():
    detection_result = {
        "boxes": np.array([[10, 20, 30, 40]]),
        "labels": np.array([1])
        # Missing 'scores'
    }
    id2label = {1: "cat"}
    
    # Mocking the .cpu().detach().numpy() method chain
    detection_result["boxes"] = MockTensor(detection_result["boxes"])
    detection_result["labels"] = MockTensor(detection_result["labels"])
    
    with pytest.raises(KeyError):
        process_transformers_detection_result(detection_result, id2label)


def test_large_number_of_detections():
    detection_result = {
        "boxes": np.random.rand(10000, 4) * 100,
        "labels": np.random.randint(1, 100, size=10000),
        "scores": np.random.rand(10000)
    }
    id2label = {i: f"label_{i}" for i in range(1, 100)}
    
    # Mocking the .cpu().detach().numpy() method chain
    for key in detection_result:
        detection_result[key] = MockTensor(detection_result[key])
    
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

# Test cases for special characters in class labels
def test_special_characters_in_class_labels():
    detection_result = {
        "boxes": np.array([[10, 20, 30, 40]]),
        "labels": np.array([1]),
        "scores": np.array([0.9])
    }
    id2label = {1: "cat & dog"}
    
    # Mocking the .cpu().detach().numpy() method chain
    for key in detection_result:
        detection_result[key] = MockTensor(detection_result[key])
    
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

# Test cases for performance and scalability
def test_high_dimensional_bounding_boxes():
    detection_result = {
        "boxes": np.random.rand(100, 6) * 100,  # Assuming 3D bounding boxes
        "labels": np.random.randint(1, 10, size=100),
        "scores": np.random.rand(100)
    }
    id2label = {i: f"label_{i}" for i in range(1, 10)}
    
    # Mocking the .cpu().detach().numpy() method chain
    for key in detection_result:
        detection_result[key] = MockTensor(detection_result[key])
    
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

# Test cases for deterministic outputs
def test_deterministic_outputs():
    detection_result = {
        "boxes": np.array([[10, 20, 30, 40], [50, 60, 70, 80]]),
        "labels": np.array([1, 2]),
        "scores": np.array([0.9, 0.8])
    }
    id2label = {1: "cat", 2: "dog"}
    
    # Mocking the .cpu().detach().numpy() method chain
    for key in detection_result:
        detection_result[key] = MockTensor(detection_result[key])
    
    codeflash_output = process_transformers_detection_result(detection_result, id2label)
    codeflash_output = process_transformers_detection_result(detection_result, id2label)

# Mock class to simulate the .cpu().detach().numpy() method chain
class MockTensor:
    def __init__(self, array):
        self.array = array
    
    def cpu(self):
        return self
    
    def detach(self):
        return self
    
    def numpy(self):
        return self.array
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

Codeflash

o3-mini
I made several improvements to reduce overhead by minimizing repeated tensor operations and by vectorizing the conversion of class IDs to class names. In particular, the .cpu().detach().numpy() operations are now only done once per key, and when id2label is provided the mapping is performed via a preconstructed lookup array rather than a Python list‐comprehension, which can be appreciably faster when there are many detections.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Feb 3, 2025
@codeflash-ai codeflash-ai bot requested a review from misrasaurabh1 February 3, 2025 05:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚡️ codeflash Optimization PR opened by Codeflash AI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

0 participants