-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Model manager for DL models to preannotate images (#289)
- Loading branch information
Showing
26 changed files
with
1,421 additions
and
354 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Generated by Django 2.1.3 on 2019-01-24 14:05 | ||
|
||
import cvat.apps.auto_annotation.models | ||
from django.conf import settings | ||
import django.core.files.storage | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='AnnotationModel', | ||
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('name', cvat.apps.auto_annotation.models.SafeCharField(max_length=256)), | ||
('created_date', models.DateTimeField(auto_now_add=True)), | ||
('updated_date', models.DateTimeField(auto_now_add=True)), | ||
('model_file', models.FileField(storage=django.core.files.storage.FileSystemStorage(), upload_to=cvat.apps.auto_annotation.models.upload_path_handler)), | ||
('weights_file', models.FileField(storage=django.core.files.storage.FileSystemStorage(), upload_to=cvat.apps.auto_annotation.models.upload_path_handler)), | ||
('labelmap_file', models.FileField(storage=django.core.files.storage.FileSystemStorage(), upload_to=cvat.apps.auto_annotation.models.upload_path_handler)), | ||
('interpretation_file', models.FileField(storage=django.core.files.storage.FileSystemStorage(), upload_to=cvat.apps.auto_annotation.models.upload_path_handler)), | ||
('shared', models.BooleanField(default=False)), | ||
('primary', models.BooleanField(default=False)), | ||
('framework', models.CharField(default=cvat.apps.auto_annotation.models.FrameworkChoice('openvino'), max_length=32)), | ||
('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), | ||
], | ||
options={ | ||
'default_permissions': (), | ||
}, | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
# Copyright (C) 2018 Intel Corporation | ||
# | ||
# SPDX-License-Identifier: MIT | ||
|
||
import django_rq | ||
import os | ||
import rq | ||
import shutil | ||
|
||
from django.db import transaction | ||
from django.utils import timezone | ||
from django.conf import settings | ||
|
||
from .models import AnnotationModel, FrameworkChoice | ||
|
||
def _remove_old_file(model_file_field): | ||
if model_file_field and os.path.exists(model_file_field.name): | ||
os.remove(model_file_field.name) | ||
|
||
@transaction.atomic | ||
def _update_dl_model_thread(dl_model_id, model_file, weights_file, labelmap_file, interpretation_file, run_tests): | ||
def _get_file_content(filename): | ||
return os.path.basename(filename), open(filename, "rb") | ||
|
||
job = rq.get_current_job() | ||
job.meta["progress"] = "Saving data" | ||
job.save_meta() | ||
|
||
dl_model = AnnotationModel.objects.select_for_update().get(pk=dl_model_id) | ||
|
||
#save files in case of files should be uploaded from share | ||
if model_file: | ||
_remove_old_file(dl_model.model_file) | ||
dl_model.model_file.save(*_get_file_content(model_file)) | ||
if weights_file: | ||
_remove_old_file(dl_model.weights_file) | ||
dl_model.weights_file.save(*_get_file_content(weights_file)) | ||
if labelmap_file: | ||
_remove_old_file(dl_model.labelmap_file) | ||
dl_model.labelmap_file.save(*_get_file_content(labelmap_file)) | ||
if interpretation_file: | ||
_remove_old_file(dl_model.interpretation_file) | ||
dl_model.interpretation_file.save(*_get_file_content(interpretation_file)) | ||
|
||
if run_tests: | ||
#only for testing | ||
import time | ||
time.sleep(3) | ||
job.meta["progress"] = "Test started" | ||
job.save_meta() | ||
time.sleep(5) | ||
job.meta["progress"] = "Test finished" | ||
|
||
@transaction.atomic | ||
def update_model(dl_model_id, name, model_file, weights_file, labelmap_file, interpretation_file, storage, is_shared): | ||
|
||
def get_abs_path(share_path): | ||
if not share_path: | ||
return share_path | ||
share_root = settings.SHARE_ROOT | ||
relpath = os.path.normpath(share_path).lstrip('/') | ||
if '..' in relpath.split(os.path.sep): | ||
raise Exception('Permission denied') | ||
abspath = os.path.abspath(os.path.join(share_root, relpath)) | ||
if os.path.commonprefix([share_root, abspath]) != share_root: | ||
raise Exception('Bad file path on share: ' + abspath) | ||
return abspath | ||
|
||
dl_model = AnnotationModel.objects.select_for_update().get(pk=dl_model_id) | ||
|
||
if name: | ||
dl_model.name = name | ||
|
||
if is_shared != None: | ||
dl_model.shared = is_shared | ||
|
||
run_tests = bool(model_file or weights_file or labelmap_file or interpretation_file) | ||
if storage != "local": | ||
model_file = get_abs_path(model_file) | ||
weights_file = get_abs_path(weights_file) | ||
labelmap_file = get_abs_path(labelmap_file) | ||
interpretation_file = get_abs_path(interpretation_file) | ||
else: | ||
if model_file: | ||
_remove_old_file(dl_model.model_file) | ||
dl_model.model_file = model_file | ||
model_file = None | ||
if weights_file: | ||
_remove_old_file(dl_model.weights_file) | ||
dl_model.weights_file = weights_file | ||
weights_file = None | ||
if labelmap_file: | ||
_remove_old_file(dl_model.labelmap_file) | ||
dl_model.labelmap_file = labelmap_file | ||
labelmap_file = None | ||
if interpretation_file: | ||
_remove_old_file(dl_model.interpretation_file) | ||
dl_model.interpretation_file = interpretation_file | ||
interpretation_file = None | ||
|
||
dl_model.updated_date = timezone.now() | ||
dl_model.save() | ||
|
||
rq_id = "auto_annotation.create.{}".format(dl_model_id) | ||
queue = django_rq.get_queue('default') | ||
queue.enqueue_call( | ||
func = _update_dl_model_thread, | ||
args = (dl_model_id, | ||
model_file, | ||
weights_file, | ||
labelmap_file, | ||
interpretation_file, | ||
run_tests, | ||
), | ||
job_id = rq_id | ||
) | ||
|
||
return rq_id | ||
|
||
def create_empty(owner, framework=FrameworkChoice.OPENVINO): | ||
db_model = AnnotationModel( | ||
owner=owner, | ||
) | ||
db_model.save() | ||
|
||
model_path = db_model.get_dirname() | ||
if os.path.isdir(model_path): | ||
shutil.rmtree(model_path) | ||
os.mkdir(model_path) | ||
|
||
return db_model.id | ||
|
||
@transaction.atomic | ||
def delete(dl_model_id): | ||
dl_model = AnnotationModel.objects.select_for_update().get(pk=dl_model_id) | ||
if dl_model: | ||
if dl_model.primary: | ||
raise Exception("Can not delete primary model {}".format(dl_model_id)) | ||
|
||
dl_model.delete() | ||
shutil.rmtree(dl_model.get_dirname(), ignore_errors=True) | ||
else: | ||
raise Exception("Requested DL model {} doesn't exist".format(dl_model_id)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Copyright (C) 2018 Intel Corporation | ||
# | ||
# SPDX-License-Identifier: MIT | ||
|
||
import rules | ||
|
||
from cvat.apps.authentication.auth import has_admin_role, has_user_role | ||
|
||
@rules.predicate | ||
def is_model_owner(db_user, db_dl_model): | ||
return db_dl_model.owner == db_user | ||
|
||
@rules.predicate | ||
def is_shared_model(_, db_dl_model): | ||
return db_dl_model.shared | ||
|
||
@rules.predicate | ||
def is_primary_model(_, db_dl_model): | ||
return db_dl_model.primary | ||
|
||
def setup_permissions(): | ||
rules.add_perm('auto_annotation.model.create', has_admin_role | has_user_role) | ||
|
||
rules.add_perm('auto_annotation.model.update', (has_admin_role | is_model_owner) & ~is_primary_model) | ||
|
||
rules.add_perm('auto_annotation.model.delete', (has_admin_role | is_model_owner) & ~is_primary_model) | ||
|
||
rules.add_perm('auto_annotation.model.access', has_admin_role | is_model_owner | | ||
is_shared_model | is_primary_model) |
Oops, something went wrong.