Skip to content
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

Add normalized_instance_similarity method #1939

Merged
merged 6 commits into from
Sep 18, 2024
Merged

Conversation

gitttt-1234
Copy link
Contributor

@gitttt-1234 gitttt-1234 commented Sep 4, 2024

Description

Currently, we are facing ID switches in tracking because of very low similarity scores (~/= 0) with instance matching similarity function as it doesn't apply normalization. To address this issue, we add a new normalized_instance_similarity function which normalizes the keypoints based on the image size.

Types of changes

  • Bugfix
  • New feature
  • Refactor / Code style update (no logical changes)
  • Build / CI changes
  • Documentation Update
  • Other (explain)

Does this address any currently open issues?

#1815

Outside contributors checklist

  • Review the guidelines for contributing to this repository
  • Read and sign the CLA and add yourself to the authors list
  • Make sure you are making a pull request against the develop branch (not main). Also you should start your branch off develop
  • Add tests that prove your fix is effective or that your feature works
  • Add necessary documentation (if appropriate)

Thank you for contributing to SLEAP!

❤️

Summary by CodeRabbit

  • New Features

    • Introduced a new similarity metric, normalized_instance, for enhanced tracking and analysis.
    • Added a new similarity metric, object_keypoint, for improved instance comparison.
    • Updated command-line interface options to include normalized_instance for tracking configurations.
    • Enhanced tracking functionality by incorporating image dimensions for more accurate processing.
  • Bug Fixes

    • Improved the accuracy of instance matching by incorporating normalization in similarity assessments.
  • Tests

    • Expanded test coverage to include the new normalized_instance and object_keypoint metrics for comprehensive validation of tracking functionality.

Copy link

coderabbitai bot commented Sep 4, 2024

Walkthrough

The pull request introduces enhancements to the tracking feature by adding new similarity metrics, "normalized_instance" and "object_keypoint," across various components. These changes are reflected in the command-line interface documentation, configuration files, and implementation of new functions. The updates improve the methods available for measuring similarity, thereby refining the tracking and analysis processes.

Changes

File Change Summary
docs/guides/cli.md, docs/guides/proofreading.md Added "normalized_instance" and "object_keypoint" to similarity options and described their functionality.
sleap/config/pipeline_form.yaml Updated similarity method options to include "normalized_instance."
sleap/nn/inference.py, sleap/nn/tracking.py Introduced img_hw parameter to the track method for improved tracking accuracy.
sleap/nn/tracker/components.py Introduced normalized_instance_similarity function for normalized keypoint comparison.
tests/nn/test_inference.py, tests/nn/test_tracker_components.py, tests/nn/test_tracking_integration.py Expanded test coverage by adding "normalized_instance" and "object_keypoint" to various test functions.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI
    participant Config
    participant Tracker
    participant Test

    User->>CLI: Request tracking with normalized_instance
    CLI->>Config: Fetch similarity options
    Config->>Tracker: Set normalized_instance for tracking
    Tracker->>Tracker: Compute similarity using normalized_instance
    Tracker->>Test: Validate tracking with new similarity metric
Loading

🐰 In the meadow, hopping with glee,
A new metric joins, oh what a spree!
"Normalized_instance," a friend so bright,
Enhancing our tracking, making it right.
With options aplenty, we leap and bound,
In the world of data, joy can be found! 🌼✨

Possibly related PRs

  • Add Keep visualizations checkbox to training GUI #1824: The changes in this PR involve modifications to the command-line interface documentation for a tracking feature, specifically updating the options for the --tracking.similarity argument, which is directly related to the addition of the keep_viz option in the training GUI that also affects how visualizations are handled during training.

Suggested labels

MultiView Stack


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    -- I pushed a fix in commit <commit_id>, please review it.
    -- Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    -- @coderabbitai generate unit testing code for this file.
    -- @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    -- @coderabbitai generate interesting stats about this repository and render them as a table.
    -- @coderabbitai read src/utils.ts and generate unit testing code.
    -- @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    -- @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Tip

Early access features: enabled

We are currently testing the following features in early access:

  • OpenAI o1 for code reviews: OpenAI's new o1 model is being tested for code reviews. This model has advanced reasoning capabilities and can provide more nuanced feedback on your code.

Note:

  • You can enable or disable early access features from the CodeRabbit UI or by updating the CodeRabbit configuration file.

@gitttt-1234 gitttt-1234 changed the title Add function to normalize keypoints Expose object_keypoint method for similarity score computation Sep 5, 2024
@gitttt-1234 gitttt-1234 changed the title Expose object_keypoint method for similarity score computation Add normalized_instance_similarity method Sep 6, 2024
Copy link

