deepdoctection 0.32__py3-none-any.whl → 0.34__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 deepdoctection might be problematic. Click here for more details.
- deepdoctection/__init__.py +8 -25
- deepdoctection/analyzer/dd.py +84 -71
- deepdoctection/dataflow/common.py +9 -5
- deepdoctection/dataflow/custom.py +5 -5
- deepdoctection/dataflow/custom_serialize.py +75 -18
- deepdoctection/dataflow/parallel_map.py +3 -3
- deepdoctection/dataflow/serialize.py +4 -4
- deepdoctection/dataflow/stats.py +3 -3
- deepdoctection/datapoint/annotation.py +78 -56
- deepdoctection/datapoint/box.py +7 -7
- deepdoctection/datapoint/convert.py +6 -6
- deepdoctection/datapoint/image.py +157 -75
- deepdoctection/datapoint/view.py +175 -151
- deepdoctection/datasets/adapter.py +30 -24
- deepdoctection/datasets/base.py +10 -10
- deepdoctection/datasets/dataflow_builder.py +3 -3
- deepdoctection/datasets/info.py +23 -25
- deepdoctection/datasets/instances/doclaynet.py +48 -49
- deepdoctection/datasets/instances/fintabnet.py +44 -45
- deepdoctection/datasets/instances/funsd.py +23 -23
- deepdoctection/datasets/instances/iiitar13k.py +8 -8
- deepdoctection/datasets/instances/layouttest.py +2 -2
- deepdoctection/datasets/instances/publaynet.py +3 -3
- deepdoctection/datasets/instances/pubtables1m.py +18 -18
- deepdoctection/datasets/instances/pubtabnet.py +30 -29
- deepdoctection/datasets/instances/rvlcdip.py +28 -29
- deepdoctection/datasets/instances/xfund.py +51 -30
- deepdoctection/datasets/save.py +6 -6
- deepdoctection/eval/accmetric.py +32 -33
- deepdoctection/eval/base.py +8 -9
- deepdoctection/eval/cocometric.py +13 -12
- deepdoctection/eval/eval.py +32 -26
- deepdoctection/eval/tedsmetric.py +16 -12
- deepdoctection/eval/tp_eval_callback.py +7 -16
- deepdoctection/extern/base.py +339 -134
- deepdoctection/extern/d2detect.py +69 -89
- deepdoctection/extern/deskew.py +11 -10
- deepdoctection/extern/doctrocr.py +81 -64
- deepdoctection/extern/fastlang.py +23 -16
- deepdoctection/extern/hfdetr.py +53 -38
- deepdoctection/extern/hflayoutlm.py +216 -155
- deepdoctection/extern/hflm.py +35 -30
- deepdoctection/extern/model.py +433 -255
- deepdoctection/extern/pdftext.py +15 -15
- deepdoctection/extern/pt/ptutils.py +4 -2
- deepdoctection/extern/tessocr.py +39 -38
- deepdoctection/extern/texocr.py +14 -16
- deepdoctection/extern/tp/tfutils.py +16 -2
- deepdoctection/extern/tp/tpcompat.py +11 -7
- deepdoctection/extern/tp/tpfrcnn/config/config.py +4 -4
- deepdoctection/extern/tp/tpfrcnn/modeling/backbone.py +1 -1
- deepdoctection/extern/tp/tpfrcnn/modeling/model_box.py +5 -5
- deepdoctection/extern/tp/tpfrcnn/modeling/model_fpn.py +6 -6
- deepdoctection/extern/tp/tpfrcnn/modeling/model_frcnn.py +4 -4
- deepdoctection/extern/tp/tpfrcnn/modeling/model_mrcnn.py +5 -3
- deepdoctection/extern/tp/tpfrcnn/preproc.py +5 -5
- deepdoctection/extern/tpdetect.py +40 -45
- deepdoctection/mapper/cats.py +36 -40
- deepdoctection/mapper/cocostruct.py +16 -12
- deepdoctection/mapper/d2struct.py +22 -22
- deepdoctection/mapper/hfstruct.py +7 -7
- deepdoctection/mapper/laylmstruct.py +22 -24
- deepdoctection/mapper/maputils.py +9 -10
- deepdoctection/mapper/match.py +33 -2
- deepdoctection/mapper/misc.py +6 -7
- deepdoctection/mapper/pascalstruct.py +4 -4
- deepdoctection/mapper/prodigystruct.py +6 -6
- deepdoctection/mapper/pubstruct.py +84 -92
- deepdoctection/mapper/tpstruct.py +3 -3
- deepdoctection/mapper/xfundstruct.py +33 -33
- deepdoctection/pipe/anngen.py +39 -14
- deepdoctection/pipe/base.py +68 -99
- deepdoctection/pipe/common.py +181 -85
- deepdoctection/pipe/concurrency.py +14 -10
- deepdoctection/pipe/doctectionpipe.py +24 -21
- deepdoctection/pipe/language.py +20 -25
- deepdoctection/pipe/layout.py +18 -16
- deepdoctection/pipe/lm.py +49 -47
- deepdoctection/pipe/order.py +63 -65
- deepdoctection/pipe/refine.py +102 -109
- deepdoctection/pipe/segment.py +157 -162
- deepdoctection/pipe/sub_layout.py +50 -40
- deepdoctection/pipe/text.py +37 -36
- deepdoctection/pipe/transform.py +19 -16
- deepdoctection/train/d2_frcnn_train.py +27 -25
- deepdoctection/train/hf_detr_train.py +22 -18
- deepdoctection/train/hf_layoutlm_train.py +49 -48
- deepdoctection/train/tp_frcnn_train.py +10 -11
- deepdoctection/utils/concurrency.py +1 -1
- deepdoctection/utils/context.py +13 -6
- deepdoctection/utils/develop.py +4 -4
- deepdoctection/utils/env_info.py +52 -14
- deepdoctection/utils/file_utils.py +6 -11
- deepdoctection/utils/fs.py +41 -14
- deepdoctection/utils/identifier.py +2 -2
- deepdoctection/utils/logger.py +15 -15
- deepdoctection/utils/metacfg.py +7 -7
- deepdoctection/utils/pdf_utils.py +39 -14
- deepdoctection/utils/settings.py +188 -182
- deepdoctection/utils/tqdm.py +1 -1
- deepdoctection/utils/transform.py +14 -9
- deepdoctection/utils/types.py +104 -0
- deepdoctection/utils/utils.py +7 -7
- deepdoctection/utils/viz.py +70 -69
- {deepdoctection-0.32.dist-info → deepdoctection-0.34.dist-info}/METADATA +7 -4
- deepdoctection-0.34.dist-info/RECORD +146 -0
- {deepdoctection-0.32.dist-info → deepdoctection-0.34.dist-info}/WHEEL +1 -1
- deepdoctection/utils/detection_types.py +0 -68
- deepdoctection-0.32.dist-info/RECORD +0 -146
- {deepdoctection-0.32.dist-info → deepdoctection-0.34.dist-info}/LICENSE +0 -0
- {deepdoctection-0.32.dist-info → deepdoctection-0.34.dist-info}/top_level.txt +0 -0
|
@@ -37,8 +37,8 @@ from ...dataflow import CustomDataFromList, DataFlow, MapData
|
|
|
37
37
|
from ...datasets.info import DatasetInfo
|
|
38
38
|
from ...mapper.cats import cat_to_sub_cat, filter_cat
|
|
39
39
|
from ...mapper.xfundstruct import xfund_to_image
|
|
40
|
-
from ...utils.detection_types import JsonDict
|
|
41
40
|
from ...utils.settings import BioTag, DatasetType, LayoutType, ObjectTypes, TokenClasses, TokenClassWithTag, WordType
|
|
41
|
+
from ...utils.types import FunsdDict
|
|
42
42
|
from ..base import _BuiltInDataset
|
|
43
43
|
from ..dataflow_builder import DataFlowBaseBuilder
|
|
44
44
|
from ..info import DatasetCategories
|
|
@@ -56,7 +56,7 @@ _LICENSE = (
|
|
|
56
56
|
)
|
|
57
57
|
_URL = "https://github.com/doc-analysis/XFUND/releases/tag/v1.0"
|
|
58
58
|
_SPLITS: Mapping[str, str] = {"train": "train", "val": "val"}
|
|
59
|
-
_TYPE = DatasetType.
|
|
59
|
+
_TYPE = DatasetType.TOKEN_CLASSIFICATION
|
|
60
60
|
_LOCATION = "xfund"
|
|
61
61
|
_ANNOTATION_FILES: Mapping[str, Union[str, Sequence[str]]] = {
|
|
62
62
|
"train": [
|
|
@@ -70,24 +70,23 @@ _ANNOTATION_FILES: Mapping[str, Union[str, Sequence[str]]] = {
|
|
|
70
70
|
],
|
|
71
71
|
"val": ["de.val.json", "es.val.json", "fr.val.json", "it.val.json", "ja.val.json", "pt.val.json", "zh.val.json"],
|
|
72
72
|
}
|
|
73
|
-
_INIT_CATEGORIES = [LayoutType.
|
|
74
|
-
_SUB_CATEGORIES: Mapping[ObjectTypes, Mapping[ObjectTypes, Sequence[ObjectTypes]]]
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
WordType.
|
|
78
|
-
WordType.
|
|
79
|
-
|
|
80
|
-
TokenClassWithTag.
|
|
81
|
-
TokenClassWithTag.
|
|
82
|
-
TokenClassWithTag.
|
|
83
|
-
TokenClassWithTag.
|
|
84
|
-
TokenClassWithTag.
|
|
85
|
-
|
|
86
|
-
BioTag.outside,
|
|
73
|
+
_INIT_CATEGORIES: Sequence[ObjectTypes] = [LayoutType.WORD, LayoutType.TEXT]
|
|
74
|
+
_SUB_CATEGORIES: Mapping[ObjectTypes, Mapping[ObjectTypes, Sequence[ObjectTypes]]] = {
|
|
75
|
+
LayoutType.WORD: {
|
|
76
|
+
WordType.TOKEN_CLASS: [TokenClasses.OTHER, TokenClasses.QUESTION, TokenClasses.ANSWER, TokenClasses.HEADER],
|
|
77
|
+
WordType.TAG: [BioTag.INSIDE, BioTag.OUTSIDE, BioTag.BEGIN],
|
|
78
|
+
WordType.TOKEN_TAG: [
|
|
79
|
+
TokenClassWithTag.B_ANSWER,
|
|
80
|
+
TokenClassWithTag.B_HEADER,
|
|
81
|
+
TokenClassWithTag.B_QUESTION,
|
|
82
|
+
TokenClassWithTag.I_ANSWER,
|
|
83
|
+
TokenClassWithTag.I_HEADER,
|
|
84
|
+
TokenClassWithTag.I_QUESTION,
|
|
85
|
+
BioTag.OUTSIDE,
|
|
87
86
|
],
|
|
88
87
|
},
|
|
89
|
-
LayoutType.
|
|
90
|
-
WordType.
|
|
88
|
+
LayoutType.TEXT: {
|
|
89
|
+
WordType.TOKEN_CLASS: [TokenClasses.OTHER, TokenClasses.QUESTION, TokenClasses.ANSWER, TokenClasses.HEADER]
|
|
91
90
|
},
|
|
92
91
|
}
|
|
93
92
|
|
|
@@ -168,7 +167,7 @@ class XfundBuilder(DataFlowBaseBuilder):
|
|
|
168
167
|
df = CustomDataFromList(datapoints, max_datapoints=max_datapoints)
|
|
169
168
|
|
|
170
169
|
# Map
|
|
171
|
-
def replace_filename(dp:
|
|
170
|
+
def replace_filename(dp: FunsdDict) -> FunsdDict:
|
|
172
171
|
folder = "_".join(dp["id"].split("_", 2)[:2])
|
|
173
172
|
dp["img"]["fname"] = os.path.join(self.get_workdir(), folder, dp["img"]["fname"])
|
|
174
173
|
return dp
|
|
@@ -176,18 +175,40 @@ class XfundBuilder(DataFlowBaseBuilder):
|
|
|
176
175
|
df = MapData(df, replace_filename)
|
|
177
176
|
categories_name_as_key = self.categories.get_categories(init=True, name_as_key=True)
|
|
178
177
|
token_class_names_mapping = {
|
|
179
|
-
"other": TokenClasses.
|
|
180
|
-
"question": TokenClasses.
|
|
181
|
-
"answer": TokenClasses.
|
|
182
|
-
"header": TokenClasses.
|
|
178
|
+
"other": TokenClasses.OTHER,
|
|
179
|
+
"question": TokenClasses.QUESTION,
|
|
180
|
+
"answer": TokenClasses.ANSWER,
|
|
181
|
+
"header": TokenClasses.HEADER,
|
|
183
182
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
183
|
+
if LayoutType.WORD in self.categories.get_categories(filtered=True, name_as_key=True):
|
|
184
|
+
ner_token_to_id_mapping = self.categories.get_sub_categories(
|
|
185
|
+
categories=LayoutType.WORD,
|
|
186
|
+
sub_categories={LayoutType.WORD: [WordType.TOKEN_TAG, WordType.TAG, WordType.TOKEN_CLASS]},
|
|
187
|
+
keys=False,
|
|
188
|
+
values_as_dict=True,
|
|
189
|
+
name_as_key=True,
|
|
190
|
+
)
|
|
191
|
+
else:
|
|
192
|
+
ner_token_to_id_mapping = {
|
|
193
|
+
LayoutType.WORD: {
|
|
194
|
+
WordType.TAG: {BioTag.BEGIN: 3, BioTag.INSIDE: 1, BioTag.OUTSIDE: 2},
|
|
195
|
+
WordType.TOKEN_CLASS: {
|
|
196
|
+
TokenClasses.ANSWER: 3,
|
|
197
|
+
TokenClasses.HEADER: 4,
|
|
198
|
+
TokenClasses.OTHER: 1,
|
|
199
|
+
TokenClasses.QUESTION: 2,
|
|
200
|
+
},
|
|
201
|
+
WordType.TOKEN_TAG: {
|
|
202
|
+
TokenClassWithTag.B_ANSWER: 1,
|
|
203
|
+
TokenClassWithTag.B_HEADER: 2,
|
|
204
|
+
TokenClassWithTag.B_QUESTION: 3,
|
|
205
|
+
TokenClassWithTag.I_ANSWER: 4,
|
|
206
|
+
TokenClassWithTag.I_HEADER: 5,
|
|
207
|
+
TokenClassWithTag.I_QUESTION: 6,
|
|
208
|
+
BioTag.OUTSIDE: 7,
|
|
209
|
+
},
|
|
210
|
+
}
|
|
211
|
+
}
|
|
191
212
|
df = MapData(
|
|
192
213
|
df,
|
|
193
214
|
xfund_to_image(
|
deepdoctection/datasets/save.py
CHANGED
|
@@ -20,20 +20,21 @@ Module for saving
|
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
import json
|
|
23
|
+
import os
|
|
23
24
|
from pathlib import Path
|
|
24
25
|
from typing import Optional
|
|
25
26
|
|
|
26
27
|
from ..dataflow import DataFlow, MapData, SerializerJsonlines
|
|
27
28
|
from ..datapoint.convert import convert_b64_to_np_array
|
|
28
29
|
from ..datapoint.image import Image
|
|
29
|
-
from ..utils.detection_types import JsonDict, Pathlike
|
|
30
30
|
from ..utils.fs import mkdir_p
|
|
31
|
+
from ..utils.types import ImageDict, PathLikeOrStr
|
|
31
32
|
from ..utils.viz import viz_handler
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
def dataflow_to_json(
|
|
35
36
|
df: DataFlow,
|
|
36
|
-
path:
|
|
37
|
+
path: PathLikeOrStr,
|
|
37
38
|
single_files: bool = False,
|
|
38
39
|
file_name: Optional[str] = None,
|
|
39
40
|
max_datapoints: Optional[int] = None,
|
|
@@ -53,8 +54,7 @@ def dataflow_to_json(
|
|
|
53
54
|
:param save_image_in_json: Will save the image to the JSON object
|
|
54
55
|
:param highest_hierarchy_only: If True it will remove all image attributes of ImageAnnotations
|
|
55
56
|
"""
|
|
56
|
-
|
|
57
|
-
path = Path(path)
|
|
57
|
+
path = Path(path)
|
|
58
58
|
if single_files:
|
|
59
59
|
mkdir_p(path)
|
|
60
60
|
if not save_image_in_json:
|
|
@@ -68,8 +68,8 @@ def dataflow_to_json(
|
|
|
68
68
|
df = MapData(df, _remove_hh)
|
|
69
69
|
df = MapData(df, lambda dp: dp.as_dict())
|
|
70
70
|
|
|
71
|
-
def _path_to_str(dp:
|
|
72
|
-
dp["location"] =
|
|
71
|
+
def _path_to_str(dp: ImageDict) -> ImageDict:
|
|
72
|
+
dp["location"] = os.fspath(dp["location"])
|
|
73
73
|
return dp
|
|
74
74
|
|
|
75
75
|
df = MapData(df, _path_to_str)
|
deepdoctection/eval/accmetric.py
CHANGED
|
@@ -19,9 +19,8 @@
|
|
|
19
19
|
Module for Accuracy metric
|
|
20
20
|
"""
|
|
21
21
|
from collections import Counter
|
|
22
|
-
from typing import Any
|
|
23
22
|
from typing import Counter as TypeCounter
|
|
24
|
-
from typing import
|
|
23
|
+
from typing import Mapping, Optional, Sequence, Union
|
|
25
24
|
|
|
26
25
|
import numpy as np
|
|
27
26
|
from numpy import float32, int32
|
|
@@ -32,10 +31,10 @@ from termcolor import colored
|
|
|
32
31
|
from ..dataflow import DataFlow
|
|
33
32
|
from ..datasets.info import DatasetCategories
|
|
34
33
|
from ..mapper.cats import image_to_cat_id
|
|
35
|
-
from ..utils.detection_types import JsonDict
|
|
36
34
|
from ..utils.file_utils import Requirement
|
|
37
35
|
from ..utils.logger import LoggingRecord, logger
|
|
38
36
|
from ..utils.settings import ObjectTypes, TypeOrStr, get_type
|
|
37
|
+
from ..utils.types import MetricResults
|
|
39
38
|
from .base import MetricBase
|
|
40
39
|
from .registry import metric_registry
|
|
41
40
|
|
|
@@ -54,7 +53,7 @@ __all__ = [
|
|
|
54
53
|
|
|
55
54
|
def _mask_some_gt_and_pr_labels(
|
|
56
55
|
np_label_gt: NDArray[int32], np_label_pr: NDArray[int32], masks: Sequence[int]
|
|
57
|
-
) ->
|
|
56
|
+
) -> tuple[NDArray[int32], NDArray[int32]]:
|
|
58
57
|
if len(np_label_gt) != len(masks):
|
|
59
58
|
raise ValueError(f"length of label_gt ({len(np_label_gt)}) and masks ({len(masks)}) must be equal")
|
|
60
59
|
np_masks = np.asarray(masks)
|
|
@@ -77,8 +76,8 @@ def accuracy(label_gt: Sequence[int], label_predictions: Sequence[int], masks: O
|
|
|
77
76
|
Calculates the accuracy given predictions and labels. Ignores masked indices. Uses
|
|
78
77
|
`sklearn.metrics.accuracy_score`
|
|
79
78
|
|
|
80
|
-
:param label_gt:
|
|
81
|
-
:param label_predictions:
|
|
79
|
+
:param label_gt: list of ground truth labels
|
|
80
|
+
:param label_predictions: list of predictions. Must have the same length as label_gt
|
|
82
81
|
:param masks: An optional list with masks to ignore some samples.
|
|
83
82
|
|
|
84
83
|
:return: Accuracy score with only unmasked values to be considered
|
|
@@ -102,9 +101,9 @@ def confusion(
|
|
|
102
101
|
"""
|
|
103
102
|
Calculates the accuracy matrix given the predictions and labels. Ignores masked indices.
|
|
104
103
|
|
|
105
|
-
:param label_gt:
|
|
106
|
-
:param label_predictions:
|
|
107
|
-
:param masks:
|
|
104
|
+
:param label_gt: list of ground truth labels
|
|
105
|
+
:param label_predictions: list of predictions. Must have the same length as label_gt
|
|
106
|
+
:param masks: list with masks of same length as label_gt.
|
|
108
107
|
|
|
109
108
|
:return: numpy array
|
|
110
109
|
"""
|
|
@@ -127,9 +126,9 @@ def precision(
|
|
|
127
126
|
Calculates the precision for a multi classification problem using a confusion matrix. The output will
|
|
128
127
|
be the precision by category.
|
|
129
128
|
|
|
130
|
-
:param label_gt:
|
|
131
|
-
:param label_predictions:
|
|
132
|
-
:param masks:
|
|
129
|
+
:param label_gt: list of ground truth labels
|
|
130
|
+
:param label_predictions: list of predictions. Must have the same length as label_gt
|
|
131
|
+
:param masks: list with masks of same length as label_gt.
|
|
133
132
|
:param micro: If True, it will calculate the micro average precision
|
|
134
133
|
:return: numpy array
|
|
135
134
|
"""
|
|
@@ -157,9 +156,9 @@ def recall(
|
|
|
157
156
|
Calculates the recall for a multi classification problem using a confusion matrix. The output will
|
|
158
157
|
be the recall by category.
|
|
159
158
|
|
|
160
|
-
:param label_gt:
|
|
161
|
-
:param label_predictions:
|
|
162
|
-
:param masks:
|
|
159
|
+
:param label_gt: list of ground truth labels
|
|
160
|
+
:param label_predictions: list of predictions. Must have the same length as label_gt
|
|
161
|
+
:param masks: list with masks of same length as label_gt.
|
|
163
162
|
:param micro: If True, it will calculate the micro average recall
|
|
164
163
|
:return: numpy array
|
|
165
164
|
"""
|
|
@@ -188,9 +187,9 @@ def f1_score(
|
|
|
188
187
|
Calculates the recall for a multi classification problem using a confusion matrix. The output will
|
|
189
188
|
be the recall by category.
|
|
190
189
|
|
|
191
|
-
:param label_gt:
|
|
192
|
-
:param label_predictions:
|
|
193
|
-
:param masks:
|
|
190
|
+
:param label_gt: list of ground truth labels
|
|
191
|
+
:param label_predictions: list of predictions. Must have the same length as label_gt
|
|
192
|
+
:param masks: list with masks of same length as label_gt.
|
|
194
193
|
:param micro: If True, it will calculate the micro average f1 score
|
|
195
194
|
:param per_label: If True, it will return the f1 score per label, otherwise will return the mean of all f1's
|
|
196
195
|
:return: numpy array
|
|
@@ -217,7 +216,7 @@ class ClassificationMetric(MetricBase):
|
|
|
217
216
|
@classmethod
|
|
218
217
|
def dump(
|
|
219
218
|
cls, dataflow_gt: DataFlow, dataflow_predictions: DataFlow, categories: DatasetCategories
|
|
220
|
-
) ->
|
|
219
|
+
) -> tuple[dict[str, list[int]], dict[str, list[int]]]:
|
|
221
220
|
dataflow_gt.reset_state()
|
|
222
221
|
dataflow_predictions.reset_state()
|
|
223
222
|
|
|
@@ -225,8 +224,8 @@ class ClassificationMetric(MetricBase):
|
|
|
225
224
|
if cls._cats is None and cls._sub_cats is None:
|
|
226
225
|
cls._cats = categories.get_categories(as_dict=False, filtered=True)
|
|
227
226
|
mapper_with_setting = cls.mapper(cls._cats, cls._sub_cats, cls._summary_sub_cats)
|
|
228
|
-
labels_gt:
|
|
229
|
-
labels_predictions:
|
|
227
|
+
labels_gt: dict[str, list[int]] = {}
|
|
228
|
+
labels_predictions: dict[str, list[int]] = {}
|
|
230
229
|
|
|
231
230
|
# returned images of gt and predictions are likely not in the same order. We therefore first stream all data
|
|
232
231
|
# into a dict and generate our result vectors thereafter.
|
|
@@ -253,7 +252,7 @@ class ClassificationMetric(MetricBase):
|
|
|
253
252
|
@classmethod
|
|
254
253
|
def get_distance(
|
|
255
254
|
cls, dataflow_gt: DataFlow, dataflow_predictions: DataFlow, categories: DatasetCategories
|
|
256
|
-
) ->
|
|
255
|
+
) -> list[MetricResults]:
|
|
257
256
|
labels_gt, labels_pr = cls.dump(dataflow_gt, dataflow_predictions, categories)
|
|
258
257
|
|
|
259
258
|
results = []
|
|
@@ -290,7 +289,7 @@ class ClassificationMetric(MetricBase):
|
|
|
290
289
|
sub_category_names = {cat1: [sub_cat1, sub_cat2], cat2: sub_cat3}
|
|
291
290
|
|
|
292
291
|
|
|
293
|
-
:param category_names:
|
|
292
|
+
:param category_names: list of category names
|
|
294
293
|
:param sub_category_names: Dict of categories and their sub categories that are supposed to be evaluated,
|
|
295
294
|
e.g. {"FOO": ["bak","baz"]} will evaluate "bak" and "baz"
|
|
296
295
|
:param summary_sub_category_names: string or list of summary sub categories
|
|
@@ -346,7 +345,7 @@ class ClassificationMetric(MetricBase):
|
|
|
346
345
|
)
|
|
347
346
|
|
|
348
347
|
@classmethod
|
|
349
|
-
def get_requirements(cls) ->
|
|
348
|
+
def get_requirements(cls) -> list[Requirement]:
|
|
350
349
|
return []
|
|
351
350
|
|
|
352
351
|
@property
|
|
@@ -395,7 +394,7 @@ class ConfusionMetric(ClassificationMetric):
|
|
|
395
394
|
@classmethod
|
|
396
395
|
def get_distance(
|
|
397
396
|
cls, dataflow_gt: DataFlow, dataflow_predictions: DataFlow, categories: DatasetCategories
|
|
398
|
-
) ->
|
|
397
|
+
) -> list[MetricResults]:
|
|
399
398
|
labels_gt, labels_pr = cls.dump(dataflow_gt, dataflow_predictions, categories)
|
|
400
399
|
|
|
401
400
|
results = []
|
|
@@ -407,10 +406,10 @@ class ConfusionMetric(ClassificationMetric):
|
|
|
407
406
|
results.append(
|
|
408
407
|
{
|
|
409
408
|
"key": key.value if isinstance(key, ObjectTypes) else key,
|
|
410
|
-
"
|
|
409
|
+
"category_id": row_number,
|
|
411
410
|
"category_id_pr": col_number,
|
|
412
411
|
"val": float(val),
|
|
413
|
-
"
|
|
412
|
+
"num_samples": number_labels[row_number],
|
|
414
413
|
}
|
|
415
414
|
)
|
|
416
415
|
cls._results = results
|
|
@@ -420,12 +419,12 @@ class ConfusionMetric(ClassificationMetric):
|
|
|
420
419
|
def print_result(cls) -> None:
|
|
421
420
|
data = {}
|
|
422
421
|
for entry in cls._results:
|
|
423
|
-
if entry["
|
|
424
|
-
data[entry["
|
|
422
|
+
if entry["category_id"] not in data:
|
|
423
|
+
data[entry["category_id"]] = [entry["category_id"], entry["val"]]
|
|
425
424
|
else:
|
|
426
|
-
data[entry["
|
|
425
|
+
data[entry["category_id"]].append(entry["val"])
|
|
427
426
|
|
|
428
|
-
header = ["predictions -> \n ground truth |\n v"] + list(
|
|
427
|
+
header = ["predictions -> \n ground truth |\n v"] + list(list(str(element) for element in data))
|
|
429
428
|
table = tabulate([data[k] for k, _ in enumerate(data, 1)], headers=header, tablefmt="pipe")
|
|
430
429
|
logger.info("Confusion matrix: \n %s", colored(table, "cyan"))
|
|
431
430
|
|
|
@@ -442,7 +441,7 @@ class PrecisionMetric(ClassificationMetric):
|
|
|
442
441
|
@classmethod
|
|
443
442
|
def get_distance(
|
|
444
443
|
cls, dataflow_gt: DataFlow, dataflow_predictions: DataFlow, categories: DatasetCategories
|
|
445
|
-
) ->
|
|
444
|
+
) -> list[MetricResults]:
|
|
446
445
|
labels_gt, labels_pr = cls.dump(dataflow_gt, dataflow_predictions, categories)
|
|
447
446
|
|
|
448
447
|
results = []
|
|
@@ -494,7 +493,7 @@ class PrecisionMetricMicro(ClassificationMetric):
|
|
|
494
493
|
@classmethod
|
|
495
494
|
def get_distance(
|
|
496
495
|
cls, dataflow_gt: DataFlow, dataflow_predictions: DataFlow, categories: DatasetCategories
|
|
497
|
-
) ->
|
|
496
|
+
) -> list[MetricResults]:
|
|
498
497
|
labels_gt, labels_pr = cls.dump(dataflow_gt, dataflow_predictions, categories)
|
|
499
498
|
|
|
500
499
|
results = []
|
deepdoctection/eval/base.py
CHANGED
|
@@ -20,13 +20,13 @@ Module for the base class for evaluations and metrics
|
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
from abc import ABC, abstractmethod
|
|
23
|
-
from typing import Any, Callable,
|
|
23
|
+
from typing import Any, Callable, Optional
|
|
24
24
|
|
|
25
25
|
from ..dataflow import DataFlow
|
|
26
26
|
from ..datasets.info import DatasetCategories
|
|
27
|
-
from ..utils.detection_types import JsonDict
|
|
28
27
|
from ..utils.error import DependencyError
|
|
29
28
|
from ..utils.file_utils import Requirement
|
|
29
|
+
from ..utils.types import MetricResults
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class MetricBase(ABC):
|
|
@@ -46,8 +46,7 @@ class MetricBase(ABC):
|
|
|
46
46
|
|
|
47
47
|
name: str
|
|
48
48
|
metric: Callable[[Any, Any], Optional[Any]]
|
|
49
|
-
|
|
50
|
-
_results: List[JsonDict]
|
|
49
|
+
_results: list[MetricResults]
|
|
51
50
|
|
|
52
51
|
def __new__(cls, *args, **kwargs): # type: ignore # pylint: disable=W0613
|
|
53
52
|
requirements = cls.get_requirements()
|
|
@@ -63,7 +62,7 @@ class MetricBase(ABC):
|
|
|
63
62
|
|
|
64
63
|
@classmethod
|
|
65
64
|
@abstractmethod
|
|
66
|
-
def get_requirements(cls) ->
|
|
65
|
+
def get_requirements(cls) -> list[Requirement]:
|
|
67
66
|
"""
|
|
68
67
|
Get a list of requirements for running the detector
|
|
69
68
|
"""
|
|
@@ -73,7 +72,7 @@ class MetricBase(ABC):
|
|
|
73
72
|
@abstractmethod
|
|
74
73
|
def get_distance(
|
|
75
74
|
cls, dataflow_gt: DataFlow, dataflow_predictions: DataFlow, categories: DatasetCategories
|
|
76
|
-
) ->
|
|
75
|
+
) -> list[MetricResults]:
|
|
77
76
|
"""
|
|
78
77
|
Takes of the ground truth processing strand as well as the prediction strand and generates the metric results.
|
|
79
78
|
|
|
@@ -87,7 +86,7 @@ class MetricBase(ABC):
|
|
|
87
86
|
@abstractmethod
|
|
88
87
|
def dump(
|
|
89
88
|
cls, dataflow_gt: DataFlow, dataflow_predictions: DataFlow, categories: DatasetCategories
|
|
90
|
-
) ->
|
|
89
|
+
) -> tuple[Any, Any]:
|
|
91
90
|
"""
|
|
92
91
|
Dump the dataflow with ground truth annotations and predictions. Use it as auxiliary method and call it from
|
|
93
92
|
`get_distance`.
|
|
@@ -99,7 +98,7 @@ class MetricBase(ABC):
|
|
|
99
98
|
raise NotImplementedError()
|
|
100
99
|
|
|
101
100
|
@classmethod
|
|
102
|
-
def result_list_to_dict(cls, results:
|
|
101
|
+
def result_list_to_dict(cls, results: list[MetricResults]) -> MetricResults:
|
|
103
102
|
"""
|
|
104
103
|
Converts the result from `get_distance` to a dict. It concatenates all keys of the inner dict and uses
|
|
105
104
|
the metric result 'val' as value.
|
|
@@ -107,7 +106,7 @@ class MetricBase(ABC):
|
|
|
107
106
|
:param results: List of dict as input
|
|
108
107
|
:return: Dict with metric results.
|
|
109
108
|
"""
|
|
110
|
-
output:
|
|
109
|
+
output: MetricResults = {}
|
|
111
110
|
for res in results:
|
|
112
111
|
new_key = ""
|
|
113
112
|
new_val = 0.0
|
|
@@ -18,9 +18,10 @@
|
|
|
18
18
|
"""
|
|
19
19
|
Module for metrics that require the COCOeval class.
|
|
20
20
|
"""
|
|
21
|
+
from __future__ import annotations
|
|
21
22
|
|
|
22
23
|
from copy import copy
|
|
23
|
-
from typing import
|
|
24
|
+
from typing import Optional, Union
|
|
24
25
|
|
|
25
26
|
import numpy as np
|
|
26
27
|
from lazy_imports import try_import
|
|
@@ -29,8 +30,8 @@ from ..dataflow import DataFlow
|
|
|
29
30
|
from ..datasets.info import DatasetCategories
|
|
30
31
|
from ..mapper.cats import re_assign_cat_ids
|
|
31
32
|
from ..mapper.cocostruct import image_to_coco
|
|
32
|
-
from ..utils.detection_types import JsonDict
|
|
33
33
|
from ..utils.file_utils import Requirement, cocotools_available, get_cocotools_requirement
|
|
34
|
+
from ..utils.types import JsonDict, MetricResults
|
|
34
35
|
from .base import MetricBase
|
|
35
36
|
from .registry import metric_registry
|
|
36
37
|
|
|
@@ -120,15 +121,15 @@ class CocoMetric(MetricBase):
|
|
|
120
121
|
|
|
121
122
|
name = "mAP and mAR"
|
|
122
123
|
metric = COCOeval if cocotools_available() else None
|
|
123
|
-
mapper = image_to_coco
|
|
124
|
+
mapper = image_to_coco
|
|
124
125
|
_f1_score = None
|
|
125
126
|
_f1_iou = None
|
|
126
|
-
_params:
|
|
127
|
+
_params: dict[str, Union[list[int], list[list[int]]]] = {}
|
|
127
128
|
|
|
128
129
|
@classmethod
|
|
129
130
|
def dump(
|
|
130
131
|
cls, dataflow_gt: DataFlow, dataflow_predictions: DataFlow, categories: DatasetCategories
|
|
131
|
-
) ->
|
|
132
|
+
) -> tuple[COCO, COCO]:
|
|
132
133
|
cats = [{"id": int(k), "name": v} for k, v in categories.get_categories(as_dict=True, filtered=True).items()]
|
|
133
134
|
imgs_gt, imgs_pr = [], []
|
|
134
135
|
anns_gt, anns_pr = [], []
|
|
@@ -137,11 +138,11 @@ class CocoMetric(MetricBase):
|
|
|
137
138
|
dataflow_predictions.reset_state()
|
|
138
139
|
|
|
139
140
|
for dp_gt, dp_pred in zip(dataflow_gt, dataflow_predictions):
|
|
140
|
-
img_gt, ann_gt = cls.mapper(dp_gt)
|
|
141
|
+
img_gt, ann_gt = cls.mapper(dp_gt)
|
|
141
142
|
dp_pred = re_assign_cat_ids(categories.get_categories(as_dict=True, filtered=True, name_as_key=True))(
|
|
142
143
|
dp_pred
|
|
143
144
|
)
|
|
144
|
-
img_pr, ann_pr = cls.mapper(dp_pred)
|
|
145
|
+
img_pr, ann_pr = cls.mapper(dp_pred)
|
|
145
146
|
imgs_gt.append(img_gt)
|
|
146
147
|
imgs_pr.append(img_pr)
|
|
147
148
|
anns_gt.extend(ann_gt)
|
|
@@ -162,7 +163,7 @@ class CocoMetric(MetricBase):
|
|
|
162
163
|
@classmethod
|
|
163
164
|
def get_distance(
|
|
164
165
|
cls, dataflow_gt: DataFlow, dataflow_predictions: DataFlow, categories: DatasetCategories
|
|
165
|
-
) ->
|
|
166
|
+
) -> list[MetricResults]:
|
|
166
167
|
coco_gt, coco_predictions = cls.dump(dataflow_gt, dataflow_predictions, categories)
|
|
167
168
|
|
|
168
169
|
metric = cls.metric(coco_gt, coco_predictions, iouType="bbox")
|
|
@@ -192,7 +193,7 @@ class CocoMetric(MetricBase):
|
|
|
192
193
|
return results
|
|
193
194
|
|
|
194
195
|
@classmethod
|
|
195
|
-
def get_summary_default_parameters(cls) ->
|
|
196
|
+
def get_summary_default_parameters(cls) -> list[JsonDict]:
|
|
196
197
|
"""
|
|
197
198
|
Returns default parameters of evaluation results. May differ from other CocoMetric classes.
|
|
198
199
|
|
|
@@ -215,8 +216,8 @@ class CocoMetric(MetricBase):
|
|
|
215
216
|
@classmethod
|
|
216
217
|
def set_params(
|
|
217
218
|
cls,
|
|
218
|
-
max_detections: Optional[
|
|
219
|
-
area_range: Optional[
|
|
219
|
+
max_detections: Optional[list[int]] = None,
|
|
220
|
+
area_range: Optional[list[list[int]]] = None,
|
|
220
221
|
f1_score: bool = False,
|
|
221
222
|
f1_iou: float = 0.9,
|
|
222
223
|
) -> None:
|
|
@@ -239,5 +240,5 @@ class CocoMetric(MetricBase):
|
|
|
239
240
|
cls._f1_iou = f1_iou
|
|
240
241
|
|
|
241
242
|
@classmethod
|
|
242
|
-
def get_requirements(cls) ->
|
|
243
|
+
def get_requirements(cls) -> list[Requirement]:
|
|
243
244
|
return [get_cocotools_requirement()]
|