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.
Files changed (76) hide show
  1. radnn/__init__.py +5 -5
  2. radnn/benchmark/__init__.py +1 -0
  3. radnn/benchmark/latency.py +55 -0
  4. radnn/core.py +146 -2
  5. radnn/data/__init__.py +5 -10
  6. radnn/data/dataset_base.py +100 -260
  7. radnn/data/dataset_base_legacy.py +280 -0
  8. radnn/data/errors.py +32 -0
  9. radnn/data/sample_preprocessor.py +58 -0
  10. radnn/data/sample_set.py +203 -90
  11. radnn/data/sample_set_kind.py +126 -0
  12. radnn/data/sequence_dataset.py +25 -30
  13. radnn/data/structs/__init__.py +1 -0
  14. radnn/data/structs/tree.py +322 -0
  15. radnn/data_beta/__init__.py +12 -0
  16. radnn/{data → data_beta}/data_feed.py +1 -1
  17. radnn/data_beta/dataset_base.py +337 -0
  18. radnn/data_beta/sample_set.py +166 -0
  19. radnn/data_beta/sequence_dataset.py +134 -0
  20. radnn/data_beta/structures/__init__.py +2 -0
  21. radnn/data_beta/structures/dictionary.py +41 -0
  22. radnn/{data → data_beta}/tf_classification_data_feed.py +5 -2
  23. radnn/errors.py +10 -2
  24. radnn/experiment/__init__.py +2 -0
  25. radnn/experiment/identification.py +7 -0
  26. radnn/experiment/ml_experiment.py +7 -2
  27. radnn/experiment/ml_experiment_log.py +47 -0
  28. radnn/images/image_processor.py +4 -1
  29. radnn/learn/__init__.py +0 -7
  30. radnn/learn/keras/__init__.py +4 -0
  31. radnn/learn/{state → keras}/keras_best_state_saver.py +5 -1
  32. radnn/learn/{learning_algorithm.py → keras/keras_learning_algorithm.py} +5 -9
  33. radnn/learn/{keras_learning_rate_scheduler.py → keras/keras_learning_rate_scheduler.py} +4 -1
  34. radnn/learn/{keras_optimization_algorithm.py → keras/keras_optimization_combo.py} +7 -3
  35. radnn/learn/torch/__init__.py +3 -0
  36. radnn/learn/torch/ml_model_freezer.py +330 -0
  37. radnn/learn/torch/ml_trainer.py +461 -0
  38. radnn/learn/torch/staircase_lr_scheduler.py +21 -0
  39. radnn/ml_system.py +68 -52
  40. radnn/models/__init__.py +5 -0
  41. radnn/models/cnn/__init__.py +0 -0
  42. radnn/models/cnn/cnn_stem_setup.py +35 -0
  43. radnn/models/model_factory.py +85 -0
  44. radnn/models/model_hyperparams.py +128 -0
  45. radnn/models/model_info.py +91 -0
  46. radnn/plots/plot_learning_curve.py +19 -8
  47. radnn/system/__init__.py +1 -0
  48. radnn/system/files/__init__.py +1 -1
  49. radnn/system/files/csvfile.py +37 -5
  50. radnn/system/files/filelist.py +30 -0
  51. radnn/system/files/fileobject.py +11 -1
  52. radnn/system/files/imgfile.py +1 -1
  53. radnn/system/files/jsonfile.py +37 -9
  54. radnn/system/files/picklefile.py +3 -3
  55. radnn/system/files/textfile.py +39 -10
  56. radnn/system/files/zipfile.py +96 -0
  57. radnn/system/filestore.py +147 -47
  58. radnn/system/filesystem.py +3 -3
  59. radnn/test/__init__.py +1 -0
  60. radnn/test/tensor_hash.py +130 -0
  61. radnn/utils.py +16 -2
  62. radnn-0.1.0.dist-info/METADATA +30 -0
  63. radnn-0.1.0.dist-info/RECORD +99 -0
  64. {radnn-0.0.8.dist-info → radnn-0.1.0.dist-info}/WHEEL +1 -1
  65. {radnn-0.0.8.dist-info → radnn-0.1.0.dist-info/licenses}/LICENSE.txt +1 -1
  66. radnn/learn/state/__init__.py +0 -4
  67. radnn-0.0.8.dist-info/METADATA +0 -58
  68. radnn-0.0.8.dist-info/RECORD +0 -70
  69. /radnn/{data → data_beta}/dataset_folder.py +0 -0
  70. /radnn/{data → data_beta}/image_dataset.py +0 -0
  71. /radnn/{data → data_beta}/image_dataset_files.py +0 -0
  72. /radnn/{data → data_beta}/preprocess/__init__.py +0 -0
  73. /radnn/{data → data_beta}/preprocess/normalizer.py +0 -0
  74. /radnn/{data → data_beta}/preprocess/standardizer.py +0 -0
  75. /radnn/{data → data_beta}/subset_type.py +0 -0
  76. {radnn-0.0.8.dist-info → radnn-0.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,330 @@
1
+ class MLModelFreezer(object):
2
+ def __init__(self, model, hyperparams):
3
+ self.model = model
4
+ self.hyperparams = hyperparams
5
+ self.model_name = self.hyperparams["Model.Name"]
6
+ self.variant = self.hyperparams.get("Training.FineTuning.Freeze", None)
7
+
8
+ if self.model_name == "MobileNet_V3_Large_Weights.IMAGENET1K_V1":
9
+ self.mobilenet_frozen()
10
+ elif self.model_name == "resnet50_Weights.IMAGENET1K_V1":
11
+ self.resnet50_frozen()
12
+ elif self.model_name == "efficientnet_b0_Weights.IMAGENET1K_V1":
13
+ self.efficientnet_frozen()
14
+ elif self.model_name == "convnext_tiny_Weights.IMAGENET1K_V1":
15
+ self.convnext_frozen()
16
+ elif self.model_name == "beitv2_large_patch16_224.in1k_ft_in22k_in1k":
17
+ self.beitv2_frozen_2()
18
+
19
+ def freeze_batch_norm(self):
20
+ oNamedParams = list(iter(self.model .named_parameters()))
21
+ for nIndex, oTuple in enumerate(oNamedParams):
22
+ name, p = oTuple
23
+ if ".bn" in name:
24
+ p.requires_grad = False
25
+
26
+ def freeze_layer_norm(self):
27
+ oNamedParams = list(iter(self.model .named_parameters()))
28
+ for nIndex, oTuple in enumerate(oNamedParams):
29
+ name, p = oTuple
30
+ if (".norm" in name) or (".gamma" in name) or (".beta" in name) :
31
+ p.requires_grad = False
32
+
33
+ def freeze_block(self, module, exclude_normalization=False):
34
+ oParams = list(iter(module.parameters()))
35
+ oNamedParams = list(iter(module.named_parameters()))
36
+ for nIndex, oTuple in enumerate(oNamedParams):
37
+ name, p = oTuple
38
+ p = oParams[nIndex]
39
+ bContinue = True
40
+ if exclude_normalization:
41
+ bContinue = not ".bn" in name
42
+ if bContinue:
43
+ p.requires_grad = False
44
+
45
+ def mobilenet_frozen(self):
46
+ """
47
+ torchvision.mobilenet_v3_large has:
48
+ model.features: Sequential([...])
49
+ model.classifier: Sequential([...])
50
+
51
+ We'll freeze by coarse slices of `features`.
52
+ The exact indices can differ slightly across torchvision versions, but this is stable enough:
53
+ - features[0] is stem
54
+ - features[1:-1] are inverted residual blocks
55
+ - features[-1] is final 1x1 conv block before pooling/classifier
56
+ """
57
+ if self.variant is None:
58
+ return
59
+
60
+ if not hasattr(self.model, "features"):
61
+ return
62
+
63
+ feats = self.model.features
64
+ n = len(feats)
65
+
66
+ # Define slices (roughly early/mid/late)
67
+ # Stem
68
+ if 0 in self.variant:
69
+ self.freeze_block(feats[0])
70
+
71
+ # Early inverted residual blocks
72
+ if 1 in self.variant:
73
+ end = max(2, n // 4)
74
+ self.freeze_block(feats[1:end])
75
+
76
+ # Mid blocks
77
+ if 2 in self.variant:
78
+ start = max(1, n // 4)
79
+ end = max(start + 1, n // 2)
80
+ self.freeze_block(feats[start:end])
81
+
82
+ # Late blocks (excluding last conv)
83
+ if 3 in self.variant:
84
+ start = max(1, n // 2)
85
+ end = max(start + 1, n - 1)
86
+ self.freeze_block(feats[start:end])
87
+
88
+
89
+
90
+
91
+ def resnet50_frozen(self):
92
+ if self.variant is None:
93
+ return
94
+
95
+ self.freeze_batch_norm()
96
+
97
+ if 0 in self.variant:
98
+ # Stem
99
+ self.freeze_block(self.model.step_conv)
100
+ self.freeze_block(self.model.bn1)
101
+
102
+ if 1 in self.variant:
103
+ # First block of multiple conv layers
104
+ self.freeze_block(self.model.block1)
105
+
106
+ if 2 in self.variant:
107
+ self.freeze_block(self.model.block2)
108
+
109
+ if 3 in self.variant:
110
+ self.freeze_block(self.model.block3)
111
+
112
+ if 4 in self.variant:
113
+ # Freezing all layers will train only the classification head
114
+ self.freeze_block(self.model.layer4)
115
+
116
+
117
+ def efficientnet_frozen(self):
118
+ """
119
+ torchvision.efficientnet_b0 has:
120
+ model.features: Sequential of stem + stages + head conv
121
+ model.classifier
122
+
123
+ Commonly len(features) == 9 in torchvision:
124
+ 0 stem
125
+ 1..7 MBConv/FusedMBConv stages
126
+ 8 head conv
127
+ We'll freeze in coarse groups.
128
+ """
129
+ if self.variant is None:
130
+ return
131
+
132
+ if not hasattr(self.model, "features"):
133
+ return
134
+
135
+ feats = self.model.features
136
+ n = len(feats)
137
+
138
+ if n == 0:
139
+ return
140
+
141
+ # Stem
142
+ if 0 in self.variant:
143
+ self.freeze_block(feats[0])
144
+
145
+ # Early stages
146
+ if 1 in self.variant:
147
+ # typically features[1:3]
148
+ self.freeze_block(feats[1:min(3, n)])
149
+
150
+ # Mid stages
151
+ if 2 in self.variant:
152
+ # typically features[3:5]
153
+ self.freeze_block(feats[min(3, n):min(5, n)])
154
+
155
+ # Late stages
156
+ if 3 in self.variant:
157
+ # typically features[5:7]
158
+ self.freeze_block(feats[min(5, n):min(7, n)])
159
+
160
+
161
+
162
+ def convnext_frozen(self):
163
+ """
164
+ torchvision.convnext_tiny has:
165
+ model.features: Sequential of 8 modules:
166
+ 0 stem
167
+ 1 stage1
168
+ 2 downsample1
169
+ 3 stage2
170
+ 4 downsample2
171
+ 5 stage3
172
+ 6 downsample3
173
+ 7 stage4
174
+ model.classifier
175
+ We'll freeze stem/stages (and their downsample ops together).
176
+ """
177
+ if self.variant is None:
178
+ return
179
+
180
+ if not hasattr(self.model, "features"):
181
+ return
182
+
183
+ feats = self.model.features
184
+ n = len(feats)
185
+ if n < 2:
186
+ return
187
+
188
+ # Stem
189
+ if 0 in self.variant:
190
+ self.freeze_block(feats[0])
191
+
192
+ # Stage 1 (+ downsample after it if present)
193
+ if 1 in self.variant:
194
+ if n > 1: self.freeze_block(feats[1])
195
+ if n > 2: self.freeze_block(feats[2])
196
+
197
+ # Stage 2 (+ downsample)
198
+ if 2 in self.variant:
199
+ if n > 3: self.freeze_block(feats[3])
200
+ if n > 4: self.freeze_block(feats[4])
201
+
202
+ # Stage 3 (+ downsample)
203
+ if 3 in self.variant:
204
+ if n > 5: self.freeze_block(feats[5])
205
+ if n > 6: self.freeze_block(feats[6])
206
+
207
+
208
+ def beitv2_frozen(self):
209
+ if self.variant is None:
210
+ return
211
+
212
+ freeze_patch_embed = 0 in self.variant
213
+ # ----------------
214
+
215
+ if freeze_patch_embed:
216
+ self.freeze_block(self.model.patch_embed)
217
+
218
+ blocks = self.model.blocks
219
+ for i, block in enumerate(blocks):
220
+ if i in self.variant:
221
+ self.freeze_block(block)
222
+
223
+
224
+ # -------------------------
225
+ # BEiT v2 (timm or HuggingFace)
226
+ # -------------------------
227
+ def beitv2_frozen_2(self):
228
+ """
229
+ Supports:
230
+ - timm-style: model.patch_embed, model.blocks (list/ModuleList), model.norm
231
+ - HF-style: model.beit.embeddings, model.beit.encoder.layer, model.beit.layernorm
232
+
233
+ variant meaning (coarse, stage-like):
234
+ 0: freeze patch embedding (+ early norms if present)
235
+ 1: freeze first quarter of transformer blocks
236
+ 2: freeze first half
237
+ 3: freeze first 3/4
238
+ 4: freeze all blocks (train head only)
239
+
240
+ If you prefer "freeze exact N blocks", you can pass an int in hyperparams instead of a list.
241
+ """
242
+ if self.variant is None:
243
+ return
244
+
245
+ # Allow variant to be an int: freeze first N blocks (and patch embed)
246
+ if isinstance(self.variant, int):
247
+ n_blocks_to_freeze = self.variant
248
+ self._beit_freeze_first_n_blocks(n_blocks_to_freeze, freeze_patch_embed=True)
249
+ return
250
+
251
+ # Otherwise assume list-like stages
252
+ vset = set(self.variant)
253
+
254
+ self.freeze_layer_norm()
255
+
256
+ # Try timm-style first
257
+ if hasattr(self.model, "blocks"):
258
+ blocks = self.model.blocks
259
+ num_blocks = len(blocks)
260
+
261
+ # 0: patch embedding / stem
262
+ if 0 in vset:
263
+ if hasattr(self.model, "patch_embed"):
264
+ self.freeze_block(self.model.patch_embed)
265
+ # some timm models have pos_embed / cls_token as params; those don't need freezing
266
+
267
+ # Helper: freeze first k blocks
268
+ def freeze_first_k(k):
269
+ for b in blocks[:max(0, min(k, num_blocks))]:
270
+ self.freeze_block(b)
271
+
272
+ # Stage mapping
273
+ if 1 in vset:
274
+ freeze_first_k(max(1, num_blocks // 4))
275
+ if 2 in vset:
276
+ freeze_first_k(max(1, num_blocks // 2))
277
+ if 3 in vset:
278
+ freeze_first_k(max(1, (3 * num_blocks) // 4))
279
+
280
+
281
+ # Fall back to HuggingFace-style
282
+ elif hasattr(self.model, "beit"):
283
+ beit = self.model.beit
284
+
285
+ if 0 in vset and hasattr(beit, "embeddings"):
286
+ self.freeze_block(beit.embeddings)
287
+
288
+ layers = None
289
+ if hasattr(beit, "encoder") and hasattr(beit.encoder, "layer"):
290
+ layers = beit.encoder.layer
291
+
292
+ if layers is not None:
293
+ num_blocks = len(layers)
294
+
295
+ def freeze_first_k(k):
296
+ for b in layers[:max(0, min(k, num_blocks))]:
297
+ self.freeze_block(b)
298
+
299
+ if 1 in vset:
300
+ freeze_first_k(max(1, num_blocks // 4))
301
+ if 2 in vset:
302
+ freeze_first_k(max(1, num_blocks // 2))
303
+ if 3 in vset:
304
+ freeze_first_k(max(1, (3 * num_blocks) // 4))
305
+
306
+
307
+
308
+ def _beit_freeze_first_n_blocks(self, n_blocks_to_freeze: int, freeze_patch_embed: bool = True):
309
+ # timm-style
310
+ if hasattr(self.model, "blocks"):
311
+ if freeze_patch_embed and hasattr(self.model, "patch_embed"):
312
+ self.freeze_block(self.model.patch_embed)
313
+ for b in self.model.blocks[:max(0, n_blocks_to_freeze)]:
314
+ self.freeze_block(b)
315
+ if hasattr(self.model, "norm") and n_blocks_to_freeze >= len(self.model.blocks):
316
+ self.freeze_block(self.model.norm)
317
+ return
318
+
319
+ # HF-style
320
+ if hasattr(self.model, "beit"):
321
+ beit = self.model.beit
322
+ if freeze_patch_embed and hasattr(beit, "embeddings"):
323
+ self.freeze_block(beit.embeddings)
324
+ if hasattr(beit, "encoder") and hasattr(beit.encoder, "layer"):
325
+ for b in beit.encoder.layer[:max(0, n_blocks_to_freeze)]:
326
+ self.freeze_block(b)
327
+ if hasattr(beit, "layernorm") and hasattr(beit, "encoder") and hasattr(beit.encoder, "layer"):
328
+ if n_blocks_to_freeze >= len(beit.encoder.layer):
329
+ self.freeze_block(beit.layernorm)
330
+