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

Detection metric release. #159

Merged
merged 116 commits into from
Oct 8, 2020
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
b2bb060
Detection metric release.
Sep 4, 2020
357e789
Documentation and function parameter changes.
benjaminrwilson Sep 8, 2020
2de0952
Cleaned up unused methods.
benjaminrwilson Sep 9, 2020
690ff3d
Fix clipping.
benjaminrwilson Sep 9, 2020
07ab68c
add some logging
seanremy Sep 10, 2020
ee9b37f
add test docstrings
seanremy Sep 10, 2020
8cbb898
doc fixes
seanremy Sep 10, 2020
8b97bcc
fix pr comments
seanremy Sep 13, 2020
c85b5a7
replace click with argparse
seanremy Sep 13, 2020
d28d01e
add missing types to function header
seanremy Sep 13, 2020
8f08b67
doc for dist_fn
seanremy Sep 13, 2020
5f532fc
Fixed a few argument issues.
Sep 14, 2020
9707b4e
Added angle normalization method.
Sep 14, 2020
83b4ef2
Temporary fix (potentially).
Sep 14, 2020
fdf1e90
Typing fixes + other enhancements.
Sep 16, 2020
8509df4
Type fixes + matplotlib fix.
Sep 17, 2020
b7abaea
Added additional shape information.
Sep 17, 2020
e8d8daa
Added additional shape info.
Sep 17, 2020
d621b3c
Fixed init variables + method signatures.
Sep 17, 2020
e16b853
Removed unused imports, corrected method signatures, added new pre-co…
Sep 17, 2020
25ef3cd
Style fixes + function renaming.
Sep 17, 2020
65e36c1
Docstring cleanup + named magic variables.
Sep 17, 2020
73fbc82
Removed truncation and cleaned up docstrings.
Sep 18, 2020
d1c4799
Return fix.
Sep 18, 2020
e5e7f39
Fixed tp metric defaults + additional constants.
Sep 18, 2020
acc703c
Corrected angle normalization, added new CDS calculation.
Sep 18, 2020
8c8d71d
Updated CDS calculation + configurable range/metric.
Sep 18, 2020
6e2d754
Fixed comments.
Sep 18, 2020
f213181
Changed variable names, cleaned up docstrings, changed default evalua…
benjaminrwilson Sep 21, 2020
d82ea5d
Ensured fix number of boxes per scene per class. Global variable upda…
Sep 21, 2020
4508687
Fixed constants to reflect actual quantity.
Sep 21, 2020
e44b806
Formatted json.
Sep 21, 2020
89dba09
Added iou function + added info to unit test docstrings.
benjaminrwilson Sep 23, 2020
52d8269
Fixed naming + missed docstring.
benjaminrwilson Sep 23, 2020
0653446
Added additional comments/clarifications.
benjaminrwilson Sep 23, 2020
6993906
Added comments, updated variable names.
Sep 23, 2020
a2863ea
Added constant comments.
Sep 23, 2020
ecb37f5
Naming fixes, docstring fixes, minor type cleanup.
Sep 23, 2020
9e39da8
Updated to be consistent with other tests.
Sep 23, 2020
632c9b7
Shape fixes, test style fixes.
Sep 23, 2020
1415d89
Docstring fix.
Sep 23, 2020
93a0df0
Fixed docstrings and renamed some variables.
Sep 24, 2020
efb1faa
Implemented function. Retrofitted and to use vectorized code.
Sep 24, 2020
97ffb87
'wrap' renamed to 'wrap_angle'.
benjaminrwilson Sep 24, 2020
db2f83f
Minor cleanup + 'as_dcm' -> 'as_matrix' -- 'as_dcm' is scheduled for …
benjaminrwilson Sep 24, 2020
a806569
Removed accidental import.
benjaminrwilson Sep 24, 2020
5078fb9
Updated docstrings in 'transform.py'
benjaminrwilson Sep 24, 2020
1d90574
Removed '@dataclass' :(.
Sep 24, 2020
67f42ec
add more thorough TP metrics tests
seanremy Sep 24, 2020
2b831db
Merge branch 'detection_metrics' of https://github.com/benjaminrwilso…
seanremy Sep 24, 2020
27cfeb5
add assignment test
seanremy Sep 24, 2020
96f8d48
fix typos
seanremy Sep 24, 2020
a62a65a
Updated docstrings.
Sep 24, 2020
66c503c
increase timeout limit for tox
Sep 25, 2020
28a5f66
helpful comment
seanremy Sep 28, 2020
96a0ed4
move ap to function
seanremy Sep 28, 2020
21187d1
move calc_ap function to detection_utils
seanremy Sep 28, 2020
05819e0
Small docstring updates.
benjaminrwilson Sep 28, 2020
9231378
Fixed tuple styling in docstrings.
benjaminrwilson Sep 28, 2020
de025a1
fix score ordering in assignment test
seanremy Sep 29, 2020
1883647
Merge branch 'detection_metrics' of https://github.com/benjaminrwilso…
seanremy Sep 29, 2020
f8fe26b
Made naming consistent + fixed printed default errors when no tp.
Sep 29, 2020
d9d0ee9
fix numerical precision check
johnwlambert Sep 30, 2020
28a35c6
re-format for black
johnwlambert Sep 30, 2020
e872471
fix return type to include Optional
johnwlambert Sep 30, 2020
95b9be5
reformat for python black
johnwlambert Sep 30, 2020
c8ff45f
fix img width, height to be integers for mypy in unit test
johnwlambert Sep 30, 2020
252aec8
reformat according to python black format
johnwlambert Sep 30, 2020
687d12b
check for None per mypy spec
johnwlambert Sep 30, 2020
995a235
Made a few detection methods functional.
benjaminrwilson Sep 30, 2020
6953336
Fixed docstring.
benjaminrwilson Sep 30, 2020
2fdb385
Removed unused imports.
benjaminrwilson Sep 30, 2020
ccf303c
Merge branch 'detection_metrics' of https://github.com/benjaminrwilso…
benjaminrwilson Sep 30, 2020
90363ff
Moved additional functions out of eval_detection.py.
benjaminrwilson Sep 30, 2020
b7b475a
Fixed plotting sorting.
benjaminrwilson Sep 30, 2020
902d3a6
Type fix.
benjaminrwilson Sep 30, 2020
7e69da1
Fixed formatting.
benjaminrwilson Sep 30, 2020
ef3b331
Fixed implement errors and flake8 issues.
benjaminrwilson Sep 30, 2020
2e6f44d
Fixed end of line issues.
benjaminrwilson Sep 30, 2020
f690224
Updated isort to align with black + tons of typing fixes.
benjaminrwilson Oct 1, 2020
aab2582
Removed legacy typing.
benjaminrwilson Oct 1, 2020
78a6e53
Fix end-of-file error.
benjaminrwilson Oct 1, 2020
84360d7
Increase travis timeout.
benjaminrwilson Oct 1, 2020
bf099e4
mypy fixes.
benjaminrwilson Oct 1, 2020
4da6b95
mypy fixes.
benjaminrwilson Oct 1, 2020
e5a50a5
mypy fixes.
benjaminrwilson Oct 1, 2020
589e897
Typing fixes.
benjaminrwilson Oct 1, 2020
2d4a490
Typing fixes.
benjaminrwilson Oct 1, 2020
befc3c5
Typing fixes.
benjaminrwilson Oct 1, 2020
538d258
More typing fixes.
benjaminrwilson Oct 1, 2020
7c7fff0
More type fixes.
benjaminrwilson Oct 1, 2020
dd99a56
More type fixes.
benjaminrwilson Oct 1, 2020
ed51c79
Update travis build.
benjaminrwilson Oct 1, 2020
d06e811
Attempt to fix environment issue.
benjaminrwilson Oct 1, 2020
3674c93
Updated pre-commit.
benjaminrwilson Oct 1, 2020
db8baa6
Updated pre-commit.
benjaminrwilson Oct 1, 2020
1e4847d
Remove mypy from pre-commit.
benjaminrwilson Oct 1, 2020
5b5b9d2
Revert back to previous pre-commit.
benjaminrwilson Oct 1, 2020
9afdf8f
Reverting travis configuration as well.
benjaminrwilson Oct 1, 2020
3609cf6
Docstring update.
benjaminrwilson Oct 1, 2020
1754a0c
Docstring update.
benjaminrwilson Oct 1, 2020
16d49ab
Add back tox timeout.
benjaminrwilson Oct 1, 2020
ad1619c
Modified isort.
benjaminrwilson Oct 1, 2020
12f2056
Another style test.
benjaminrwilson Oct 1, 2020
4673043
Black update.
benjaminrwilson Oct 1, 2020
bae3b7d
Black + isort fix.
benjaminrwilson Oct 1, 2020
96b83bd
Ensure 120 length isort.
benjaminrwilson Oct 1, 2020
64ecce3
Added units tests and stubs.
benjaminrwilson Oct 2, 2020
c778106
Added new tests + updated docstrings.
benjaminrwilson Oct 5, 2020
3bf475c
add assign and accumulate tests, plus other small fixes
seanremy Oct 5, 2020
e1adfa6
slight clarification of some unit tests
seanremy Oct 5, 2020
24d1c5d
Removed unused import.
Oct 5, 2020
7301fd1
Restructured fpaths.
Oct 7, 2020
95845ed
Small fixes.
Oct 7, 2020
de65f3e
Removed unused import.
Oct 7, 2020
f77119c
Uncommented unit test.
Oct 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion argoverse/data_loading/object_label_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def __init__(
occlusion: int,
label_class: Optional[str] = None,
track_id: Optional[str] = None,
score: float = 1.0,
) -> None:
"""Create an ObjectLabelRecord.

Expand All @@ -48,6 +49,7 @@ def __init__(
self.occlusion = occlusion
self.label_class = label_class
self.track_id = track_id
self.score = score

def as_2d_bbox(self) -> np.ndarray:
"""Construct a 2D bounding box from this label.
Expand Down Expand Up @@ -271,7 +273,11 @@ def json_label_dict_to_obj_record(label: Dict[str, Any]) -> ObjectLabelRecord:
track_id = label["track_label_uuid"]
else:
track_id = None
obj_rec = ObjectLabelRecord(quaternion, translation, length, width, height, occlusion, label_class, track_id)
if "score" in label:
score = label["score"]
else:
score = 1.0
obj_rec = ObjectLabelRecord(quaternion, translation, length, width, height, occlusion, label_class, track_id, score)
return obj_rec


Expand Down
175 changes: 175 additions & 0 deletions argoverse/evaluation/detection_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# <Copyright 2020, Argo AI, LLC. Released under the MIT license.>
"""Detection utilities for the Argoverse detection leaderboard.

Accepts detections (in Argoverse ground truth format) and ground truth labels
for computing evaluation metrics for 3d object detection. We have five different,
metrics: mAP, ATE, ASE, AOE, and DCS. A true positive for mAP is defined as the
highest confidence prediction within a specified Euclidean distance threshold
from a bird's-eye view. We prefer these metrics instead of IoU due to the
increased interpretability of the error modes in a set of detections.
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved

"""

from enum import Enum, auto
from typing import List, Tuple

import numpy as np
import pandas as pd
from scipy.spatial.distance import cdist
from scipy.spatial.transform import Rotation as R

from argoverse.utils.transform import quat_argo2scipy_vectorized


johnwlambert marked this conversation as resolved.
Show resolved Hide resolved
class SimFnType(Enum):
CENTER = auto()


class DistFnType(Enum):
TRANSLATION = auto()
SCALE = auto()
ORIENTATION = auto()


class InterpType(Enum):
ALL = auto()


class FilterMetric(Enum):
EUCLIDEAN = auto()


def filter_instances(
instances: np.ndarray,
target_class: str,
filter_metric: FilterMetric = FilterMetric.EUCLIDEAN,
max_dist: float = 50.0,
) -> np.ndarray:
"""Filter the GT annotations based on a set of conditions (e.g., distance from egovehicle).
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved

Args:
instances: The instances to be filtered.
target_class: The name of the class of interest.
filter_metric: The range metric used for filtering.
max_dist: The maximum distance for range filtering.

Returns:
The filtered annotations.
"""
instances = np.array([instance for instance in instances if instance.label_class == target_class])

if filter_metric == FilterMetric.EUCLIDEAN:
centers = np.array([dt.translation for dt in instances])
filtered_annos = np.array([])

if centers.shape[0] > 0:
dt_dists = np.linalg.norm(centers, axis=1)
filtered_annos = instances[dt_dists < max_dist]

return filtered_annos


def get_ranks(dts: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved
"""Get the rankings for the detections.
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved

Args:
dts: Detections.

Returns:
scores: The detection scores.
ranks: The ranking for the detections.
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved

"""
scores = np.array([dt.score for dt in dts])
ranks = scores.argsort()[::-1]
return np.expand_dims(scores, 1)[ranks], ranks


def interp(prec: np.ndarray, method: InterpType = InterpType.ALL) -> np.ndarray:
johnwlambert marked this conversation as resolved.
Show resolved Hide resolved
"""Interpolate the precision over all recall levels.
Copy link
Contributor

@johnwlambert johnwlambert Sep 27, 2020

Choose a reason for hiding this comment

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

it is a bit of a stretch to call this interpolation, since we are using the values at all data points, rather than interpolating at fixed recall points, e.g. 11 (PASCAL) 40 or 100 evenly spaced points of recall. (e.g. https://www.youtube.com/watch?v=yjCMEjoc_ZI)

I would mention that this function forces monotonicity of precision, from right to left.

Copy link
Contributor

@seanremy seanremy Sep 28, 2020

Choose a reason for hiding this comment

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

What's the difference between enforcing right-left monotonicity and interpolated precision/recall? I thought they were the same, like slide 27 in: https://www.cl.cam.ac.uk/teaching/1415/InfoRtrv/lecture5.pdf

Copy link
Contributor

Choose a reason for hiding this comment

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

Because if it's the difference between using all data points and using fixed recall points, doesn't that contradict the later comment about all-type interpolation?


Args:
prec: Precision at all recall levels.
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved
method: Accumulation method.

Returns:
Interpolated precision at all recall levels.
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved
"""
if method == InterpType.ALL:
prec_interp = np.maximum.accumulate(prec[::-1])[::-1]
else:
raise NotImplemented("This interpolation method is not implemented!")
return prec_interp


def compute_match_matrix(dts: np.ndarray, gts: np.ndarray, metric: SimFnType) -> np.ndarray:
"""Calculate the match matrix between detections and ground truth labels,
using a specified similarity function.

Args:
dts: Detections.
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved
gts: Ground truth labels.
metric: Similarity metric type.

Returns:
Interpolated precision at all recall levels.
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved
"""
if metric == SimFnType.CENTER:
dt_centers = np.array([dt.translation for dt in dts])
gt_centers = np.array([gt.translation for gt in gts])
sims = -cdist(dt_centers, gt_centers)
else:
raise NotImplemented("This similarity metric is not implemented!")
return sims


def dist_fn(dts: pd.DataFrame, gts: pd.DataFrame, metric: DistFnType) -> np.ndarray:
"""Distance functions between detections and ground truth.

Args:
dts: Detections.
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved
gts: Ground truth labels.
metric: Distance function type.

Returns:
Distance between the detections and ground truth, using the provided metric.
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved
"""
if metric == DistFnType.TRANSLATION:
dt_centers = np.vstack(dts["translation"].array)
gt_centers = np.vstack(gts["translation"].array)
trans_errors = np.linalg.norm(dt_centers - gt_centers, axis=1)
return trans_errors
elif metric == DistFnType.SCALE:
dt_dims = dts[["width", "length", "height"]]
gt_dims = gts[["width", "length", "height"]]
inter = np.minimum(dt_dims, gt_dims).prod(axis=1)
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved
union = np.maximum(dt_dims, gt_dims).prod(axis=1)
scale_errors = 1 - (inter / union)
return scale_errors
elif metric == DistFnType.ORIENTATION:
# re-order quaternions to go from Argoverse format to scipy format, then the third euler angle (z) is yaw
dt_quats = np.vstack(dts["quaternion"].array)
dt_yaws = R.from_quat(quat_argo2scipy_vectorized(dt_quats)).as_euler("xyz")[:, 2]

gt_quats = np.vstack(gts["quaternion"].array)
gt_yaws = R.from_quat(quat_argo2scipy_vectorized(gt_quats)).as_euler("xyz")[:, 2]

signed_orientation_errors = normalize_angle(dt_yaws - gt_yaws)
orientation_errors = np.abs(signed_orientation_errors)
return orientation_errors
else:
raise NotImplemented("This distance metric is not implemented!")


def normalize_angle(angle: float) -> float:
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved
"""Map angle (in radians) to [0, 2π).

Args:
johnwlambert marked this conversation as resolved.
Show resolved Hide resolved
angle: Angle (in radians).
benjaminrwilson marked this conversation as resolved.
Show resolved Hide resolved

Returns:
The angle (in radians) mapped to the interval [0, 2π).
"""
period = 2 * np.pi
phase_shift = np.pi
return (angle + np.pi) % period - phase_shift
johnwlambert marked this conversation as resolved.
Show resolved Hide resolved
Loading