learning-loop-node 0.10.12__py3-none-any.whl → 0.10.14__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 learning-loop-node might be problematic. Click here for more details.
- learning_loop_node/annotation/annotator_node.py +11 -10
- learning_loop_node/data_classes/detections.py +34 -25
- learning_loop_node/data_classes/general.py +27 -17
- learning_loop_node/data_exchanger.py +6 -5
- learning_loop_node/detector/detector_logic.py +10 -4
- learning_loop_node/detector/detector_node.py +80 -54
- learning_loop_node/detector/inbox_filter/relevance_filter.py +9 -3
- learning_loop_node/detector/outbox.py +8 -1
- learning_loop_node/detector/rest/about.py +34 -9
- learning_loop_node/detector/rest/backdoor_controls.py +10 -29
- learning_loop_node/detector/rest/detect.py +27 -19
- learning_loop_node/detector/rest/model_version_control.py +30 -13
- learning_loop_node/detector/rest/operation_mode.py +11 -5
- learning_loop_node/detector/rest/outbox_mode.py +7 -1
- learning_loop_node/helpers/log_conf.py +5 -0
- learning_loop_node/node.py +97 -49
- learning_loop_node/rest.py +55 -0
- learning_loop_node/tests/detector/conftest.py +36 -2
- learning_loop_node/tests/detector/test_client_communication.py +21 -19
- learning_loop_node/tests/detector/test_detector_node.py +86 -0
- learning_loop_node/tests/trainer/conftest.py +4 -4
- learning_loop_node/tests/trainer/states/test_state_detecting.py +8 -9
- learning_loop_node/tests/trainer/states/test_state_download_train_model.py +8 -8
- learning_loop_node/tests/trainer/states/test_state_prepare.py +6 -7
- learning_loop_node/tests/trainer/states/test_state_sync_confusion_matrix.py +21 -18
- learning_loop_node/tests/trainer/states/test_state_train.py +6 -8
- learning_loop_node/tests/trainer/states/test_state_upload_detections.py +7 -9
- learning_loop_node/tests/trainer/states/test_state_upload_model.py +7 -8
- learning_loop_node/tests/trainer/test_errors.py +2 -2
- learning_loop_node/trainer/io_helpers.py +3 -6
- learning_loop_node/trainer/rest/backdoor_controls.py +19 -40
- learning_loop_node/trainer/trainer_logic.py +4 -4
- learning_loop_node/trainer/trainer_logic_generic.py +15 -12
- learning_loop_node/trainer/trainer_node.py +5 -4
- {learning_loop_node-0.10.12.dist-info → learning_loop_node-0.10.14.dist-info}/METADATA +16 -15
- {learning_loop_node-0.10.12.dist-info → learning_loop_node-0.10.14.dist-info}/RECORD +37 -35
- {learning_loop_node-0.10.12.dist-info → learning_loop_node-0.10.14.dist-info}/WHEEL +0 -0
|
@@ -8,11 +8,10 @@ from ..state_helper import assert_training_state, create_active_training_file
|
|
|
8
8
|
from ..testing_trainer_logic import TestingTrainerLogic
|
|
9
9
|
|
|
10
10
|
# pylint: disable=protected-access
|
|
11
|
-
error_key = 'upload_model'
|
|
12
11
|
|
|
13
12
|
|
|
14
|
-
def
|
|
15
|
-
return trainer.errors.has_error_for(
|
|
13
|
+
def trainer_has_upload_model_error(trainer: TrainerLogic):
|
|
14
|
+
return trainer.errors.has_error_for('upload_model')
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
async def test_successful_upload(mocker: MockerFixture, test_initialized_trainer: TestingTrainerLogic):
|
|
@@ -28,7 +27,7 @@ async def test_successful_upload(mocker: MockerFixture, test_initialized_trainer
|
|
|
28
27
|
await assert_training_state(trainer.training, TrainerState.TrainModelUploading, timeout=1, interval=0.001)
|
|
29
28
|
await train_task
|
|
30
29
|
|
|
31
|
-
assert
|
|
30
|
+
assert trainer_has_upload_model_error(trainer) is False
|
|
32
31
|
assert trainer.training.training_state == TrainerState.TrainModelUploaded
|
|
33
32
|
assert trainer.training.model_uuid_for_detecting is not None
|
|
34
33
|
assert trainer.node.last_training_io.load() == trainer.training
|
|
@@ -40,7 +39,7 @@ async def test_abort_upload_model(test_initialized_trainer: TestingTrainerLogic)
|
|
|
40
39
|
create_active_training_file(trainer, training_state=TrainerState.ConfusionMatrixSynced)
|
|
41
40
|
trainer._init_from_last_training()
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
trainer._begin_training_task()
|
|
44
43
|
|
|
45
44
|
await assert_training_state(trainer.training, TrainerState.TrainModelUploading, timeout=1, interval=0.001)
|
|
46
45
|
|
|
@@ -60,13 +59,13 @@ async def test_bad_server_response_content(test_initialized_trainer: TestingTrai
|
|
|
60
59
|
create_active_training_file(trainer, training_state=TrainerState.ConfusionMatrixSynced)
|
|
61
60
|
trainer._init_from_last_training()
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
trainer._begin_training_task()
|
|
64
63
|
|
|
65
64
|
await assert_training_state(trainer.training, TrainerState.TrainModelUploading, timeout=1, interval=0.001)
|
|
66
65
|
# TODO goes to finished because of the error
|
|
67
|
-
await assert_training_state(trainer.training, TrainerState.ReadyForCleanup, timeout=
|
|
66
|
+
await assert_training_state(trainer.training, TrainerState.ReadyForCleanup, timeout=10, interval=0.001)
|
|
68
67
|
|
|
69
|
-
assert
|
|
68
|
+
assert trainer_has_upload_model_error(trainer)
|
|
70
69
|
assert trainer.training.training_state == TrainerState.ReadyForCleanup
|
|
71
70
|
assert trainer.training.model_uuid_for_detecting is None
|
|
72
71
|
assert trainer.node.last_training_io.load() == trainer.training
|
|
@@ -14,7 +14,7 @@ async def test_training_process_is_stopped_when_trainer_reports_error(test_initi
|
|
|
14
14
|
trainer = test_initialized_trainer
|
|
15
15
|
create_active_training_file(trainer, training_state=TrainerState.TrainModelDownloaded)
|
|
16
16
|
trainer._init_from_last_training()
|
|
17
|
-
|
|
17
|
+
trainer._begin_training_task()
|
|
18
18
|
|
|
19
19
|
await assert_training_state(trainer.training, TrainerState.TrainingRunning, timeout=1, interval=0.001)
|
|
20
20
|
trainer.error_msg = 'some_error'
|
|
@@ -26,7 +26,7 @@ async def test_log_can_provide_only_data_for_current_run(test_initialized_traine
|
|
|
26
26
|
trainer = test_initialized_trainer
|
|
27
27
|
create_active_training_file(trainer, training_state=TrainerState.TrainModelDownloaded)
|
|
28
28
|
trainer._init_from_last_training()
|
|
29
|
-
|
|
29
|
+
trainer._begin_training_task()
|
|
30
30
|
|
|
31
31
|
await assert_training_state(trainer.training, TrainerState.TrainingRunning, timeout=1, interval=0.001)
|
|
32
32
|
await asyncio.sleep(0.1) # give tests a bit time to to check for the state
|
|
@@ -16,12 +16,9 @@ from ..loop_communication import LoopCommunicator
|
|
|
16
16
|
|
|
17
17
|
class EnvironmentVars:
|
|
18
18
|
def __init__(self) -> None:
|
|
19
|
-
self.restart_after_training = os.environ.get(
|
|
20
|
-
|
|
21
|
-
self.
|
|
22
|
-
'KEEP_OLD_TRAININGS', 'FALSE').lower() in ['true', '1']
|
|
23
|
-
self.inference_batch_size = int(
|
|
24
|
-
os.environ.get('INFERENCE_BATCH_SIZE', '10'))
|
|
19
|
+
self.restart_after_training = os.environ.get('RESTART_AFTER_TRAINING', 'FALSE').lower() in ['true', '1']
|
|
20
|
+
self.keep_old_trainings = os.environ.get('KEEP_OLD_TRAININGS', 'FALSE').lower() in ['true', '1']
|
|
21
|
+
self.inference_batch_size = int(os.environ.get('INFERENCE_BATCH_SIZE', '10'))
|
|
25
22
|
|
|
26
23
|
|
|
27
24
|
class LastTrainingIO:
|
|
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Dict
|
|
|
7
7
|
|
|
8
8
|
from fastapi import APIRouter, HTTPException, Request
|
|
9
9
|
|
|
10
|
-
from ...data_classes import ErrorConfiguration
|
|
10
|
+
from ...data_classes import ErrorConfiguration
|
|
11
11
|
from ..trainer_logic import TrainerLogic
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
@@ -16,32 +16,10 @@ if TYPE_CHECKING:
|
|
|
16
16
|
router = APIRouter()
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
@router.put("/socketio")
|
|
20
|
-
async def switch_socketio(request: Request):
|
|
21
|
-
'''
|
|
22
|
-
Example Usage
|
|
23
|
-
|
|
24
|
-
curl -X PUT -d "on" http://localhost:8001/socketio
|
|
25
|
-
'''
|
|
26
|
-
state = str(await request.body(), 'utf-8')
|
|
27
|
-
await _switch_socketio(state, request.app)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
async def _switch_socketio(state: str, trainer_node: TrainerNode):
|
|
31
|
-
if state == 'off':
|
|
32
|
-
if trainer_node.status.state != NodeState.Offline:
|
|
33
|
-
logging.debug('turning socketio off')
|
|
34
|
-
await trainer_node.sio_client.disconnect() # pylint: disable=protected-access
|
|
35
|
-
if state == 'on':
|
|
36
|
-
if trainer_node.status.state == NodeState.Offline:
|
|
37
|
-
logging.debug('turning socketio on')
|
|
38
|
-
await trainer_node.connect_sio()
|
|
39
|
-
|
|
40
|
-
|
|
41
19
|
@router.put("/provide_new_model")
|
|
42
20
|
async def provide_new_model(request: Request):
|
|
43
21
|
value = str(await request.body(), 'utf-8')
|
|
44
|
-
trainer_node =
|
|
22
|
+
trainer_node = request.app
|
|
45
23
|
# trainer_logic is MockTrainerLogic which has a property provide_new_model
|
|
46
24
|
assert hasattr(trainer_node.trainer_logic,
|
|
47
25
|
'provide_new_model'), 'trainer_logic does not have property provide_new_model'
|
|
@@ -56,17 +34,22 @@ async def provide_new_model(request: Request):
|
|
|
56
34
|
|
|
57
35
|
@router.post("/reset")
|
|
58
36
|
async def reset(request: Request):
|
|
59
|
-
|
|
60
|
-
|
|
37
|
+
logging.info('BC: reset')
|
|
38
|
+
trainer_node: 'TrainerNode' = request.app
|
|
39
|
+
async with trainer_node.repeat_loop_lock:
|
|
61
40
|
|
|
62
|
-
|
|
63
|
-
|
|
41
|
+
await trainer_node.trainer_logic.stop() # NOTE first stop may only kill running training process
|
|
42
|
+
await trainer_node.trainer_logic.stop()
|
|
43
|
+
trainer_node.last_training_io.delete()
|
|
44
|
+
trainer_node.status.reset_all_errors()
|
|
64
45
|
|
|
65
|
-
|
|
46
|
+
try:
|
|
47
|
+
await trainer_node.reconnect_to_loop()
|
|
48
|
+
except Exception:
|
|
49
|
+
logging.exception('Could not reset sio connection to loop')
|
|
66
50
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
await trainer_node.send_status()
|
|
51
|
+
logging.info('training should be killed, sending new state to LearningLoop')
|
|
52
|
+
await trainer_node.send_status()
|
|
70
53
|
|
|
71
54
|
|
|
72
55
|
@router.put("/error_configuration")
|
|
@@ -82,7 +65,7 @@ def set_error_configuration(msg: Dict, request: Request):
|
|
|
82
65
|
save_model=msg.get('save_model', None), )
|
|
83
66
|
|
|
84
67
|
logging.info(f'setting error configuration to: {asdict(error_configuration)}')
|
|
85
|
-
trainer_logic =
|
|
68
|
+
trainer_logic = request.app.trainer_logic
|
|
86
69
|
|
|
87
70
|
# NOTE: trainer_logic is MockTrainerLogic which has a property error_configuration
|
|
88
71
|
assert hasattr(trainer_logic, 'error_configuration'), 'trainer_logic does not have property error_configuration'
|
|
@@ -92,7 +75,7 @@ def set_error_configuration(msg: Dict, request: Request):
|
|
|
92
75
|
@router.post("/steps")
|
|
93
76
|
async def add_steps(request: Request):
|
|
94
77
|
logging.warning('Steps was called')
|
|
95
|
-
trainer_node =
|
|
78
|
+
trainer_node = request.app
|
|
96
79
|
trainer_logic = trainer_node.trainer_logic # NOTE: is MockTrainerLogic which has 'provide_new_model' and 'current_iteration'
|
|
97
80
|
|
|
98
81
|
assert isinstance(trainer_logic, TrainerLogic), 'trainer_logic is not TrainerLogic'
|
|
@@ -123,7 +106,7 @@ async def add_steps(request: Request):
|
|
|
123
106
|
async def kill_process(request: Request):
|
|
124
107
|
|
|
125
108
|
# pylint: disable=protected-access
|
|
126
|
-
trainer_node =
|
|
109
|
+
trainer_node = request.app
|
|
127
110
|
trainer_logic = trainer_node.trainer_logic
|
|
128
111
|
assert isinstance(trainer_logic, TrainerLogic), 'trainer_logic is not TrainerLogic'
|
|
129
112
|
if not trainer_logic._executor or not trainer_logic._executor.is_running():
|
|
@@ -133,9 +116,5 @@ async def kill_process(request: Request):
|
|
|
133
116
|
|
|
134
117
|
@router.post("/force_status_update")
|
|
135
118
|
async def force_status_update(request: Request):
|
|
136
|
-
trainer_node =
|
|
119
|
+
trainer_node = request.app
|
|
137
120
|
await trainer_node.send_status()
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def trainer_node_from_request(request: Request) -> TrainerNode:
|
|
141
|
-
return request.app
|
|
@@ -25,7 +25,7 @@ class TrainerLogic(TrainerLogicGeneric):
|
|
|
25
25
|
self._detection_progress: Optional[float] = None
|
|
26
26
|
self._executor: Optional[Executor] = None
|
|
27
27
|
self.start_training_task: Optional[Coroutine] = None
|
|
28
|
-
self.inference_batch_size =
|
|
28
|
+
self.inference_batch_size = self._environment_vars.inference_batch_size
|
|
29
29
|
|
|
30
30
|
# ---------------------------------------- IMPLEMENTED ABSTRACT PROPERTIES ----------------------------------------
|
|
31
31
|
|
|
@@ -92,7 +92,7 @@ class TrainerLogic(TrainerLogicGeneric):
|
|
|
92
92
|
|
|
93
93
|
shutil.rmtree(tmp_folder, ignore_errors=True)
|
|
94
94
|
os.makedirs(tmp_folder)
|
|
95
|
-
logging.info(
|
|
95
|
+
logging.info('downloading detection model to %s', tmp_folder)
|
|
96
96
|
|
|
97
97
|
await self.node.data_exchanger.download_model(tmp_folder, context, model_id, self.model_format)
|
|
98
98
|
with open(f'{tmp_folder}/model.json', 'r') as f:
|
|
@@ -104,10 +104,10 @@ class TrainerLogic(TrainerLogicGeneric):
|
|
|
104
104
|
image_ids = []
|
|
105
105
|
for state, p in zip(['inbox', 'annotate', 'review', 'complete'], [0.1, 0.2, 0.3, 0.4]):
|
|
106
106
|
self._detection_progress = p
|
|
107
|
-
logging.info(
|
|
107
|
+
logging.info('fetching image ids of state %s', state)
|
|
108
108
|
new_ids = await self.node.data_exchanger.fetch_image_uuids(query_params=f'state={state}')
|
|
109
109
|
image_ids += new_ids
|
|
110
|
-
logging.info(
|
|
110
|
+
logging.info('downloading %d images', len(new_ids))
|
|
111
111
|
await self.node.data_exchanger.download_images(new_ids, image_folder)
|
|
112
112
|
self._detection_progress = 0.42
|
|
113
113
|
# await delete_corrupt_images(image_folder)
|
|
@@ -179,7 +179,7 @@ class TrainerLogicGeneric(ABC):
|
|
|
179
179
|
if not self.training_active and self.last_training_io.exists():
|
|
180
180
|
self._init_from_last_training()
|
|
181
181
|
logger.info('found incomplete training, continuing now.')
|
|
182
|
-
|
|
182
|
+
self._begin_training_task()
|
|
183
183
|
return True
|
|
184
184
|
return False
|
|
185
185
|
|
|
@@ -195,7 +195,11 @@ class TrainerLogicGeneric(ABC):
|
|
|
195
195
|
"""Called on `begin_training` event from the Learning Loop.
|
|
196
196
|
"""
|
|
197
197
|
self._init_new_training(Context(organization=organization, project=project), details)
|
|
198
|
-
|
|
198
|
+
self._begin_training_task()
|
|
199
|
+
|
|
200
|
+
def _begin_training_task(self) -> None:
|
|
201
|
+
# NOTE: Task object is used to potentially cancel the task
|
|
202
|
+
self.training_task = asyncio.get_event_loop().create_task(self._run())
|
|
199
203
|
|
|
200
204
|
def _init_new_training(self, context: Context, details: Dict) -> None:
|
|
201
205
|
"""Called on `begin_training` event from the Learning Loop.
|
|
@@ -210,7 +214,7 @@ class TrainerLogicGeneric(ABC):
|
|
|
210
214
|
|
|
211
215
|
self._active_training_io = ActiveTrainingIO(
|
|
212
216
|
self._training.training_folder, self.node.loop_communicator, context)
|
|
213
|
-
logger.info(
|
|
217
|
+
logger.info('new training initialized: %s', self._training)
|
|
214
218
|
|
|
215
219
|
async def _run(self) -> None:
|
|
216
220
|
"""Called on `begin_training` event from the Learning Loop.
|
|
@@ -218,8 +222,7 @@ class TrainerLogicGeneric(ABC):
|
|
|
218
222
|
"""
|
|
219
223
|
self.errors.reset_all()
|
|
220
224
|
try:
|
|
221
|
-
|
|
222
|
-
await self.training_task # NOTE: Task object is used to potentially cancel the task
|
|
225
|
+
await self._training_loop()
|
|
223
226
|
except asyncio.CancelledError:
|
|
224
227
|
if not self.shutdown_event.is_set():
|
|
225
228
|
logger.info('CancelledError in _run - training task was cancelled but not by shutdown event')
|
|
@@ -229,8 +232,8 @@ class TrainerLogicGeneric(ABC):
|
|
|
229
232
|
self._may_restart()
|
|
230
233
|
else:
|
|
231
234
|
logger.info('CancelledError in _run - shutting down')
|
|
232
|
-
except Exception
|
|
233
|
-
logger.exception(
|
|
235
|
+
except Exception:
|
|
236
|
+
logger.exception('(Ignored) exception in trainer_logic._run:')
|
|
234
237
|
|
|
235
238
|
# ---------------------------------------- TRAINING STATES ----------------------------------------
|
|
236
239
|
|
|
@@ -271,7 +274,7 @@ class TrainerLogicGeneric(ABC):
|
|
|
271
274
|
'''
|
|
272
275
|
|
|
273
276
|
await asyncio.sleep(0.1)
|
|
274
|
-
logger.info(
|
|
277
|
+
logger.info('Performing state: %s', state_during)
|
|
275
278
|
previous_state = self.training.training_state
|
|
276
279
|
self.training.training_state = state_during
|
|
277
280
|
await asyncio.sleep(0.1)
|
|
@@ -283,12 +286,12 @@ class TrainerLogicGeneric(ABC):
|
|
|
283
286
|
|
|
284
287
|
except asyncio.CancelledError:
|
|
285
288
|
if self.shutdown_event.is_set():
|
|
286
|
-
logger.info(
|
|
289
|
+
logger.info('CancelledError in %s - shutdown event set', state_during)
|
|
287
290
|
raise
|
|
288
|
-
logger.info(
|
|
291
|
+
logger.info('CancelledError in %s - cleaning up', state_during)
|
|
289
292
|
self.training.training_state = TrainerState.ReadyForCleanup
|
|
290
293
|
except CriticalError as e:
|
|
291
|
-
logger.error(
|
|
294
|
+
logger.error('CriticalError in %s - Exception: %s', state_during, e)
|
|
292
295
|
self.errors.set(error_key, str(e))
|
|
293
296
|
self.training.training_state = TrainerState.ReadyForCleanup
|
|
294
297
|
except Exception as e:
|
|
@@ -297,7 +300,7 @@ class TrainerLogicGeneric(ABC):
|
|
|
297
300
|
self.training.training_state = previous_state
|
|
298
301
|
return
|
|
299
302
|
else:
|
|
300
|
-
logger.info(
|
|
303
|
+
logger.info('Successfully finished state: %s', state_during)
|
|
301
304
|
if not reset_early:
|
|
302
305
|
self.errors.reset(error_key)
|
|
303
306
|
self.training.training_state = state_after
|
|
@@ -32,7 +32,7 @@ class TrainerNode(Node):
|
|
|
32
32
|
self.log.info(
|
|
33
33
|
f'Trainer started with an idle_timeout of {self.idle_timeout} seconds. Note that shutdown does not work if docker container has the restart policy set to always')
|
|
34
34
|
|
|
35
|
-
if use_backdoor_controls:
|
|
35
|
+
if use_backdoor_controls or os.environ.get('USE_BACKDOOR_CONTROLS', '0').lower() in ('1', 'true'):
|
|
36
36
|
self.include_router(backdoor_controls.router, tags=["controls"])
|
|
37
37
|
|
|
38
38
|
# ----------------------------------- NODE LIVECYCLE METHODS --------------------------
|
|
@@ -77,7 +77,7 @@ class TrainerNode(Node):
|
|
|
77
77
|
|
|
78
78
|
async def send_status(self):
|
|
79
79
|
if not self.sio_client.connected:
|
|
80
|
-
self.log.
|
|
80
|
+
self.log.debug('cannot send status - not connected to the Learning Loop')
|
|
81
81
|
return
|
|
82
82
|
|
|
83
83
|
status = TrainingStatus(id=self.uuid,
|
|
@@ -98,10 +98,11 @@ class TrainerNode(Node):
|
|
|
98
98
|
status.errors = self.trainer_logic.errors.errors
|
|
99
99
|
status.context = self.trainer_logic.training_context
|
|
100
100
|
|
|
101
|
-
self.log.
|
|
101
|
+
self.log.debug('sending status: %s', status.short_str())
|
|
102
102
|
result = await self.sio_client.call('update_trainer', jsonable_encoder(asdict(status)), timeout=30)
|
|
103
103
|
if isinstance(result, Dict) and not result['success']:
|
|
104
|
-
self.
|
|
104
|
+
self.socket_connection_broken = True
|
|
105
|
+
self.log.error('Error when sending status update: Response from loop was:\n %s', result)
|
|
105
106
|
|
|
106
107
|
def check_idle_timeout(self):
|
|
107
108
|
if not self.idle_timeout:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: learning-loop-node
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.14
|
|
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
|
|
@@ -57,20 +57,21 @@ To start a node you have to implement the logic by inheriting from the correspon
|
|
|
57
57
|
|
|
58
58
|
You can configure connection to our Learning Loop by specifying the following environment variables before starting:
|
|
59
59
|
|
|
60
|
-
| Name | Alias | Purpose | Required by
|
|
61
|
-
| ------------------------ | ------------ | ------------------------------------------------------------ |
|
|
62
|
-
| LOOP_HOST | HOST | Learning Loop address (e.g. learning-loop.ai) | all
|
|
63
|
-
| LOOP_USERNAME | USERNAME | Learning Loop user name | all besides Detector
|
|
64
|
-
| LOOP_PASSWORD | PASSWORD | Learning Loop password | all besides Detector
|
|
65
|
-
| LOOP_SSL_CERT_PATH | - | Path to the SSL certificate | all (opt.)
|
|
66
|
-
| LOOP_ORGANIZATION | ORGANIZATION | Organization name | Detector
|
|
67
|
-
| LOOP_PROJECT | PROJECT | Project name | Detector
|
|
68
|
-
| MIN_UNCERTAIN_THRESHOLD |
|
|
69
|
-
| MAX_UNCERTAIN_THRESHOLD |
|
|
70
|
-
| INFERENCE_BATCH_SIZE | - | Batch size of trainer when calculating detections | Trainer (opt.)
|
|
71
|
-
| RESTART_AFTER_TRAINING | - | Restart the trainer after training (set to 1) | Trainer (opt.)
|
|
72
|
-
| KEEP_OLD_TRAININGS | - | Do not delete old trainings (set to 1) | Trainer (opt.)
|
|
73
|
-
| TRAINER_IDLE_TIMEOUT_SEC | - | Automatically shutdown trainer after timeout (in seconds) | Trainer (opt.)
|
|
60
|
+
| Name | Alias | Purpose | Required by |
|
|
61
|
+
| ------------------------ | ------------ | ------------------------------------------------------------ | ------------------------- |
|
|
62
|
+
| LOOP_HOST | HOST | Learning Loop address (e.g. learning-loop.ai) | all |
|
|
63
|
+
| LOOP_USERNAME | USERNAME | Learning Loop user name | all besides Detector |
|
|
64
|
+
| LOOP_PASSWORD | PASSWORD | Learning Loop password | all besides Detector |
|
|
65
|
+
| LOOP_SSL_CERT_PATH | - | Path to the SSL certificate | all (opt.) |
|
|
66
|
+
| LOOP_ORGANIZATION | ORGANIZATION | Organization name | Detector |
|
|
67
|
+
| LOOP_PROJECT | PROJECT | Project name | Detector (opt.) |
|
|
68
|
+
| MIN_UNCERTAIN_THRESHOLD | - | smallest confidence (float) at which auto-upload will happen | Detector (opt.) |
|
|
69
|
+
| MAX_UNCERTAIN_THRESHOLD | - | largest confidence (float) at which auto-upload will happen | Detector (opt.) |
|
|
70
|
+
| INFERENCE_BATCH_SIZE | - | Batch size of trainer when calculating detections | Trainer (opt.) |
|
|
71
|
+
| RESTART_AFTER_TRAINING | - | Restart the trainer after training (set to 1) | Trainer (opt.) |
|
|
72
|
+
| KEEP_OLD_TRAININGS | - | Do not delete old trainings (set to 1) | Trainer (opt.) |
|
|
73
|
+
| TRAINER_IDLE_TIMEOUT_SEC | - | Automatically shutdown trainer after timeout (in seconds) | Trainer (opt.) |
|
|
74
|
+
| USE_BACKDOOR_CONTROLS | - | Always enable backdoor controls (set to 1) | Trainer / Detector (opt.) |
|
|
74
75
|
|
|
75
76
|
#### Testing
|
|
76
77
|
|
|
@@ -1,53 +1,55 @@
|
|
|
1
1
|
learning_loop_node/__init__.py,sha256=onN5s8-x_xBsCM6NLmJO0Ym1sJHeCFaGw8qb0oQZmz8,364
|
|
2
2
|
learning_loop_node/annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
learning_loop_node/annotation/annotator_logic.py,sha256=BTaopkJZkIf1CI5lfsVKsxbxoUIbDJrevavuQUT5e_c,1000
|
|
4
|
-
learning_loop_node/annotation/annotator_node.py,sha256=
|
|
4
|
+
learning_loop_node/annotation/annotator_node.py,sha256=UrJ8MpZ44UhsjmVuSHr2BhHyLC-kIMDi3IuBBMKzN1g,4117
|
|
5
5
|
learning_loop_node/data_classes/__init__.py,sha256=wCX88lDgbb8V-gtVCVe9i-NvvZuMe5FX7eD_UJgYYXw,1305
|
|
6
6
|
learning_loop_node/data_classes/annotations.py,sha256=iInU0Nuy_oYT_sj4k_n-W0UShCBI2cHQYrt8imymbtM,1211
|
|
7
|
-
learning_loop_node/data_classes/detections.py,sha256=
|
|
8
|
-
learning_loop_node/data_classes/general.py,sha256=
|
|
7
|
+
learning_loop_node/data_classes/detections.py,sha256=hifsGz2LbmeKLZdHxG7cnlOYNEqDmtJd2gxhyU-Xjjs,5811
|
|
8
|
+
learning_loop_node/data_classes/general.py,sha256=usXokcTOVqTuaKJtBf0ffFWfzZhMrQtF7puKfwi6A5k,6195
|
|
9
9
|
learning_loop_node/data_classes/socket_response.py,sha256=tIdt-oYf6ULoJIDYQCecNM9OtWR6_wJ9tL0Ksu83Vko,655
|
|
10
10
|
learning_loop_node/data_classes/training.py,sha256=hnMHZMk-WNRERyo7U97qL09v1tIdhnzPfTH-JgifLwU,6164
|
|
11
|
-
learning_loop_node/data_exchanger.py,sha256=
|
|
11
|
+
learning_loop_node/data_exchanger.py,sha256=mwZvJf8L1-r6Wi2ZvDfFf4kFjkqxsThXj7AGLUANGlU,8979
|
|
12
12
|
learning_loop_node/detector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
learning_loop_node/detector/detector_logic.py,sha256=
|
|
14
|
-
learning_loop_node/detector/detector_node.py,sha256=
|
|
13
|
+
learning_loop_node/detector/detector_logic.py,sha256=IG1s9RF_cCBcNQ8WW1rAS37QKdGzlVoVkuO_CrLGvYs,2084
|
|
14
|
+
learning_loop_node/detector/detector_node.py,sha256=TeChzkpVVmEiZbnfWmtkjuUXNwCZvIWfingmcuAz2cs,19567
|
|
15
15
|
learning_loop_node/detector/inbox_filter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
learning_loop_node/detector/inbox_filter/cam_observation_history.py,sha256=TD346I9ymtIP0_CJXCIKMRuiXbfVVanXNu_iHAwDd7Q,3318
|
|
17
|
-
learning_loop_node/detector/inbox_filter/relevance_filter.py,sha256=
|
|
18
|
-
learning_loop_node/detector/outbox.py,sha256=
|
|
17
|
+
learning_loop_node/detector/inbox_filter/relevance_filter.py,sha256=7_-x8D8Zf6KJeJXmiC2VrRHU8Ig_R98uhdXVwwX0N4M,1240
|
|
18
|
+
learning_loop_node/detector/outbox.py,sha256=HrYeS6XJLC-1kqq2hDufxXLRmOYGiBlz-m9B6HG5Ie8,8227
|
|
19
19
|
learning_loop_node/detector/rest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
learning_loop_node/detector/rest/about.py,sha256=
|
|
21
|
-
learning_loop_node/detector/rest/backdoor_controls.py,sha256=
|
|
22
|
-
learning_loop_node/detector/rest/detect.py,sha256=
|
|
23
|
-
learning_loop_node/detector/rest/model_version_control.py,sha256=
|
|
24
|
-
learning_loop_node/detector/rest/operation_mode.py,sha256=
|
|
25
|
-
learning_loop_node/detector/rest/outbox_mode.py,sha256=
|
|
20
|
+
learning_loop_node/detector/rest/about.py,sha256=COYgmYO1tXGSIwjF__P79mVZUfSDZoHsW0GUarQ2rv0,1686
|
|
21
|
+
learning_loop_node/detector/rest/backdoor_controls.py,sha256=ZNaFOvC0OLWNtcLiG-NIqS_y1kkLP4csgk3CHhp8Gis,885
|
|
22
|
+
learning_loop_node/detector/rest/detect.py,sha256=KSYUOuTxuc2q3RgV37cBBuCvCJf11BFL7QtnPAM4XbU,2343
|
|
23
|
+
learning_loop_node/detector/rest/model_version_control.py,sha256=jLp3rvCYq8T_QC3KK7uLDYpbDjydwazWkQCUXvkxl-c,4654
|
|
24
|
+
learning_loop_node/detector/rest/operation_mode.py,sha256=RAzVLtGzy4n9-LSIq_XSwMfXDehU4XmorgWAWbQ6BW8,1804
|
|
25
|
+
learning_loop_node/detector/rest/outbox_mode.py,sha256=H8coDNbgLGEfXmKQrhtXWeUHBAHpnrdZktuHXQz0xis,1148
|
|
26
26
|
learning_loop_node/detector/rest/upload.py,sha256=IPzxJPayD7_Gx5uYC1lVJwWxdnQgM8MYGa5NugXVosY,544
|
|
27
27
|
learning_loop_node/examples/novelty_score_updater.py,sha256=1DRgM9lxjFV-q2JvGDDsNLz_ic_rhEZ9wc6ZdjcxwPE,2038
|
|
28
28
|
learning_loop_node/globals.py,sha256=tgw_8RYOipPV9aYlyUhYtXfUxvJKRvfUk6u-qVAtZmY,174
|
|
29
29
|
learning_loop_node/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
30
|
learning_loop_node/helpers/environment_reader.py,sha256=OtCTDc0KT9r-SMygkZB_Mw-ZIJPfUZVyUzHJoDCgJP8,1658
|
|
31
31
|
learning_loop_node/helpers/gdrive_downloader.py,sha256=zeYJciTAJVRpu_eFjwgYLCpIa6hU1d71anqEBb564Rk,1145
|
|
32
|
-
learning_loop_node/helpers/log_conf.py,sha256=
|
|
32
|
+
learning_loop_node/helpers/log_conf.py,sha256=z_0PHh7U7DkJbSbKoSPyUfS7NhBHtRxXHdNcj67Hpbc,951
|
|
33
33
|
learning_loop_node/helpers/misc.py,sha256=j4is8Rv0ttnCqF-R-wP3xwEi67OI6IBJav5Woo5lyDk,7701
|
|
34
34
|
learning_loop_node/loop_communication.py,sha256=rG5MdavSTaREZ6OWfAUIT_qkkYPw3is2_FujLmHQeIc,6576
|
|
35
|
-
learning_loop_node/node.py,sha256=
|
|
35
|
+
learning_loop_node/node.py,sha256=7Xc6VM_Rk1yDKDjKoUjoY4gSsC1zokjt5YQJu0PP5ao,9931
|
|
36
36
|
learning_loop_node/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
|
+
learning_loop_node/rest.py,sha256=o1dl4Mtznd5duyEQtCYSGlK04l1Y-p_YRjG40Q4l31c,1491
|
|
37
38
|
learning_loop_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
39
|
learning_loop_node/tests/annotator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
40
|
learning_loop_node/tests/annotator/conftest.py,sha256=G4ZvdZUdvPp9bYCzg3eEVkGCeXn9INZ3AcN7d5CyLkU,1931
|
|
40
41
|
learning_loop_node/tests/annotator/pytest.ini,sha256=8QdjmawLy1zAzXrJ88or1kpFDhJw0W5UOnDfGGs_igU,262
|
|
41
42
|
learning_loop_node/tests/annotator/test_annotator_node.py,sha256=TPNPPrQAxQ_zEecQcH7hlczgD3ABtTCNtUvWD1_oApk,1985
|
|
42
43
|
learning_loop_node/tests/detector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
|
-
learning_loop_node/tests/detector/conftest.py,sha256=
|
|
44
|
+
learning_loop_node/tests/detector/conftest.py,sha256=Q14KHTSuSCsASVIxY9CttdVJm5FC7_JH-W5Q4CdDqoM,5414
|
|
44
45
|
learning_loop_node/tests/detector/inbox_filter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
46
|
learning_loop_node/tests/detector/inbox_filter/test_observation.py,sha256=k4WYdvnuV7d_r7zI4M2aA8WuBjm0aycQ0vj1rGE2q4w,1370
|
|
46
47
|
learning_loop_node/tests/detector/inbox_filter/test_relevance_group.py,sha256=XjiMsS0LgvM0OkPf5-s2rjFbG7C42LTmz_rDVMGHKoY,7603
|
|
47
48
|
learning_loop_node/tests/detector/inbox_filter/test_unexpected_observations_count.py,sha256=MWC7PbaCy14jjRw0_oilkXj6gymAsUZXHJdzNW5m2D4,1639
|
|
48
49
|
learning_loop_node/tests/detector/pytest.ini,sha256=8QdjmawLy1zAzXrJ88or1kpFDhJw0W5UOnDfGGs_igU,262
|
|
49
50
|
learning_loop_node/tests/detector/test.jpg,sha256=msA-vHPmvPiro_D102Qmn1fn4vNfooqYYEXPxZUmYpk,161390
|
|
50
|
-
learning_loop_node/tests/detector/test_client_communication.py,sha256=
|
|
51
|
+
learning_loop_node/tests/detector/test_client_communication.py,sha256=NAOUrHWxoI4yG6oy3BGxWWXX794IOODEj9QBKF3CyrY,9375
|
|
52
|
+
learning_loop_node/tests/detector/test_detector_node.py,sha256=KX2RcFpdIbpPEmcyYM0YMs-6wwTpbOOZONoiwIWryUI,2922
|
|
51
53
|
learning_loop_node/tests/detector/test_outbox.py,sha256=5RMKQfuu1-rvpVCpEtt_D70bYgma-sIrTHWxHdTdU9Y,3001
|
|
52
54
|
learning_loop_node/tests/detector/test_relevance_filter.py,sha256=3VLhHKaxPzLYmiNZagvgg9ZHkPhWk4_-qpmkJw36wBU,2046
|
|
53
55
|
learning_loop_node/tests/detector/testing_detector.py,sha256=FeQroV85IvsT8dmalQBqf1FLNt_buCtZK3-lgtmbrBI,542
|
|
@@ -62,32 +64,32 @@ learning_loop_node/tests/general/test_downloader.py,sha256=C6b_wG3TfQX53lmuanpH1
|
|
|
62
64
|
learning_loop_node/tests/general/test_learning_loop_node.py,sha256=SZd-VChpWnnsPN46pr4E_LL3ZevYx6psU-AWdVeOFpQ,770
|
|
63
65
|
learning_loop_node/tests/test_helper.py,sha256=nTynYtuUaK2hKh87pk7t7AIJaOiD3wJ5d6nCPqnwRMk,3012
|
|
64
66
|
learning_loop_node/tests/trainer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
65
|
-
learning_loop_node/tests/trainer/conftest.py,sha256=
|
|
67
|
+
learning_loop_node/tests/trainer/conftest.py,sha256=E3SQL_CGFJ_sNjEfVJbxbvH0g6hjI5753ndAFUbnkQk,3366
|
|
66
68
|
learning_loop_node/tests/trainer/pytest.ini,sha256=8QdjmawLy1zAzXrJ88or1kpFDhJw0W5UOnDfGGs_igU,262
|
|
67
69
|
learning_loop_node/tests/trainer/state_helper.py,sha256=MDe9opeKruip74FoRFff8MSWGiQNFqDpPtIEIbgPnFc,919
|
|
68
70
|
learning_loop_node/tests/trainer/states/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
69
71
|
learning_loop_node/tests/trainer/states/test_state_cleanup.py,sha256=gZNxSSwnj9f0esExNnQzqadM6-sE3IsF5sNbD0bZNu8,1250
|
|
70
|
-
learning_loop_node/tests/trainer/states/test_state_detecting.py,sha256=
|
|
71
|
-
learning_loop_node/tests/trainer/states/test_state_download_train_model.py,sha256=
|
|
72
|
-
learning_loop_node/tests/trainer/states/test_state_prepare.py,sha256=
|
|
73
|
-
learning_loop_node/tests/trainer/states/test_state_sync_confusion_matrix.py,sha256=
|
|
74
|
-
learning_loop_node/tests/trainer/states/test_state_train.py,sha256=
|
|
75
|
-
learning_loop_node/tests/trainer/states/test_state_upload_detections.py,sha256=
|
|
76
|
-
learning_loop_node/tests/trainer/states/test_state_upload_model.py,sha256=
|
|
77
|
-
learning_loop_node/tests/trainer/test_errors.py,sha256=
|
|
72
|
+
learning_loop_node/tests/trainer/states/test_state_detecting.py,sha256=KGXTR69J_1pJoT8S0ceC3vSyHLw52mIpjbawH4c-8JA,3696
|
|
73
|
+
learning_loop_node/tests/trainer/states/test_state_download_train_model.py,sha256=AuTY63sgrlKT0awS6o38fF3mTkDguAFJtcX7J7WhjgQ,2855
|
|
74
|
+
learning_loop_node/tests/trainer/states/test_state_prepare.py,sha256=3hzRo9ycM802QUZO2Zs_rJRZ23hxTi3XjRCwL9M9m9o,2315
|
|
75
|
+
learning_loop_node/tests/trainer/states/test_state_sync_confusion_matrix.py,sha256=6s4A2d5ahD9UJJiHGK1VtmOrhumzuqTlOwyc_8Oc1vk,5073
|
|
76
|
+
learning_loop_node/tests/trainer/states/test_state_train.py,sha256=HYe1O6zcdtD4dnmfX3cyM1_iF7eGig7dQI4M4Xat7YU,2916
|
|
77
|
+
learning_loop_node/tests/trainer/states/test_state_upload_detections.py,sha256=0Qkavl4i2tZmCOxKkNsQUqa1JWhAgcOsbrW3_eYHfxo,7417
|
|
78
|
+
learning_loop_node/tests/trainer/states/test_state_upload_model.py,sha256=y2o4WBo7kBG_JWSWmt4icjrwya5hQ30zCWC-YMVEwEk,3621
|
|
79
|
+
learning_loop_node/tests/trainer/test_errors.py,sha256=khWCTzi-JW4nSz9QnsRh9wDPmiuE_zdxXukh59qixuY,2109
|
|
78
80
|
learning_loop_node/tests/trainer/test_trainer_states.py,sha256=djYCs5ieajQHRjk8QcUVBUkQEG8UGYFoNGwSX0z2oGk,1067
|
|
79
81
|
learning_loop_node/tests/trainer/testing_trainer_logic.py,sha256=KslqDJDntkgH4Yd_z-guiVPvzi5Q-l-Bqc3fUjT5N7U,3883
|
|
80
82
|
learning_loop_node/trainer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
81
83
|
learning_loop_node/trainer/downloader.py,sha256=Qk-oBcrGCVuWTVs3hvAJzQSqCIHPGZ7NXLJ_fAqvCoY,1469
|
|
82
84
|
learning_loop_node/trainer/exceptions.py,sha256=hLLDGncC6PLZjKg4lZBpu-QA8itQIxiuxExz1uptgnw,40
|
|
83
85
|
learning_loop_node/trainer/executor.py,sha256=-0BxDqmAI1NCiISi7Rw8McJQfgxxVy1gSa1epYuL3U0,3942
|
|
84
|
-
learning_loop_node/trainer/io_helpers.py,sha256=
|
|
86
|
+
learning_loop_node/trainer/io_helpers.py,sha256=hGEtNAQBSBbVB56U1ndwfP8qK5K4YIwMQrjCDcaMy9I,7218
|
|
85
87
|
learning_loop_node/trainer/rest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
86
|
-
learning_loop_node/trainer/rest/backdoor_controls.py,sha256
|
|
88
|
+
learning_loop_node/trainer/rest/backdoor_controls.py,sha256=-pU4iHheBWf0SW2QzBVBsLiCMZBRz9CDdVZv6414Ts8,5134
|
|
87
89
|
learning_loop_node/trainer/test_executor.py,sha256=6BVGDN_6f5GEMMEvDLSG1yzMybSvgXaP5uYpSfsVPP0,2224
|
|
88
|
-
learning_loop_node/trainer/trainer_logic.py,sha256=
|
|
89
|
-
learning_loop_node/trainer/trainer_logic_generic.py,sha256=
|
|
90
|
-
learning_loop_node/trainer/trainer_node.py,sha256=
|
|
91
|
-
learning_loop_node-0.10.
|
|
92
|
-
learning_loop_node-0.10.
|
|
93
|
-
learning_loop_node-0.10.
|
|
90
|
+
learning_loop_node/trainer/trainer_logic.py,sha256=PlYExIskU9pWJO0e9m_0KJnUdOI10GtW0oDOevYmg1o,8461
|
|
91
|
+
learning_loop_node/trainer/trainer_logic_generic.py,sha256=dVsvl1LC1w3svl4O8HCW49R7vSpVpC9Ermu4C20sFoA,25821
|
|
92
|
+
learning_loop_node/trainer/trainer_node.py,sha256=8ANS9iy-swdTLvt9wEFixE6YlmqvqBl17A-R4tVYD-I,5384
|
|
93
|
+
learning_loop_node-0.10.14.dist-info/METADATA,sha256=RHHVhHfTIPjxY5lO3UsR6L7BbHzwXs9wch4WJzePXJQ,11907
|
|
94
|
+
learning_loop_node-0.10.14.dist-info/WHEEL,sha256=WGfLGfLX43Ei_YORXSnT54hxFygu34kMpcQdmgmEwCQ,88
|
|
95
|
+
learning_loop_node-0.10.14.dist-info/RECORD,,
|
|
File without changes
|