Skip to content

⚡️ Speed up method Recall._compute_confusion_matrix by 51% #53

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

📄 51% (0.51x) speedup for Recall._compute_confusion_matrix in supervision/metrics/recall.py

⏱️ Runtime : 2.92 milliseconds 1.93 millisecond (best of 231 runs)

📝 Explanation and details

Here is the optimized version.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 18 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.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.detection.core import Detections
from supervision.metrics.core import AveragingMethod, Metric, MetricTarget
from supervision.metrics.recall import Recall

# unit tests

def test_single_class_single_threshold_perfect_match():
    sorted_matches = np.array([[True]])
    sorted_prediction_class_ids = np.array([1])
    unique_classes = np.array([1])
    class_counts = np.array([1])
    expected_output = np.array([[[1, 0, 0]]])
    np.testing.assert_array_equal(
        Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts),
        expected_output
    )

def test_single_class_single_threshold_no_match():
    sorted_matches = np.array([[False]])
    sorted_prediction_class_ids = np.array([1])
    unique_classes = np.array([1])
    class_counts = np.array([1])
    expected_output = np.array([[[0, 1, 1]]])
    np.testing.assert_array_equal(
        Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts),
        expected_output
    )

def test_multiple_classes_single_threshold_perfect_matches():
    sorted_matches = np.array([[True], [True]])
    sorted_prediction_class_ids = np.array([1, 2])
    unique_classes = np.array([1, 2])
    class_counts = np.array([1, 1])
    expected_output = np.array([[[1, 0, 0]], [[1, 0, 0]]])
    np.testing.assert_array_equal(
        Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts),
        expected_output
    )

def test_single_class_multiple_thresholds_varying_iou():
    sorted_matches = np.array([[True, False]])
    sorted_prediction_class_ids = np.array([1])
    unique_classes = np.array([1])
    class_counts = np.array([1])
    expected_output = np.array([[[1, 0, 0], [0, 1, 1]]])
    np.testing.assert_array_equal(
        Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts),
        expected_output
    )


def test_no_true_instances():
    sorted_matches = np.array([[False]])
    sorted_prediction_class_ids = np.array([1])
    unique_classes = np.array([1])
    class_counts = np.array([0])
    expected_output = np.array([[[0, 1, 0]]])
    np.testing.assert_array_equal(
        Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts),
        expected_output
    )

def test_large_number_of_predictions_and_true_instances():
    np.random.seed(0)
    sorted_matches = np.random.rand(1000, 10) > 0.5
    sorted_prediction_class_ids = np.random.randint(1, 10, 1000)
    unique_classes = np.arange(1, 11)
    class_counts = np.random.randint(1, 100, 10)
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)

def test_high_dimensional_data():
    np.random.seed(0)
    sorted_matches = np.random.rand(1000, 50) > 0.5
    sorted_prediction_class_ids = np.random.randint(1, 100, 1000)
    unique_classes = np.arange(1, 101)
    class_counts = np.random.randint(1, 100, 100)
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)

def test_consistent_results():
    np.random.seed(0)
    sorted_matches = np.random.rand(100, 10) > 0.5
    sorted_prediction_class_ids = np.random.randint(1, 10, 100)
    unique_classes = np.arange(1, 11)
    class_counts = np.random.randint(1, 20, 10)
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)
    np.testing.assert_array_equal(confusion_matrix_1, confusion_matrix_2)

def test_mixed_cases():
    np.random.seed(0)
    sorted_matches = np.random.rand(200, 15) > 0.5
    sorted_prediction_class_ids = np.random.randint(1, 20, 200)
    unique_classes = np.arange(1, 21)
    class_counts = np.random.randint(1, 30, 20)
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

from __future__ import annotations

from typing import List

import numpy as np
# imports
import pytest  # used for our unit tests
from supervision.detection.core import Detections
from supervision.metrics.core import AveragingMethod, Metric, MetricTarget
from supervision.metrics.recall import Recall

# unit tests


def test_basic_valid_input_multiple_classes():
    # Multiple classes with a mix of true positives and false positives
    sorted_matches = np.array([[True, False, True], [False, True, False]])
    sorted_prediction_class_ids = np.array([0, 1])
    unique_classes = np.array([0, 1])
    class_counts = np.array([2, 1])
    expected_output = np.array([
        [[1, 0, 1], [0, 1, 2], [1, 0, 1]],
        [[0, 1, 1], [1, 0, 0], [0, 1, 1]]
    ])
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)
    np.testing.assert_array_equal(result, expected_output)


def test_no_true_instances():
    # No true instances for any class
    sorted_matches = np.array([[False, False], [False, False]])
    sorted_prediction_class_ids = np.array([0, 1])
    unique_classes = np.array([0, 1])
    class_counts = np.array([0, 0])
    expected_output = np.array([
        [[0, 1, 0], [0, 1, 0]],
        [[0, 1, 0], [0, 1, 0]]
    ])
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)
    np.testing.assert_array_equal(result, expected_output)

def test_all_predictions_false_positives():
    # Single class where all predictions are false positives
    sorted_matches = np.array([[False, False, False]])
    sorted_prediction_class_ids = np.array([0])
    unique_classes = np.array([0])
    class_counts = np.array([3])
    expected_output = np.array([[[0, 1, 3], [0, 1, 3], [0, 1, 3]]])
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)
    np.testing.assert_array_equal(result, expected_output)


def test_mixed_predictions_single_class():
    # Single class with a mix of true positives and false positives
    sorted_matches = np.array([[True, False, True]])
    sorted_prediction_class_ids = np.array([0])
    unique_classes = np.array([0])
    class_counts = np.array([2])
    expected_output = np.array([[[1, 0, 1], [0, 1, 2], [1, 0, 1]]])
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)
    np.testing.assert_array_equal(result, expected_output)

def test_single_prediction_true_positive():
    # Single prediction that is a true positive
    sorted_matches = np.array([[True]])
    sorted_prediction_class_ids = np.array([0])
    unique_classes = np.array([0])
    class_counts = np.array([1])
    expected_output = np.array([[[1, 0, 0]]])
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)
    np.testing.assert_array_equal(result, expected_output)


def test_large_number_of_predictions():
    # Large number of predictions for a single class
    sorted_matches = np.random.rand(1000, 10) > 0.5
    sorted_prediction_class_ids = np.zeros(1000)
    unique_classes = np.array([0])
    class_counts = np.array([500])
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)

def test_high_iou_thresholds_dense_predictions():
    # High IoU thresholds with dense predictions
    sorted_matches = np.random.rand(100, 10) > 0.9
    sorted_prediction_class_ids = np.random.randint(0, 5, 100)
    unique_classes = np.array([0, 1, 2, 3, 4])
    class_counts = np.array([20, 20, 20, 20, 20])
    codeflash_output = Recall._compute_confusion_matrix(sorted_matches, sorted_prediction_class_ids, unique_classes, class_counts)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

Codeflash

@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 07:04
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