radnn 0.0.8__py3-none-any.whl → 0.1.0__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.
- radnn/__init__.py +5 -5
- radnn/benchmark/__init__.py +1 -0
- radnn/benchmark/latency.py +55 -0
- radnn/core.py +146 -2
- radnn/data/__init__.py +5 -10
- radnn/data/dataset_base.py +100 -260
- radnn/data/dataset_base_legacy.py +280 -0
- radnn/data/errors.py +32 -0
- radnn/data/sample_preprocessor.py +58 -0
- radnn/data/sample_set.py +203 -90
- radnn/data/sample_set_kind.py +126 -0
- radnn/data/sequence_dataset.py +25 -30
- radnn/data/structs/__init__.py +1 -0
- radnn/data/structs/tree.py +322 -0
- radnn/data_beta/__init__.py +12 -0
- radnn/{data → data_beta}/data_feed.py +1 -1
- radnn/data_beta/dataset_base.py +337 -0
- radnn/data_beta/sample_set.py +166 -0
- radnn/data_beta/sequence_dataset.py +134 -0
- radnn/data_beta/structures/__init__.py +2 -0
- radnn/data_beta/structures/dictionary.py +41 -0
- radnn/{data → data_beta}/tf_classification_data_feed.py +5 -2
- radnn/errors.py +10 -2
- radnn/experiment/__init__.py +2 -0
- radnn/experiment/identification.py +7 -0
- radnn/experiment/ml_experiment.py +7 -2
- radnn/experiment/ml_experiment_log.py +47 -0
- radnn/images/image_processor.py +4 -1
- radnn/learn/__init__.py +0 -7
- radnn/learn/keras/__init__.py +4 -0
- radnn/learn/{state → keras}/keras_best_state_saver.py +5 -1
- radnn/learn/{learning_algorithm.py → keras/keras_learning_algorithm.py} +5 -9
- radnn/learn/{keras_learning_rate_scheduler.py → keras/keras_learning_rate_scheduler.py} +4 -1
- radnn/learn/{keras_optimization_algorithm.py → keras/keras_optimization_combo.py} +7 -3
- radnn/learn/torch/__init__.py +3 -0
- radnn/learn/torch/ml_model_freezer.py +330 -0
- radnn/learn/torch/ml_trainer.py +461 -0
- radnn/learn/torch/staircase_lr_scheduler.py +21 -0
- radnn/ml_system.py +68 -52
- radnn/models/__init__.py +5 -0
- radnn/models/cnn/__init__.py +0 -0
- radnn/models/cnn/cnn_stem_setup.py +35 -0
- radnn/models/model_factory.py +85 -0
- radnn/models/model_hyperparams.py +128 -0
- radnn/models/model_info.py +91 -0
- radnn/plots/plot_learning_curve.py +19 -8
- radnn/system/__init__.py +1 -0
- radnn/system/files/__init__.py +1 -1
- radnn/system/files/csvfile.py +37 -5
- radnn/system/files/filelist.py +30 -0
- radnn/system/files/fileobject.py +11 -1
- radnn/system/files/imgfile.py +1 -1
- radnn/system/files/jsonfile.py +37 -9
- radnn/system/files/picklefile.py +3 -3
- radnn/system/files/textfile.py +39 -10
- radnn/system/files/zipfile.py +96 -0
- radnn/system/filestore.py +147 -47
- radnn/system/filesystem.py +3 -3
- radnn/test/__init__.py +1 -0
- radnn/test/tensor_hash.py +130 -0
- radnn/utils.py +16 -2
- radnn-0.1.0.dist-info/METADATA +30 -0
- radnn-0.1.0.dist-info/RECORD +99 -0
- {radnn-0.0.8.dist-info → radnn-0.1.0.dist-info}/WHEEL +1 -1
- {radnn-0.0.8.dist-info → radnn-0.1.0.dist-info/licenses}/LICENSE.txt +1 -1
- radnn/learn/state/__init__.py +0 -4
- radnn-0.0.8.dist-info/METADATA +0 -58
- radnn-0.0.8.dist-info/RECORD +0 -70
- /radnn/{data → data_beta}/dataset_folder.py +0 -0
- /radnn/{data → data_beta}/image_dataset.py +0 -0
- /radnn/{data → data_beta}/image_dataset_files.py +0 -0
- /radnn/{data → data_beta}/preprocess/__init__.py +0 -0
- /radnn/{data → data_beta}/preprocess/normalizer.py +0 -0
- /radnn/{data → data_beta}/preprocess/standardizer.py +0 -0
- /radnn/{data → data_beta}/subset_type.py +0 -0
- {radnn-0.0.8.dist-info → radnn-0.1.0.dist-info}/top_level.txt +0 -0
radnn/data/sample_set.py
CHANGED
|
@@ -22,30 +22,84 @@
|
|
|
22
22
|
# SOFTWARE.
|
|
23
23
|
|
|
24
24
|
# ......................................................................................
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
import numpy as np
|
|
26
|
+
import pandas as pd
|
|
27
|
+
from .errors import *
|
|
28
|
+
from sklearn.utils.class_weight import compute_class_weight
|
|
29
|
+
from .sample_set_kind import SampleSetKindInfo
|
|
27
30
|
|
|
31
|
+
from radnn.core import RequiredLibs
|
|
32
|
+
oReqs = RequiredLibs()
|
|
33
|
+
if oReqs.is_torch_installed:
|
|
34
|
+
# [TODO] Additional coupling to torch (+)->MANOLO
|
|
35
|
+
import platform
|
|
36
|
+
import torch
|
|
37
|
+
from torch.utils.data import DataLoader
|
|
28
38
|
|
|
29
39
|
|
|
30
40
|
class SampleSet(object):
|
|
41
|
+
LOADER_NUM_WORKERS = 8
|
|
42
|
+
|
|
31
43
|
# --------------------------------------------------------------------------------------------------------------------
|
|
32
|
-
def __init__(self,
|
|
33
|
-
|
|
34
|
-
|
|
44
|
+
def __init__(self, parent_dataset, subset_kind: str, **kwargs):
|
|
45
|
+
'''
|
|
46
|
+
Create a sample subset on a dataset
|
|
47
|
+
|
|
48
|
+
:param parent_dataset: The parent dataset that implements the composition relationship.
|
|
49
|
+
:param subset_kind: The kind of the subset. Can be one of:
|
|
50
|
+
training/train/ts for the known samples that are presented to an algorithm
|
|
51
|
+
validation/val/vs for the known samples that are not presented to an algorithm, used to validate during its execution
|
|
52
|
+
testing/test/ut for the unknown samples that are not given to the researcher that develops the algorithm
|
|
53
|
+
|
|
54
|
+
:**param sample_file_records: A Pandas dataframe that contains two columns: 1) The list of sample file absolute paths and 2) Correspondng labels.
|
|
55
|
+
:**param is_classification: True if the dataset used for a classification task.
|
|
56
|
+
:**param batch_size: The count of samples in a minibatch.
|
|
57
|
+
:**param sample_transform_augment: A callback method that performs a single sample preprocessing task.
|
|
58
|
+
'''
|
|
59
|
+
self.parent_dataset = parent_dataset
|
|
60
|
+
self.info = SampleSetKindInfo(subset_kind)
|
|
61
|
+
self.info.is_classification = kwargs.get("is_classification", False)
|
|
62
|
+
self.batch_size = kwargs.get("batch_size", None)
|
|
63
|
+
self.transform_augment = kwargs.get("sample_transform_augment", None)
|
|
64
|
+
self._sample_count = 0
|
|
35
65
|
|
|
36
|
-
self.
|
|
66
|
+
self.ids = None
|
|
67
|
+
self.samples: list|np.ndarray|None = kwargs.get("samples", None)
|
|
68
|
+
if (self.samples is not None) and isinstance(self.samples, list):
|
|
69
|
+
self.samples = np.array(self.samples, np.float32)
|
|
70
|
+
self._sample_count = self.samples.shape[0]
|
|
71
|
+
self.labels: list|np.ndarray|None = kwargs.get("labels", None)
|
|
37
72
|
|
|
38
|
-
self.
|
|
39
|
-
self.
|
|
40
|
-
self.
|
|
41
|
-
|
|
73
|
+
self.files = None
|
|
74
|
+
self._sample_directory: pd.DataFrame | None = kwargs.get("sample_file_records", None)
|
|
75
|
+
if self._sample_directory is not None:
|
|
76
|
+
self.files = self._sample_directory.iloc[:, 0].to_list()
|
|
77
|
+
self._sample_count = len(self.files)
|
|
78
|
+
self.labels = self._sample_directory.iloc[:, 1].to_list()
|
|
42
79
|
|
|
80
|
+
assert self._sample_count > 0, ERR_SUBSET_MUST_HAVE_SAMPLES
|
|
43
81
|
self._step = 1
|
|
44
82
|
self._iter_start_pos = 0
|
|
45
83
|
self._iter_counter = 0
|
|
84
|
+
self._are_samples_in_memory = self.samples is not None
|
|
85
|
+
|
|
86
|
+
self.has_sample_ids = self.ids is not None
|
|
46
87
|
|
|
47
|
-
self.
|
|
88
|
+
self.minibatch_count = self._sample_count
|
|
89
|
+
if self.batch_size is not None:
|
|
90
|
+
self.loader = DataLoader(self, batch_size=self.batch_size, shuffle=self.info.must_shuffle,
|
|
91
|
+
num_workers=self.LOADER_NUM_WORKERS)
|
|
92
|
+
self.minibatch_count = len(self.loader)
|
|
93
|
+
else:
|
|
94
|
+
self.loader = DataLoader(self, shuffle=self.info.must_shuffle, num_workers=self.LOADER_NUM_WORKERS)
|
|
48
95
|
|
|
96
|
+
if self.info.is_classification:
|
|
97
|
+
self.info.class_indices = np.sort(np.unique(self.labels))
|
|
98
|
+
self.info.class_weights = compute_class_weight(class_weight='balanced', classes=self.info.class_indices, y=np.array(self.labels))
|
|
99
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
100
|
+
@property
|
|
101
|
+
def sample_count(self):
|
|
102
|
+
return self._sample_count
|
|
49
103
|
# --------------------------------------------------------------------------------------------------------------------
|
|
50
104
|
@property
|
|
51
105
|
def has_labels(self):
|
|
@@ -53,114 +107,173 @@ class SampleSet(object):
|
|
|
53
107
|
# --------------------------------------------------------------------------------------------------------------------
|
|
54
108
|
@property
|
|
55
109
|
def data_tuple(self):
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
110
|
+
'''
|
|
111
|
+
:return: For in-memory samples: A tuple with the samples, their respective labels and their ids.
|
|
112
|
+
For file-based dataiterators: None
|
|
113
|
+
'''
|
|
114
|
+
if self._are_samples_in_memory:
|
|
115
|
+
if self.has_sample_ids:
|
|
116
|
+
if self.labels is None:
|
|
117
|
+
return (self.ids, self.samples)
|
|
118
|
+
else:
|
|
119
|
+
return (self.ids, self.samples, self.labels)
|
|
59
120
|
else:
|
|
60
|
-
|
|
121
|
+
if self.labels is None:
|
|
122
|
+
return self.samples
|
|
123
|
+
else:
|
|
124
|
+
return (self.ids, self.samples, self.labels)
|
|
61
125
|
else:
|
|
62
|
-
|
|
63
|
-
return self.samples
|
|
64
|
-
else:
|
|
65
|
-
return (self.ids, self.samples, self.labels)
|
|
126
|
+
return None
|
|
66
127
|
# --------------------------------------------------------------------------------------------------------------------
|
|
67
|
-
def
|
|
68
|
-
self.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
self.ids = self.parent_dataset.ts_sample_ids
|
|
74
|
-
self.samples = self.parent_dataset.ts_samples
|
|
75
|
-
self.sample_count = self.parent_dataset.ts_sample_count
|
|
76
|
-
self.labels = self.parent_dataset.ts_labels
|
|
77
|
-
elif self.subset_type.is_validation_set:
|
|
78
|
-
if self.parent_dataset.vs_samples is not None:
|
|
79
|
-
self.parent_dataset.vs = self
|
|
80
|
-
self.ids = self.parent_dataset.vs_sample_ids
|
|
81
|
-
self.samples = self.parent_dataset.vs_samples
|
|
82
|
-
self.sample_count = self.parent_dataset.vs_sample_count
|
|
83
|
-
self.labels = self.parent_dataset.vs_labels
|
|
84
|
-
elif self.subset_type.is_unknown_test_set:
|
|
85
|
-
if self.parent_dataset.ut_samples is not None:
|
|
86
|
-
self.parent_dataset.ut = self
|
|
87
|
-
self.ids = self.parent_dataset.ut_sample_ids
|
|
88
|
-
self.samples = self.parent_dataset.ut_samples
|
|
89
|
-
self.sample_count = self.parent_dataset.ut_sample_count
|
|
90
|
-
self.labels = self.parent_dataset.ut_labels
|
|
91
|
-
|
|
92
|
-
self.has_ids = self.ids is not None
|
|
93
|
-
# --------------------------------------------------------------------------------------------------------------------
|
|
94
|
-
'''
|
|
95
|
-
def create_feed(self, has_ids=False):
|
|
96
|
-
self.has_ids = has_ids
|
|
97
|
-
if is_tensorflow_installed:
|
|
98
|
-
import tensorflow as tf
|
|
99
|
-
|
|
100
|
-
if has_ids:
|
|
101
|
-
self.feed = tf.data.Dataset.from_tensor_slices((self.ids, self.samples, self.labels))
|
|
102
|
-
else:
|
|
103
|
-
self.feed = tf.data.Dataset.from_tensor_slices((self.samples, self.labels))
|
|
104
|
-
|
|
105
|
-
self.feed = self.feed.map(preprocess_tf, num_parallel_calls=8)
|
|
106
|
-
|
|
107
|
-
if (self.subset_type == "training") or (self.subset_type == "train") or (self.subset_type == "ts"):
|
|
108
|
-
# -----------------------------------------------------------------------------------
|
|
109
|
-
def preprocess_tf(self, sample_pack):
|
|
110
|
-
|
|
111
|
-
import tensorflow as tf
|
|
112
|
-
|
|
113
|
-
if self.has_ids:
|
|
114
|
-
nId, nSample, nLabel = sample_pack
|
|
128
|
+
def __len__(self):
|
|
129
|
+
return self._sample_count
|
|
130
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
131
|
+
def __getitem__(self, index):
|
|
132
|
+
if self._are_samples_in_memory:
|
|
133
|
+
tSample = self.do_load_sample(index)
|
|
115
134
|
else:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
tNormalizedImage = self.normalizeImage(tImage)
|
|
120
|
-
|
|
121
|
-
tTargetOneHot = tf.one_hot(p_tLabelInVS, self.ClassCount)
|
|
122
|
-
|
|
123
|
-
return tNormalizedImage, tTargetOneHot
|
|
124
|
-
'''
|
|
135
|
+
tSample = self.do_load_sample_from_file(index)
|
|
136
|
+
if self.transform_augment is not None:
|
|
137
|
+
tSample = self.transform_augment(tSample)
|
|
125
138
|
|
|
139
|
+
if self.ids is not None:
|
|
140
|
+
if self.labels is not None:
|
|
141
|
+
# Supervised with ids
|
|
142
|
+
return self.ids[index], tSample, self.do_load_target(index)
|
|
143
|
+
else:
|
|
144
|
+
# Unsupervised with ids
|
|
145
|
+
return self.ids[index], tSample
|
|
146
|
+
else:
|
|
147
|
+
if self.labels is not None:
|
|
148
|
+
# Supervised
|
|
149
|
+
return tSample, self.do_load_target(index)
|
|
150
|
+
else:
|
|
151
|
+
# Unsupervised
|
|
152
|
+
return tSample
|
|
126
153
|
# --------------------------------------------------------------------------------------------------------------------
|
|
127
154
|
def __iter__(self):
|
|
128
155
|
self._iter_counter = 0
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
156
|
+
|
|
157
|
+
if self._are_samples_in_memory:
|
|
158
|
+
if self.ids is not None:
|
|
159
|
+
if self.labels is not None:
|
|
160
|
+
yield from self._numpy_generator_for_supervised_with_ids()
|
|
161
|
+
else:
|
|
162
|
+
yield from self._numpy_generator_for_unsupervised_with_ids()
|
|
132
163
|
else:
|
|
133
|
-
|
|
164
|
+
if self.labels is not None:
|
|
165
|
+
yield from self._numpy_generator_for_supervised()
|
|
166
|
+
else:
|
|
167
|
+
yield from self._numpy_generator_for_unsupervised()
|
|
134
168
|
else:
|
|
135
169
|
if self.labels is not None:
|
|
136
|
-
yield from self.
|
|
170
|
+
yield from self._file_generator_for_supervised()
|
|
137
171
|
else:
|
|
138
|
-
yield from self.
|
|
172
|
+
yield from self._file_generator_for_unsupervised()
|
|
173
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
174
|
+
def do_load_sample_from_file(self, index):
|
|
175
|
+
'''
|
|
176
|
+
Override this method with the custom code of loading a single sample file
|
|
177
|
+
:param index: The index of the sample in the sample file list
|
|
178
|
+
'''
|
|
179
|
+
pass
|
|
180
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
181
|
+
def do_load_sample(self, index):
|
|
182
|
+
'''
|
|
183
|
+
Override this method with the custom code of getting a single sample file from a numpy array
|
|
184
|
+
:param index: The index of the sample in the sample subset
|
|
185
|
+
:return:
|
|
186
|
+
'''
|
|
187
|
+
return torch.tensor(self.samples[index, ...], dtype=torch.float32)
|
|
188
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
189
|
+
def do_load_target(self, index):
|
|
190
|
+
'''
|
|
191
|
+
Override this method with some custom code that loads sample label(s) or transforms them into a training target (e.g. one-hot encoding)
|
|
192
|
+
:param index: The index of the sample in the sample subset
|
|
193
|
+
'''
|
|
194
|
+
return torch.tensor(self.labels[index, ...], dtype=torch.long)
|
|
195
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
196
|
+
def _file_generator_for_supervised(self):
|
|
197
|
+
nIndex = self._iter_start_pos
|
|
198
|
+
while self._iter_counter < self.sample_count:
|
|
199
|
+
tSample = self.do_load_sample_from_file(nIndex)
|
|
200
|
+
if self.transform_augment is not None:
|
|
201
|
+
tSample = self.transform_augment(tSample)
|
|
202
|
+
yield (tSample, self.do_load_target(nIndex))
|
|
203
|
+
nIndex += self._step
|
|
204
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
205
|
+
def _file_generator_for_unsupervised(self):
|
|
206
|
+
nIndex = self._iter_start_pos
|
|
207
|
+
while self._iter_counter < self.sample_count:
|
|
208
|
+
tSample = self.do_load_sample_from_file(nIndex)
|
|
209
|
+
if self.transform_augment is not None:
|
|
210
|
+
tSample = self.transform_augment(tSample)
|
|
211
|
+
yield (tSample)
|
|
212
|
+
nIndex += self._step
|
|
139
213
|
# --------------------------------------------------------------------------------------------------------------------
|
|
140
|
-
def
|
|
214
|
+
def _numpy_generator_for_supervised(self):
|
|
141
215
|
nIndex = self._iter_start_pos
|
|
142
216
|
while self._iter_counter < self.sample_count:
|
|
143
|
-
|
|
217
|
+
tSample = self.do_load_sample(nIndex)
|
|
218
|
+
if self.transform_augment is not None:
|
|
219
|
+
tSample = self.transform_augment(tSample)
|
|
220
|
+
yield (tSample, self.do_load_target(nIndex))
|
|
144
221
|
nIndex += self._step
|
|
145
222
|
# --------------------------------------------------------------------------------------------------------------------
|
|
146
|
-
def
|
|
223
|
+
def _numpy_generator_for_supervised_with_ids(self):
|
|
147
224
|
nIndex = self._iter_start_pos
|
|
148
225
|
while self._iter_counter < self.sample_count:
|
|
149
|
-
|
|
226
|
+
tSample = self.do_load_sample(nIndex)
|
|
227
|
+
if self.transform_augment is not None:
|
|
228
|
+
tSample = self.transform_augment(tSample)
|
|
229
|
+
yield (self.ids[nIndex], tSample, self.do_load_target(nIndex))
|
|
150
230
|
nIndex += self._step
|
|
151
231
|
# --------------------------------------------------------------------------------------------------------------------
|
|
152
|
-
def
|
|
232
|
+
def _numpy_generator_for_unsupervised(self):
|
|
153
233
|
nIndex = self._iter_start_pos
|
|
154
234
|
while self._iter_counter < self.sample_count:
|
|
155
|
-
|
|
235
|
+
tSample = self.do_load_sample(nIndex)
|
|
236
|
+
if self.transform_augment is not None:
|
|
237
|
+
tSample = self.transform_augment(tSample)
|
|
238
|
+
yield tSample
|
|
156
239
|
nIndex += self._step
|
|
157
240
|
# --------------------------------------------------------------------------------------------------------------------
|
|
158
|
-
def
|
|
241
|
+
def _numpy_generator_for_unsupervised_with_ids(self):
|
|
159
242
|
nIndex = self._iter_start_pos
|
|
160
243
|
while self._iter_counter < self.sample_count:
|
|
161
|
-
|
|
244
|
+
tSample = self.do_load_sample(nIndex)
|
|
245
|
+
if self.transform_augment is not None:
|
|
246
|
+
tSample = self.transform_augment(tSample)
|
|
247
|
+
yield (self.ids[nIndex], tSample)
|
|
162
248
|
nIndex += self._step
|
|
163
249
|
# --------------------------------------------------------------------------------------------------------------------
|
|
250
|
+
def print_info(self):
|
|
251
|
+
sDescription = self.info.kind_description
|
|
252
|
+
sDescription = sDescription[0].upper() + sDescription[1:]
|
|
253
|
+
sMinibatches = ""
|
|
254
|
+
if self.minibatch_count is not None:
|
|
255
|
+
sMinibatches = f" minbatches: {self.minibatch_count}"
|
|
256
|
+
if (self.samples is not None) and isinstance(self.samples, np.ndarray):
|
|
257
|
+
print(f" |__ {sDescription} set samples: {self.sample_count} shape: {self.samples.shape}{sMinibatches}")
|
|
258
|
+
print(f" |__ {sDescription} set labels: {self.sample_count} shape: {self.labels.shape}")
|
|
259
|
+
else:
|
|
260
|
+
print(f" |__ {sDescription} set samples: {self.sample_count} {sMinibatches}")
|
|
164
261
|
|
|
262
|
+
if (self.labels is not None) and isinstance(self.labels, np.ndarray):
|
|
263
|
+
print(f" |__ Labels: {self.sample_count} shape:{self.labels.shape}")
|
|
264
|
+
else:
|
|
265
|
+
print(f" |__ Labels: {self.sample_count}")
|
|
266
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
267
|
+
def __str__(self):
|
|
268
|
+
return f"{self.info.kind_description} samples:{self.sample_count} minibatches:{self.minibatch_count}"
|
|
269
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
270
|
+
def __repr__(self):
|
|
271
|
+
return self.__str__()
|
|
272
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
165
273
|
|
|
166
274
|
|
|
275
|
+
# Fix for torch on Windows
|
|
276
|
+
if platform.system().lower() == "windows":
|
|
277
|
+
SampleSet.LOADER_NUM_WORKERS = 0
|
|
278
|
+
else:
|
|
279
|
+
SampleSet.LOADER_NUM_WORKERS = 8
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# ......................................................................................
|
|
2
|
+
# MIT License
|
|
3
|
+
|
|
4
|
+
# Copyright (c) 2019-2025 Pantelis I. Kaplanoglou
|
|
5
|
+
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
# copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
# SOFTWARE.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ......................................................................................
|
|
26
|
+
from enum import Enum
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# ======================================================================================================================
|
|
30
|
+
class SampleSetKind(Enum):
|
|
31
|
+
TRAINING_SET = 0
|
|
32
|
+
VALIDATION_SET = 1
|
|
33
|
+
UNKNOWN_TEST_SET = 2
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ======================================================================================================================
|
|
37
|
+
class SampleSetKindInfo(dict):
|
|
38
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
39
|
+
def __init__(self, kind_str: str|None=None, kind: int | None=None, **kwargs):
|
|
40
|
+
super().__init__(**kwargs)
|
|
41
|
+
self._kind: int | None = kind
|
|
42
|
+
self._kind_str: str | None = None
|
|
43
|
+
if kind_str is not None:
|
|
44
|
+
self._kind_str = kind_str.lower()
|
|
45
|
+
|
|
46
|
+
# Invoke the property getters
|
|
47
|
+
self["kind"] = self.kind
|
|
48
|
+
self["kind_str"] = self.kind_description
|
|
49
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
50
|
+
@property
|
|
51
|
+
def kind_description(self):
|
|
52
|
+
if (self._kind_str is None):
|
|
53
|
+
nKind = self.get("type", -1)
|
|
54
|
+
if nKind == SampleSetKind.TRAINING_SET.value:
|
|
55
|
+
self._kind_str = "training"
|
|
56
|
+
elif nKind == SampleSetKind.value:
|
|
57
|
+
self._kind_str = "validation"
|
|
58
|
+
elif nKind == SampleSetKind.value:
|
|
59
|
+
self._kind_str = "training"
|
|
60
|
+
return self._kind_str
|
|
61
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
62
|
+
@property
|
|
63
|
+
def kind(self):
|
|
64
|
+
if (self._kind is None):
|
|
65
|
+
nKind = -1 # Unknown
|
|
66
|
+
if self.is_training_set:
|
|
67
|
+
nKind = SampleSetKind.TRAINING_SET.value
|
|
68
|
+
elif self.is_validation_set:
|
|
69
|
+
nKind = SampleSetKind.VALIDATION_SET.value
|
|
70
|
+
elif self.is_unknown_test_set:
|
|
71
|
+
nKind = SampleSetKind.UNKNOWN_TEST_SET.value
|
|
72
|
+
self._kind = nKind
|
|
73
|
+
return self._kind
|
|
74
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
75
|
+
@property
|
|
76
|
+
def must_shuffle(self):
|
|
77
|
+
return self.kind == SampleSetKind.TRAINING_SET.value
|
|
78
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
79
|
+
@property
|
|
80
|
+
def is_training_set(self):
|
|
81
|
+
return (self._kind_str == "training") or (self._kind_str == "train") or (self._kind_str == "ts")
|
|
82
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
83
|
+
@property
|
|
84
|
+
def is_validation_set(self):
|
|
85
|
+
return (self._kind_str == "validation") or (self._kind_str == "val") or (self._kind_str == "vs")
|
|
86
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
87
|
+
@property
|
|
88
|
+
def is_unknown_test_set(self):
|
|
89
|
+
return (self._kind_str == "testing") or (self._kind_str == "test") or (self._kind_str == "ut")
|
|
90
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
91
|
+
@property
|
|
92
|
+
def is_classification(self):
|
|
93
|
+
return self["Task"] == "classification"
|
|
94
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
95
|
+
@is_classification.setter
|
|
96
|
+
def is_classification(self, value):
|
|
97
|
+
if value:
|
|
98
|
+
self["Task"] = "classification"
|
|
99
|
+
self["Classes.Count"] = None
|
|
100
|
+
self["Classes.Indices"] = None
|
|
101
|
+
self["Classes.Weights"] = None
|
|
102
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
103
|
+
@property
|
|
104
|
+
def class_count(self):
|
|
105
|
+
return self["Classes.Count"]
|
|
106
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
107
|
+
@class_count.setter
|
|
108
|
+
def class_count(self, value):
|
|
109
|
+
self["Classes.Count"] = value
|
|
110
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
111
|
+
@property
|
|
112
|
+
def class_indices(self):
|
|
113
|
+
return self["Classes.Indices"]
|
|
114
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
115
|
+
@class_indices.setter
|
|
116
|
+
def class_indices(self, value):
|
|
117
|
+
self["Classes.Indices"] = value
|
|
118
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
119
|
+
@property
|
|
120
|
+
def class_weights(self):
|
|
121
|
+
return self["Classes.Weights"]
|
|
122
|
+
# --------------------------------------------------------------------------------------------------------------------
|
|
123
|
+
@class_weights.setter
|
|
124
|
+
def class_weights(self, value):
|
|
125
|
+
self["Classes.Weights"] = value
|
|
126
|
+
# --------------------------------------------------------------------------------------------------------------------
|
radnn/data/sequence_dataset.py
CHANGED
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
|
|
24
24
|
# ......................................................................................
|
|
25
25
|
import numpy as np
|
|
26
|
-
|
|
26
|
+
|
|
27
|
+
from .sample_set import SampleSet
|
|
28
|
+
from .dataset_base import DataSetBase, DataSetCallbacks
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
# ----------------------------------------------------------------------------------------------------------------------
|
|
@@ -54,37 +56,26 @@ def generate_sequence_clips(samples, labels, window_size, stride, is_padding_zer
|
|
|
54
56
|
|
|
55
57
|
|
|
56
58
|
|
|
57
|
-
class
|
|
58
|
-
# --------------------------------------------------------------------------------------------------------------------
|
|
59
|
-
def __init__(self, name, fs, clip_window_size=None, clip_stride=None, is_padding_zeros=False, random_seed=None, is_classification=True):
|
|
60
|
-
super(SequenceDataset, self).__init__(name, fs, random_seed, is_classification)
|
|
61
|
-
self.clip_window_size = clip_window_size
|
|
62
|
-
self.clip_stride = clip_stride
|
|
63
|
-
self.is_padding_zeros = is_padding_zeros
|
|
64
|
-
self.card["clips.window_size"] = self.clip_window_size
|
|
65
|
-
self.card["clips.stride"] = self.clip_stride
|
|
66
|
-
self.card["clips.is_padding_zeros"] = self.is_padding_zeros
|
|
59
|
+
class SequenceDataSet(DataSetBase):
|
|
67
60
|
# --------------------------------------------------------------------------------------------------------------------
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
61
|
+
def __init__(self, name: str, variant: str|None=None, file_store=None, random_seed: int | None=None, callbacks: DataSetCallbacks | None = None):
|
|
62
|
+
super().__init__(name, variant, file_store, random_seed, callbacks)
|
|
63
|
+
|
|
64
|
+
#self, name, fs, clip_window_size=None, clip_stride=None, is_padding_zeros=False, random_seed=None, is_classification=True):
|
|
65
|
+
#super(SequenceDataSet, self).__init__(name, fs, random_seed, is_classification)
|
|
66
|
+
|
|
67
|
+
self.clip_window_size: int|None = None
|
|
68
|
+
self.clip_stride: int|None = None
|
|
69
|
+
self.is_padding_zeros: bool|None = None
|
|
72
70
|
# --------------------------------------------------------------------------------------------------------------------
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
self.is_padding_zeros)
|
|
78
|
-
else:
|
|
79
|
-
return None
|
|
71
|
+
def do_read_hyperparams(self):
|
|
72
|
+
self.clip_window_size = self.hparams.get("Data.Clip.WindowSize", None)
|
|
73
|
+
self.clip_stride = self.hparams.get("Data.Clip.Stride", None)
|
|
74
|
+
self.is_padding_zeros = self.hparams.get("Data.Clip.IsPaddingZeroes", None)
|
|
80
75
|
# --------------------------------------------------------------------------------------------------------------------
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return generate_sequence_clips(self.ut_samples, self.ut_labels, self.clip_window_size, self.clip_stride,
|
|
85
|
-
self.is_padding_zeros)
|
|
86
|
-
else:
|
|
87
|
-
return None
|
|
76
|
+
def generate_clips(self, subset: SampleSet):
|
|
77
|
+
return generate_sequence_clips(self, subset.samples, subset.labels,
|
|
78
|
+
self.clip_window_size, self.clip_stride, self.is_padding_zeros)
|
|
88
79
|
# --------------------------------------------------------------------------------------------------------------------
|
|
89
80
|
def convert_samples_to_clips(self, clip_window_size=None, clip_stride=None, is_padding_zeros=False):
|
|
90
81
|
if clip_window_size is not None:
|
|
@@ -94,14 +85,18 @@ class SequenceDataset(DataSetBase):
|
|
|
94
85
|
if is_padding_zeros and (not self.is_padding_zeros):
|
|
95
86
|
self.is_padding_zeros = is_padding_zeros
|
|
96
87
|
|
|
88
|
+
# TODO: Reinstate dataset card
|
|
89
|
+
'''
|
|
97
90
|
self.card["clips.window_size"] = self.clip_window_size
|
|
98
91
|
self.card["clips.stride"] = self.clip_stride
|
|
99
92
|
self.card["clips.is_padding_zeros"] = self.is_padding_zeros
|
|
93
|
+
'''
|
|
100
94
|
|
|
101
95
|
# Create training set clips
|
|
96
|
+
oSubsets = [self.ts, self.vs, self.us]
|
|
102
97
|
nClips = []
|
|
103
98
|
nClipLabels = []
|
|
104
|
-
for (nClip, nClipLabel) in self.
|
|
99
|
+
for (nClip, nClipLabel) in self.generate_clips():
|
|
105
100
|
nClips.append(nClip)
|
|
106
101
|
nClipLabels.append(nClipLabel)
|
|
107
102
|
nClips = np.asarray(nClips)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .tree import Tree, TreeNode, TreeNodeList, TreeNodeQueue
|