Skip to content

⚡️ Speed up method MeanAveragePrecision._detections_content by 14% #46

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

📄 14% (0.14x) speedup for MeanAveragePrecision._detections_content in supervision/metrics/mean_average_precision.py

⏱️ Runtime : 9.19 microseconds 8.07 microseconds (best of 83 runs)

📝 Explanation and details

o3-mini
We can speed things up a little by “caching” attribute lookups in a local variable and using np.asarray (which avoids unnecessary copies if the input is already an ndarray) in the oriented bounding boxes branch. These micro‐optimizations avoid repeating attribute lookups and slightly cut down on the overhead while keeping the exact same output.

Below is the optimized code:


Explanation of changes made:

  1. Cached self._metric_target into a local variable (mt) in both functions to avoid repeated attribute lookups.
  2. In the oriented bounding boxes branch, replaced np.array with np.asarray so that if obb is already an array, no unnecessary copy is made.
  3. Combined some conditions with elif to make the code a bit more streamlined.
    The function returns remain exactly the same.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 12 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 50.0%
🌀 Generated Regression Tests Details
from __future__ import annotations

from typing import List

import numpy as np
# imports
import pytest  # used for our unit tests
from supervision.config import ORIENTED_BOX_COORDINATES
from supervision.detection.core import Detections
from supervision.metrics.core import Metric, MetricTarget
from supervision.metrics.mean_average_precision import MeanAveragePrecision

# unit tests

def test_boxes_with_valid_data():
    # Test with valid bounding box data
    detections = Detections(xyxy=np.array([[0, 0, 10, 10], [10, 10, 20, 20]]))
    metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES)
    codeflash_output = metric._detections_content(detections)

def test_boxes_with_empty_data():
    # Test with empty bounding box data
    detections = Detections(xyxy=np.empty((0, 4)))
    metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES)
    codeflash_output = metric._detections_content(detections)








def test_class_agnostic_flag():
    # Test that the class_agnostic flag does not affect the output
    detections = Detections(xyxy=np.array([[0, 0, 10, 10], [10, 10, 20, 20]]))
    metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES, class_agnostic=True)
    codeflash_output = metric._detections_content(detections)
    metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES, class_agnostic=False)
    codeflash_output = metric._detections_content(detections)

def test_large_number_of_boxes():
    # Test with a large number of bounding boxes
    large_number_of_boxes = np.random.rand(1000, 4).astype(np.float32)
    detections = Detections(xyxy=large_number_of_boxes)
    metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES)
    codeflash_output = metric._detections_content(detections)




from __future__ import annotations

from typing import List

import numpy as np
# imports
import pytest  # used for our unit tests
from supervision.config import ORIENTED_BOX_COORDINATES
from supervision.detection.core import Detections
from supervision.metrics.core import Metric, MetricTarget
from supervision.metrics.mean_average_precision import MeanAveragePrecision

# unit tests

def test_boxes_valid_detections():
    # Test valid BOXES target with valid detections
    detections = Detections(xyxy=np.array([[0, 0, 10, 10], [10, 10, 20, 20]], dtype=np.float32))
    metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES)
    codeflash_output = metric._detections_content(detections)



def test_boxes_empty_detections():
    # Test BOXES target with empty detections
    detections = Detections(xyxy=np.empty((0, 4), dtype=np.float32))
    metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES)
    codeflash_output = metric._detections_content(detections)







def test_large_number_of_boxes():
    # Test large number of bounding boxes
    detections = Detections(xyxy=np.random.rand(10000, 4).astype(np.float32))
    metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES)
    codeflash_output = metric._detections_content(detections)



def test_single_bounding_box():
    # Test single bounding box
    detections = Detections(xyxy=np.array([[0, 0, 10, 10]], dtype=np.float32))
    metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES)
    codeflash_output = metric._detections_content(detections)



def test_boxes_non_float_data():
    # Test BOXES target with non-float data
    detections = Detections(xyxy=np.array([[0, 0, 10, 10], [10, 10, 20, 20]], dtype=int))
    metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES)
    codeflash_output = metric._detections_content(detections)



def test_performance_and_scalability():
    # Test performance and scalability with maximum possible data
    detections = Detections(xyxy=np.random.rand(1000000, 4).astype(np.float32))
    metric = MeanAveragePrecision(metric_target=MetricTarget.BOXES)
    codeflash_output = metric._detections_content(detections)
# 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
We can speed things up a little by “caching” attribute lookups in a local variable and using np.asarray (which avoids unnecessary copies if the input is already an ndarray) in the oriented bounding boxes branch. These micro‐optimizations avoid repeating attribute lookups and slightly cut down on the overhead while keeping the exact same output. 

Below is the optimized code:

------------------------------------------------
Explanation of changes made:
1. Cached self._metric_target into a local variable (mt) in both functions to avoid repeated attribute lookups.
2. In the oriented bounding boxes branch, replaced np.array with np.asarray so that if obb is already an array, no unnecessary copy is made.
3. Combined some conditions with elif to make the code a bit more streamlined.
The function returns remain exactly the same.
@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 04:15
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