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.

Files changed (37) hide show
  1. learning_loop_node/annotation/annotator_node.py +11 -10
  2. learning_loop_node/data_classes/detections.py +34 -25
  3. learning_loop_node/data_classes/general.py +27 -17
  4. learning_loop_node/data_exchanger.py +6 -5
  5. learning_loop_node/detector/detector_logic.py +10 -4
  6. learning_loop_node/detector/detector_node.py +80 -54
  7. learning_loop_node/detector/inbox_filter/relevance_filter.py +9 -3
  8. learning_loop_node/detector/outbox.py +8 -1
  9. learning_loop_node/detector/rest/about.py +34 -9
  10. learning_loop_node/detector/rest/backdoor_controls.py +10 -29
  11. learning_loop_node/detector/rest/detect.py +27 -19
  12. learning_loop_node/detector/rest/model_version_control.py +30 -13
  13. learning_loop_node/detector/rest/operation_mode.py +11 -5
  14. learning_loop_node/detector/rest/outbox_mode.py +7 -1
  15. learning_loop_node/helpers/log_conf.py +5 -0
  16. learning_loop_node/node.py +97 -49
  17. learning_loop_node/rest.py +55 -0
  18. learning_loop_node/tests/detector/conftest.py +36 -2
  19. learning_loop_node/tests/detector/test_client_communication.py +21 -19
  20. learning_loop_node/tests/detector/test_detector_node.py +86 -0
  21. learning_loop_node/tests/trainer/conftest.py +4 -4
  22. learning_loop_node/tests/trainer/states/test_state_detecting.py +8 -9
  23. learning_loop_node/tests/trainer/states/test_state_download_train_model.py +8 -8
  24. learning_loop_node/tests/trainer/states/test_state_prepare.py +6 -7
  25. learning_loop_node/tests/trainer/states/test_state_sync_confusion_matrix.py +21 -18
  26. learning_loop_node/tests/trainer/states/test_state_train.py +6 -8
  27. learning_loop_node/tests/trainer/states/test_state_upload_detections.py +7 -9
  28. learning_loop_node/tests/trainer/states/test_state_upload_model.py +7 -8
  29. learning_loop_node/tests/trainer/test_errors.py +2 -2
  30. learning_loop_node/trainer/io_helpers.py +3 -6
  31. learning_loop_node/trainer/rest/backdoor_controls.py +19 -40
  32. learning_loop_node/trainer/trainer_logic.py +4 -4
  33. learning_loop_node/trainer/trainer_logic_generic.py +15 -12
  34. learning_loop_node/trainer/trainer_node.py +5 -4
  35. {learning_loop_node-0.10.12.dist-info → learning_loop_node-0.10.14.dist-info}/METADATA +16 -15
  36. {learning_loop_node-0.10.12.dist-info → learning_loop_node-0.10.14.dist-info}/RECORD +37 -35
  37. {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 trainer_has_error(trainer: TrainerLogic):
15
- return trainer.errors.has_error_for(error_key)
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 trainer_has_error(trainer) is False
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
- _ = asyncio.get_running_loop().create_task(trainer._run())
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
- _ = asyncio.get_running_loop().create_task(trainer._run())
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=2, interval=0.001)
66
+ await assert_training_state(trainer.training, TrainerState.ReadyForCleanup, timeout=10, interval=0.001)
68
67
 