codecov bot commented Sep 9, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 75.37%. Comparing base (7ed1229) to head (e1ee966).
Report is 51 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1939      +/-   ##
===========================================
+ Coverage    73.30%   75.37%   +2.06%     
===========================================
  Files          134      133       -1     
  Lines        24087    24480     +393     
===========================================
+ Hits         17658    18452     +794     
+ Misses        6429     6028     -401     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@gitttt-1234 gitttt-1234 marked this pull request as ready for review September 10, 2024 17:10
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 35463a1 and 6bc6ca8.

Files selected for processing (7)
  • docs/guides/cli.md (1 hunks)
  • docs/guides/proofreading.md (1 hunks)
  • sleap/config/pipeline_form.yaml (2 hunks)
  • sleap/nn/tracker/components.py (2 hunks)
  • sleap/nn/tracking.py (2 hunks)
  • tests/nn/test_tracker_components.py (1 hunks)
  • tests/nn/test_tracking_integration.py (1 hunks)
Additional context used
Ruff
sleap/nn/tracking.py

8-8: functools imported but unused

Remove unused import: functools

(F401)

Additional comments not posted (9)
tests/nn/test_tracking_integration.py (1)

141-141: LGTM!

The code change to include the new normalized_instance similarity method is approved. This change is consistent with the PR summary and expands the set of similarity metrics that can be tested within the main function.

docs/guides/proofreading.md (1)

53-53: LGTM!

The documentation change to include "**normalized_instance**" as a new method for measuring similarity in instances is approved. This change is consistent with the AI-generated summary and expands the existing methods of similarity measurement by providing an additional layer of normalization that could improve the accuracy of instance matching.

tests/nn/test_tracker_components.py (1)

40-40: LGTM!

The code change to include "normalized_instance" in the @pytest.mark.parametrize decorator for the similarity parameter is approved. This change expands the set of similarity metrics that can be tested within the test_tracker_by_name function, allowing for more comprehensive validation of the tracker behavior under varied conditions. The overall logic and control flow of the test function remain unchanged.

docs/guides/cli.md (1)

210-210: LGTM!

The documentation update is consistent with the new normalized_instance_similarity method introduced in the code.

sleap/config/pipeline_form.yaml (2)

442-442: LGTM!

The configuration update is consistent with the new normalized_instance_similarity method introduced in the code.


541-541: This is a duplicate of the previous configuration update. No need to comment again.

sleap/nn/tracker/components.py (2)

33-47: LGTM!

The new normalized_instance_similarity function looks good:

  • It correctly normalizes the keypoints using the maximum x and y coordinates from both instances.
  • The similarity computation using squared differences and averaging over visible reference points is a reasonable approach.
  • The function is well-documented with a clear docstring.

55-55: LGTM!

The change in the instance_similarity function improves the readability by removing unnecessary line breaks. The core logic remains unchanged.

sleap/nn/tracking.py (1)

500-501: LGTM!

The changes to the get_candidates function look good:

  • The new normalized_instance and object_keypoint parameters have been added to the function signature.
  • object_keypoint is now assigned the value of factory_object_keypoint_similarity() instead of instance_similarity, indicating an updated approach for computing object keypoint similarity.
  • The addition of normalized_instance suggests an enhancement to incorporate normalized instance similarity for improved candidate selection.

The code changes are approved.

sleap/nn/tracking.py Show resolved Hide resolved
@getzze
Copy link
Contributor

getzze commented Sep 11, 2024

I'm just seeing this PR and it seems similar in spirit to the "object keypoint" similarity (#1003) that was recently merged, but not correctly documented I'm afraid (I am the author so I am to blame!).

@talmo
Copy link
Collaborator

talmo commented Sep 12, 2024

I'm just seeing this PR and it seems similar in spirit to the "object keypoint" similarity (#1003) that was recently merged, but not correctly documented I'm afraid (I am the author so I am to blame!).

Hi @getzze,

I think part of the problem is that we thought your method was not being hooked up to the GUI at all. Here is where we map the string names of the similarity methods to the actual functions:

sleap/sleap/nn/tracking.py

Lines 494 to 499 in e4bb444

similarity_policies = dict(
instance=instance_similarity,
centroid=centroid_distance,
iou=instance_iou,
object_keypoint=instance_similarity,
)

The object_keypoint key is mapping to the same instance_similarity, though I see now upon closer inspection that it's getting special-cased here:

sleap/sleap/nn/tracking.py

Lines 886 to 893 in e4bb444

