accusleepy 0.9.3__py3-none-any.whl → 0.10.1__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.
- accusleepy/__init__.py +1 -0
- accusleepy/__main__.py +2 -0
- accusleepy/bouts.py +2 -0
- accusleepy/brain_state_set.py +2 -0
- accusleepy/classification.py +2 -0
- accusleepy/config.json +2 -1
- accusleepy/constants.py +4 -0
- accusleepy/fileio.py +12 -3
- accusleepy/gui/__init__.py +1 -0
- accusleepy/gui/images/primary_window.png +0 -0
- accusleepy/gui/main.py +5 -7
- accusleepy/gui/manual_scoring.py +105 -42
- accusleepy/gui/mplwidget.py +2 -1
- accusleepy/gui/primary_window.py +85 -85
- accusleepy/gui/primary_window.ui +95 -107
- accusleepy/gui/recording_manager.py +24 -14
- accusleepy/gui/settings_widget.py +12 -0
- accusleepy/gui/text/main_guide.md +15 -12
- accusleepy/gui/text/manual_scoring_guide.md +1 -0
- accusleepy/models.py +2 -0
- accusleepy/multitaper.py +3 -60
- accusleepy/signal_processing.py +2 -0
- accusleepy/temperature_scaling.py +2 -0
- accusleepy/validation.py +2 -0
- {accusleepy-0.9.3.dist-info → accusleepy-0.10.1.dist-info}/METADATA +5 -8
- accusleepy-0.10.1.dist-info/RECORD +47 -0
- {accusleepy-0.9.3.dist-info → accusleepy-0.10.1.dist-info}/WHEEL +1 -1
- accusleepy-0.9.3.dist-info/RECORD +0 -47
accusleepy/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""AccuSleePy: Python implementation of AccuSleep for automated sleep scoring."""
|
accusleepy/__main__.py
CHANGED
accusleepy/bouts.py
CHANGED
accusleepy/brain_state_set.py
CHANGED
accusleepy/classification.py
CHANGED
accusleepy/config.json
CHANGED
accusleepy/constants.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Application-wide constants and default settings."""
|
|
2
|
+
|
|
1
3
|
import numpy as np
|
|
2
4
|
|
|
3
5
|
# probably don't change these unless you really need to
|
|
@@ -72,6 +74,7 @@ EMG_FILTER_KEY = "emg_filter"
|
|
|
72
74
|
HYPERPARAMETERS_KEY = "hyperparameters"
|
|
73
75
|
EPOCHS_TO_SHOW_KEY = "epochs_to_show"
|
|
74
76
|
AUTOSCROLL_KEY = "autoscroll_state"
|
|
77
|
+
DELETE_TRAINING_IMAGES_KEY = "delete_training_images"
|
|
75
78
|
|
|
76
79
|
# default values
|
|
77
80
|
# default UI settings
|
|
@@ -87,6 +90,7 @@ DEFAULT_BATCH_SIZE = 64
|
|
|
87
90
|
DEFAULT_LEARNING_RATE = 1e-3
|
|
88
91
|
DEFAULT_MOMENTUM = 0.9
|
|
89
92
|
DEFAULT_TRAINING_EPOCHS = 6
|
|
93
|
+
DEFAULT_DELETE_TRAINING_IMAGES_STATE = True
|
|
90
94
|
# default manual scoring settings
|
|
91
95
|
DEFAULT_EPOCHS_TO_SHOW = 5
|
|
92
96
|
DEFAULT_AUTOSCROLL_STATE = False
|
accusleepy/fileio.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""File I/O for recordings, labels, calibration data, and configuration."""
|
|
2
|
+
|
|
1
3
|
import json
|
|
2
4
|
import os
|
|
3
5
|
from dataclasses import dataclass
|
|
@@ -5,7 +7,6 @@ from importlib.metadata import version, PackageNotFoundError
|
|
|
5
7
|
|
|
6
8
|
import numpy as np
|
|
7
9
|
import pandas as pd
|
|
8
|
-
from PySide6.QtWidgets import QListWidgetItem
|
|
9
10
|
|
|
10
11
|
from accusleepy.brain_state_set import BRAIN_STATES_KEY, BrainState, BrainStateSet
|
|
11
12
|
import accusleepy.constants as c
|
|
@@ -43,6 +44,7 @@ class AccuSleePyConfig:
|
|
|
43
44
|
hyperparameters: Hyperparameters
|
|
44
45
|
epochs_to_show: int
|
|
45
46
|
autoscroll_state: bool
|
|
47
|
+
delete_training_images: bool
|
|
46
48
|
|
|
47
49
|
|
|
48
50
|
@dataclass
|
|
@@ -54,7 +56,6 @@ class Recording:
|
|
|
54
56
|
label_file: str = "" # path to label file
|
|
55
57
|
calibration_file: str = "" # path to calibration file
|
|
56
58
|
sampling_rate: int | float = 0.0 # sampling rate, in Hz
|
|
57
|
-
widget: QListWidgetItem = None # list item widget shown in the GUI
|
|
58
59
|
|
|
59
60
|
|
|
60
61
|
def load_calibration_file(filename: str) -> tuple[np.ndarray, np.ndarray]:
|
|
@@ -139,7 +140,8 @@ def load_config() -> AccuSleePyConfig:
|
|
|
139
140
|
EMG filter parameters,
|
|
140
141
|
model training hyperparameters,
|
|
141
142
|
default epochs to show for manual scoring,
|
|
142
|
-
default autoscroll state for manual scoring
|
|
143
|
+
default autoscroll state for manual scoring,
|
|
144
|
+
setting to delete training images automatically
|
|
143
145
|
"""
|
|
144
146
|
with open(
|
|
145
147
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), c.CONFIG_FILE), "r"
|
|
@@ -183,6 +185,9 @@ def load_config() -> AccuSleePyConfig:
|
|
|
183
185
|
),
|
|
184
186
|
epochs_to_show=data.get(c.EPOCHS_TO_SHOW_KEY, c.DEFAULT_EPOCHS_TO_SHOW),
|
|
185
187
|
autoscroll_state=data.get(c.AUTOSCROLL_KEY, c.DEFAULT_AUTOSCROLL_STATE),
|
|
188
|
+
delete_training_images=data.get(
|
|
189
|
+
c.DELETE_TRAINING_IMAGES_KEY, c.DEFAULT_DELETE_TRAINING_IMAGES_STATE
|
|
190
|
+
),
|
|
186
191
|
)
|
|
187
192
|
|
|
188
193
|
|
|
@@ -196,6 +201,7 @@ def save_config(
|
|
|
196
201
|
hyperparameters: Hyperparameters,
|
|
197
202
|
epochs_to_show: int,
|
|
198
203
|
autoscroll_state: bool,
|
|
204
|
+
delete_training_images: bool,
|
|
199
205
|
) -> None:
|
|
200
206
|
"""Save configuration of brain state options to json file
|
|
201
207
|
|
|
@@ -210,6 +216,8 @@ def save_config(
|
|
|
210
216
|
:param hyperparameters: model training hyperparameters
|
|
211
217
|
:param epochs_to_show: default epochs to show for manual scoring,
|
|
212
218
|
:param autoscroll_state: default autoscroll state for manual scoring
|
|
219
|
+
:param delete_training_images: whether to automatically delete images
|
|
220
|
+
created for model training once training is complete
|
|
213
221
|
"""
|
|
214
222
|
output_dict = brain_state_set.to_output_dict()
|
|
215
223
|
output_dict.update({c.DEFAULT_EPOCH_LENGTH_KEY: default_epoch_length})
|
|
@@ -220,6 +228,7 @@ def save_config(
|
|
|
220
228
|
output_dict.update({c.HYPERPARAMETERS_KEY: hyperparameters.__dict__})
|
|
221
229
|
output_dict.update({c.EPOCHS_TO_SHOW_KEY: epochs_to_show})
|
|
222
230
|
output_dict.update({c.AUTOSCROLL_KEY: autoscroll_state})
|
|
231
|
+
output_dict.update({c.DELETE_TRAINING_IMAGES_KEY: delete_training_images})
|
|
223
232
|
with open(
|
|
224
233
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), c.CONFIG_FILE), "w"
|
|
225
234
|
) as f:
|
accusleepy/gui/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Graphical user interface components for AccuSleePy."""
|
|
Binary file
|
accusleepy/gui/main.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"""AccuSleePy main window.
|
|
2
|
+
|
|
3
|
+
Icon source: Arkinasi, https://www.flaticon.com/authors/arkinasi
|
|
4
|
+
"""
|
|
3
5
|
|
|
4
6
|
import logging
|
|
5
7
|
import os
|
|
@@ -76,7 +78,6 @@ class TrainingSettings:
|
|
|
76
78
|
"""Settings for training a new model"""
|
|
77
79
|
|
|
78
80
|
epochs_per_img: int = 9
|
|
79
|
-
delete_images: bool = True
|
|
80
81
|
model_type: str = DEFAULT_MODEL_TYPE
|
|
81
82
|
calibrate: bool = True
|
|
82
83
|
|
|
@@ -176,9 +177,6 @@ class AccuSleepWindow(QMainWindow):
|
|
|
176
177
|
self.ui.image_number_input.valueChanged.connect(
|
|
177
178
|
lambda v: setattr(self.training, "epochs_per_img", v)
|
|
178
179
|
)
|
|
179
|
-
self.ui.delete_image_box.stateChanged.connect(
|
|
180
|
-
lambda v: setattr(self.training, "delete_images", bool(v))
|
|
181
|
-
)
|
|
182
180
|
self.ui.calibrate_checkbox.stateChanged.connect(
|
|
183
181
|
self.update_training_calibration
|
|
184
182
|
)
|
|
@@ -304,7 +302,7 @@ class AccuSleepWindow(QMainWindow):
|
|
|
304
302
|
emg_filter=self.config.emg_filter,
|
|
305
303
|
hyperparameters=self.config.hyperparameters,
|
|
306
304
|
model_filename=model_filename,
|
|
307
|
-
delete_images=self.
|
|
305
|
+
delete_images=self.config.delete_training_images,
|
|
308
306
|
)
|
|
309
307
|
|
|
310
308
|
# Display results
|
accusleepy/gui/manual_scoring.py
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
# Icon sources:
|
|
3
|
-
# Arkinasi, https://www.flaticon.com/authors/arkinasi
|
|
4
|
-
# kendis lasman, https://www.flaticon.com/packs/ui-79
|
|
1
|
+
"""AccuSleePy manual scoring GUI.
|
|
5
2
|
|
|
3
|
+
Icon sources:
|
|
4
|
+
Arkinasi, https://www.flaticon.com/authors/arkinasi
|
|
5
|
+
kendis lasman, https://www.flaticon.com/packs/ui-79
|
|
6
|
+
"""
|
|
6
7
|
|
|
7
8
|
import copy
|
|
8
9
|
import os
|
|
10
|
+
import time
|
|
9
11
|
from dataclasses import dataclass
|
|
10
12
|
from functools import partial
|
|
11
13
|
from types import SimpleNamespace
|
|
@@ -82,9 +84,10 @@ UNDO_LIMIT = 1000
|
|
|
82
84
|
# brightness scaling factors for the spectrogram
|
|
83
85
|
BRIGHTER_SCALE_FACTOR = 0.96
|
|
84
86
|
DIMMER_SCALE_FACTOR = 1.07
|
|
85
|
-
# zoom factor for upper plots
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
# zoom factor for upper plots - larger values = bigger changes
|
|
88
|
+
ZOOM_FACTOR = 0.1
|
|
89
|
+
# rate limit for zoom events triggered by scrolling
|
|
90
|
+
MAX_SCROLL_EVENTS_PER_SEC = 24
|
|
88
91
|
|
|
89
92
|
|
|
90
93
|
@dataclass
|
|
@@ -352,8 +355,10 @@ class ManualScoringWindow(QDialog):
|
|
|
352
355
|
)
|
|
353
356
|
keypress_redo.activated.connect(self.redo)
|
|
354
357
|
|
|
355
|
-
# user input:
|
|
358
|
+
# user input: mouse events
|
|
356
359
|
self.ui.upperfigure.canvas.mpl_connect("button_press_event", self.click_to_jump)
|
|
360
|
+
self.ui.upperfigure.canvas.mpl_connect("scroll_event", self.scroll_zoom)
|
|
361
|
+
self.now_zooming = False # impose timeout on zoom events
|
|
357
362
|
|
|
358
363
|
# user input: buttons
|
|
359
364
|
self.ui.savebutton.clicked.connect(self.save)
|
|
@@ -483,7 +488,7 @@ class ManualScoringWindow(QDialog):
|
|
|
483
488
|
|
|
484
489
|
def closeEvent(self, event: QCloseEvent) -> None:
|
|
485
490
|
"""Check if there are unsaved changes before closing"""
|
|
486
|
-
if not
|
|
491
|
+
if not np.array_equal(self.labels, self.last_saved_labels):
|
|
487
492
|
result = QMessageBox.question(
|
|
488
493
|
self,
|
|
489
494
|
"Unsaved changes",
|
|
@@ -668,6 +673,8 @@ class ManualScoringWindow(QDialog):
|
|
|
668
673
|
self.label_display_options,
|
|
669
674
|
)
|
|
670
675
|
self.update_figures()
|
|
676
|
+
# upper plot x limits might need to change
|
|
677
|
+
self.zoom_x(direction=None)
|
|
671
678
|
|
|
672
679
|
def update_signal_offset(self, signal: str, direction: str) -> None:
|
|
673
680
|
"""Shift EEG or EMG up or down
|
|
@@ -713,39 +720,19 @@ class ManualScoringWindow(QDialog):
|
|
|
713
720
|
(self.upper_left_epoch, self.upper_right_epoch + 1)
|
|
714
721
|
)
|
|
715
722
|
|
|
716
|
-
def zoom_x(self, direction: str) -> None:
|
|
723
|
+
def zoom_x(self, direction: str | None) -> None:
|
|
717
724
|
"""Change upper figure x-axis zoom level
|
|
718
725
|
|
|
719
|
-
:param direction: in, out, or
|
|
726
|
+
:param direction: in, out, reset, or None
|
|
720
727
|
"""
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
self.upper_left_epoch
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
self.upper_right_epoch = min(
|
|
731
|
-
[
|
|
732
|
-
self.upper_right_epoch,
|
|
733
|
-
round(self.epoch + ZOOM_IN_FACTOR * epochs_shown),
|
|
734
|
-
]
|
|
735
|
-
)
|
|
736
|
-
|
|
737
|
-
elif direction == ZOOM_OUT:
|
|
738
|
-
self.upper_left_epoch = max(
|
|
739
|
-
[0, round(self.epoch - ZOOM_OUT_FACTOR * epochs_shown)]
|
|
740
|
-
)
|
|
741
|
-
|
|
742
|
-
self.upper_right_epoch = min(
|
|
743
|
-
[self.n_epochs - 1, round(self.epoch + ZOOM_OUT_FACTOR * epochs_shown)]
|
|
744
|
-
)
|
|
745
|
-
|
|
746
|
-
else: # reset
|
|
747
|
-
self.upper_left_epoch = 0
|
|
748
|
-
self.upper_right_epoch = self.n_epochs - 1
|
|
728
|
+
self.upper_left_epoch, self.upper_right_epoch = find_new_x_limits(
|
|
729
|
+
direction=direction,
|
|
730
|
+
left_epoch=self.upper_left_epoch,
|
|
731
|
+
right_epoch=self.upper_right_epoch,
|
|
732
|
+
min_n_shown=self.epochs_to_show,
|
|
733
|
+
total_epochs=self.n_epochs,
|
|
734
|
+
selected_epoch=self.epoch,
|
|
735
|
+
)
|
|
749
736
|
self.adjust_upper_figure_x_limits()
|
|
750
737
|
self.ui.upperfigure.canvas.draw()
|
|
751
738
|
|
|
@@ -806,8 +793,11 @@ class ManualScoringWindow(QDialog):
|
|
|
806
793
|
# update upper plot if needed
|
|
807
794
|
upper_epochs_shown = self.upper_right_epoch - self.upper_left_epoch + 1
|
|
808
795
|
if (
|
|
809
|
-
|
|
810
|
-
|
|
796
|
+
(
|
|
797
|
+
self.epoch
|
|
798
|
+
> self.upper_left_epoch + (1 - SCROLL_BOUNDARY) * upper_epochs_shown
|
|
799
|
+
or self.epoch + (self.epochs_to_show - 1) / 2 > self.upper_right_epoch
|
|
800
|
+
)
|
|
811
801
|
and self.upper_right_epoch < (self.n_epochs - 1)
|
|
812
802
|
and direction == DIRECTION_RIGHT
|
|
813
803
|
):
|
|
@@ -815,7 +805,11 @@ class ManualScoringWindow(QDialog):
|
|
|
815
805
|
self.upper_right_epoch += 1
|
|
816
806
|
self.adjust_upper_figure_x_limits()
|
|
817
807
|
elif (
|
|
818
|
-
|
|
808
|
+
(
|
|
809
|
+
self.epoch
|
|
810
|
+
< self.upper_left_epoch + SCROLL_BOUNDARY * upper_epochs_shown
|
|
811
|
+
or self.epoch - (self.epochs_to_show - 1) / 2 < self.upper_left_epoch
|
|
812
|
+
)
|
|
819
813
|
and self.upper_left_epoch > 0
|
|
820
814
|
and direction == DIRECTION_LEFT
|
|
821
815
|
):
|
|
@@ -984,6 +978,23 @@ class ManualScoringWindow(QDialog):
|
|
|
984
978
|
|
|
985
979
|
self.update_figures()
|
|
986
980
|
|
|
981
|
+
def scroll_zoom(self, event) -> None:
|
|
982
|
+
"""Zoom on mouse scroll events"""
|
|
983
|
+
if self.now_zooming:
|
|
984
|
+
return
|
|
985
|
+
|
|
986
|
+
self.now_zooming = True
|
|
987
|
+
start_time = time.time()
|
|
988
|
+
if event.button == "up":
|
|
989
|
+
self.zoom_x(direction=ZOOM_IN)
|
|
990
|
+
else:
|
|
991
|
+
self.zoom_x(direction=ZOOM_OUT)
|
|
992
|
+
end_time = time.time()
|
|
993
|
+
time_elapsed = end_time - start_time
|
|
994
|
+
if time_elapsed < 1 / MAX_SCROLL_EVENTS_PER_SEC:
|
|
995
|
+
time.sleep(1 / MAX_SCROLL_EVENTS_PER_SEC - time_elapsed)
|
|
996
|
+
self.now_zooming = False
|
|
997
|
+
|
|
987
998
|
|
|
988
999
|
def convert_labels(labels: np.array, style: str) -> np.array:
|
|
989
1000
|
"""Convert labels between "display" and "digit" formats
|
|
@@ -1095,3 +1106,55 @@ def transform_eeg_emg(eeg: np.array, emg: np.array) -> (np.array, np.array):
|
|
|
1095
1106
|
eeg = eeg / np.percentile(eeg, 95) / 2.2
|
|
1096
1107
|
emg = emg / np.percentile(emg, 95) / 2.2
|
|
1097
1108
|
return eeg, emg
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
def find_new_x_limits(
|
|
1112
|
+
direction: str | None,
|
|
1113
|
+
left_epoch: int,
|
|
1114
|
+
right_epoch: int,
|
|
1115
|
+
total_epochs: int,
|
|
1116
|
+
min_n_shown: int,
|
|
1117
|
+
selected_epoch: int,
|
|
1118
|
+
) -> (int, int):
|
|
1119
|
+
"""Calculate new plot x limits to allow zooming
|
|
1120
|
+
|
|
1121
|
+
:param direction: in, out, reset, or None
|
|
1122
|
+
:param left_epoch: index of current leftmost epoch
|
|
1123
|
+
:param right_epoch: index of current rightmost epoch
|
|
1124
|
+
:param total_epochs: total number of epochs in the recording
|
|
1125
|
+
:param min_n_shown: minimum number of epochs to display
|
|
1126
|
+
:param selected_epoch: currently selected epoch
|
|
1127
|
+
"""
|
|
1128
|
+
# number of epochs currently displayed in the upper plots
|
|
1129
|
+
current_n_shown = right_epoch - left_epoch + 1
|
|
1130
|
+
if direction == ZOOM_IN:
|
|
1131
|
+
# can't display fewer than the number of epochs in the lower plot
|
|
1132
|
+
new_n_shown = max([min_n_shown, round(current_n_shown * (1 - ZOOM_FACTOR))])
|
|
1133
|
+
elif direction == ZOOM_OUT:
|
|
1134
|
+
# can't display more than the total number of epochs
|
|
1135
|
+
new_n_shown = min([total_epochs, round(current_n_shown / (1 - ZOOM_FACTOR))])
|
|
1136
|
+
elif direction == ZOOM_RESET:
|
|
1137
|
+
left_epoch = 0
|
|
1138
|
+
right_epoch = total_epochs - 1
|
|
1139
|
+
return left_epoch, right_epoch
|
|
1140
|
+
else: # just recalculating if min_n_shown has changed
|
|
1141
|
+
new_n_shown = int(
|
|
1142
|
+
np.clip(current_n_shown, a_min=min_n_shown, a_max=total_epochs)
|
|
1143
|
+
)
|
|
1144
|
+
|
|
1145
|
+
# count epochs to show on either side of the selected epoch
|
|
1146
|
+
epochs_on_left_side = int(np.ceil((new_n_shown - 1) / 2))
|
|
1147
|
+
epochs_on_right_side = new_n_shown - epochs_on_left_side - 1
|
|
1148
|
+
if selected_epoch - epochs_on_left_side < 0:
|
|
1149
|
+
# can't go further left than 0
|
|
1150
|
+
left_epoch = 0
|
|
1151
|
+
right_epoch = new_n_shown - 1
|
|
1152
|
+
elif selected_epoch + epochs_on_right_side >= total_epochs:
|
|
1153
|
+
# can't go further right than the total number of epochs
|
|
1154
|
+
left_epoch = total_epochs - new_n_shown
|
|
1155
|
+
right_epoch = total_epochs - 1
|
|
1156
|
+
else:
|
|
1157
|
+
left_epoch = selected_epoch - epochs_on_left_side
|
|
1158
|
+
right_epoch = selected_epoch + epochs_on_right_side
|
|
1159
|
+
|
|
1160
|
+
return left_epoch, right_epoch
|
accusleepy/gui/mplwidget.py
CHANGED
accusleepy/gui/primary_window.py
CHANGED
|
@@ -757,7 +757,7 @@ class Ui_PrimaryWindow(object):
|
|
|
757
757
|
self.top_training_layout.setSpacing(10)
|
|
758
758
|
self.top_training_layout.setObjectName("top_training_layout")
|
|
759
759
|
self.horizontalLayout_5 = QHBoxLayout()
|
|
760
|
-
self.horizontalLayout_5.setSpacing(
|
|
760
|
+
self.horizontalLayout_5.setSpacing(3)
|
|
761
761
|
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
|
|
762
762
|
self.label = QLabel(self.model_training_tab)
|
|
763
763
|
self.label.setObjectName("label")
|
|
@@ -786,21 +786,48 @@ class Ui_PrimaryWindow(object):
|
|
|
786
786
|
|
|
787
787
|
self.top_training_layout.addItem(self.horizontalSpacer)
|
|
788
788
|
|
|
789
|
-
self.
|
|
790
|
-
self.
|
|
789
|
+
self.calibrate_checkbox = QCheckBox(self.model_training_tab)
|
|
790
|
+
self.calibrate_checkbox.setObjectName("calibrate_checkbox")
|
|
791
791
|
sizePolicy1.setHeightForWidth(
|
|
792
|
-
self.
|
|
792
|
+
self.calibrate_checkbox.sizePolicy().hasHeightForWidth()
|
|
793
793
|
)
|
|
794
|
-
self.
|
|
795
|
-
self.
|
|
794
|
+
self.calibrate_checkbox.setSizePolicy(sizePolicy1)
|
|
795
|
+
self.calibrate_checkbox.setChecked(True)
|
|
796
|
+
|
|
797
|
+
self.top_training_layout.addWidget(self.calibrate_checkbox)
|
|
798
|
+
|
|
799
|
+
self.horizontalLayout_84 = QHBoxLayout()
|
|
800
|
+
self.horizontalLayout_84.setSpacing(3)
|
|
801
|
+
self.horizontalLayout_84.setObjectName("horizontalLayout_84")
|
|
802
|
+
self.horizontalLayout_84.setContentsMargins(10, -1, -1, -1)
|
|
803
|
+
self.calibrate_label = QLabel(self.model_training_tab)
|
|
804
|
+
self.calibrate_label.setObjectName("calibrate_label")
|
|
805
|
+
sizePolicy1.setHeightForWidth(
|
|
806
|
+
self.calibrate_label.sizePolicy().hasHeightForWidth()
|
|
807
|
+
)
|
|
808
|
+
self.calibrate_label.setSizePolicy(sizePolicy1)
|
|
809
|
+
|
|
810
|
+
self.horizontalLayout_84.addWidget(self.calibrate_label)
|
|
811
|
+
|
|
812
|
+
self.calibration_spinbox = QSpinBox(self.model_training_tab)
|
|
813
|
+
self.calibration_spinbox.setObjectName("calibration_spinbox")
|
|
814
|
+
sizePolicy1.setHeightForWidth(
|
|
815
|
+
self.calibration_spinbox.sizePolicy().hasHeightForWidth()
|
|
816
|
+
)
|
|
817
|
+
self.calibration_spinbox.setSizePolicy(sizePolicy1)
|
|
818
|
+
self.calibration_spinbox.setMinimum(10)
|
|
819
|
+
self.calibration_spinbox.setMaximum(50)
|
|
820
|
+
self.calibration_spinbox.setValue(15)
|
|
821
|
+
|
|
822
|
+
self.horizontalLayout_84.addWidget(self.calibration_spinbox)
|
|
796
823
|
|
|
797
|
-
self.top_training_layout.
|
|
824
|
+
self.top_training_layout.addLayout(self.horizontalLayout_84)
|
|
798
825
|
|
|
799
|
-
self.
|
|
826
|
+
self.horizontalSpacer_3 = QSpacerItem(
|
|
800
827
|
10, 5, QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Minimum
|
|
801
828
|
)
|
|
802
829
|
|
|
803
|
-
self.top_training_layout.addItem(self.
|
|
830
|
+
self.top_training_layout.addItem(self.horizontalSpacer_3)
|
|
804
831
|
|
|
805
832
|
self.horizontalLayout_6 = QHBoxLayout()
|
|
806
833
|
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
|
|
@@ -836,18 +863,12 @@ class Ui_PrimaryWindow(object):
|
|
|
836
863
|
|
|
837
864
|
self.top_training_layout.addLayout(self.horizontalLayout_6)
|
|
838
865
|
|
|
839
|
-
self.
|
|
840
|
-
10, 5, QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Minimum
|
|
841
|
-
)
|
|
842
|
-
|
|
843
|
-
self.top_training_layout.addItem(self.horizontalSpacer_3)
|
|
844
|
-
|
|
845
|
-
self.top_training_layout.setStretch(0, 2)
|
|
866
|
+
self.top_training_layout.setStretch(0, 5)
|
|
846
867
|
self.top_training_layout.setStretch(1, 1)
|
|
847
|
-
self.top_training_layout.setStretch(2,
|
|
848
|
-
self.top_training_layout.setStretch(3,
|
|
849
|
-
self.top_training_layout.setStretch(4,
|
|
850
|
-
self.top_training_layout.setStretch(5,
|
|
868
|
+
self.top_training_layout.setStretch(2, 3)
|
|
869
|
+
self.top_training_layout.setStretch(3, 4)
|
|
870
|
+
self.top_training_layout.setStretch(4, 1)
|
|
871
|
+
self.top_training_layout.setStretch(5, 5)
|
|
851
872
|
|
|
852
873
|
self.model_training_layout.addLayout(self.top_training_layout, 0, 0, 1, 1)
|
|
853
874
|
|
|
@@ -855,10 +876,10 @@ class Ui_PrimaryWindow(object):
|
|
|
855
876
|
self.bottom_training_layout.setObjectName("bottom_training_layout")
|
|
856
877
|
self.train_model_button = QPushButton(self.model_training_tab)
|
|
857
878
|
self.train_model_button.setObjectName("train_model_button")
|
|
858
|
-
|
|
879
|
+
sizePolicy1.setHeightForWidth(
|
|
859
880
|
self.train_model_button.sizePolicy().hasHeightForWidth()
|
|
860
881
|
)
|
|
861
|
-
self.train_model_button.setSizePolicy(
|
|
882
|
+
self.train_model_button.setSizePolicy(sizePolicy1)
|
|
862
883
|
|
|
863
884
|
self.bottom_training_layout.addWidget(self.train_model_button)
|
|
864
885
|
|
|
@@ -868,56 +889,8 @@ class Ui_PrimaryWindow(object):
|
|
|
868
889
|
|
|
869
890
|
self.bottom_training_layout.addItem(self.horizontalSpacer_8)
|
|
870
891
|
|
|
871
|
-
self.
|
|
872
|
-
self.calibrate_checkbox.setObjectName("calibrate_checkbox")
|
|
873
|
-
sizePolicy1.setHeightForWidth(
|
|
874
|
-
self.calibrate_checkbox.sizePolicy().hasHeightForWidth()
|
|
875
|
-
)
|
|
876
|
-
self.calibrate_checkbox.setSizePolicy(sizePolicy1)
|
|
877
|
-
self.calibrate_checkbox.setChecked(True)
|
|
878
|
-
|
|
879
|
-
self.bottom_training_layout.addWidget(self.calibrate_checkbox)
|
|
880
|
-
|
|
881
|
-
self.horizontalSpacer_7 = QSpacerItem(
|
|
882
|
-
10, 10, QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Minimum
|
|
883
|
-
)
|
|
884
|
-
|
|
885
|
-
self.bottom_training_layout.addItem(self.horizontalSpacer_7)
|
|
886
|
-
|
|
887
|
-
self.calibrate_label = QLabel(self.model_training_tab)
|
|
888
|
-
self.calibrate_label.setObjectName("calibrate_label")
|
|
889
|
-
sizePolicy1.setHeightForWidth(
|
|
890
|
-
self.calibrate_label.sizePolicy().hasHeightForWidth()
|
|
891
|
-
)
|
|
892
|
-
self.calibrate_label.setSizePolicy(sizePolicy1)
|
|
893
|
-
|
|
894
|
-
self.bottom_training_layout.addWidget(self.calibrate_label)
|
|
895
|
-
|
|
896
|
-
self.calibration_spinbox = QSpinBox(self.model_training_tab)
|
|
897
|
-
self.calibration_spinbox.setObjectName("calibration_spinbox")
|
|
898
|
-
sizePolicy1.setHeightForWidth(
|
|
899
|
-
self.calibration_spinbox.sizePolicy().hasHeightForWidth()
|
|
900
|
-
)
|
|
901
|
-
self.calibration_spinbox.setSizePolicy(sizePolicy1)
|
|
902
|
-
self.calibration_spinbox.setMinimum(10)
|
|
903
|
-
self.calibration_spinbox.setMaximum(50)
|
|
904
|
-
self.calibration_spinbox.setValue(15)
|
|
905
|
-
|
|
906
|
-
self.bottom_training_layout.addWidget(self.calibration_spinbox)
|
|
907
|
-
|
|
908
|
-
self.horizontalSpacer_78 = QSpacerItem(
|
|
909
|
-
10, 10, QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Minimum
|
|
910
|
-
)
|
|
911
|
-
|
|
912
|
-
self.bottom_training_layout.addItem(self.horizontalSpacer_78)
|
|
913
|
-
|
|
914
|
-
self.bottom_training_layout.setStretch(0, 6)
|
|
892
|
+
self.bottom_training_layout.setStretch(0, 5)
|
|
915
893
|
self.bottom_training_layout.setStretch(1, 5)
|
|
916
|
-
self.bottom_training_layout.setStretch(2, 3)
|
|
917
|
-
self.bottom_training_layout.setStretch(3, 1)
|
|
918
|
-
self.bottom_training_layout.setStretch(4, 3)
|
|
919
|
-
self.bottom_training_layout.setStretch(5, 1)
|
|
920
|
-
self.bottom_training_layout.setStretch(6, 1)
|
|
921
894
|
|
|
922
895
|
self.model_training_layout.addLayout(self.bottom_training_layout, 1, 0, 1, 1)
|
|
923
896
|
|
|
@@ -2749,6 +2722,30 @@ class Ui_PrimaryWindow(object):
|
|
|
2749
2722
|
|
|
2750
2723
|
self.verticalLayout_14.addLayout(self.horizontalLayout_71)
|
|
2751
2724
|
|
|
2725
|
+
self.horizontalLayout_79 = QHBoxLayout()
|
|
2726
|
+
self.horizontalLayout_79.setObjectName("horizontalLayout_79")
|
|
2727
|
+
self.horizontalLayout_85 = QHBoxLayout()
|
|
2728
|
+
self.horizontalLayout_85.setObjectName("horizontalLayout_85")
|
|
2729
|
+
self.delete_image_box = QCheckBox(self.hyperparameter_page)
|
|
2730
|
+
self.delete_image_box.setObjectName("delete_image_box")
|
|
2731
|
+
sizePolicy1.setHeightForWidth(
|
|
2732
|
+
self.delete_image_box.sizePolicy().hasHeightForWidth()
|
|
2733
|
+
)
|
|
2734
|
+
self.delete_image_box.setSizePolicy(sizePolicy1)
|
|
2735
|
+
self.delete_image_box.setChecked(True)
|
|
2736
|
+
|
|
2737
|
+
self.horizontalLayout_85.addWidget(self.delete_image_box)
|
|
2738
|
+
|
|
2739
|
+
self.horizontalLayout_79.addLayout(self.horizontalLayout_85)
|
|
2740
|
+
|
|
2741
|
+
self.horizontalSpacer_93 = QSpacerItem(
|
|
2742
|
+
40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum
|
|
2743
|
+
)
|
|
2744
|
+
|
|
2745
|
+
self.horizontalLayout_79.addItem(self.horizontalSpacer_93)
|
|
2746
|
+
|
|
2747
|
+
self.verticalLayout_14.addLayout(self.horizontalLayout_79)
|
|
2748
|
+
|
|
2752
2749
|
self.horizontalLayout_74 = QHBoxLayout()
|
|
2753
2750
|
self.horizontalLayout_74.setObjectName("horizontalLayout_74")
|
|
2754
2751
|
self.horizontalSpacer_86 = QSpacerItem(
|
|
@@ -3033,11 +3030,16 @@ class Ui_PrimaryWindow(object):
|
|
|
3033
3030
|
self.label.setText(
|
|
3034
3031
|
QCoreApplication.translate("PrimaryWindow", "Epochs per image:", None)
|
|
3035
3032
|
)
|
|
3036
|
-
self.
|
|
3037
|
-
QCoreApplication.translate(
|
|
3038
|
-
"PrimaryWindow", "Delete images after training", None
|
|
3039
|
-
)
|
|
3033
|
+
self.calibrate_checkbox.setText(
|
|
3034
|
+
QCoreApplication.translate("PrimaryWindow", "Calibrate model", None)
|
|
3040
3035
|
)
|
|
3036
|
+
self.calibrate_label.setText(
|
|
3037
|
+
QCoreApplication.translate("PrimaryWindow", "Calibration set size:", None)
|
|
3038
|
+
)
|
|
3039
|
+
self.calibration_spinbox.setSuffix(
|
|
3040
|
+
QCoreApplication.translate("PrimaryWindow", "%", None)
|
|
3041
|
+
)
|
|
3042
|
+
self.calibration_spinbox.setPrefix("")
|
|
3041
3043
|
self.label_2.setText(
|
|
3042
3044
|
QCoreApplication.translate("PrimaryWindow", "Model type:", None)
|
|
3043
3045
|
)
|
|
@@ -3059,15 +3061,6 @@ class Ui_PrimaryWindow(object):
|
|
|
3059
3061
|
"PrimaryWindow", "Train classification model", None
|
|
3060
3062
|
)
|
|
3061
3063
|
)
|
|
3062
|
-
self.calibrate_checkbox.setText(
|
|
3063
|
-
QCoreApplication.translate("PrimaryWindow", "Calibrate model", None)
|
|
3064
|
-
)
|
|
3065
|
-
self.calibrate_label.setText(
|
|
3066
|
-
QCoreApplication.translate("PrimaryWindow", "Calibration set size:", None)
|
|
3067
|
-
)
|
|
3068
|
-
self.calibration_spinbox.setSuffix(
|
|
3069
|
-
QCoreApplication.translate("PrimaryWindow", "%", None)
|
|
3070
|
-
)
|
|
3071
3064
|
self.lower_tab_widget.setTabText(
|
|
3072
3065
|
self.lower_tab_widget.indexOf(self.model_training_tab),
|
|
3073
3066
|
QCoreApplication.translate("PrimaryWindow", "Model training", None),
|
|
@@ -3296,6 +3289,11 @@ class Ui_PrimaryWindow(object):
|
|
|
3296
3289
|
self.training_epochs_label.setText(
|
|
3297
3290
|
QCoreApplication.translate("PrimaryWindow", "Epochs:", None)
|
|
3298
3291
|
)
|
|
3292
|
+
self.delete_image_box.setText(
|
|
3293
|
+
QCoreApplication.translate(
|
|
3294
|
+
"PrimaryWindow", "Delete images after training", None
|
|
3295
|
+
)
|
|
3296
|
+
)
|
|
3299
3297
|
self.reset_hyperparams_button.setText(
|
|
3300
3298
|
QCoreApplication.translate("PrimaryWindow", "reset to defaults", None)
|
|
3301
3299
|
)
|
|
@@ -3306,7 +3304,9 @@ class Ui_PrimaryWindow(object):
|
|
|
3306
3304
|
"- Batch size: number of examples in each training iteration\n"
|
|
3307
3305
|
"- Learning rate: step size for adjusting model weights\n"
|
|
3308
3306
|
"- Momentum: amount of past gradients to use in the current update. Typically between 0.6 and 0.99\n"
|
|
3309
|
-
"- Epochs: number of passes over the training data"
|
|
3307
|
+
"- Epochs: number of passes over the training data\n"
|
|
3308
|
+
"\n"
|
|
3309
|
+
"You can also choose whether to delete images created by the training process once it's finished. This is recommended unless you are debugging the training code.",
|
|
3310
3310
|
None,
|
|
3311
3311
|
)
|
|
3312
3312
|
)
|