learning-loop-node 0.13.7__tar.gz → 0.14.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.13.7 → learning_loop_node-0.14.0}/PKG-INFO +33 -38
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/README.md +32 -37
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/detector_logic.py +2 -4
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/detector_node.py +44 -30
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/inbox_filter/relevance_filter.py +11 -9
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/outbox.py +134 -44
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/rest/detect.py +3 -3
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/rest/upload.py +4 -3
- learning_loop_node-0.14.0/learning_loop_node/helpers/background_tasks.py +78 -0
- learning_loop_node-0.14.0/learning_loop_node/helpers/run.py +21 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/node.py +11 -4
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/annotator/conftest.py +9 -4
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/annotator/test_annotator_node.py +10 -2
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/inbox_filter/test_unexpected_observations_count.py +4 -3
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/test_client_communication.py +1 -23
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/test_outbox.py +7 -16
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/general/conftest.py +8 -2
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/pyproject.toml +1 -1
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/annotation/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/annotation/annotator_logic.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/annotation/annotator_node.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/data_classes/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/data_classes/annotations.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/data_classes/detections.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/data_classes/general.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/data_classes/image_metadata.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/data_classes/socket_response.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/data_classes/training.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/data_exchanger.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/exceptions.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/inbox_filter/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/inbox_filter/cam_observation_history.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/rest/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/rest/about.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/rest/backdoor_controls.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/rest/model_version_control.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/rest/operation_mode.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/rest/outbox_mode.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/enums/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/enums/annotator.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/enums/detector.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/enums/general.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/enums/trainer.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/examples/novelty_score_updater.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/globals.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/helpers/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/helpers/environment_reader.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/helpers/gdrive_downloader.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/helpers/log_conf.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/helpers/misc.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/loop_communication.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/py.typed +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/rest.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/annotator/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/annotator/pytest.ini +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/conftest.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/inbox_filter/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/inbox_filter/test_observation.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/inbox_filter/test_relevance_group.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/pytest.ini +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/test.jpg +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/test_detector_node.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/test_relevance_filter.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/detector/testing_detector.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/general/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/general/pytest.ini +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/general/test_data/file_1.txt +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/general/test_data/file_2.txt +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/general/test_data/model.json +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/general/test_data_classes.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/general/test_downloader.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/general/test_learning_loop_node.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/test_helper.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/conftest.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/pytest.ini +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/state_helper.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/states/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/states/test_state_cleanup.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/states/test_state_detecting.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/states/test_state_download_train_model.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/states/test_state_prepare.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/states/test_state_sync_confusion_matrix.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/states/test_state_train.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/states/test_state_upload_detections.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/states/test_state_upload_model.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/test_errors.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/test_trainer_states.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/tests/trainer/testing_trainer_logic.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/trainer/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/trainer/downloader.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/trainer/exceptions.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/trainer/executor.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/trainer/io_helpers.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/trainer/rest/__init__.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/trainer/rest/backdoor_controls.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/trainer/test_executor.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/trainer/trainer_logic.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/trainer/trainer_logic_generic.py +0 -0
- {learning_loop_node-0.13.7 → learning_loop_node-0.14.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.14.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
|
|
@@ -105,6 +105,9 @@ The detector also has a sio **upload endpoint** that can be used to upload image
|
|
|
105
105
|
- `image`: the image data in jpg format
|
|
106
106
|
- `tags`: a list of strings. If not provided the tag is `picked_by_system`
|
|
107
107
|
- `detections`: a dictionary representing the detections. UUIDs for the classes are automatically determined based on the category names. This field is optional. If not provided, no detections are uploaded.
|
|
108
|
+
- `source`: optional source identifier for the image
|
|
109
|
+
- `creation_date`: optional creation date for the image
|
|
110
|
+
- `upload_priority`: boolean flag to prioritize the upload (defaults to False)
|
|
108
111
|
|
|
109
112
|
The endpoint returns None if the upload was successful and an error message otherwise.
|
|
110
113
|
|
|
@@ -187,58 +190,52 @@ Upload a model with
|
|
|
187
190
|
The model should now be available for the format 'format_a'
|
|
188
191
|
`curl "https://learning-loop.ai/api/zauberzeug/projects/demo/models?format=format_a"`
|
|
189
192
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
{
|
|
193
|
-
"models": [
|
|
193
|
+
```json
|
|
194
194
|
{
|
|
195
|
-
"
|
|
196
|
-
|
|
197
|
-
"
|
|
198
|
-
"
|
|
199
|
-
|
|
200
|
-
"
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
195
|
+
"models": [
|
|
196
|
+
{
|
|
197
|
+
"id": "3c20d807-f71c-40dc-a996-8a8968aa5431",
|
|
198
|
+
"version": "4.0",
|
|
199
|
+
"formats": [
|
|
200
|
+
"format_a"
|
|
201
|
+
],
|
|
202
|
+
"created": "2021-06-01T06:28:21.289092",
|
|
203
|
+
"comment": "uploaded at 2021-06-01 06:28:21.288442",
|
|
204
|
+
...
|
|
205
|
+
}
|
|
206
|
+
]
|
|
205
207
|
}
|
|
206
|
-
|
|
207
208
|
```
|
|
208
209
|
|
|
209
210
|
but not in the format_b
|
|
210
211
|
`curl "https://learning-loop.ai/api/zauberzeug/projects/demo/models?format=format_b"`
|
|
211
212
|
|
|
212
|
-
```
|
|
213
|
-
|
|
213
|
+
```json
|
|
214
214
|
{
|
|
215
|
-
"models": []
|
|
215
|
+
"models": []
|
|
216
216
|
}
|
|
217
|
-
|
|
218
217
|
```
|
|
219
218
|
|
|
220
219
|
Connect the Node to the Learning Loop by simply starting the container.
|
|
221
220
|
After a short time the converted model should be available as well.
|
|
222
221
|
`curl https://learning-loop.ai/api/zauberzeug/projects/demo/models?format=format_b`
|
|
223
222
|
|
|
224
|
-
```
|
|
225
|
-
|
|
223
|
+
```json
|
|
226
224
|
{
|
|
227
|
-
"models": [
|
|
228
|
-
{
|
|
229
|
-
"id": "3c20d807-f71c-40dc-a996-8a8968aa5431",
|
|
230
|
-
"version": "4.0",
|
|
231
|
-
"formats": [
|
|
232
|
-
"format_a",
|
|
233
|
-
"format_b",
|
|
234
|
-
],
|
|
235
|
-
"created": "2021-06-01T06:28:21.289092",
|
|
236
|
-
"comment": "uploaded at 2021-06-01 06:28:21.288442",
|
|
237
|
-
...
|
|
225
|
+
"models": [
|
|
226
|
+
{
|
|
227
|
+
"id": "3c20d807-f71c-40dc-a996-8a8968aa5431",
|
|
228
|
+
"version": "4.0",
|
|
229
|
+
"formats": [
|
|
230
|
+
"format_a",
|
|
231
|
+
"format_b",
|
|
232
|
+
],
|
|
233
|
+
"created": "2021-06-01T06:28:21.289092",
|
|
234
|
+
"comment": "uploaded at 2021-06-01 06:28:21.288442",
|
|
235
|
+
...
|
|
236
|
+
}
|
|
237
|
+
]
|
|
238
238
|
}
|
|
239
|
-
]
|
|
240
|
-
}
|
|
241
|
-
|
|
242
239
|
```
|
|
243
240
|
|
|
244
241
|
## About Models (the currency between Nodes)
|
|
@@ -257,6 +254,4 @@ After a short time the converted model should be available as well.
|
|
|
257
254
|
- Nodes add properties to `model.json`, which contains all the information which are needed by subsequent nodes. These are typically the properties:
|
|
258
255
|
- `resolution`: resolution in which the model expects images (as `int`, since the resolution is mostly square - later, ` resolution_x`` resolution_y ` would also be conceivable or `resolutions` to give a list of possible resolutions)
|
|
259
256
|
- `categories`: list of categories with name, id, (later also type), in the order in which they are used by the model -- this is neccessary to be robust about renamings
|
|
260
|
-
```
|
|
261
|
-
````
|
|
262
257
|
|
|
@@ -65,6 +65,9 @@ The detector also has a sio **upload endpoint** that can be used to upload image
|
|
|
65
65
|
- `image`: the image data in jpg format
|
|
66
66
|
- `tags`: a list of strings. If not provided the tag is `picked_by_system`
|
|
67
67
|
- `detections`: a dictionary representing the detections. UUIDs for the classes are automatically determined based on the category names. This field is optional. If not provided, no detections are uploaded.
|
|
68
|
+
- `source`: optional source identifier for the image
|
|
69
|
+
- `creation_date`: optional creation date for the image
|
|
70
|
+
- `upload_priority`: boolean flag to prioritize the upload (defaults to False)
|
|
68
71
|
|
|
69
72
|
The endpoint returns None if the upload was successful and an error message otherwise.
|
|
70
73
|
|
|
@@ -147,58 +150,52 @@ Upload a model with
|
|
|
147
150
|
The model should now be available for the format 'format_a'
|
|
148
151
|
`curl "https://learning-loop.ai/api/zauberzeug/projects/demo/models?format=format_a"`
|
|
149
152
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
{
|
|
153
|
-
"models": [
|
|
153
|
+
```json
|
|
154
154
|
{
|
|
155
|
-
"
|
|
156
|
-
|
|
157
|
-
"
|
|
158
|
-
"
|
|
159
|
-
|
|
160
|
-
"
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
155
|
+
"models": [
|
|
156
|
+
{
|
|
157
|
+
"id": "3c20d807-f71c-40dc-a996-8a8968aa5431",
|
|
158
|
+
"version": "4.0",
|
|
159
|
+
"formats": [
|
|
160
|
+
"format_a"
|
|
161
|
+
],
|
|
162
|
+
"created": "2021-06-01T06:28:21.289092",
|
|
163
|
+
"comment": "uploaded at 2021-06-01 06:28:21.288442",
|
|
164
|
+
...
|
|
165
|
+
}
|
|
166
|
+
]
|
|
165
167
|
}
|
|
166
|
-
|
|
167
168
|
```
|
|
168
169
|
|
|
169
170
|
but not in the format_b
|
|
170
171
|
`curl "https://learning-loop.ai/api/zauberzeug/projects/demo/models?format=format_b"`
|
|
171
172
|
|
|
172
|
-
```
|
|
173
|
-
|
|
173
|
+
```json
|
|
174
174
|
{
|
|
175
|
-
"models": []
|
|
175
|
+
"models": []
|
|
176
176
|
}
|
|
177
|
-
|
|
178
177
|
```
|
|
179
178
|
|
|
180
179
|
Connect the Node to the Learning Loop by simply starting the container.
|
|
181
180
|
After a short time the converted model should be available as well.
|
|
182
181
|
`curl https://learning-loop.ai/api/zauberzeug/projects/demo/models?format=format_b`
|
|
183
182
|
|
|
184
|
-
```
|
|
185
|
-
|
|
183
|
+
```json
|
|
186
184
|
{
|
|
187
|
-
"models": [
|
|
188
|
-
{
|
|
189
|
-
"id": "3c20d807-f71c-40dc-a996-8a8968aa5431",
|
|
190
|
-
"version": "4.0",
|
|
191
|
-
"formats": [
|
|
192
|
-
"format_a",
|
|
193
|
-
"format_b",
|
|
194
|
-
],
|
|
195
|
-
"created": "2021-06-01T06:28:21.289092",
|
|
196
|
-
"comment": "uploaded at 2021-06-01 06:28:21.288442",
|
|
197
|
-
...
|
|
185
|
+
"models": [
|
|
186
|
+
{
|
|
187
|
+
"id": "3c20d807-f71c-40dc-a996-8a8968aa5431",
|
|
188
|
+
"version": "4.0",
|
|
189
|
+
"formats": [
|
|
190
|
+
"format_a",
|
|
191
|
+
"format_b",
|
|
192
|
+
],
|
|
193
|
+
"created": "2021-06-01T06:28:21.289092",
|
|
194
|
+
"comment": "uploaded at 2021-06-01 06:28:21.288442",
|
|
195
|
+
...
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
198
|
}
|
|
199
|
-
]
|
|
200
|
-
}
|
|
201
|
-
|
|
202
199
|
```
|
|
203
200
|
|
|
204
201
|
## About Models (the currency between Nodes)
|
|
@@ -217,5 +214,3 @@ After a short time the converted model should be available as well.
|
|
|
217
214
|
- Nodes add properties to `model.json`, which contains all the information which are needed by subsequent nodes. These are typically the properties:
|
|
218
215
|
- `resolution`: resolution in which the model expects images (as `int`, since the resolution is mostly square - later, ` resolution_x`` resolution_y ` would also be conceivable or `resolutions` to give a list of possible resolutions)
|
|
219
216
|
- `categories`: list of categories with name, id, (later also type), in the order in which they are used by the model -- this is neccessary to be robust about renamings
|
|
220
|
-
```
|
|
221
|
-
````
|
|
@@ -2,8 +2,6 @@ import logging
|
|
|
2
2
|
from abc import abstractmethod
|
|
3
3
|
from typing import List, Optional
|
|
4
4
|
|
|
5
|
-
import numpy as np
|
|
6
|
-
|
|
7
5
|
from ..data_classes import ImageMetadata, ModelInformation
|
|
8
6
|
from ..globals import GLOBALS
|
|
9
7
|
from .exceptions import NodeNeedsRestartError
|
|
@@ -44,13 +42,13 @@ class DetectorLogic():
|
|
|
44
42
|
def init(self):
|
|
45
43
|
"""Called when a (new) model was loaded. Initialize the model. Model information available via `self.model_info`"""
|
|
46
44
|
|
|
47
|
-
def evaluate_with_all_info(self, image:
|
|
45
|
+
def evaluate_with_all_info(self, image: bytes, tags: List[str], source: Optional[str] = None, creation_date: Optional[str] = None) -> ImageMetadata: # pylint: disable=unused-argument
|
|
48
46
|
"""Called by the detector node when an image should be evaluated (REST or SocketIO).
|
|
49
47
|
Tags, source come from the caller and may be used in this function.
|
|
50
48
|
By default, this function simply calls `evaluate`"""
|
|
51
49
|
return self.evaluate(image)
|
|
52
50
|
|
|
53
51
|
@abstractmethod
|
|
54
|
-
def evaluate(self, image:
|
|
52
|
+
def evaluate(self, image: bytes) -> ImageMetadata:
|
|
55
53
|
"""Evaluate the image and return the detections.
|
|
56
54
|
The object should return empty detections if it is not initialized"""
|
{learning_loop_node-0.13.7 → learning_loop_node-0.14.0}/learning_loop_node/detector/detector_node.py
RENAMED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import contextlib
|
|
3
|
-
import math
|
|
4
3
|
import os
|
|
5
4
|
import shutil
|
|
6
5
|
import subprocess
|
|
7
6
|
import sys
|
|
8
7
|
from dataclasses import asdict
|
|
9
8
|
from datetime import datetime
|
|
10
|
-
from
|
|
11
|
-
from typing import Dict, List, Optional
|
|
9
|
+
from typing import Dict, List, Optional, cast
|
|
12
10
|
|
|
13
11
|
import numpy as np
|
|
14
12
|
import socketio
|
|
@@ -30,7 +28,7 @@ from ..data_classes.socket_response import SocketResponse
|
|
|
30
28
|
from ..data_exchanger import DataExchanger, DownloadError
|
|
31
29
|
from ..enums import OperationMode, VersionMode
|
|
32
30
|
from ..globals import GLOBALS
|
|
33
|
-
from ..helpers import environment_reader
|
|
31
|
+
from ..helpers import background_tasks, environment_reader, run
|
|
34
32
|
from ..node import Node
|
|
35
33
|
from .detector_logic import DetectorLogic
|
|
36
34
|
from .exceptions import NodeNeedsRestartError
|
|
@@ -227,7 +225,7 @@ class DetectorNode(Node):
|
|
|
227
225
|
async def detect(sid, data: Dict) -> Dict:
|
|
228
226
|
try:
|
|
229
227
|
det = await self.get_detections(
|
|
230
|
-
raw_image=
|
|
228
|
+
raw_image=data['image'],
|
|
231
229
|
camera_id=data.get('camera-id', None) or data.get('mac', None),
|
|
232
230
|
tags=data.get('tags', []),
|
|
233
231
|
source=data.get('source', None),
|
|
@@ -279,9 +277,10 @@ class DetectorNode(Node):
|
|
|
279
277
|
return {'error': str(e)}
|
|
280
278
|
|
|
281
279
|
@self.sio.event
|
|
282
|
-
async def upload(sid, data: Dict) ->
|
|
283
|
-
|
|
280
|
+
async def upload(sid, data: Dict) -> Dict:
|
|
281
|
+
"""Upload an image with detections"""
|
|
284
282
|
|
|
283
|
+
self.log.debug('Processing upload via socketio.')
|
|
285
284
|
detection_data = data.get('detections', {})
|
|
286
285
|
if detection_data and self.detector_logic.model_info is not None:
|
|
287
286
|
try:
|
|
@@ -293,22 +292,19 @@ class DetectorNode(Node):
|
|
|
293
292
|
else:
|
|
294
293
|
image_metadata = ImageMetadata()
|
|
295
294
|
|
|
296
|
-
tags = data.get('tags', [])
|
|
297
|
-
tags.append('picked_by_system')
|
|
298
|
-
|
|
299
|
-
source = data.get('source', None)
|
|
300
|
-
creation_date = data.get('creation_date', None)
|
|
301
|
-
|
|
302
|
-
self.log.debug('running upload via socketio. tags: %s, source: %s, creation_date: %s',
|
|
303
|
-
tags, source, creation_date)
|
|
304
|
-
|
|
305
|
-
loop = asyncio.get_event_loop()
|
|
306
295
|
try:
|
|
307
|
-
await
|
|
296
|
+
await self.upload_images(
|
|
297
|
+
images=[data['image']],
|
|
298
|
+
image_metadata=image_metadata,
|
|
299
|
+
tags=data.get('tags', []),
|
|
300
|
+
source=data.get('source', None),
|
|
301
|
+
creation_date=data.get('creation_date', None),
|
|
302
|
+
upload_priority=data.get('upload_priority', False)
|
|
303
|
+
)
|
|
308
304
|
except Exception as e:
|
|
309
305
|
self.log.exception('could not upload via socketio')
|
|
310
306
|
return {'error': str(e)}
|
|
311
|
-
return
|
|
307
|
+
return {'status': 'OK'}
|
|
312
308
|
|
|
313
309
|
@self.sio.event
|
|
314
310
|
def connect(sid, environ, auth) -> None:
|
|
@@ -469,7 +465,7 @@ class DetectorNode(Node):
|
|
|
469
465
|
self.log.warning('Operation mode set to %s, but sync failed: %s', mode, e)
|
|
470
466
|
|
|
471
467
|
def reload(self, reason: str):
|
|
472
|
-
|
|
468
|
+
"""provide a cause for the reload"""
|
|
473
469
|
|
|
474
470
|
self.log.info('########## reloading app because %s', reason)
|
|
475
471
|
if os.path.isfile('/app/app_code/restart/restart.py'):
|
|
@@ -482,7 +478,7 @@ class DetectorNode(Node):
|
|
|
482
478
|
self.log.error('could not reload app')
|
|
483
479
|
|
|
484
480
|
async def get_detections(self,
|
|
485
|
-
raw_image:
|
|
481
|
+
raw_image: bytes,
|
|
486
482
|
camera_id: Optional[str],
|
|
487
483
|
tags: List[str],
|
|
488
484
|
source: Optional[str] = None,
|
|
@@ -494,8 +490,7 @@ class DetectorNode(Node):
|
|
|
494
490
|
It can be converted e.g. using cv2.imdecode(raw_image, cv2.IMREAD_COLOR)"""
|
|
495
491
|
|
|
496
492
|
await self.detection_lock.acquire()
|
|
497
|
-
|
|
498
|
-
detections = await loop.run_in_executor(None, self.detector_logic.evaluate_with_all_info, raw_image, tags, source, creation_date)
|
|
493
|
+
detections = await run.io_bound(self.detector_logic.evaluate_with_all_info, raw_image, tags, source, creation_date)
|
|
499
494
|
self.detection_lock.release()
|
|
500
495
|
|
|
501
496
|
fix_shape_detections(detections)
|
|
@@ -503,21 +498,40 @@ class DetectorNode(Node):
|
|
|
503
498
|
n_po, n_se = len(detections.point_detections), len(detections.segmentation_detections)
|
|
504
499
|
self.log.debug('Detected: %d boxes, %d points, %d segs, %d classes', n_bo, n_po, n_se, n_cl)
|
|
505
500
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
501
|
+
autoupload = autoupload or 'filtered'
|
|
502
|
+
if autoupload == 'filtered' and camera_id is not None:
|
|
503
|
+
background_tasks.create(self.relevance_filter.may_upload_detections(
|
|
504
|
+
detections, camera_id, raw_image, tags, source, creation_date
|
|
505
|
+
))
|
|
509
506
|
elif autoupload == 'all':
|
|
510
|
-
|
|
507
|
+
background_tasks.create(self.outbox.save(raw_image, detections, tags, source, creation_date))
|
|
511
508
|
elif autoupload == 'disabled':
|
|
512
509
|
pass
|
|
513
510
|
else:
|
|
514
511
|
self.log.error('unknown autoupload value %s', autoupload)
|
|
515
512
|
return detections
|
|
516
513
|
|
|
517
|
-
async def upload_images(
|
|
518
|
-
|
|
514
|
+
async def upload_images(
|
|
515
|
+
self, *,
|
|
516
|
+
images: List[bytes],
|
|
517
|
+
image_metadata: Optional[ImageMetadata] = None,
|
|
518
|
+
tags: Optional[List[str]] = None,
|
|
519
|
+
source: Optional[str],
|
|
520
|
+
creation_date: Optional[str],
|
|
521
|
+
upload_priority: bool = False
|
|
522
|
+
) -> None:
|
|
523
|
+
"""Save images to the outbox using an asyncio executor.
|
|
524
|
+
Used by SIO and REST upload endpoints."""
|
|
525
|
+
|
|
526
|
+
if image_metadata is None:
|
|
527
|
+
image_metadata = ImageMetadata()
|
|
528
|
+
if tags is None:
|
|
529
|
+
tags = []
|
|
530
|
+
|
|
531
|
+
tags.append('picked_by_system')
|
|
532
|
+
|
|
519
533
|
for image in images:
|
|
520
|
-
await
|
|
534
|
+
await self.outbox.save(image, image_metadata, tags, source, creation_date, upload_priority)
|
|
521
535
|
|
|
522
536
|
def add_category_id_to_detections(self, model_info: ModelInformation, image_metadata: ImageMetadata):
|
|
523
537
|
def find_category_id_by_name(categories: List[Category], category_name: str):
|
|
@@ -11,14 +11,16 @@ class RelevanceFilter():
|
|
|
11
11
|
self.cam_histories: Dict[str, CamObservationHistory] = {}
|
|
12
12
|
self.outbox: Outbox = outbox
|
|
13
13
|
|
|
14
|
-
def may_upload_detections(self,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
async def may_upload_detections(self,
|
|
15
|
+
image_metadata: ImageMetadata,
|
|
16
|
+
cam_id: str,
|
|
17
|
+
raw_image: bytes,
|
|
18
|
+
tags: List[str],
|
|
19
|
+
source: Optional[str] = None,
|
|
20
|
+
creation_date: Optional[str] = None) -> List[str]:
|
|
21
|
+
"""Check if the detection should be uploaded to the outbox.
|
|
22
|
+
If so, upload it and return the list of causes for the upload.
|
|
23
|
+
"""
|
|
22
24
|
for group in self.cam_histories.values():
|
|
23
25
|
group.forget_old_detections()
|
|
24
26
|
|
|
@@ -30,5 +32,5 @@ class RelevanceFilter():
|
|
|
30
32
|
if len(causes) > 0:
|
|
31
33
|
tags = tags if tags is not None else []
|
|
32
34
|
tags.extend(causes)
|
|
33
|
-
self.outbox.save(raw_image, image_metadata, tags, source, creation_date)
|
|
35
|
+
await self.outbox.save(raw_image, image_metadata, tags, source, creation_date)
|
|
34
36
|
return causes
|