learning-loop-node 0.14.0__tar.gz → 0.15.0__tar.gz
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 learning-loop-node might be problematic. Click here for more details.
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/PKG-INFO +3 -1
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/README.md +2 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_classes/__init__.py +2 -2
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_classes/image_metadata.py +5 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_classes/training.py +3 -2
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_exchanger.py +3 -3
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/detector_logic.py +6 -1
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/detector_node.py +63 -16
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/test_relevance_filter.py +3 -3
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/conftest.py +2 -2
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/trainer_logic_generic.py +16 -4
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/pyproject.toml +1 -1
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/annotation/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/annotation/annotator_logic.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/annotation/annotator_node.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_classes/annotations.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_classes/detections.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_classes/general.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_classes/socket_response.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/exceptions.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/inbox_filter/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/inbox_filter/cam_observation_history.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/inbox_filter/relevance_filter.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/outbox.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/about.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/backdoor_controls.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/detect.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/model_version_control.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/operation_mode.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/outbox_mode.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/upload.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/enums/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/enums/annotator.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/enums/detector.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/enums/general.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/enums/trainer.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/examples/novelty_score_updater.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/globals.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/helpers/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/helpers/background_tasks.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/helpers/environment_reader.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/helpers/gdrive_downloader.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/helpers/log_conf.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/helpers/misc.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/helpers/run.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/loop_communication.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/node.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/py.typed +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/rest.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/annotator/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/annotator/conftest.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/annotator/pytest.ini +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/annotator/test_annotator_node.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/conftest.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/inbox_filter/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/inbox_filter/test_observation.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/inbox_filter/test_relevance_group.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/inbox_filter/test_unexpected_observations_count.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/pytest.ini +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/test.jpg +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/test_client_communication.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/test_detector_node.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/test_outbox.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/testing_detector.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/conftest.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/pytest.ini +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/test_data/file_1.txt +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/test_data/file_2.txt +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/test_data/model.json +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/test_data_classes.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/test_downloader.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/test_learning_loop_node.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/test_helper.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/pytest.ini +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/state_helper.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/states/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/states/test_state_cleanup.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/states/test_state_detecting.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/states/test_state_download_train_model.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/states/test_state_prepare.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/states/test_state_sync_confusion_matrix.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/states/test_state_train.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/states/test_state_upload_detections.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/states/test_state_upload_model.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/test_errors.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/test_trainer_states.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/testing_trainer_logic.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/downloader.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/exceptions.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/executor.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/io_helpers.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/rest/__init__.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/rest/backdoor_controls.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/test_executor.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/trainer_logic.py +0 -0
- {learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/trainer_node.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: learning-loop-node
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: Python Library for Nodes which connect to the Zauberzeug Learning Loop
|
|
5
5
|
Home-page: https://github.com/zauberzeug/learning_loop_node
|
|
6
6
|
License: MIT
|
|
@@ -100,6 +100,8 @@ You can additionally provide the following camera parameters:
|
|
|
100
100
|
- `autoupload`: configures auto-submission to the learning loop; `filtered` (default), `all`, `disabled` (example curl parameter `-H 'autoupload: all'`)
|
|
101
101
|
- `camera-id`: a string which groups images for submission together (example curl parameter `-H 'camera-id: front_cam'`)
|
|
102
102
|
|
|
103
|
+
To use the socketio interface, the caller needs to connect to the detector node's socketio server and emit the `detect` or `batch_detect` event with the image data and image metadata. Example code can be found [in the rosys implementation](https://github.com/zauberzeug/rosys/blob/main/rosys/vision/detector_hardware.py).
|
|
104
|
+
|
|
103
105
|
The detector also has a sio **upload endpoint** that can be used to upload images and detections to the learning loop. The function receives a json dictionary, with the following entries:
|
|
104
106
|
|
|
105
107
|
- `image`: the image data in jpg format
|
|
@@ -60,6 +60,8 @@ You can additionally provide the following camera parameters:
|
|
|
60
60
|
- `autoupload`: configures auto-submission to the learning loop; `filtered` (default), `all`, `disabled` (example curl parameter `-H 'autoupload: all'`)
|
|
61
61
|
- `camera-id`: a string which groups images for submission together (example curl parameter `-H 'camera-id: front_cam'`)
|
|
62
62
|
|
|
63
|
+
To use the socketio interface, the caller needs to connect to the detector node's socketio server and emit the `detect` or `batch_detect` event with the image data and image metadata. Example code can be found [in the rosys implementation](https://github.com/zauberzeug/rosys/blob/main/rosys/vision/detector_hardware.py).
|
|
64
|
+
|
|
63
65
|
The detector also has a sio **upload endpoint** that can be used to upload images and detections to the learning loop. The function receives a json dictionary, with the following entries:
|
|
64
66
|
|
|
65
67
|
- `image`: the image data in jpg format
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_classes/__init__.py
RENAMED
|
@@ -3,7 +3,7 @@ from .detections import (BoxDetection, ClassificationDetection, Detections, Obse
|
|
|
3
3
|
SegmentationDetection, Shape)
|
|
4
4
|
from .general import (AboutResponse, AnnotationNodeStatus, Category, Context, DetectionStatus, ErrorConfiguration,
|
|
5
5
|
ModelInformation, ModelVersionResponse, NodeState, NodeStatus)
|
|
6
|
-
from .image_metadata import ImageMetadata
|
|
6
|
+
from .image_metadata import ImageMetadata, ImagesMetadata
|
|
7
7
|
from .socket_response import SocketResponse
|
|
8
8
|
from .training import Errors, PretrainedModel, Training, TrainingError, TrainingOut, TrainingStateData, TrainingStatus
|
|
9
9
|
|
|
@@ -12,7 +12,7 @@ __all__ = [
|
|
|
12
12
|
'BoxDetection', 'ClassificationDetection', 'ImageMetadata', 'Observation', 'Point', 'PointDetection',
|
|
13
13
|
'SegmentationDetection', 'Shape', 'Detections',
|
|
14
14
|
'AnnotationNodeStatus', 'Category', 'Context', 'DetectionStatus', 'ErrorConfiguration',
|
|
15
|
-
'ModelInformation', 'NodeState', 'NodeStatus', 'ModelVersionResponse',
|
|
15
|
+
'ModelInformation', 'NodeState', 'NodeStatus', 'ModelVersionResponse', 'ImagesMetadata',
|
|
16
16
|
'SocketResponse',
|
|
17
17
|
'Errors', 'PretrainedModel', 'Training',
|
|
18
18
|
'TrainingError', 'TrainingOut', 'TrainingStateData', 'TrainingStatus',
|
|
@@ -35,3 +35,8 @@ class ImageMetadata():
|
|
|
35
35
|
|
|
36
36
|
def __len__(self):
|
|
37
37
|
return len(self.box_detections) + len(self.point_detections) + len(self.segmentation_detections) + len(self.classification_detections)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(**KWONLY_SLOTS)
|
|
41
|
+
class ImagesMetadata():
|
|
42
|
+
items: List[ImageMetadata] = field(default_factory=list, metadata={'description': 'List of image metadata'})
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_classes/training.py
RENAMED
|
@@ -8,6 +8,7 @@ from uuid import uuid4
|
|
|
8
8
|
|
|
9
9
|
from ..enums import TrainerState
|
|
10
10
|
from ..helpers.misc import create_image_folder, create_training_folder
|
|
11
|
+
|
|
11
12
|
# pylint: disable=no-name-in-module
|
|
12
13
|
from .general import Category, Context
|
|
13
14
|
|
|
@@ -52,7 +53,7 @@ class Training():
|
|
|
52
53
|
training_folder: str # f'{project_folder}/trainings/{trainings_id}'
|
|
53
54
|
|
|
54
55
|
categories: List[Category]
|
|
55
|
-
hyperparameters:
|
|
56
|
+
hyperparameters: Dict[str, Any]
|
|
56
57
|
|
|
57
58
|
training_number: int
|
|
58
59
|
training_state: str
|
|
@@ -63,7 +64,7 @@ class Training():
|
|
|
63
64
|
base_model_uuid: Optional[str] = None # model uuid to continue training (is loaded from loop)
|
|
64
65
|
|
|
65
66
|
# NOTE: these are set later after the model has been uploaded
|
|
66
|
-
image_data: Optional[List[
|
|
67
|
+
image_data: Optional[List[Dict]] = None
|
|
67
68
|
skipped_image_count: Optional[int] = None
|
|
68
69
|
model_uuid_for_detecting: Optional[str] = None # Model uuid to load from the loop after training and upload
|
|
69
70
|
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_exchanger.py
RENAMED
|
@@ -7,7 +7,7 @@ from glob import glob
|
|
|
7
7
|
from http import HTTPStatus
|
|
8
8
|
from io import BytesIO
|
|
9
9
|
from time import time
|
|
10
|
-
from typing import Dict, List, Optional
|
|
10
|
+
from typing import Any, Dict, List, Optional
|
|
11
11
|
|
|
12
12
|
import aiofiles # type: ignore
|
|
13
13
|
|
|
@@ -68,7 +68,7 @@ class DataExchanger():
|
|
|
68
68
|
assert response.status_code == 200, response
|
|
69
69
|
return (response.json())['image_ids']
|
|
70
70
|
|
|
71
|
-
async def download_images_data(self, image_uuids: List[str], chunk_size: int = 100) -> List[Dict]:
|
|
71
|
+
async def download_images_data(self, image_uuids: List[str], chunk_size: int = 100) -> List[Dict[str, Any]]:
|
|
72
72
|
"""Download image annotations, tags, set and other information for the given image uuids."""
|
|
73
73
|
logging.info('Fetching annotations, tags, sets, etc. for %s images..', len(image_uuids))
|
|
74
74
|
|
|
@@ -78,7 +78,7 @@ class DataExchanger():
|
|
|
78
78
|
return []
|
|
79
79
|
|
|
80
80
|
progress_factor = 0.5 / num_image_ids # first 50% of progress is for downloading data
|
|
81
|
-
images_data: List[Dict] = []
|
|
81
|
+
images_data: List[Dict[str, Any]] = []
|
|
82
82
|
for i in range(0, num_image_ids, chunk_size):
|
|
83
83
|
self.progress = i * progress_factor
|
|
84
84
|
chunk_ids = image_uuids[i:i+chunk_size]
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
from abc import abstractmethod
|
|
3
3
|
from typing import List, Optional
|
|
4
4
|
|
|
5
|
-
from ..data_classes import ImageMetadata, ModelInformation
|
|
5
|
+
from ..data_classes import ImageMetadata, ImagesMetadata, ModelInformation
|
|
6
6
|
from ..globals import GLOBALS
|
|
7
7
|
from .exceptions import NodeNeedsRestartError
|
|
8
8
|
|
|
@@ -52,3 +52,8 @@ class DetectorLogic():
|
|
|
52
52
|
def evaluate(self, image: bytes) -> ImageMetadata:
|
|
53
53
|
"""Evaluate the image and return the detections.
|
|
54
54
|
The object should return empty detections if it is not initialized"""
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def batch_evaluate(self, images: List[bytes]) -> ImagesMetadata:
|
|
58
|
+
"""Evaluate a batch of images and return the detections.
|
|
59
|
+
The object should return empty detections if it is not initialized"""
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/detector_node.py
RENAMED
|
@@ -6,24 +6,15 @@ import subprocess
|
|
|
6
6
|
import sys
|
|
7
7
|
from dataclasses import asdict
|
|
8
8
|
from datetime import datetime
|
|
9
|
-
from typing import Dict, List, Optional
|
|
9
|
+
from typing import Dict, List, Optional
|
|
10
10
|
|
|
11
|
-
import numpy as np
|
|
12
11
|
import socketio
|
|
13
12
|
from dacite import from_dict
|
|
14
13
|
from fastapi.encoders import jsonable_encoder
|
|
15
14
|
from socketio import AsyncClient
|
|
16
15
|
|
|
17
|
-
from ..data_classes import (
|
|
18
|
-
|
|
19
|
-
Category,
|
|
20
|
-
Context,
|
|
21
|
-
DetectionStatus,
|
|
22
|
-
ImageMetadata,
|
|
23
|
-
ModelInformation,
|
|
24
|
-
ModelVersionResponse,
|
|
25
|
-
Shape,
|
|
26
|
-
)
|
|
16
|
+
from ..data_classes import (AboutResponse, Category, Context, DetectionStatus, ImageMetadata, ImagesMetadata,
|
|
17
|
+
ModelInformation, ModelVersionResponse, Shape)
|
|
27
18
|
from ..data_classes.socket_response import SocketResponse
|
|
28
19
|
from ..data_exchanger import DataExchanger, DownloadError
|
|
29
20
|
from ..enums import OperationMode, VersionMode
|
|
@@ -238,8 +229,29 @@ class DetectorNode(Node):
|
|
|
238
229
|
return detection_dict
|
|
239
230
|
except Exception as e:
|
|
240
231
|
self.log.exception('could not detect via socketio')
|
|
241
|
-
with open('/tmp/bad_img_from_socket_io.jpg', 'wb') as f:
|
|
242
|
-
|
|
232
|
+
# with open('/tmp/bad_img_from_socket_io.jpg', 'wb') as f:
|
|
233
|
+
# f.write(data['image'])
|
|
234
|
+
return {'error': str(e)}
|
|
235
|
+
|
|
236
|
+
@self.sio.event
|
|
237
|
+
async def batch_detect(sid, data: Dict) -> Dict:
|
|
238
|
+
try:
|
|
239
|
+
det = await self.get_batch_detections(
|
|
240
|
+
raw_images=data['images'],
|
|
241
|
+
tags=data.get('tags', []),
|
|
242
|
+
camera_id=data.get('camera-id', None) or data.get('mac', None),
|
|
243
|
+
source=data.get('source', None),
|
|
244
|
+
autoupload=data.get('autoupload', None),
|
|
245
|
+
creation_date=data.get('creation_date', None)
|
|
246
|
+
)
|
|
247
|
+
if det is None:
|
|
248
|
+
return {'error': 'no model loaded'}
|
|
249
|
+
detection_dict = jsonable_encoder(asdict(det))
|
|
250
|
+
return detection_dict
|
|
251
|
+
except Exception as e:
|
|
252
|
+
self.log.exception('could not detect via socketio')
|
|
253
|
+
# with open('/tmp/bad_img_from_socket_io.jpg', 'wb') as f:
|
|
254
|
+
# f.write(data['image'])
|
|
243
255
|
return {'error': str(e)}
|
|
244
256
|
|
|
245
257
|
@self.sio.event
|
|
@@ -479,13 +491,14 @@ class DetectorNode(Node):
|
|
|
479
491
|
|
|
480
492
|
async def get_detections(self,
|
|
481
493
|
raw_image: bytes,
|
|
482
|
-
camera_id: Optional[str],
|
|
483
494
|
tags: List[str],
|
|
495
|
+
*,
|
|
496
|
+
camera_id: Optional[str] = None,
|
|
484
497
|
source: Optional[str] = None,
|
|
485
498
|
autoupload: Optional[str] = None,
|
|
486
499
|
creation_date: Optional[str] = None) -> ImageMetadata:
|
|
487
500
|
""" Main processing function for the detector node when an image is received via REST or SocketIO.
|
|
488
|
-
This function infers the detections from the image, cares about uploading to the loop and returns the detections as
|
|
501
|
+
This function infers the detections from the image, cares about uploading to the loop and returns the detections as ImageMetadata object.
|
|
489
502
|
Note: raw_image is a numpy array of type uint8, but not in the correct shape!
|
|
490
503
|
It can be converted e.g. using cv2.imdecode(raw_image, cv2.IMREAD_COLOR)"""
|
|
491
504
|
|
|
@@ -511,6 +524,40 @@ class DetectorNode(Node):
|
|
|
511
524
|
self.log.error('unknown autoupload value %s', autoupload)
|
|
512
525
|
return detections
|
|
513
526
|
|
|
527
|
+
async def get_batch_detections(self,
|
|
528
|
+
raw_images: List[bytes],
|
|
529
|
+
tags: List[str],
|
|
530
|
+
*,
|
|
531
|
+
camera_id: Optional[str] = None,
|
|
532
|
+
source: Optional[str] = None,
|
|
533
|
+
autoupload: Optional[str] = None,
|
|
534
|
+
creation_date: Optional[str] = None) -> ImagesMetadata:
|
|
535
|
+
""" Processing function for the detector node when a a batch inference is requested via SocketIO.
|
|
536
|
+
This function infers the detections from all images, cares about uploading to the loop and returns the detections as a list of ImageMetadata."""
|
|
537
|
+
|
|
538
|
+
await self.detection_lock.acquire()
|
|
539
|
+
all_detections = await run.io_bound(self.detector_logic.batch_evaluate, raw_images)
|
|
540
|
+
self.detection_lock.release()
|
|
541
|
+
|
|
542
|
+
for detections, raw_image in zip(all_detections.items, raw_images):
|
|
543
|
+
fix_shape_detections(detections)
|
|
544
|
+
n_bo, n_cl = len(detections.box_detections), len(detections.classification_detections)
|
|
545
|
+
n_po, n_se = len(detections.point_detections), len(detections.segmentation_detections)
|
|
546
|
+
self.log.debug('Detected: %d boxes, %d points, %d segs, %d classes', n_bo, n_po, n_se, n_cl)
|
|
547
|
+
|
|
548
|
+
autoupload = autoupload or 'filtered'
|
|
549
|
+
if autoupload == 'filtered' and camera_id is not None:
|
|
550
|
+
background_tasks.create(self.relevance_filter.may_upload_detections(
|
|
551
|
+
detections, camera_id, raw_image, tags, source, creation_date
|
|
552
|
+
))
|
|
553
|
+
elif autoupload == 'all':
|
|
554
|
+
background_tasks.create(self.outbox.save(raw_image, detections, tags, source, creation_date))
|
|
555
|
+
elif autoupload == 'disabled':
|
|
556
|
+
pass
|
|
557
|
+
else:
|
|
558
|
+
self.log.error('unknown autoupload value %s', autoupload)
|
|
559
|
+
return all_detections
|
|
560
|
+
|
|
514
561
|
async def upload_images(
|
|
515
562
|
self, *,
|
|
516
563
|
images: List[bytes],
|
|
@@ -30,10 +30,10 @@ async def test_filter_is_used_by_node(test_detector_node: DetectorNode, autouplo
|
|
|
30
30
|
assert test_detector_node.outbox.path.startswith('/tmp')
|
|
31
31
|
assert len(get_outbox_files(test_detector_node.outbox)) == 0
|
|
32
32
|
|
|
33
|
-
image = np.fromfile(file=test_image_path, dtype=np.uint8)
|
|
34
|
-
_ = await test_detector_node.get_detections(image, '00:.....',
|
|
33
|
+
image = bytes(np.fromfile(file=test_image_path, dtype=np.uint8))
|
|
34
|
+
_ = await test_detector_node.get_detections(image, tags=[], camera_id='00:.....', autoupload=autoupload)
|
|
35
35
|
# NOTE adding second images with identical detections
|
|
36
|
-
_ = await test_detector_node.get_detections(image, '00:.....',
|
|
36
|
+
_ = await test_detector_node.get_detections(image, tags=[], camera_id='00:.....', autoupload=autoupload)
|
|
37
37
|
await asyncio.sleep(.5) # files are stored asynchronously
|
|
38
38
|
|
|
39
39
|
assert len(get_outbox_files(test_detector_node.outbox)) == expected_file_count, \
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/conftest.py
RENAMED
|
@@ -35,7 +35,7 @@ async def test_initialized_trainer_node():
|
|
|
35
35
|
'training_number': 0,
|
|
36
36
|
'model_variant': '',
|
|
37
37
|
'hyperparameters': {
|
|
38
|
-
'resolution':
|
|
38
|
+
'resolution': 832,
|
|
39
39
|
'fliplr': 0.5,
|
|
40
40
|
'flipud': 0.5}
|
|
41
41
|
})
|
|
@@ -58,7 +58,7 @@ async def test_initialized_trainer():
|
|
|
58
58
|
'training_number': 0,
|
|
59
59
|
'model_variant': '',
|
|
60
60
|
'hyperparameters': {
|
|
61
|
-
'resolution':
|
|
61
|
+
'resolution': 832,
|
|
62
62
|
'fliplr': 0.5,
|
|
63
63
|
'flipud': 0.5}
|
|
64
64
|
})
|
|
@@ -6,13 +6,25 @@ import sys
|
|
|
6
6
|
import time
|
|
7
7
|
from abc import ABC, abstractmethod
|
|
8
8
|
from dataclasses import asdict
|
|
9
|
-
from typing import TYPE_CHECKING, Callable, Coroutine, Dict, List, Optional
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Callable, Coroutine, Dict, List, Optional
|
|
10
10
|
|
|
11
11
|
from fastapi.encoders import jsonable_encoder
|
|
12
12
|
|
|
13
|
-
from ..data_classes import
|
|
13
|
+
from ..data_classes import (
|
|
14
|
+
Context,
|
|
15
|
+
Errors,
|
|
16
|
+
PretrainedModel,
|
|
17
|
+
Training,
|
|
18
|
+
TrainingOut,
|
|
19
|
+
TrainingStateData,
|
|
20
|
+
TrainingStatus,
|
|
21
|
+
)
|
|
14
22
|
from ..enums import TrainerState
|
|
15
|
-
from ..helpers.misc import
|
|
23
|
+
from ..helpers.misc import (
|
|
24
|
+
create_project_folder,
|
|
25
|
+
delete_all_training_folders,
|
|
26
|
+
is_valid_uuid4,
|
|
27
|
+
)
|
|
16
28
|
from .downloader import TrainingsDownloader
|
|
17
29
|
from .exceptions import CriticalError, NodeNeedsRestartError
|
|
18
30
|
from .io_helpers import ActiveTrainingIO, EnvironmentVars, LastTrainingIO
|
|
@@ -66,7 +78,7 @@ class TrainerLogicGeneric(ABC):
|
|
|
66
78
|
return self._training
|
|
67
79
|
|
|
68
80
|
@property
|
|
69
|
-
def hyperparameters(self) ->
|
|
81
|
+
def hyperparameters(self) -> Dict[str, Any]:
|
|
70
82
|
assert self._training is not None, 'Training should have data'
|
|
71
83
|
return self._training.hyperparameters
|
|
72
84
|
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/annotation/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/data_classes/general.py
RENAMED
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/__init__.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/outbox.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/__init__.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/about.py
RENAMED
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/detect.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/detector/rest/upload.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/enums/__init__.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/enums/annotator.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/enums/detector.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/helpers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/helpers/log_conf.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/loop_communication.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/pytest.ini
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/detector/test.jpg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/__init__.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/conftest.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/general/pytest.ini
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/test_helper.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/__init__.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/tests/trainer/pytest.ini
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/__init__.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/downloader.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/exceptions.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/executor.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/io_helpers.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/rest/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/test_executor.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/trainer_logic.py
RENAMED
|
File without changes
|
{learning_loop_node-0.14.0 → learning_loop_node-0.15.0}/learning_loop_node/trainer/trainer_node.py
RENAMED
|
File without changes
|