lightly-studio 0.3.2__py3-none-any.whl → 0.3.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of lightly-studio might be problematic. Click here for more details.
- lightly_studio/__init__.py +1 -1
- lightly_studio/api/app.py +8 -4
- lightly_studio/api/db_tables.py +0 -3
- lightly_studio/api/routes/api/annotation.py +26 -0
- lightly_studio/api/routes/api/annotations/__init__.py +7 -0
- lightly_studio/api/routes/api/annotations/create_annotation.py +52 -0
- lightly_studio/api/routes/api/caption.py +30 -0
- lightly_studio/api/routes/api/dataset.py +3 -5
- lightly_studio/api/routes/api/embeddings2d.py +136 -0
- lightly_studio/api/routes/api/export.py +73 -0
- lightly_studio/api/routes/api/metadata.py +57 -1
- lightly_studio/api/routes/api/selection.py +87 -0
- lightly_studio/core/add_samples.py +138 -9
- lightly_studio/core/dataset.py +174 -63
- lightly_studio/core/dataset_query/dataset_query.py +5 -0
- lightly_studio/dataset/env.py +4 -0
- lightly_studio/dataset/file_utils.py +13 -2
- lightly_studio/dataset/loader.py +2 -62
- lightly_studio/dataset/mobileclip_embedding_generator.py +3 -2
- lightly_studio/db_manager.py +10 -4
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.B3oFNb6O.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/2.CkOblLn7.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/Samples.CIbricz7.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.7Ma7YdVg.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/{useFeatureFlags.CV-KWLNP.css → _layout.CefECEWA.css} +1 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/transform.2jKMtOWG.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/-DXuGN29.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{Ccq4ZD0B.js → B7302SU7.js} +1 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BeWf8-vJ.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Bqz7dyEC.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C1FmrZbK.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{DRZO-E-T.js → CSCQddQS.js} +1 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CZGpyrcA.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CfQ4mGwl.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CiaNZCBa.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cqo0Vpvt.js +417 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cy4fgWTG.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D5w4xp5l.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DD63uD-T.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DQ8aZ1o-.js +3 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{Df3aMO5B.js → DSxvnAMh.js} +1 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D_JuJOO3.js +20 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D_ynJAfY.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Dafy4oEQ.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{BqBqV92V.js → Dj4O-5se.js} +1 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DmjAI-UV.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Dug7Bq1S.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Dv5BSBQG.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DzBTnFhV.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DzX_yyqb.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Frwd2CjB.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/H4l0JFh9.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/H60ATh8g.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/qIv1kPyv.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/sLqs1uaK.js +20 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/u-it74zV.js +96 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.BPc0HQPq.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.SNvc2nrm.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.5jT7P06o.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/1.Cdy-7S5q.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.C_uoESTX.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.DcO8wIAc.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/2.BIldfkxL.js +1012 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{3.w9g4AcAx.js → 3.BC9z_TWM.js} +1 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{4.BBI8KwnD.js → 4.D8X_Ch5n.js} +1 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.CAXhxJu6.js +39 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{6.CrbkRPam.js → 6.DRA5Ru_2.js} +1 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.WVBsruHQ.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.BuKUrCEN.js +20 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/9.CUIn1yCR.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/clustering.worker-DKqeLtG0.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/search.worker-vNSty3B0.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/version.json +1 -1
- lightly_studio/dist_lightly_studio_view_app/index.html +15 -14
- lightly_studio/examples/example.py +4 -0
- lightly_studio/examples/example_coco.py +4 -0
- lightly_studio/examples/example_coco_caption.py +24 -0
- lightly_studio/examples/example_metadata.py +4 -1
- lightly_studio/examples/example_selection.py +4 -0
- lightly_studio/examples/example_split_work.py +4 -0
- lightly_studio/examples/example_yolo.py +4 -0
- lightly_studio/export/export_dataset.py +73 -0
- lightly_studio/export/lightly_studio_label_input.py +120 -0
- lightly_studio/few_shot_classifier/classifier_manager.py +5 -26
- lightly_studio/metadata/compute_typicality.py +67 -0
- lightly_studio/models/annotation/annotation_base.py +11 -12
- lightly_studio/models/caption.py +73 -0
- lightly_studio/models/dataset.py +1 -2
- lightly_studio/models/metadata.py +1 -1
- lightly_studio/models/sample.py +2 -2
- lightly_studio/resolvers/annotation_label_resolver/__init__.py +2 -1
- lightly_studio/resolvers/annotation_label_resolver/get_all.py +15 -0
- lightly_studio/resolvers/annotation_resolver/__init__.py +2 -3
- lightly_studio/resolvers/annotation_resolver/create_many.py +3 -3
- lightly_studio/resolvers/annotation_resolver/delete_annotation.py +1 -1
- lightly_studio/resolvers/annotation_resolver/delete_annotations.py +7 -3
- lightly_studio/resolvers/annotation_resolver/get_by_id.py +19 -1
- lightly_studio/resolvers/annotation_resolver/update_annotation_label.py +0 -1
- lightly_studio/resolvers/annotations/annotations_filter.py +1 -11
- lightly_studio/resolvers/caption_resolver.py +80 -0
- lightly_studio/resolvers/dataset_resolver.py +4 -7
- lightly_studio/resolvers/metadata_resolver/__init__.py +2 -2
- lightly_studio/resolvers/metadata_resolver/sample/__init__.py +3 -3
- lightly_studio/resolvers/metadata_resolver/sample/bulk_update_metadata.py +46 -0
- lightly_studio/resolvers/samples_filter.py +18 -10
- lightly_studio/selection/mundig.py +7 -10
- lightly_studio/selection/selection_config.py +4 -1
- lightly_studio/services/annotations_service/__init__.py +8 -0
- lightly_studio/services/annotations_service/create_annotation.py +63 -0
- lightly_studio/services/annotations_service/delete_annotation.py +22 -0
- lightly_studio/type_definitions.py +2 -0
- {lightly_studio-0.3.2.dist-info → lightly_studio-0.3.4.dist-info}/METADATA +231 -41
- {lightly_studio-0.3.2.dist-info → lightly_studio-0.3.4.dist-info}/RECORD +114 -104
- lightly_studio/api/routes/api/annotation_task.py +0 -37
- lightly_studio/api/routes/api/metrics.py +0 -76
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.DenzbfeK.css +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/SelectableSvgGroup.BBm0IWdq.css +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/SelectableSvgGroup.BNTuXSAe.css +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.T-zjSUd3.css +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/2O287xak.js +0 -3
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/7YNGEs1C.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BBoGk9hq.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BRnH9v23.js +0 -92
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Bg1Y5eUZ.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C0JiMuYn.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C98Hk3r5.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CG0dMCJi.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cpy-nab_.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Crk-jcvV.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cs31G8Qn.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CsKrY2zA.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cur71c3O.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CzgC3GFB.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D8GZDMNN.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DFRh-Spp.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DcGCxgpH.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DkR_EZ_B.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DqUGznj_.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/H7C68rOM.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/KpAtIldw.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/M1Q1F7bw.js +0 -4
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/OH7-C_mc.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/gLNdjSzu.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/i0ZZ4z06.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.BI-EA5gL.js +0 -2
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.CcsRl3cZ.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.BbO4Zc3r.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/1._I9GR805.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.J2RBFrSr.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.Cmqj25a-.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/2.C45iKJHA.js +0 -6
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.huHuxdiF.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.FomEdhD6.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.Cb_ADSLk.js +0 -1
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/9.CajIG5ce.js +0 -1
- lightly_studio/metrics/__init__.py +0 -0
- lightly_studio/metrics/detection/__init__.py +0 -0
- lightly_studio/metrics/detection/map.py +0 -268
- lightly_studio/models/annotation_task.py +0 -28
- lightly_studio/resolvers/annotation_resolver/create.py +0 -19
- lightly_studio/resolvers/annotation_task_resolver.py +0 -31
- lightly_studio/resolvers/metadata_resolver/sample/bulk_set_metadata.py +0 -48
- {lightly_studio-0.3.2.dist-info → lightly_studio-0.3.4.dist-info}/WHEEL +0 -0
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
"""Implementation for calculating Mean Average Precision (MAP)."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import math
|
|
6
|
-
from collections import defaultdict
|
|
7
|
-
from collections.abc import Sequence
|
|
8
|
-
from uuid import UUID
|
|
9
|
-
|
|
10
|
-
import torch
|
|
11
|
-
from pydantic import BaseModel
|
|
12
|
-
from torch import Tensor
|
|
13
|
-
from torchmetrics.detection.mean_ap import MeanAveragePrecision
|
|
14
|
-
|
|
15
|
-
from lightly_studio.models.annotation.annotation_base import AnnotationBaseTable
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class DetectionMetricsMAP(BaseModel):
|
|
19
|
-
"""Response for computing the MAP detection metric."""
|
|
20
|
-
|
|
21
|
-
name: str
|
|
22
|
-
map: float
|
|
23
|
-
map_small: float
|
|
24
|
-
map_medium: float
|
|
25
|
-
map_large: float
|
|
26
|
-
mar_1: float
|
|
27
|
-
mar_10: float
|
|
28
|
-
mar_100: float
|
|
29
|
-
mar_small: float
|
|
30
|
-
mar_medium: float
|
|
31
|
-
mar_large: float
|
|
32
|
-
map_50: float
|
|
33
|
-
map_75: float
|
|
34
|
-
map_per_class: dict[str, float] | None = None
|
|
35
|
-
mar_100_per_class: dict[str, float] | None = None
|
|
36
|
-
classes: list[int]
|
|
37
|
-
|
|
38
|
-
@property
|
|
39
|
-
def value(self) -> float:
|
|
40
|
-
"""Backwards compatibility alias for map."""
|
|
41
|
-
return self.map
|
|
42
|
-
|
|
43
|
-
@property
|
|
44
|
-
def per_class(self) -> dict[str, float] | None:
|
|
45
|
-
"""Backwards compatibility alias for map_per_class."""
|
|
46
|
-
return self.map_per_class
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def calculate_map_metric( # noqa: C901
|
|
50
|
-
pred_annotations: Sequence[AnnotationBaseTable],
|
|
51
|
-
gt_annotations: Sequence[AnnotationBaseTable],
|
|
52
|
-
) -> DetectionMetricsMAP:
|
|
53
|
-
"""Calculate the Mean Average Precision (MAP) metric."""
|
|
54
|
-
if not gt_annotations or not pred_annotations:
|
|
55
|
-
return DetectionMetricsMAP(
|
|
56
|
-
name="mAP@.5:.95",
|
|
57
|
-
map=0.0,
|
|
58
|
-
map_small=0.0,
|
|
59
|
-
map_medium=0.0,
|
|
60
|
-
map_large=0.0,
|
|
61
|
-
mar_1=0.0,
|
|
62
|
-
mar_10=0.0,
|
|
63
|
-
mar_100=0.0,
|
|
64
|
-
mar_small=0.0,
|
|
65
|
-
mar_medium=0.0,
|
|
66
|
-
mar_large=0.0,
|
|
67
|
-
map_50=-1.0,
|
|
68
|
-
map_75=-1.0,
|
|
69
|
-
map_per_class=None,
|
|
70
|
-
mar_100_per_class=None,
|
|
71
|
-
classes=[],
|
|
72
|
-
)
|
|
73
|
-
uuid_to_int_label: dict[UUID, int] = {}
|
|
74
|
-
|
|
75
|
-
# Map sample_id to annotations.
|
|
76
|
-
sample_id_to_annotations = _group_by_sample_id(
|
|
77
|
-
pred_annotations=pred_annotations,
|
|
78
|
-
gt_annotations=gt_annotations,
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
# Create the MeanAveragePrecision object.
|
|
82
|
-
map_metric = MeanAveragePrecision(
|
|
83
|
-
box_format="xywh",
|
|
84
|
-
iou_thresholds=None,
|
|
85
|
-
class_metrics=True,
|
|
86
|
-
average="macro",
|
|
87
|
-
backend="faster_coco_eval",
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
# Compute MAP updating the object sample by sample.
|
|
91
|
-
for _sample_id, (
|
|
92
|
-
sample_pred_annotations,
|
|
93
|
-
sample_gt_annotations,
|
|
94
|
-
) in sample_id_to_annotations.items():
|
|
95
|
-
# Convert to torchmetrics format.
|
|
96
|
-
prediction_tm = _convert_to_torchmetrics(
|
|
97
|
-
annotations=sample_pred_annotations,
|
|
98
|
-
is_prediction=True,
|
|
99
|
-
uuid_to_int_label_map=uuid_to_int_label,
|
|
100
|
-
)
|
|
101
|
-
ground_truth_tm = _convert_to_torchmetrics(
|
|
102
|
-
annotations=sample_gt_annotations,
|
|
103
|
-
is_prediction=False,
|
|
104
|
-
uuid_to_int_label_map=uuid_to_int_label,
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
# Update the metric.
|
|
108
|
-
map_metric.update(preds=[prediction_tm], target=[ground_truth_tm])
|
|
109
|
-
|
|
110
|
-
# Compute the final results.
|
|
111
|
-
results = map_metric.compute()
|
|
112
|
-
# Invert label map to recover original UUIDs
|
|
113
|
-
int_to_uuid = {v: k for k, v in uuid_to_int_label.items()}
|
|
114
|
-
|
|
115
|
-
# Helper to convert Tensor to Python list
|
|
116
|
-
def to_list(t: Tensor) -> list[float]:
|
|
117
|
-
if t.dim() == 0:
|
|
118
|
-
return [t.item()]
|
|
119
|
-
return t.tolist()
|
|
120
|
-
|
|
121
|
-
# Scalar metrics
|
|
122
|
-
map_val = results["map"].item()
|
|
123
|
-
map_small = results["map_small"].item()
|
|
124
|
-
map_medium = results["map_medium"].item()
|
|
125
|
-
map_large = results["map_large"].item()
|
|
126
|
-
mar_1 = results["mar_1"].item()
|
|
127
|
-
mar_10 = results["mar_10"].item()
|
|
128
|
-
mar_100 = results["mar_100"].item()
|
|
129
|
-
mar_small = results["mar_small"].item()
|
|
130
|
-
mar_medium = results["mar_medium"].item()
|
|
131
|
-
mar_large = results["mar_large"].item()
|
|
132
|
-
|
|
133
|
-
# IoU-specific metrics
|
|
134
|
-
map_50 = results.get("map_50")
|
|
135
|
-
map_50 = map_50.item() if isinstance(map_50, Tensor) and map_50.dim() == 0 else -1.0
|
|
136
|
-
map_75 = results.get("map_75")
|
|
137
|
-
map_75 = map_75.item() if isinstance(map_75, Tensor) and map_75.dim() == 0 else -1.0
|
|
138
|
-
|
|
139
|
-
# Per-class metrics
|
|
140
|
-
raw_map_pc = results.get("map_per_class")
|
|
141
|
-
per_class_dict: dict[str, float] | None = None
|
|
142
|
-
if raw_map_pc is not None:
|
|
143
|
-
pc_list = to_list(raw_map_pc)
|
|
144
|
-
per_class_dict = {}
|
|
145
|
-
for idx, val in enumerate(pc_list):
|
|
146
|
-
if not math.isnan(val):
|
|
147
|
-
per_class_dict[str(int_to_uuid[idx])] = val
|
|
148
|
-
|
|
149
|
-
# Per-class recall at 100 detections
|
|
150
|
-
raw_mar100_pc = results.get("mar_100_per_class")
|
|
151
|
-
mar_100_pc_dict: dict[str, float] | None = None
|
|
152
|
-
if raw_mar100_pc is not None:
|
|
153
|
-
m100_list = to_list(raw_mar100_pc)
|
|
154
|
-
mar_100_pc_dict = {}
|
|
155
|
-
for idx, val in enumerate(m100_list):
|
|
156
|
-
if not math.isnan(val):
|
|
157
|
-
mar_100_pc_dict[str(int_to_uuid[idx])] = val
|
|
158
|
-
|
|
159
|
-
# Observed classes
|
|
160
|
-
raw_classes = results.get("classes")
|
|
161
|
-
classes_list_output: list[int] = []
|
|
162
|
-
if raw_classes is not None:
|
|
163
|
-
classes_list_output = [int(x) for x in to_list(raw_classes)]
|
|
164
|
-
|
|
165
|
-
return DetectionMetricsMAP(
|
|
166
|
-
name="mAP@.5:.95",
|
|
167
|
-
map=map_val,
|
|
168
|
-
map_small=map_small,
|
|
169
|
-
map_medium=map_medium,
|
|
170
|
-
map_large=map_large,
|
|
171
|
-
mar_1=mar_1,
|
|
172
|
-
mar_10=mar_10,
|
|
173
|
-
mar_100=mar_100,
|
|
174
|
-
mar_small=mar_small,
|
|
175
|
-
mar_medium=mar_medium,
|
|
176
|
-
mar_large=mar_large,
|
|
177
|
-
map_50=map_50,
|
|
178
|
-
map_75=map_75,
|
|
179
|
-
map_per_class=per_class_dict,
|
|
180
|
-
mar_100_per_class=mar_100_pc_dict,
|
|
181
|
-
classes=classes_list_output,
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def _group_by_sample_id(
|
|
186
|
-
pred_annotations: Sequence[AnnotationBaseTable],
|
|
187
|
-
gt_annotations: Sequence[AnnotationBaseTable],
|
|
188
|
-
) -> dict[
|
|
189
|
-
UUID,
|
|
190
|
-
tuple[list[AnnotationBaseTable], list[AnnotationBaseTable]],
|
|
191
|
-
]:
|
|
192
|
-
"""Group prediction and ground truth annotations by sample_id.
|
|
193
|
-
|
|
194
|
-
Returns a dictionary with sample_id as key and a tuple of
|
|
195
|
-
(list of prediction annotations, list of ground truth annotations) as value.
|
|
196
|
-
"""
|
|
197
|
-
sample_id_to_annotations: defaultdict[
|
|
198
|
-
UUID,
|
|
199
|
-
tuple[list[AnnotationBaseTable], list[AnnotationBaseTable]],
|
|
200
|
-
] = defaultdict(lambda: ([], []))
|
|
201
|
-
for ann in pred_annotations:
|
|
202
|
-
sample_id_to_annotations[ann.sample_id][0].append(ann)
|
|
203
|
-
for ann in gt_annotations:
|
|
204
|
-
sample_id_to_annotations[ann.sample_id][1].append(ann)
|
|
205
|
-
return sample_id_to_annotations
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
def _convert_to_torchmetrics(
|
|
209
|
-
annotations: Sequence[AnnotationBaseTable],
|
|
210
|
-
is_prediction: bool,
|
|
211
|
-
uuid_to_int_label_map: dict[UUID, int],
|
|
212
|
-
) -> dict[str, Tensor]:
|
|
213
|
-
"""Convert annotations to torchmetrics format.
|
|
214
|
-
|
|
215
|
-
Args:
|
|
216
|
-
annotations: List of bounding box annotations.
|
|
217
|
-
is_prediction: Whether the annotations are predictions.
|
|
218
|
-
uuid_to_int_label_map: Map from UUID to integer label.
|
|
219
|
-
|
|
220
|
-
Returns:
|
|
221
|
-
Dictionary in torchmetrics format. For predictions the keys are
|
|
222
|
-
`boxes`, `scores`, `labels`. For ground truth they are `boxes`,
|
|
223
|
-
`labels`.
|
|
224
|
-
|
|
225
|
-
"""
|
|
226
|
-
if not annotations:
|
|
227
|
-
empty_boxes = torch.empty((0, 4), dtype=torch.float32)
|
|
228
|
-
empty_labels = torch.empty((0,), dtype=torch.int64)
|
|
229
|
-
if is_prediction:
|
|
230
|
-
return {
|
|
231
|
-
"boxes": empty_boxes,
|
|
232
|
-
"scores": torch.empty((0,), dtype=torch.float32),
|
|
233
|
-
"labels": empty_labels,
|
|
234
|
-
}
|
|
235
|
-
return {"boxes": empty_boxes, "labels": empty_labels}
|
|
236
|
-
|
|
237
|
-
boxes = torch.tensor(
|
|
238
|
-
[
|
|
239
|
-
[
|
|
240
|
-
a.object_detection_details.x,
|
|
241
|
-
a.object_detection_details.y,
|
|
242
|
-
a.object_detection_details.width,
|
|
243
|
-
a.object_detection_details.height,
|
|
244
|
-
]
|
|
245
|
-
for a in annotations
|
|
246
|
-
if a.object_detection_details is not None
|
|
247
|
-
],
|
|
248
|
-
dtype=torch.float32,
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
mapped_labels = []
|
|
252
|
-
# Use the passed-in map instead of a global one
|
|
253
|
-
for uuid_label in (a.annotation_label_id for a in annotations):
|
|
254
|
-
if uuid_label not in uuid_to_int_label_map:
|
|
255
|
-
# Assign the next available integer ID based on the current map size
|
|
256
|
-
uuid_to_int_label_map[uuid_label] = len(uuid_to_int_label_map)
|
|
257
|
-
mapped_labels.append(uuid_to_int_label_map[uuid_label])
|
|
258
|
-
|
|
259
|
-
labels = torch.tensor(mapped_labels, dtype=torch.int64)
|
|
260
|
-
|
|
261
|
-
if is_prediction:
|
|
262
|
-
scores = torch.tensor([a.confidence for a in annotations], dtype=torch.float32)
|
|
263
|
-
return {
|
|
264
|
-
"boxes": boxes,
|
|
265
|
-
"scores": scores,
|
|
266
|
-
"labels": labels,
|
|
267
|
-
}
|
|
268
|
-
return {"boxes": boxes, "labels": labels}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"""This module defines the AnnotationTask model."""
|
|
2
|
-
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
from enum import Enum
|
|
5
|
-
from uuid import UUID, uuid4
|
|
6
|
-
|
|
7
|
-
from sqlmodel import Field, SQLModel
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class AnnotationType(str, Enum):
|
|
11
|
-
"""The type of annotation task."""
|
|
12
|
-
|
|
13
|
-
BBOX = "bbox"
|
|
14
|
-
CLASSIFICATION = "classification"
|
|
15
|
-
SEMANTIC_SEGMENTATION = "semantic_segmentation"
|
|
16
|
-
INSTANCE_SEGMENTATION = "instance_segmentation"
|
|
17
|
-
OBJECT_DETECTION = "object_detection"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class AnnotationTaskTable(SQLModel, table=True):
|
|
21
|
-
"""The annotation task model."""
|
|
22
|
-
|
|
23
|
-
__tablename__ = "annotation_tasks"
|
|
24
|
-
annotation_task_id: UUID = Field(default_factory=uuid4, primary_key=True)
|
|
25
|
-
name: str
|
|
26
|
-
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
27
|
-
annotation_type: AnnotationType
|
|
28
|
-
is_prediction: bool
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"""Handler for database operations related to annotations."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from sqlmodel import Session
|
|
6
|
-
|
|
7
|
-
from lightly_studio.models.annotation.annotation_base import (
|
|
8
|
-
AnnotationBaseTable,
|
|
9
|
-
AnnotationCreate,
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def create(session: Session, annotation: AnnotationCreate) -> AnnotationBaseTable:
|
|
14
|
-
"""Create a new annotation in the database."""
|
|
15
|
-
db_annotation = AnnotationBaseTable.model_validate(annotation)
|
|
16
|
-
session.add(db_annotation)
|
|
17
|
-
session.commit()
|
|
18
|
-
session.refresh(db_annotation)
|
|
19
|
-
return db_annotation
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"""Resolver for annotation tasks."""
|
|
2
|
-
|
|
3
|
-
from typing import List, Optional, Sequence
|
|
4
|
-
from uuid import UUID
|
|
5
|
-
|
|
6
|
-
from sqlmodel import Session, col, select
|
|
7
|
-
|
|
8
|
-
from lightly_studio.models.annotation_task import AnnotationTaskTable
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def create(session: Session, annotation_task: AnnotationTaskTable) -> AnnotationTaskTable:
|
|
12
|
-
"""Create a new annotation task."""
|
|
13
|
-
session.add(annotation_task)
|
|
14
|
-
session.commit()
|
|
15
|
-
session.refresh(annotation_task)
|
|
16
|
-
return annotation_task
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def get_by_id(session: Session, annotation_task_id: UUID) -> Optional[AnnotationTaskTable]:
|
|
20
|
-
"""Get an annotation task by ID."""
|
|
21
|
-
statement = select(AnnotationTaskTable).where(
|
|
22
|
-
AnnotationTaskTable.annotation_task_id == annotation_task_id
|
|
23
|
-
)
|
|
24
|
-
return session.exec(statement).first()
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def get_all(session: Session) -> List[AnnotationTaskTable]:
|
|
28
|
-
"""Get all annotation tasks."""
|
|
29
|
-
statement = select(AnnotationTaskTable).order_by(col(AnnotationTaskTable.created_at).asc())
|
|
30
|
-
results: Sequence[AnnotationTaskTable] = session.exec(statement).all()
|
|
31
|
-
return list(results)
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
"""Resolver for operations for setting metadata."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from datetime import datetime, timezone
|
|
6
|
-
from typing import Any
|
|
7
|
-
from uuid import UUID
|
|
8
|
-
|
|
9
|
-
from sqlmodel import Session
|
|
10
|
-
|
|
11
|
-
from lightly_studio.metadata.complex_metadata import serialize_complex_metadata
|
|
12
|
-
from lightly_studio.models.metadata import (
|
|
13
|
-
SampleMetadataTable,
|
|
14
|
-
get_type_name,
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def bulk_set_metadata(
|
|
19
|
-
session: Session,
|
|
20
|
-
sample_metadata: list[tuple[UUID, dict[str, Any]]],
|
|
21
|
-
) -> None:
|
|
22
|
-
"""Bulk insert metadata for multiple samples.
|
|
23
|
-
|
|
24
|
-
Args:
|
|
25
|
-
session: The database session.
|
|
26
|
-
sample_metadata: List of (sample_id, metadata_dict) tuples.
|
|
27
|
-
"""
|
|
28
|
-
now = datetime.now(timezone.utc)
|
|
29
|
-
objects = []
|
|
30
|
-
for sample_id, metadata in sample_metadata:
|
|
31
|
-
metadata_schema = {}
|
|
32
|
-
serialized_data = {}
|
|
33
|
-
for key, value in metadata.items():
|
|
34
|
-
# Serialize complex metadata objects.
|
|
35
|
-
serialized_data[key] = serialize_complex_metadata(value)
|
|
36
|
-
# Get the type name
|
|
37
|
-
metadata_schema[key] = get_type_name(value)
|
|
38
|
-
|
|
39
|
-
obj = SampleMetadataTable(
|
|
40
|
-
sample_id=sample_id,
|
|
41
|
-
data=serialized_data,
|
|
42
|
-
metadata_schema=metadata_schema,
|
|
43
|
-
created_at=now,
|
|
44
|
-
updated_at=now,
|
|
45
|
-
)
|
|
46
|
-
objects.append(obj)
|
|
47
|
-
session.bulk_save_objects(objects)
|
|
48
|
-
session.commit()
|
|
File without changes
|