if similarity == "object_keypoint":
similarity_function = factory_object_keypoint_similarity(
keypoint_errors=oks_errors,
score_weighting=oks_score_weighting,
normalization_keypoints=oks_normalization,
)
else:
similarity_function = similarity_policies[similarity]

Docs would definitely help, but either way, I think what we're doing here is a bit different as it's basically just normalizing the keypoints by the image size rather than changing how we account for number of keypoints or confidence.

I suppose the best thing would be to have something more unified that can (optionally?) use all three factors.

For the moment, the easiest might just be to have separate methods as we'll be refactoring a lot of the tracking backend in the coming months anyway as part of our transition to PyTorch.

If you're curious or would like to weigh in on the design of the new backend, check out: talmolab/sleap-nn#53 and the current state of the implementation in this source tree.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Outside diff range and nitpick comments (5)
sleap/nn/tracking.py (2)

645-646: Ensure the new img_hw parameter is properly used and documented.

The new img_hw parameter represents the height and width of the image. Make sure it is used correctly within the track method and consider adding a docstring to document its purpose.


653-653: Update the docstring to include the new img_hw parameter.

The docstring for the track method should be updated to include a description of the new img_hw parameter.

sleap/nn/inference.py (3)

Line range hint 3911-3914: Pass img_hw to the tracker for consistency.

In the TopDownPredictor and BottomUpPredictor classes, the img_hw argument was added to the track method call to provide the image dimensions to the tracker. For consistency and to ensure the tracker has access to the same context, consider adding img_hw here as well:

predicted_instances = self.tracker.track(
    untracked_instances=predicted_instances,
    img_hw=ex["image"].shape[-2:],  # Add this line
    img=image,
    t=frame_ind,
)

Line range hint 4554-4557: Consider adding tracking functionality for consistency.

In the other predictor classes (TopDownPredictor, BottomUpPredictor, TopDownMultiClassPredictor), if self.tracker is available, the predicted instances are passed through the tracker before being added to the predicted_frames list.

For consistency, consider adding similar tracking code here:

if self.tracker:
    # Set tracks for predicted instances in this frame.
    predicted_instances = self.tracker.track(
        untracked_instances=predicted_instances,
        img_hw=ex["image"].shape[-2:],
        img=image, 
        t=frame_ind,
    )

Line range hint 4850-4853: Clarify the purpose of modifying args.models.

The code block:

if args.models is not None and "movenet" in args.models[0]:
    args.models = args.models[0]

modifies the args.models list if it contains the string "movenet" in the first element. It's unclear why this specific condition is being checked and why args.models is being reassigned to its first element.

Please provide more context on the reasoning behind this code and ensure that it aligns with the intended behavior of the main function.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 6bc6ca8 and 172e395.

Files selected for processing (7)
  • docs/guides/cli.md (1 hunks)
  • docs/guides/proofreading.md (1 hunks)
  • sleap/nn/inference.py (2 hunks)
  • sleap/nn/tracker/components.py (2 hunks)
  • sleap/nn/tracking.py (3 hunks)
  • tests/nn/test_tracker_components.py (1 hunks)
  • tests/nn/test_tracking_integration.py (1 hunks)
Files skipped from review as they are similar to previous changes (3)
  • docs/guides/cli.md
  • tests/nn/test_tracker_components.py
  • tests/nn/test_tracking_integration.py
Additional comments not posted (10)
docs/guides/proofreading.md (2)

53-53: LGTM!

The new "normalized_instance" similarity method is a valuable addition that enhances the existing "instance" method by normalizing keypoints by image size. This can make the similarity measure more robust to variations in image resolution or object scale across different datasets.

The method is clearly described and fits well with the existing set of similarity methods.


54-54: Looks good!

The new "object_keypoint" similarity method is a great addition that provides a complementary approach to the existing methods. By measuring keypoint-level distances with an exponential decay function and normalizing by the number of visible keypoints, it can effectively capture fine-grained instance similarity while being robust to partial occlusions.

The method is clearly described and adds a valuable new option for measuring instance similarity during tracking.

sleap/nn/tracker/components.py (2)

33-45: LGTM!

The normalized_instance_similarity function is a great addition to improve instance matching accuracy by normalizing keypoints based on image dimensions. The implementation is mathematically sound, well-documented, and follows good coding practices.


53-53: Refactoring looks good.

The removal of unnecessary line breaks in the distance calculation improves code readability. The core logic remains intact.

sleap/nn/tracking.py (2)

Line range hint 1-1: Skipped reviewing run_tracker function.

This function is not part of the changeset. No changes have been made that warrant a review.


