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

Tried to optimize annotation fetching #5974

Merged
merged 21 commits into from
Apr 5, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
63 changes: 56 additions & 7 deletions cvat/apps/dataset_manager/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from django.db.models.query import Prefetch
from django.utils import timezone

from cvat.apps.engine import models, serializers
from cvat.apps.engine import models
from cvat.apps.engine.plugins import plugin_decorator
from cvat.apps.profiler import silk_profile

Expand Down Expand Up @@ -42,6 +42,13 @@ def values(cls):
def __str__(self):
return self.value

def _remove_none(dictionary):
keys = list(dictionary.keys())
for field in keys:
if dictionary[field] is None:
del dictionary[field]
return dictionary

def _merge_table_rows(rows, keys_for_merge, field_id):
# It is necessary to keep a stable order of original rows
# (e.g. for tracked boxes). Otherwise prev_box.frame can be bigger
Expand Down Expand Up @@ -313,6 +320,7 @@ def _create(self, data):
self._set_updated_date()
self.db_job.save()


def create(self, data):
self._create(data)

Expand Down Expand Up @@ -366,6 +374,7 @@ def _extend_attributes(attributeval_set, default_attribute_values):
attributeval_set.append(dotdict([
('spec_id', db_attr.spec_id),
('value', db_attr.value),
('id', None),
bsekachev marked this conversation as resolved.
Show resolved Hide resolved
]))

def _init_tags_from_db(self):
Expand Down Expand Up @@ -399,8 +408,15 @@ def _init_tags_from_db(self):
self._extend_attributes(db_tag.labeledimageattributeval_set,
self.db_attributes[db_tag.label_id]["all"].values())

serializer = serializers.LabeledImageSerializer(db_tags, many=True)
self.ir_data.tags = serializer.data
def convert_tag(tag):
tag['attributes'] = tag['labeledshapeattributeval_set']
del tag['labeledshapeattributeval_set']
bsekachev marked this conversation as resolved.
Show resolved Hide resolved

_remove_none(tag)
for attr in tag['attributes']:
del attr['id']

self.ir_data.tags = [convert_tag(value) for value in db_tags]

def _init_shapes_from_db(self):
db_shapes = self.db_job.labeledshape_set.prefetch_related(
Expand Down Expand Up @@ -453,8 +469,20 @@ def _init_shapes_from_db(self):
for shape_id, shape_elements in elements.items():
shapes[shape_id].elements = shape_elements

serializer = serializers.LabeledShapeSerializer(list(shapes.values()), many=True)
self.ir_data.shapes = serializer.data
bsekachev marked this conversation as resolved.
Show resolved Hide resolved
def convert_shape(shape):
shape['attributes'] = shape['labeledshapeattributeval_set']
del shape['labeledshapeattributeval_set']
_remove_none(shape)
for attr in shape['attributes']:
del attr['id']

if 'elements' in shape:
for element in shape['elements']:
convert_shape(element)

return shape

self.ir_data.shapes = [convert_shape(value) for value in shapes.values()]

def _init_tracks_from_db(self):
db_tracks = self.db_job.labeledtrack_set.prefetch_related(
Expand Down Expand Up @@ -512,6 +540,7 @@ def _init_tracks_from_db(self):
tracks = {}
elements = {}
for db_track in db_tracks:
db_track['elements'] = []
bsekachev marked this conversation as resolved.
Show resolved Hide resolved
db_track["trackedshape_set"] = _merge_table_rows(db_track["trackedshape_set"], {
'trackedshapeattributeval_set': [
'trackedshapeattributeval__value',
Expand Down Expand Up @@ -546,8 +575,28 @@ def _init_tracks_from_db(self):
for track_id, track_elements in elements.items():
tracks[track_id].elements = track_elements

serializer = serializers.LabeledTrackSerializer(list(tracks.values()), many=True)
self.ir_data.tracks = serializer.data
def convert_track(track):
track['shapes'] = track['trackedshape_set']
del track['trackedshape_set']
track['attributes'] = track['labeledtrackattributeval_set']
del track['labeledtrackattributeval_set']
_remove_none(track)
for attr in track['attributes']:
del attr['id']

for shape in track['shapes']:
_remove_none(shape)
shape['attributes'] = shape['trackedshapeattributeval_set']
bsekachev marked this conversation as resolved.
Show resolved Hide resolved
for attr in shape['attributes']:
del attr['id']

if 'elements' in track:
for element in track['elements']:
convert_track(element)

return track

self.ir_data.tracks = [convert_track(value) for value in tracks.values()]

def _init_version_from_db(self):
self.ir_data.version = 0 # FIXME: should be removed in the future
Expand Down
3 changes: 1 addition & 2 deletions cvat/apps/engine/backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,7 @@ def serialize_annotations():
for db_job_id in db_job_ids:
annotations = dm.task.get_job_data(db_job_id)
annotations_serializer = LabeledDataSerializer(data=annotations)
annotations_serializer.is_valid(raise_exception=True)
job_annotations.append(self._prepare_annotations(annotations_serializer.data, self._label_mapping))
job_annotations.append(self._prepare_annotations(annotations_serializer.initial_data, self._label_mapping))
bsekachev marked this conversation as resolved.
Show resolved Hide resolved

return job_annotations

Expand Down
3 changes: 1 addition & 2 deletions cvat/apps/engine/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,7 @@ def export_annotations(self, request, db_obj, export_func, callback, get_data=No

data = get_data(self._object.pk)
serializer = LabeledDataSerializer(data=data)
if serializer.is_valid(raise_exception=True):
return Response(serializer.data)
return Response(serializer.initial_data)
bsekachev marked this conversation as resolved.
Show resolved Hide resolved

def import_annotations(self, request, db_obj, import_func, rq_func, rq_id):
is_tus_request = request.headers.get('Upload-Length', None) is not None or \
Expand Down