69
- assert trainer_has_error(trainer)
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
- _ = asyncio.get_running_loop().create_task(trainer._run())
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
- _ = asyncio.get_running_loop().create_task(trainer._run())
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
- 'RESTART_AFTER_TRAINING', 'FALSE').lower() in ['true', '1']
21
- self.keep_old_trainings = os.environ.get(
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, NodeState
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 = trainer_node_from_request(request)
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
- trainer_node = trainer_node_from_request(request)
60
- await _switch_socketio('on', trainer_node)
37
+ logging.info('BC: reset')
38
+ trainer_node: 'TrainerNode' = request.app
39
+ async with trainer_node.repeat_loop_lock:
61
40
 
62
- await trainer_node.trainer_logic.stop() # NOTE first stop may only kill running training process
63
- await trainer_node.trainer_logic.stop()
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
- trainer_node.last_training_io.delete()
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
- trainer_node.status.reset_all_errors()
68
- logging.info('training should be killed, sending new state to LearningLoop')
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 = trainer_node_from_request(request).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 = trainer_node_from_request(request)
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 = trainer_node_from_request(request)
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 = trainer_node_from_request(request)
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 = 10
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(f'downloading detection model to {tmp_folder}')
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(f'fetching image ids of {state}')
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(f'downloading {len(new_ids)} images')
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
- asyncio.get_event_loop().create_task(self._run())
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
- asyncio.get_event_loop().create_task(self._run())
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(f'new training initialized: {self._training}')
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
- self.training_task = asyncio.get_running_loop().create_task(self._training_loop())
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 as e:
233
- logger.exception(f'Error in train: {e}')
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(f'Performing state: {state_during}')
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(f'CancelledError in {state_during} - shutdown event set')
289
+ logger.info('CancelledError in %s - shutdown event set', state_during)
287
290
  raise
288
- logger.info(f'CancelledError in {state_during} - cleaning up')
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(f'CriticalError in {state_during} - Exception: {e}')
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(f'Successfully finished state: {state_during}')
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.warning('cannot send status - not connected to the Learning Loop')
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.info(f'sending status: {status.short_str()}')
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.log.error(f'Error when sending status update: Response from loop was:\n {result}')
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.12
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 | PROJECT | smallest confidence (float) at which auto-upload will happen | Detector |
69
- | MAX_UNCERTAIN_THRESHOLD | PROJECT | largest confidence (float) at which auto-upload will happen | Detector |
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=wk11CQtM3A0Dr7efCn_Mw2X7ql5xn2sgEJzrIeSBC6Q,4043
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=1BcU5PNzIbryWcj2xJ6ysLBTBwGOdv9SxSJiUG8WEmw,4349
8
- learning_loop_node/data_classes/general.py,sha256=Bd0ngYhYvS_9OYOO6lAKEnDzLuSdPmR4I2YV-0DRsxs,4694
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=U_MrBKSq1MbBwBmjrjxoIo_7xV4Lcwtk6uZDIgmhT_4,8914
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=se0jRFbV7BfTvCuCI3gcUllSYIZ5dxTkvdISe6pPTRg,1660
14
- learning_loop_node/detector/detector_node.py,sha256=v7hX06HuBtS4LiqlqOxDBaJlqkJanHQ4mrdjc4fVwDQ,18282
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=s2FuwZ-tD_5obkSutstjc8pE_hLGbrv9WjrEO9t8rJ8,1011
18
- learning_loop_node/detector/outbox.py,sha256=MHHP4rnGaV8JxDSig96KZN4hSQ3i9z6-7WYhTTrMtp0,8082
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=pNnIllLBJYc_edFCJGFTCBT55pIj7GI-zYsCZyjQ8EA,623
21
- learning_loop_node/detector/rest/backdoor_controls.py,sha256=38axRG66Z3_Q6bYKa7Hw-ldChEAu-dJcBM_Sl_17Ozo,1725
22
- learning_loop_node/detector/rest/detect.py,sha256=8Rl1swANKgHc42P1z75t_PErQxpCKKPdAsKqDIZgdNU,1873
23
- learning_loop_node/detector/rest/model_version_control.py,sha256=PKG7foFyNSvjoMhWCDb7w3mq-2e0bx5gq3ov7Rao8HU,3703
24
- learning_loop_node/detector/rest/operation_mode.py,sha256=eIo6_56qyZECftf4AEN8wJMABIojC0TRazvWeg0Uj_s,1664
25
- learning_loop_node/detector/rest/outbox_mode.py,sha256=anSZHB6jliz1t3fxrmEzgwNB62UHNdWNc9ZYOc5Nn9s,1018
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=3yd-jaMOeD5cRIgA5w_BH2L5odf8c4-ZjD89Bdqwe44,824
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=mohvJGGfrMSGPTDvQOlX7TWs4QZ8YZHqr1YkyyGQphc,7983
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=_zNEYIuiRmXj4qPsQli82JbqRR5CzhChkyo3dP8WWaU,4161
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=2gJARodJSDuJHgeN1_xLMbvDcPQkXpBXEefu7MOyePk,8998
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=7nncnC2ZApakdyta9TMUfk0sgr_nyZhGFYCHuUlBlFI,3356
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=nvhkjBnGZgGVyomvPDcXuBR_WLqC4-QD2qE5enWiJ-g,3724
71
- learning_loop_node/tests/trainer/states/test_state_download_train_model.py,sha256=aJBh0ksz9g2kQ3qqk8yrX-50kdRS4I7ZaeeFkr9CR3c,2863
72
- learning_loop_node/tests/trainer/states/test_state_prepare.py,sha256=yaDhT-1676asGfgqhK2mfdoktAgeyWUwc2h0xyOoWzQ,2340
73
- learning_loop_node/tests/trainer/states/test_state_sync_confusion_matrix.py,sha256=0Ak5bU2uiqRDSEzVSTBEoT9GN5UgL7SqBqJRyyxjmWE,4727
74
- learning_loop_node/tests/trainer/states/test_state_train.py,sha256=dQDUvVI_FUYdLWm11F_7WxGge30l0OvML40Hil9r--k,3149
75
- learning_loop_node/tests/trainer/states/test_state_upload_detections.py,sha256=U2qK1Vbzb0yBMBYNvB815AYBD6MsII7wxzYJrwFnUHQ,7554
76
- learning_loop_node/tests/trainer/states/test_state_upload_model.py,sha256=u_YXELOWOXoaU4v41jgr3jHPWVFeVbe330k8GCEL9K0,3659
77
- learning_loop_node/tests/trainer/test_errors.py,sha256=Z3BWvUkVKxMGe_RNYeVbrhPps7ylek3qS1zK2FpdMmU,2165
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=Ylxz8HAId0Jlz95So5kXdJEp1yKQuwroDKIhbTUscF4,7257
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=YQcG0KwxzKDNYeMtHrSwr26q__N7ty0o6Kar6CLWAd0,5869
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=PJxiO1chPdvpq8UTtzv_nVam9CouCswX9b1FnRwT2Tw,8411
89
- learning_loop_node/trainer/trainer_logic_generic.py,sha256=AzllMMiUPP_CMkjIVqse8wY50Cg5RDnk5y5ERVUjtZg,25801
90
- learning_loop_node/trainer/trainer_node.py,sha256=dIptgXTwBC_bnPo-U2sG_zDaaqZixY7FA0dPt7P2Lps,5261
91
- learning_loop_node-0.10.12.dist-info/METADATA,sha256=CskPsSnBXkMeNHiPOewq2UAN0qAMazghb7ReZvlBKGI,11702
92
- learning_loop_node-0.10.12.dist-info/WHEEL,sha256=WGfLGfLX43Ei_YORXSnT54hxFygu34kMpcQdmgmEwCQ,88
93
- learning_loop_node-0.10.12.dist-info/RECORD,,
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,,