660-663: Verify the partial function usage of normalized_instance_similarity.

The logic for setting the similarity_function has been modified to utilize a partial function of normalized_instance_similarity when the similarity function is set to normalized_instance_similarity.

This change indicates a more dynamic approach to similarity computation, allowing for the inclusion of image dimensions in the similarity calculations.

Ensure that this partial function is used correctly throughout the codebase and that it provides the expected behavior.

Run the following script to verify the usage of normalized_instance_similarity:

Verification successful

Partial function usage of normalized_instance_similarity is correctly implemented. The partial function factory_normalized_instance is assigned and used as expected within the sleap/nn/tracking.py file, and there are no direct calls to normalized_instance_similarity, confirming the intended design.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify usage of `normalized_instance_similarity` partial function.

# Test 1: Search for the partial function assignment. 
# Expect: Only the assignment within the `track` method.
rg --type python -A 5 $'factory_normalized_instance = functools.partial\(normalized_instance_similarity,'

# Test 2: Search for usage of the `factory_normalized_instance` variable.
# Expect: Usage only within the `track` method after assignment.
rg --type python -A 5 $'factory_normalized_instance'

# Test 3: Search for direct calls to `normalized_instance_similarity`.
# Expect: No direct calls, only usage via the partial function.
rg --type python -A 5 $'normalized_instance_similarity\('

Length of output: 310


Script:

#!/bin/bash
# Description: Verify usage of `normalized_instance_similarity` partial function.

# Test 1: Search for the partial function assignment. 
# Expect: Only the assignment within the `track` method.
rg --type py -A 5 $'factory_normalized_instance = functools.partial\(normalized_instance_similarity,'

# Test 2: Search for usage of the `factory_normalized_instance` variable.
# Expect: Usage only within the `track` method after assignment.
rg --type py -A 5 $'factory_normalized_instance'

# Test 3: Search for direct calls to `normalized_instance_similarity`.
# Expect: No direct calls, only usage via the partial function.
rg --type py -A 5 $'normalized_instance_similarity\('

Length of output: 1620

sleap/nn/inference.py (4)

2625-2628: LGTM!

Passing the image height and width to the tracker via img_hw is a good change. It provides additional context that the tracking algorithm can utilize.


3268-3271: Looks good!

As with the previous change in TopDownPredictor, passing img_hw to provide the image dimensions to the tracker is a positive addition.


Line range hint 4872-4875: LGTM!

Creating the predictor and setting its tracker based on the command-line arguments is a logical step in the main function. The code looks good as is.


Line range hint 5020-5023: Nice addition!

Supporting running the tracker on existing predictions when no models are provided is a handy feature. It allows users to perform tracking separately from inference, which can be useful in certain workflows.

The code looks good and integrates well with the existing logic in the main function.

@getzze
Copy link
Contributor

getzze commented Sep 12, 2024

Docs would definitely help, but either way, I think what we're doing here is a bit different as it's basically just normalizing the keypoints by the image size rather than changing how we account for number of keypoints or confidence.

There is that, but the key point of object_keypoint_similarity is actually to normalize the distances before taking the exponential.

# Compute distances
dists = np.sum((query_points - ref_points) ** 2, axis=1) * kp_precision
similarity = (
np.nansum(ref_scores * query_scores * np.exp(-dists)) / max_n_keypoints
)

You can specify the normalization factor for each node, but what makes more sense is to use the standard error of infering the nodes (say 5 pixels). I didn't find a way to get this error simply though, so the extra parameter (but it's also more flexible like that).

Quoting what I wrote in the original PR #1003 :

  1. Adding an scale to the distance between the reference and query keypoint. Otherwise, if the ref and query keypoints are 3 pixels apart, they contribute to 0.0001 to the similarity score, versus 0.36 if they are 1 pixel apart. This is very sensitive to single pixel fluctuations.
    Instead, the distance is divided by a user-defined pixel scale before applying the gaussian function. The scale can be chosen to be the error for each keypoint found during training of the model with the validation set. Ideally this could be retrieved automatically, it is now hidden in the metrics.val.npz file of the model.
    This is what they use in this paper.

I should have put some explanation in the docs, really sorry about that...

So I think instance_similarity, object_keypoint_similarity and normalized_instance_similarity could be unified, with options to select one or the other.

Thanks for linking to the refactoring of tracking, the roadmap looks very exciting!

sleap/nn/inference.py Show resolved Hide resolved
@gitttt-1234 gitttt-1234 merged commit 3c7f5af into develop Sep 18, 2024
19 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Sep 26, 2024
11 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants