-
Notifications
You must be signed in to change notification settings - Fork 67
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
Distance based AP metric #1946
Distance based AP metric #1946
Conversation
One idea is to use GIoU as a proxy for whether any object overlaps the patch: https://giou.stanford.edu. It extends IoU to take into account the case when boxes do not overlap. |
Trying it out with GIoU. GIoU ranges from -1 to 1 where anything greater than 0 indicates some overlap with the patch. However, it is also possible for overlapping boxes to have negative GIoU, especially if the box and patch have very different sizes. Consider an example of a pedestrian box of area 10 totally inside a patch of area 100. This makes it hard to interpret exactly which boxes are included if I report an mAP value for boxes at a given GIoU. To further complicate things, the patch is not expected to be square due to foreshortening, so I have used the smallest box enclosing the patch instead. Thus, a positive GIoU does not necessarily imply patch overlap but it will be close. These are potential downsides of this approach. Any thoughts @deprit @dxoigmn @jprokos26 ? The output is now as follows:
It would of course be possible to threshold above 0 as well, but my impression was that we wanted to consider all "overlapping" objects together. Thresholding above 0 might tend to sort by box size -- larger overlapping boxes would better match the patch and so have higher GIoU. |
I tried constructing this scenario using torchvision's >>> import torch
>>> from torchvision.ops import generalized_box_iou_loss
>>> 1 - generalized_box_iou_loss(torch.tensor([0, 0, 5, 2]), torch.tensor([0, 0, 10, 10]))
tensor(0.1000) Note that |
Good catch, thank you. In fact, if the box is completely within the patch, then |
@swsuggs Would it be too cumbersome to handle non-square patches? We'd need to compute the following:
|
armory/metrics/task.py
Outdated
"boxes": y["boxes"][y_d > threshold], | ||
"labels": y["labels"][y_d > threshold], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would also be nice to produce metrics for y_d < threshold
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think output like this is sufficiently clear and useful? Note the latter subdict does not include -0.9 because there were no boxes that distant.
adversarial_AP_per_class_by_giou_from_patch on benign examples w.r.t. ground truth labels: {
'cumulative_by_min_giou': {
0.0: {'mean': 0.005, 'class': {1: 0.0, 2: 0.01}},
-0.1: {'mean': 0.065, 'class': {1: 0.05, 2: 0.08}},
-0.2: {'mean': 0.15000000000000002, 'class': {1: 0.07, 2: 0.23}},
-0.30000000000000004: {'mean': 0.185, 'class': {1: 0.13, 2: 0.24}},
-0.4: {'mean': 0.2, 'class': {1: 0.15, 2: 0.25}},
-0.5: {'mean': 0.265, 'class': {1: 0.2, 2: 0.33}},
-0.6000000000000001: {'mean': 0.285, 'class': {1: 0.22, 2: 0.35}},
-0.7000000000000001: {'mean': 0.305, 'class': {1: 0.25, 2: 0.36}},
-0.8: {'mean': 0.315, 'class': {1: 0.27, 2: 0.36}},
-0.9: {'mean': 0.355, 'class': {1: 0.29, 2: 0.42}},
-1.0: {'mean': 0.355, 'class': {1: 0.29, 2: 0.42}}
},
'cumulative_by_max_giou': {
0.0: {'mean': 0.505, 'class': {1: 0.4, 2: 0.61}},
-0.1: {'mean': 0.63, 'class': {1: 0.58, 2: 0.68}},
-0.2: {'mean': 0.645, 'class': {1: 0.6, 2: 0.69}},
-0.30000000000000004: {'mean': 0.6799999999999999, 'class': {1: 0.65, 2: 0.71}},
-0.4: {'mean': 0.655, 'class': {1: 0.6, 2: 0.71}},
-0.5: {'mean': 0.6399999999999999, 'class': {1: 0.59, 2: 0.69}},
-0.6000000000000001: {'mean': 0.675, 'class': {1: 0.67, 2: 0.68}},
-0.7000000000000001: {'mean': 0.675, 'class': {1: 0.65, 2: 0.7}},
-0.8: {'mean': 0.755, 'class': {1: 0.79, 2: 0.72}}
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think this makes sense. I do wonder, however, if a histogram of GIoUs might be more intuitive to interpret. The cocoapi does this, for example, with APs computed at different groundtruth object mask areas (see "AP Across Scales" https://cocodataset.org/#detection-eval):
In COCO, there are more small objects than large objects. Specifically: approximately 41% of objects are small (area < 322), 34% are medium (322 < area < 962), and 24% are large (area > 962). Area is measured as the number of pixels in the segmentation mask.
…istance-based-carla-metric
I'm getting an error when running the
Config used
{
"_description": "CARLA single modality object detection, contributed by MITRE Corporation",
"adhoc": null,
"attack": {
"knowledge": "white",
"kwargs": {
"batch_size": 1,
"learning_rate": 0.003,
"max_iter": 1000,
"optimizer": "pgd",
"targeted": false,
"verbose": true
},
"module": "armory.art_experimental.attacks.carla_obj_det_adversarial_patch",
"name": "CARLAAdversarialPatchPyTorch",
"use_label": true
},
"dataset": {
"batch_size": 1,
"eval_split": "test",
"framework": "numpy",
"modality": "rgb",
"module": "armory.data.adversarial_datasets",
"name": "carla_over_obj_det_test"
},
"defense": null,
"metric": {
"means": true,
"perturbation": "l0",
"record_metric_per_sample": false,
"task": [
"carla_od_AP_per_class",
"carla_od_disappearance_rate",
"carla_od_hallucinations_per_image",
"carla_od_misclassification_rate",
"carla_od_true_positive_rate",
"object_detection_AP_per_class_by_giou_from_patch",
"object_detection_mAP_tide"
]
},
"model": {
"fit": false,
"fit_kwargs": {},
"model_kwargs": {
"max_size": 1280,
"min_size": 960,
"num_classes": 3
},
"module": "armory.baseline_models.pytorch.carla_single_modality_object_detection_frcnn",
"name": "get_art_model",
"weights_file": "carla_rgb_weights_eval7and8.pt",
"wrapper_kwargs": {}
},
"scenario": {
"export_batches": true,
"kwargs": {},
"module": "armory.scenarios.carla_object_detection",
"name": "CarlaObjectDetectionTask"
},
"sysconfig": {
"docker_image": "twosixarmory/armory",
"external_github_repo": null,
"gpus": "all",
"output_dir": null,
"output_filename": null,
"use_gpu": false
}
}
|
@jprokos26 The automatic loading of metrics from the config does assume a certain argument set of y, y_pred, y_pred_adv. There's really no good way that I could see to list arbitrary metrics in the config and have the MetricsLogger pass the correct arguments. Since this metric also requires y_patch_metadata, I manually add the metric in the carla_object_detection scenario as you can see in the diff associated with this PR. Hence, there is no need to modify the config; it will use the metric automatically. |
@swsuggs Understood, yes I see that behavior on my end; thank you for the clarification |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After suggested changes getting the following using python3 -m armory utils plot-mAP-by-giou /home/jonathan.prokos/.armory/outputs/2023-08-07T182041.696236/CarlaObjectDetectionTask_1691432448.json --output ~/tmp.png
. Note x11 forwarding works as well.
Should default size be changed to prevent overlapping titles?
Co-authored-by: Jonathan Prokos <107635150+jprokos26@users.noreply.github.com>
Co-authored-by: Jonathan Prokos <107635150+jprokos26@users.noreply.github.com>
Co-authored-by: Jonathan Prokos <107635150+jprokos26@users.noreply.github.com>
I didn't set a default size since I envisioned mainly using show=True, i.e. not saving plots sight unseen. I suppose it would still be nice though. Would you care to add some default sizes based on the number of rows and columns? |
@jprokos26 Ultimately the fig size isn't the root of the display issues. I took a whack at automating it based on number of columns and rows, but there continue to be elements that are too close together or too far apart. These could certainly be fixed as well, but I'd rather not hold up evals for it. We can address it later if needed. |
For #1945.
I decided to take the simple approach of measuring distance in pixels from the center of the patch to the center of the objects.
This means it does not regard patch or object size. E.g. an object 200 pixels away from the patch center may or may not be overlapping with the patch. So there is no distinction between objects overlapping the patch and objects not overlapping the patch. It would be easy enough to normalize the distance by the size of the patch, but this would still be a little ambiguous if, say, the patch was a rectangle. I'm open to thoughts on this.
Output is of the following format, where the dictionary key is the distance in pixels: