deepdoctection 0.31__py3-none-any.whl → 0.33__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 +16 -29
- deepdoctection/analyzer/dd.py +70 -59
- deepdoctection/configs/conf_dd_one.yaml +34 -31
- 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 +41 -56
- deepdoctection/datapoint/box.py +9 -8
- deepdoctection/datapoint/convert.py +6 -6
- deepdoctection/datapoint/image.py +56 -44
- deepdoctection/datapoint/view.py +245 -150
- deepdoctection/datasets/__init__.py +1 -4
- deepdoctection/datasets/adapter.py +35 -26
- deepdoctection/datasets/base.py +14 -12
- deepdoctection/datasets/dataflow_builder.py +3 -3
- deepdoctection/datasets/info.py +24 -26
- deepdoctection/datasets/instances/doclaynet.py +51 -51
- deepdoctection/datasets/instances/fintabnet.py +46 -46
- deepdoctection/datasets/instances/funsd.py +25 -24
- deepdoctection/datasets/instances/iiitar13k.py +13 -10
- deepdoctection/datasets/instances/layouttest.py +4 -3
- deepdoctection/datasets/instances/publaynet.py +5 -5
- deepdoctection/datasets/instances/pubtables1m.py +24 -21
- deepdoctection/datasets/instances/pubtabnet.py +32 -30
- deepdoctection/datasets/instances/rvlcdip.py +30 -30
- deepdoctection/datasets/instances/xfund.py +26 -26
- deepdoctection/datasets/save.py +6 -6
- deepdoctection/eval/__init__.py +1 -4
- deepdoctection/eval/accmetric.py +32 -33
- deepdoctection/eval/base.py +8 -9
- deepdoctection/eval/cocometric.py +15 -13
- deepdoctection/eval/eval.py +41 -37
- deepdoctection/eval/tedsmetric.py +30 -23
- deepdoctection/eval/tp_eval_callback.py +16 -19
- deepdoctection/extern/__init__.py +2 -7
- deepdoctection/extern/base.py +339 -134
- deepdoctection/extern/d2detect.py +85 -113
- deepdoctection/extern/deskew.py +14 -11
- deepdoctection/extern/doctrocr.py +141 -130
- deepdoctection/extern/fastlang.py +27 -18
- deepdoctection/extern/hfdetr.py +71 -62
- deepdoctection/extern/hflayoutlm.py +504 -211
- deepdoctection/extern/hflm.py +230 -0
- deepdoctection/extern/model.py +488 -302
- deepdoctection/extern/pdftext.py +23 -19
- deepdoctection/extern/pt/__init__.py +1 -3
- deepdoctection/extern/pt/nms.py +6 -2
- deepdoctection/extern/pt/ptutils.py +29 -19
- deepdoctection/extern/tessocr.py +39 -38
- deepdoctection/extern/texocr.py +18 -18
- deepdoctection/extern/tp/tfutils.py +57 -9
- deepdoctection/extern/tp/tpcompat.py +21 -14
- deepdoctection/extern/tp/tpfrcnn/__init__.py +20 -0
- deepdoctection/extern/tp/tpfrcnn/common.py +7 -3
- deepdoctection/extern/tp/tpfrcnn/config/__init__.py +20 -0
- deepdoctection/extern/tp/tpfrcnn/config/config.py +13 -10
- deepdoctection/extern/tp/tpfrcnn/modeling/__init__.py +20 -0
- deepdoctection/extern/tp/tpfrcnn/modeling/backbone.py +18 -8
- deepdoctection/extern/tp/tpfrcnn/modeling/generalized_rcnn.py +12 -6
- deepdoctection/extern/tp/tpfrcnn/modeling/model_box.py +14 -9
- deepdoctection/extern/tp/tpfrcnn/modeling/model_cascade.py +8 -5
- deepdoctection/extern/tp/tpfrcnn/modeling/model_fpn.py +22 -17
- deepdoctection/extern/tp/tpfrcnn/modeling/model_frcnn.py +21 -14
- deepdoctection/extern/tp/tpfrcnn/modeling/model_mrcnn.py +19 -11
- deepdoctection/extern/tp/tpfrcnn/modeling/model_rpn.py +15 -10
- deepdoctection/extern/tp/tpfrcnn/predict.py +9 -4
- deepdoctection/extern/tp/tpfrcnn/preproc.py +12 -8
- deepdoctection/extern/tp/tpfrcnn/utils/__init__.py +20 -0
- deepdoctection/extern/tp/tpfrcnn/utils/box_ops.py +10 -2
- deepdoctection/extern/tpdetect.py +45 -53
- deepdoctection/mapper/__init__.py +3 -8
- deepdoctection/mapper/cats.py +27 -29
- deepdoctection/mapper/cocostruct.py +10 -10
- deepdoctection/mapper/d2struct.py +27 -26
- deepdoctection/mapper/hfstruct.py +13 -8
- deepdoctection/mapper/laylmstruct.py +178 -37
- deepdoctection/mapper/maputils.py +12 -11
- deepdoctection/mapper/match.py +2 -2
- deepdoctection/mapper/misc.py +11 -9
- deepdoctection/mapper/pascalstruct.py +4 -4
- deepdoctection/mapper/prodigystruct.py +5 -5
- deepdoctection/mapper/pubstruct.py +84 -92
- deepdoctection/mapper/tpstruct.py +5 -5
- deepdoctection/mapper/xfundstruct.py +33 -33
- deepdoctection/pipe/__init__.py +1 -1
- deepdoctection/pipe/anngen.py +12 -14
- deepdoctection/pipe/base.py +52 -106
- deepdoctection/pipe/common.py +72 -59
- deepdoctection/pipe/concurrency.py +16 -11
- deepdoctection/pipe/doctectionpipe.py +24 -21
- deepdoctection/pipe/language.py +20 -25
- deepdoctection/pipe/layout.py +20 -16
- deepdoctection/pipe/lm.py +75 -105
- deepdoctection/pipe/order.py +194 -89
- deepdoctection/pipe/refine.py +111 -124
- deepdoctection/pipe/segment.py +156 -161
- deepdoctection/pipe/{cell.py → sub_layout.py} +50 -40
- deepdoctection/pipe/text.py +37 -36
- deepdoctection/pipe/transform.py +19 -16
- deepdoctection/train/__init__.py +6 -12
- deepdoctection/train/d2_frcnn_train.py +48 -41
- deepdoctection/train/hf_detr_train.py +41 -30
- deepdoctection/train/hf_layoutlm_train.py +153 -135
- deepdoctection/train/tp_frcnn_train.py +32 -31
- deepdoctection/utils/concurrency.py +1 -1
- deepdoctection/utils/context.py +13 -6
- deepdoctection/utils/develop.py +4 -4
- deepdoctection/utils/env_info.py +87 -125
- deepdoctection/utils/file_utils.py +6 -11
- deepdoctection/utils/fs.py +22 -18
- deepdoctection/utils/identifier.py +2 -2
- deepdoctection/utils/logger.py +16 -15
- deepdoctection/utils/metacfg.py +7 -7
- deepdoctection/utils/mocks.py +93 -0
- deepdoctection/utils/pdf_utils.py +11 -11
- deepdoctection/utils/settings.py +185 -181
- 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 +74 -72
- {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/METADATA +30 -21
- deepdoctection-0.33.dist-info/RECORD +146 -0
- {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/WHEEL +1 -1
- deepdoctection/utils/detection_types.py +0 -68
- deepdoctection-0.31.dist-info/RECORD +0 -144
- {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/LICENSE +0 -0
- {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/top_level.txt +0 -0
|
@@ -25,7 +25,6 @@ from itertools import chain
|
|
|
25
25
|
from typing import Mapping, Optional
|
|
26
26
|
|
|
27
27
|
from ..datapoint import BoundingBox, CategoryAnnotation, ContainerAnnotation, Image, ImageAnnotation
|
|
28
|
-
from ..utils.detection_types import JsonDict
|
|
29
28
|
from ..utils.fs import load_image_from_file
|
|
30
29
|
from ..utils.settings import (
|
|
31
30
|
BioTag,
|
|
@@ -37,17 +36,18 @@ from ..utils.settings import (
|
|
|
37
36
|
get_type,
|
|
38
37
|
token_class_tag_to_token_class_with_tag,
|
|
39
38
|
)
|
|
39
|
+
from ..utils.types import FunsdDict
|
|
40
40
|
from .maputils import MappingContextManager, curry, maybe_get_fake_score
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
@curry
|
|
44
44
|
def xfund_to_image(
|
|
45
|
-
dp:
|
|
45
|
+
dp: FunsdDict,
|
|
46
46
|
load_image: bool,
|
|
47
47
|
fake_score: bool,
|
|
48
|
-
categories_dict_name_as_key: Mapping[
|
|
48
|
+
categories_dict_name_as_key: Mapping[ObjectTypes, int],
|
|
49
49
|
token_class_names_mapping: Mapping[str, str],
|
|
50
|
-
ner_token_to_id_mapping: Mapping[ObjectTypes, Mapping[ObjectTypes, Mapping[ObjectTypes,
|
|
50
|
+
ner_token_to_id_mapping: Mapping[ObjectTypes, Mapping[ObjectTypes, Mapping[ObjectTypes, int]]],
|
|
51
51
|
) -> Optional[Image]:
|
|
52
52
|
"""
|
|
53
53
|
Map a datapoint of annotation structure as given as from xfund or funsd dataset in to an Image structure
|
|
@@ -75,9 +75,9 @@ def xfund_to_image(
|
|
|
75
75
|
|
|
76
76
|
_, file_name = os.path.split(full_path)
|
|
77
77
|
external_id = dp.get("uid")
|
|
78
|
-
tag_to_id_mapping = ner_token_to_id_mapping[LayoutType.
|
|
79
|
-
token_class_to_id_mapping = ner_token_to_id_mapping[LayoutType.
|
|
80
|
-
token_tag_to_id_mapping = ner_token_to_id_mapping[LayoutType.
|
|
78
|
+
tag_to_id_mapping = ner_token_to_id_mapping[LayoutType.WORD][WordType.TAG]
|
|
79
|
+
token_class_to_id_mapping = ner_token_to_id_mapping[LayoutType.WORD][WordType.TOKEN_CLASS]
|
|
80
|
+
token_tag_to_id_mapping = ner_token_to_id_mapping[LayoutType.WORD][WordType.TOKEN_TAG]
|
|
81
81
|
|
|
82
82
|
with MappingContextManager(file_name) as mapping_context:
|
|
83
83
|
image = Image(file_name=file_name, location=full_path, external_id=external_id)
|
|
@@ -101,16 +101,16 @@ def xfund_to_image(
|
|
|
101
101
|
bbox = BoundingBox(absolute_coords=True, ulx=box[0], uly=box[1], lrx=box[2], lry=box[3])
|
|
102
102
|
score = maybe_get_fake_score(fake_score)
|
|
103
103
|
entity_ann = ImageAnnotation(
|
|
104
|
-
category_name=LayoutType.
|
|
104
|
+
category_name=LayoutType.TEXT,
|
|
105
105
|
bounding_box=bbox,
|
|
106
|
-
category_id=categories_dict_name_as_key[LayoutType.
|
|
106
|
+
category_id=categories_dict_name_as_key[LayoutType.TEXT],
|
|
107
107
|
score=score,
|
|
108
108
|
)
|
|
109
109
|
category_name = token_class_names_mapping[entity["label"]]
|
|
110
110
|
sub_cat_semantic = CategoryAnnotation(
|
|
111
111
|
category_name=category_name, category_id=token_class_to_id_mapping[get_type(category_name)]
|
|
112
112
|
)
|
|
113
|
-
entity_ann.dump_sub_category(WordType.
|
|
113
|
+
entity_ann.dump_sub_category(WordType.TOKEN_CLASS, sub_cat_semantic)
|
|
114
114
|
image.dump(entity_ann)
|
|
115
115
|
|
|
116
116
|
words = entity.get("words")
|
|
@@ -122,61 +122,61 @@ def xfund_to_image(
|
|
|
122
122
|
score = maybe_get_fake_score(fake_score)
|
|
123
123
|
|
|
124
124
|
ann = ImageAnnotation(
|
|
125
|
-
category_name=LayoutType.
|
|
125
|
+
category_name=LayoutType.WORD,
|
|
126
126
|
bounding_box=bbox,
|
|
127
|
-
category_id=categories_dict_name_as_key[LayoutType.
|
|
127
|
+
category_id=categories_dict_name_as_key[LayoutType.WORD],
|
|
128
128
|
score=score,
|
|
129
129
|
)
|
|
130
130
|
image.dump(ann)
|
|
131
|
-
entity_ann.dump_relationship(Relationships.
|
|
131
|
+
entity_ann.dump_relationship(Relationships.CHILD, ann.annotation_id)
|
|
132
132
|
sub_cat_semantic = CategoryAnnotation(
|
|
133
133
|
category_name=category_name, category_id=token_class_to_id_mapping[get_type(category_name)]
|
|
134
134
|
)
|
|
135
|
-
ann.dump_sub_category(WordType.
|
|
136
|
-
sub_cat_chars = ContainerAnnotation(category_name=WordType.
|
|
137
|
-
ann.dump_sub_category(WordType.
|
|
138
|
-
if sub_cat_semantic.category_name == TokenClasses.
|
|
135
|
+
ann.dump_sub_category(WordType.TOKEN_CLASS, sub_cat_semantic)
|
|
136
|
+
sub_cat_chars = ContainerAnnotation(category_name=WordType.CHARACTERS, value=word["text"])
|
|
137
|
+
ann.dump_sub_category(WordType.CHARACTERS, sub_cat_chars)
|
|
138
|
+
if sub_cat_semantic.category_name == TokenClasses.OTHER:
|
|
139
139
|
sub_cat_tag = CategoryAnnotation(
|
|
140
|
-
category_name=BioTag.
|
|
140
|
+
category_name=BioTag.OUTSIDE, category_id=tag_to_id_mapping[BioTag.OUTSIDE]
|
|
141
141
|
)
|
|
142
|
-
ann.dump_sub_category(WordType.
|
|
142
|
+
ann.dump_sub_category(WordType.TAG, sub_cat_tag)
|
|
143
143
|
# populating ner token to be used for training and evaluation
|
|
144
144
|
sub_cat_ner_tok = CategoryAnnotation(
|
|
145
|
-
category_name=BioTag.
|
|
145
|
+
category_name=BioTag.OUTSIDE, category_id=token_tag_to_id_mapping[BioTag.OUTSIDE]
|
|
146
146
|
)
|
|
147
|
-
ann.dump_sub_category(WordType.
|
|
147
|
+
ann.dump_sub_category(WordType.TOKEN_TAG, sub_cat_ner_tok)
|
|
148
148
|
elif not idx:
|
|
149
149
|
sub_cat_tag = CategoryAnnotation(
|
|
150
|
-
category_name=BioTag.
|
|
150
|
+
category_name=BioTag.BEGIN, category_id=tag_to_id_mapping[BioTag.BEGIN]
|
|
151
151
|
)
|
|
152
|
-
ann.dump_sub_category(WordType.
|
|
152
|
+
ann.dump_sub_category(WordType.TAG, sub_cat_tag)
|
|
153
153
|
sub_cat_ner_tok = CategoryAnnotation(
|
|
154
154
|
category_name=token_class_tag_to_token_class_with_tag(
|
|
155
|
-
get_type(sub_cat_semantic.category_name), BioTag.
|
|
155
|
+
get_type(sub_cat_semantic.category_name), BioTag.BEGIN
|
|
156
156
|
),
|
|
157
157
|
category_id=token_tag_to_id_mapping[
|
|
158
158
|
token_class_tag_to_token_class_with_tag(
|
|
159
|
-
get_type(sub_cat_semantic.category_name), BioTag.
|
|
159
|
+
get_type(sub_cat_semantic.category_name), BioTag.BEGIN
|
|
160
160
|
)
|
|
161
161
|
],
|
|
162
162
|
)
|
|
163
|
-
ann.dump_sub_category(WordType.
|
|
163
|
+
ann.dump_sub_category(WordType.TOKEN_TAG, sub_cat_ner_tok)
|
|
164
164
|
else:
|
|
165
165
|
sub_cat_tag = CategoryAnnotation(
|
|
166
|
-
category_name=BioTag.
|
|
166
|
+
category_name=BioTag.INSIDE, category_id=tag_to_id_mapping[BioTag.INSIDE]
|
|
167
167
|
)
|
|
168
|
-
ann.dump_sub_category(WordType.
|
|
168
|
+
ann.dump_sub_category(WordType.TAG, sub_cat_tag)
|
|
169
169
|
sub_cat_ner_tok = CategoryAnnotation(
|
|
170
170
|
category_name=token_class_tag_to_token_class_with_tag(
|
|
171
|
-
get_type(sub_cat_semantic.category_name), BioTag.
|
|
171
|
+
get_type(sub_cat_semantic.category_name), BioTag.INSIDE
|
|
172
172
|
),
|
|
173
173
|
category_id=token_tag_to_id_mapping[
|
|
174
174
|
token_class_tag_to_token_class_with_tag(
|
|
175
|
-
get_type(sub_cat_semantic.category_name), BioTag.
|
|
175
|
+
get_type(sub_cat_semantic.category_name), BioTag.INSIDE
|
|
176
176
|
)
|
|
177
177
|
],
|
|
178
178
|
)
|
|
179
|
-
ann.dump_sub_category(WordType.
|
|
179
|
+
ann.dump_sub_category(WordType.TOKEN_TAG, sub_cat_ner_tok)
|
|
180
180
|
|
|
181
181
|
entity_id_to_ann_id[entity["id"]].append(ann.annotation_id)
|
|
182
182
|
ann_id_to_entity_id[ann.annotation_id] = entity["id"]
|
|
@@ -184,7 +184,7 @@ def xfund_to_image(
|
|
|
184
184
|
entity_id_to_entity_link_id[entity["id"]].extend(entity["linking"])
|
|
185
185
|
|
|
186
186
|
# now populating semantic links
|
|
187
|
-
word_anns = image.get_annotation(category_names=LayoutType.
|
|
187
|
+
word_anns = image.get_annotation(category_names=LayoutType.WORD)
|
|
188
188
|
for word in word_anns:
|
|
189
189
|
entity_id = ann_id_to_entity_id[word.annotation_id]
|
|
190
190
|
all_linked_entities = list(chain(*entity_id_to_entity_link_id[entity_id]))
|
|
@@ -193,7 +193,7 @@ def xfund_to_image(
|
|
|
193
193
|
ann_ids.extend(entity_id_to_ann_id[linked_entity])
|
|
194
194
|
for ann_id in ann_ids:
|
|
195
195
|
if ann_id != word.annotation_id:
|
|
196
|
-
word.dump_relationship(Relationships.
|
|
196
|
+
word.dump_relationship(Relationships.SEMANTIC_ENTITY_LINK, ann_id)
|
|
197
197
|
|
|
198
198
|
if mapping_context.context_error:
|
|
199
199
|
return None
|
deepdoctection/pipe/__init__.py
CHANGED
|
@@ -22,7 +22,6 @@ Contains pipeline components that can be plugged into each other and predictors
|
|
|
22
22
|
|
|
23
23
|
from .anngen import *
|
|
24
24
|
from .base import *
|
|
25
|
-
from .cell import *
|
|
26
25
|
from .common import *
|
|
27
26
|
from .concurrency import *
|
|
28
27
|
from .doctectionpipe import *
|
|
@@ -33,5 +32,6 @@ from .order import *
|
|
|
33
32
|
from .refine import *
|
|
34
33
|
from .registry import *
|
|
35
34
|
from .segment import *
|
|
35
|
+
from .sub_layout import *
|
|
36
36
|
from .text import *
|
|
37
37
|
from .transform import *
|
deepdoctection/pipe/anngen.py
CHANGED
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
Module for datapoint populating helpers
|
|
20
20
|
"""
|
|
21
21
|
from dataclasses import asdict
|
|
22
|
-
from typing import
|
|
22
|
+
from typing import Mapping, Optional, Union
|
|
23
23
|
|
|
24
24
|
import numpy as np
|
|
25
25
|
|
|
26
|
-
from ..datapoint.annotation import CategoryAnnotation, ContainerAnnotation, ImageAnnotation
|
|
26
|
+
from ..datapoint.annotation import DEFAULT_CATEGORY_ID, CategoryAnnotation, ContainerAnnotation, ImageAnnotation
|
|
27
27
|
from ..datapoint.box import BoundingBox, local_to_global_coords, rescale_coords
|
|
28
28
|
from ..datapoint.image import Image
|
|
29
29
|
from ..extern.base import DetectionResult
|
|
@@ -44,7 +44,7 @@ class DatapointManager:
|
|
|
44
44
|
|
|
45
45
|
def __init__(self, service_id: str, model_id: Optional[str] = None) -> None:
|
|
46
46
|
self._datapoint: Optional[Image] = None
|
|
47
|
-
self._cache_anns:
|
|
47
|
+
self._cache_anns: dict[str, ImageAnnotation] = {}
|
|
48
48
|
self.datapoint_is_passed: bool = False
|
|
49
49
|
self.category_id_mapping: Optional[Mapping[int, int]] = None
|
|
50
50
|
self.service_id = service_id
|
|
@@ -155,7 +155,7 @@ class DatapointManager:
|
|
|
155
155
|
ann = ImageAnnotation(
|
|
156
156
|
category_name=detect_result.class_name,
|
|
157
157
|
bounding_box=box,
|
|
158
|
-
category_id=
|
|
158
|
+
category_id=detect_result.class_id,
|
|
159
159
|
score=detect_result.score,
|
|
160
160
|
service_id=self.service_id,
|
|
161
161
|
model_id=self.model_id,
|
|
@@ -174,7 +174,7 @@ class DatapointManager:
|
|
|
174
174
|
raise ValueError("image cannot be None")
|
|
175
175
|
ann.image.set_embedding(parent_ann.annotation_id, ann.bounding_box)
|
|
176
176
|
ann.image.set_embedding(self.datapoint.image_id, ann_global_box)
|
|
177
|
-
parent_ann.dump_relationship(Relationships.
|
|
177
|
+
parent_ann.dump_relationship(Relationships.CHILD, ann.annotation_id)
|
|
178
178
|
|
|
179
179
|
self.datapoint.dump(ann)
|
|
180
180
|
self._cache_anns[ann.annotation_id] = ann
|
|
@@ -189,7 +189,7 @@ class DatapointManager:
|
|
|
189
189
|
def set_category_annotation(
|
|
190
190
|
self,
|
|
191
191
|
category_name: ObjectTypes,
|
|
192
|
-
category_id: Optional[
|
|
192
|
+
category_id: Optional[int],
|
|
193
193
|
sub_cat_key: ObjectTypes,
|
|
194
194
|
annotation_id: str,
|
|
195
195
|
score: Optional[float] = None,
|
|
@@ -216,7 +216,7 @@ class DatapointManager:
|
|
|
216
216
|
) as annotation_context:
|
|
217
217
|
cat_ann = CategoryAnnotation(
|
|
218
218
|
category_name=category_name,
|
|
219
|
-
category_id=
|
|
219
|
+
category_id=category_id if category_id is not None else DEFAULT_CATEGORY_ID,
|
|
220
220
|
score=score,
|
|
221
221
|
service_id=self.service_id,
|
|
222
222
|
model_id=self.model_id,
|
|
@@ -230,10 +230,10 @@ class DatapointManager:
|
|
|
230
230
|
def set_container_annotation(
|
|
231
231
|
self,
|
|
232
232
|
category_name: ObjectTypes,
|
|
233
|
-
category_id: Optional[
|
|
233
|
+
category_id: Optional[int],
|
|
234
234
|
sub_cat_key: ObjectTypes,
|
|
235
235
|
annotation_id: str,
|
|
236
|
-
value: Union[str,
|
|
236
|
+
value: Union[str, list[str]],
|
|
237
237
|
score: Optional[float] = None,
|
|
238
238
|
) -> Optional[str]:
|
|
239
239
|
"""
|
|
@@ -260,7 +260,7 @@ class DatapointManager:
|
|
|
260
260
|
) as annotation_context:
|
|
261
261
|
cont_ann = ContainerAnnotation(
|
|
262
262
|
category_name=category_name,
|
|
263
|
-
category_id=
|
|
263
|
+
category_id=category_id if category_id is not None else DEFAULT_CATEGORY_ID,
|
|
264
264
|
value=value,
|
|
265
265
|
score=score,
|
|
266
266
|
service_id=self.service_id,
|
|
@@ -299,8 +299,6 @@ class DatapointManager:
|
|
|
299
299
|
else:
|
|
300
300
|
image = self.datapoint
|
|
301
301
|
assert image is not None, image
|
|
302
|
-
if image.summary is None:
|
|
303
|
-
image.summary = SummaryAnnotation()
|
|
304
302
|
|
|
305
303
|
ann: Union[CategoryAnnotation, ContainerAnnotation]
|
|
306
304
|
with MappingContextManager(
|
|
@@ -316,7 +314,7 @@ class DatapointManager:
|
|
|
316
314
|
if summary_value is not None:
|
|
317
315
|
ann = ContainerAnnotation(
|
|
318
316
|
category_name=summary_name,
|
|
319
|
-
category_id=
|
|
317
|
+
category_id=summary_number if summary_number else DEFAULT_CATEGORY_ID,
|
|
320
318
|
value=summary_value,
|
|
321
319
|
score=summary_score,
|
|
322
320
|
service_id=self.service_id,
|
|
@@ -326,7 +324,7 @@ class DatapointManager:
|
|
|
326
324
|
else:
|
|
327
325
|
ann = CategoryAnnotation(
|
|
328
326
|
category_name=summary_name,
|
|
329
|
-
category_id=
|
|
327
|
+
category_id=summary_number if summary_number is not None else DEFAULT_CATEGORY_ID,
|
|
330
328
|
score=summary_score,
|
|
331
329
|
service_id=self.service_id,
|
|
332
330
|
model_id=self.model_id,
|
deepdoctection/pipe/base.py
CHANGED
|
@@ -19,21 +19,33 @@
|
|
|
19
19
|
"""
|
|
20
20
|
Module for the base class for building pipelines
|
|
21
21
|
"""
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
22
24
|
from abc import ABC, abstractmethod
|
|
23
25
|
from collections import defaultdict
|
|
24
|
-
from
|
|
25
|
-
from typing import Any,
|
|
26
|
+
from dataclasses import dataclass, field
|
|
27
|
+
from typing import Any, Mapping, Optional, Union
|
|
26
28
|
from uuid import uuid1
|
|
27
29
|
|
|
28
30
|
from ..dataflow import DataFlow, MapData
|
|
29
31
|
from ..datapoint.image import Image
|
|
30
|
-
from ..extern.base import ImageTransformer, ObjectDetector, PdfMiner, TextRecognizer
|
|
31
32
|
from ..utils.context import timed_operation
|
|
32
|
-
from ..utils.detection_types import JsonDict
|
|
33
33
|
from ..utils.identifier import get_uuid_from_str
|
|
34
|
+
from ..utils.settings import ObjectTypes
|
|
34
35
|
from .anngen import DatapointManager
|
|
35
36
|
|
|
36
37
|
|
|
38
|
+
@dataclass(frozen=True)
|
|
39
|
+
class MetaAnnotation:
|
|
40
|
+
"""A immutable dataclass that stores information about what `Image` are being
|
|
41
|
+
modified through a pipeline compoenent."""
|
|
42
|
+
|
|
43
|
+
image_annotations: tuple[ObjectTypes, ...] = field(default=())
|
|
44
|
+
sub_categories: dict[ObjectTypes, set[ObjectTypes]] = field(default_factory=dict)
|
|
45
|
+
relationships: dict[ObjectTypes, set[ObjectTypes]] = field(default_factory=dict)
|
|
46
|
+
summaries: tuple[ObjectTypes, ...] = field(default=())
|
|
47
|
+
|
|
48
|
+
|
|
37
49
|
class PipelineComponent(ABC):
|
|
38
50
|
"""
|
|
39
51
|
Base class for pipeline components. Pipeline components are the parts that make up a pipeline. They contain the
|
|
@@ -54,15 +66,14 @@ class PipelineComponent(ABC):
|
|
|
54
66
|
planned.
|
|
55
67
|
"""
|
|
56
68
|
|
|
57
|
-
def __init__(self, name: str):
|
|
69
|
+
def __init__(self, name: str, model_id: Optional[str] = None) -> None:
|
|
58
70
|
"""
|
|
59
71
|
:param name: The name of the pipeline component. The name will be used to identify a pipeline component in a
|
|
60
72
|
pipeline. Use something that describe the task of the pipeline.
|
|
61
73
|
"""
|
|
62
74
|
self.name = name
|
|
63
75
|
self.service_id = self.get_service_id()
|
|
64
|
-
self.
|
|
65
|
-
self.dp_manager = DatapointManager(self.service_id)
|
|
76
|
+
self.dp_manager = DatapointManager(self.service_id, model_id)
|
|
66
77
|
self.timer_on = False
|
|
67
78
|
|
|
68
79
|
@abstractmethod
|
|
@@ -108,14 +119,14 @@ class PipelineComponent(ABC):
|
|
|
108
119
|
return MapData(df, self.pass_datapoint)
|
|
109
120
|
|
|
110
121
|
@abstractmethod
|
|
111
|
-
def clone(self) ->
|
|
122
|
+
def clone(self) -> PipelineComponent:
|
|
112
123
|
"""
|
|
113
124
|
Clone an instance
|
|
114
125
|
"""
|
|
115
126
|
raise NotImplementedError()
|
|
116
127
|
|
|
117
128
|
@abstractmethod
|
|
118
|
-
def get_meta_annotation(self) ->
|
|
129
|
+
def get_meta_annotation(self) -> MetaAnnotation:
|
|
119
130
|
"""
|
|
120
131
|
Get a dict of list of annotation type. The dict must contain
|
|
121
132
|
|
|
@@ -127,96 +138,30 @@ class PipelineComponent(ABC):
|
|
|
127
138
|
"""
|
|
128
139
|
raise NotImplementedError()
|
|
129
140
|
|
|
130
|
-
def _meta_has_all_types(self) -> None:
|
|
131
|
-
if not {"image_annotations", "sub_categories", "relationships", "summaries"}.issubset(
|
|
132
|
-
set(self.get_meta_annotation().keys())
|
|
133
|
-
):
|
|
134
|
-
raise TypeError(
|
|
135
|
-
f" 'get_meta_annotation' must return dict with all required keys. "
|
|
136
|
-
f"Got {self.get_meta_annotation().keys()}"
|
|
137
|
-
)
|
|
138
|
-
|
|
139
141
|
def get_service_id(self) -> str:
|
|
140
142
|
"""
|
|
141
143
|
Get the generating model
|
|
142
144
|
"""
|
|
143
145
|
return get_uuid_from_str(self.name)[:8]
|
|
144
146
|
|
|
145
|
-
|
|
146
|
-
class PredictorPipelineComponent(PipelineComponent, ABC):
|
|
147
|
-
"""
|
|
148
|
-
Lightweight abstract pipeline component class with `predictor`. Object detectors that only read in images as
|
|
149
|
-
numpy array and return `DetectResult`s are currently permitted.
|
|
150
|
-
"""
|
|
151
|
-
|
|
152
|
-
def __init__(
|
|
153
|
-
self,
|
|
154
|
-
name: str,
|
|
155
|
-
predictor: Union[ObjectDetector, PdfMiner, TextRecognizer],
|
|
156
|
-
) -> None:
|
|
147
|
+
def clear_predictor(self) -> None:
|
|
157
148
|
"""
|
|
158
|
-
|
|
159
|
-
:param predictor: An Object detector for predicting
|
|
149
|
+
Clear the predictor of the pipeline component if it has one. Needed for model updates during training.
|
|
160
150
|
"""
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
151
|
+
raise NotImplementedError(
|
|
152
|
+
"Maybe you forgot to implement this method in your pipeline component. This might "
|
|
153
|
+
"be the case when you run evaluation during training and need to update the "
|
|
154
|
+
"trained model in your pipeline component."
|
|
155
|
+
)
|
|
164
156
|
|
|
165
|
-
|
|
166
|
-
def clone(self) -> "PredictorPipelineComponent":
|
|
167
|
-
raise NotImplementedError()
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class LanguageModelPipelineComponent(PipelineComponent, ABC):
|
|
171
|
-
"""
|
|
172
|
-
Abstract pipeline component class with two attributes `tokenizer` and `language_model` .
|
|
173
|
-
"""
|
|
174
|
-
|
|
175
|
-
def __init__(
|
|
176
|
-
self,
|
|
177
|
-
name: str,
|
|
178
|
-
tokenizer: Any,
|
|
179
|
-
mapping_to_lm_input_func: Callable[..., Callable[[Image], Optional[Any]]],
|
|
180
|
-
):
|
|
157
|
+
def has_predictor(self) -> bool:
|
|
181
158
|
"""
|
|
182
|
-
|
|
183
|
-
:param tokenizer: Tokenizer, typing allows currently anything. This will be changed in the future
|
|
184
|
-
:param mapping_to_lm_input_func: Function mapping image to layout language model features
|
|
159
|
+
Check if the pipeline component has a predictor
|
|
185
160
|
"""
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
@abstractmethod
|
|
192
|
-
def clone(self) -> "LanguageModelPipelineComponent":
|
|
193
|
-
"""
|
|
194
|
-
Clone an instance
|
|
195
|
-
"""
|
|
196
|
-
raise NotImplementedError()
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
class ImageTransformPipelineComponent(PipelineComponent, ABC):
|
|
200
|
-
"""
|
|
201
|
-
Abstract pipeline component class with one model to transform images. This component is meant to be used at the
|
|
202
|
-
beginning of a pipeline
|
|
203
|
-
"""
|
|
204
|
-
|
|
205
|
-
def __init__(self, name: str, transform_predictor: ImageTransformer):
|
|
206
|
-
"""
|
|
207
|
-
:param name: Will be passed to base class
|
|
208
|
-
:param transform_predictor: An `ImageTransformer` for image transformation
|
|
209
|
-
"""
|
|
210
|
-
|
|
211
|
-
self.transform_predictor = transform_predictor
|
|
212
|
-
super().__init__(name)
|
|
213
|
-
|
|
214
|
-
@abstractmethod
|
|
215
|
-
def clone(self) -> "ImageTransformPipelineComponent":
|
|
216
|
-
"""
|
|
217
|
-
Clone an instance
|
|
218
|
-
"""
|
|
219
|
-
raise NotImplementedError()
|
|
161
|
+
if hasattr(self, "predictor"):
|
|
162
|
+
if self.predictor is not None:
|
|
163
|
+
return True
|
|
164
|
+
return False
|
|
220
165
|
|
|
221
166
|
|
|
222
167
|
class Pipeline(ABC):
|
|
@@ -262,7 +207,7 @@ class Pipeline(ABC):
|
|
|
262
207
|
df = pipe.analyze(input = "path/to/dir") # session_id is generated automatically
|
|
263
208
|
"""
|
|
264
209
|
|
|
265
|
-
def __init__(self, pipeline_component_list:
|
|
210
|
+
def __init__(self, pipeline_component_list: list[PipelineComponent]) -> None:
|
|
266
211
|
"""
|
|
267
212
|
:param pipeline_component_list: A list of pipeline components.
|
|
268
213
|
"""
|
|
@@ -305,7 +250,7 @@ class Pipeline(ABC):
|
|
|
305
250
|
"""
|
|
306
251
|
raise NotImplementedError()
|
|
307
252
|
|
|
308
|
-
def get_meta_annotation(self) ->
|
|
253
|
+
def get_meta_annotation(self) -> MetaAnnotation:
|
|
309
254
|
"""
|
|
310
255
|
Collects meta annotations from all pipeline components and summarizes the returned results
|
|
311
256
|
|
|
@@ -313,23 +258,24 @@ class Pipeline(ABC):
|
|
|
313
258
|
names and generated sub categories), relationships (dict with category names and generated
|
|
314
259
|
relationships) as well as summaries (list with sub categories)
|
|
315
260
|
"""
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
"summaries": [],
|
|
321
|
-
}
|
|
261
|
+
image_annotations: list[ObjectTypes] = []
|
|
262
|
+
sub_categories = defaultdict(set)
|
|
263
|
+
relationships = defaultdict(set)
|
|
264
|
+
summaries: list[ObjectTypes] = []
|
|
322
265
|
for component in self.pipe_component_list:
|
|
323
|
-
meta_anns =
|
|
324
|
-
|
|
325
|
-
for key, value in meta_anns
|
|
326
|
-
|
|
327
|
-
for key, value in meta_anns
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
266
|
+
meta_anns = component.get_meta_annotation()
|
|
267
|
+
image_annotations.extend(meta_anns.image_annotations)
|
|
268
|
+
for key, value in meta_anns.sub_categories.items():
|
|
269
|
+
sub_categories[key].update(value)
|
|
270
|
+
for key, value in meta_anns.relationships.items():
|
|
271
|
+
relationships[key].update(value)
|
|
272
|
+
summaries.extend(meta_anns.summaries)
|
|
273
|
+
return MetaAnnotation(
|
|
274
|
+
image_annotations=tuple(image_annotations),
|
|
275
|
+
sub_categories=dict(sub_categories),
|
|
276
|
+
relationships=dict(relationships),
|
|
277
|
+
summaries=tuple(summaries),
|
|
278
|
+
)
|
|
333
279
|
|
|
334
280
|
def get_pipeline_info(
|
|
335
281
|
self, service_id: Optional[str] = None, name: Optional[str] = None
|