ONNX
josh-gregory commited on
Commit
d5a0332
·
1 Parent(s): c9175bb

Initial commit

Browse files
Files changed (45) hide show
  1. README.md +236 -0
  2. base/convnext_tiny/convnext_tiny_base.onnx +3 -0
  3. base/convnext_tiny/convnext_tiny_base.safetensors +3 -0
  4. base/enet_b0/enet_b0_base.onnx +3 -0
  5. base/enet_b0/enet_b0_base.safetensors +3 -0
  6. base/enet_b3/enet_b3_base.onnx +3 -0
  7. base/enet_b3/enet_b3_base.safetensors +3 -0
  8. base/enet_b7/enet_b7_base.onnx +3 -0
  9. base/enet_b7/enet_b7_base.safetensors +3 -0
  10. base/mlp_dend/mlp_dend_base.onnx +3 -0
  11. base/mlp_dend/mlp_dend_base.safetensors +3 -0
  12. base/mlp_full/mlp_full_base.onnx +3 -0
  13. base/mlp_full/mlp_full_base.safetensors +3 -0
  14. base/mlp_o1/mlp_o1_3d_pretrain_300_unfreeze_all.onnx +3 -0
  15. base/mlp_o1/mlp_o1_3d_pretrain_300_unfreeze_all.safetensors +3 -0
  16. base/mlp_o1/mlp_o1_base.onnx +3 -0
  17. base/mlp_o1/mlp_o1_base.safetensors +3 -0
  18. base/resnet_152/resnet_152_base.onnx +3 -0
  19. base/resnet_152/resnet_152_base.safetensors +3 -0
  20. base/resnet_18/resnet_18_base.onnx +3 -0
  21. base/resnet_18/resnet_18_base.safetensors +3 -0
  22. base/resnet_50/resnet_50_base.onnx +3 -0
  23. base/resnet_50/resnet_50_base.safetensors +3 -0
  24. hyperparameters/best_params_convnext_tiny.json +14 -0
  25. hyperparameters/best_params_enet_b0.json +14 -0
  26. hyperparameters/best_params_enet_b3.json +14 -0
  27. hyperparameters/best_params_enet_b7.json +14 -0
  28. hyperparameters/best_params_mlp.json +13 -0
  29. hyperparameters/best_params_mlp_dend.json +13 -0
  30. hyperparameters/best_params_mlp_o1.json +13 -0
  31. hyperparameters/best_params_resnet_152.json +14 -0
  32. hyperparameters/best_params_resnet_18.json +14 -0
  33. hyperparameters/best_params_resnet_50.json +14 -0
  34. model_classes/ConvNeXt.py +528 -0
  35. model_classes/EfficientNets.py +512 -0
  36. model_classes/MLP.py +186 -0
  37. model_classes/ResNets.py +542 -0
  38. model_classes/__init__.py +0 -0
  39. model_classes/__pycache__/ConvNeXt.cpython-311.pyc +0 -0
  40. model_classes/__pycache__/ConvNeXt_Large.cpython-311.pyc +0 -0
  41. model_classes/__pycache__/EfficientNets.cpython-311.pyc +0 -0
  42. model_classes/__pycache__/MLP.cpython-311.pyc +0 -0
  43. model_classes/__pycache__/MLP_drop.cpython-311.pyc +0 -0
  44. model_classes/__pycache__/ResNets.cpython-311.pyc +0 -0
  45. model_classes/__pycache__/__init__.cpython-311.pyc +0 -0
README.md ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: gpl-3.0
3
+ ---
4
+
5
+ # Model Card for ClotSimNet
6
+
7
+ <!-- Provide a quick summary of what the model is/does. -->
8
+
9
+ This is the HuggingFace storage location for all of the models for the ClotSimNet project. They include several base models as well as their tuned variants. All models were trained in PyTorch.
10
+
11
+ ## Model Details
12
+
13
+ ### Model Description
14
+
15
+ There are several models that were trained on the ClotSimNet dataset:
16
+
17
+ * EfficientNet (B0, B3, B7)
18
+ * ResNet (50, 152)
19
+ * ConvNeXt-Large
20
+
21
+ <!-- Provide a longer summary of what this model is. -->
22
+
23
+
24
+
25
+ - **Developed by:** Josh Gregory
26
+ - **Funded by [optional]:** [More Information Needed]
27
+ - **Shared by [optional]:** [More Information Needed]
28
+ - **Model type:** [More Information Needed]
29
+ - **Language(s) (NLP):** [More Information Needed]
30
+ - **License:** [More Information Needed]
31
+ - **Finetuned from model [optional]:** [More Information Needed]
32
+
33
+ ### Model Sources [optional]
34
+
35
+ Each model was imported using the instructions from the [PyTorch documentation](https://pytorch.org/vision/stable/models.html). The specific links for each model architecture are as follows:
36
+
37
+ * [EfficientNet](https://proceedings.mlr.press/v97/tan19a.html)
38
+ * [ResNet](https://ieeexplore.ieee.org/document/7780459)
39
+ * [ConvNeXt-Large](https://ieeexplore.ieee.org/document/9879745)
40
+
41
+ ## Uses
42
+
43
+ These models are intended to be used to predict permeabilities from porous simulations, such as those found in blood clots or other porous media. The training set was exclusively computational fluid dynamics (CFD) simulations of blood clots, however these models could be fine-tuned on other porous media datasets.
44
+
45
+ <!-- Address questions around how the model is intended to be used, including the foreseeable users of the model and those affected by the model. -->
46
+
47
+ ### Direct Use
48
+
49
+ <!-- This section is for the model use without fine-tuning or plugging into a larger ecosystem/app. -->
50
+
51
+ [More Information Needed]
52
+
53
+ ### Downstream Use [optional]
54
+
55
+ <!-- This section is for the model use when fine-tuned for a task, or when plugged into a larger ecosystem/app -->
56
+
57
+ [More Information Needed]
58
+
59
+ ### Out-of-Scope Use
60
+
61
+ As of this publication, these models are not intended to treat, diagnose, or prevent any disease. They have not been approved by the FDA and are not intended for clinical or human use.
62
+
63
+ ## How to Get Started with the Model
64
+
65
+ There are two flavors of each model. The base variants all had the same learning rate, weight decay, etc. Specifically for the CNNs:
66
+
67
+ * Learning rate: 1e-3
68
+ * Weight decay: 1e-5
69
+ * Kernel size: 3
70
+ * Stride: 2
71
+ * Padding: 1
72
+ * Use ImageNet pre-trained weights: True
73
+ * Batch size: 2
74
+ * Num workers: 70
75
+ * Epochs: 500
76
+ * Use image augmentation transforms: True
77
+ * Learning rate reduction factor: 0.1
78
+ * Learning rate reduction patience: 10
79
+ * Learning rate reduction threshold: 1e-4
80
+
81
+ For the MLPs, obviously things like the stride and padding are not applicable. Instead, the number of neurons per hidden layer and the number of hidden layers were set as:
82
+
83
+ * Number of hidden layers: 3
84
+ * Size of each hidden layer: 128
85
+
86
+ Each model was exported in [ONNX](https://onnx.ai/) (`.onnx`) and [Safetensors](https://huggingface.co/docs/safetensors/index) (`.safetensors`).
87
+
88
+ ### Loading the Models
89
+
90
+ To import the ONNX (`.onnx`) file:
91
+
92
+ ```python
93
+ import onnx
94
+ import onnxruntime as ort
95
+ import numpy as np
96
+
97
+
98
+ # Load ONNX model
99
+ model = onnx.load('path_to_model/model.onnx')
100
+
101
+ # Validate model
102
+ onnx.checker.check_model(onnx_model)
103
+
104
+ # Create an inference session
105
+ session = ort.InferenceSession('path_to_model/model.onnx')
106
+ ```
107
+
108
+ TODO: Update inference to work with images
109
+
110
+
111
+ [More Information Needed]
112
+
113
+ ## Training Details
114
+
115
+ ### Training Data
116
+
117
+ <!-- This should link to a Dataset Card, perhaps with a short stub of information on what the training data is all about as well as documentation related to data pre-processing or additional filtering. -->
118
+
119
+ [More Information Needed]
120
+
121
+ ### Training Procedure
122
+
123
+ <!-- This relates heavily to the Technical Specifications. Content here should link to that section when it is relevant to the training procedure. -->
124
+
125
+ #### Preprocessing [optional]
126
+
127
+ [More Information Needed]
128
+
129
+
130
+ #### Training Hyperparameters
131
+
132
+ - **Training regime:** [More Information Needed] <!--fp32, fp16 mixed precision, bf16 mixed precision, bf16 non-mixed precision, fp16 non-mixed precision, fp8 mixed precision -->
133
+
134
+ #### Speeds, Sizes, Times [optional]
135
+
136
+ <!-- This section provides information about throughput, start/end time, checkpoint size if relevant, etc. -->
137
+
138
+ [More Information Needed]
139
+
140
+ ## Evaluation
141
+
142
+ <!-- This section describes the evaluation protocols and provides the results. -->
143
+
144
+ ### Testing Data, Factors & Metrics
145
+
146
+ #### Testing Data
147
+
148
+ <!-- This should link to a Dataset Card if possible. -->
149
+
150
+ [More Information Needed]
151
+
152
+ #### Factors
153
+
154
+ <!-- These are the things the evaluation is disaggregating by, e.g., subpopulations or domains. -->
155
+
156
+ [More Information Needed]
157
+
158
+ #### Metrics
159
+
160
+ <!-- These are the evaluation metrics being used, ideally with a description of why. -->
161
+
162
+ [More Information Needed]
163
+
164
+ ### Results
165
+
166
+ [More Information Needed]
167
+
168
+ #### Summary
169
+
170
+
171
+
172
+ ## Model Examination [optional]
173
+
174
+ <!-- Relevant interpretability work for the model goes here -->
175
+
176
+ [More Information Needed]
177
+
178
+ ## Environmental Impact
179
+
180
+ <!-- Total emissions (in grams of CO2eq) and additional considerations, such as electricity usage, go here. Edit the suggested text below accordingly -->
181
+
182
+ Carbon emissions can be estimated using the [Machine Learning Impact calculator](https://mlco2.github.io/impact#compute) presented in [Lacoste et al. (2019)](https://arxiv.org/abs/1910.09700).
183
+
184
+ - **Hardware Type:** [More Information Needed]
185
+ - **Hours used:** [More Information Needed]
186
+ - **Cloud Provider:** [More Information Needed]
187
+ - **Compute Region:** [More Information Needed]
188
+ - **Carbon Emitted:** [More Information Needed]
189
+
190
+ ## Technical Specifications [optional]
191
+
192
+ ### Model Architecture and Objective
193
+
194
+ [More Information Needed]
195
+
196
+ ### Compute Infrastructure
197
+
198
+ [More Information Needed]
199
+
200
+ #### Hardware
201
+
202
+ [More Information Needed]
203
+
204
+ #### Software
205
+
206
+ [More Information Needed]
207
+
208
+ ## Citation [optional]
209
+
210
+ <!-- If there is a paper or blog post introducing the model, the APA and Bibtex information for that should go in this section. -->
211
+
212
+ **BibTeX:**
213
+
214
+ [More Information Needed]
215
+
216
+ **APA:**
217
+
218
+ [More Information Needed]
219
+
220
+ ## Glossary [optional]
221
+
222
+ <!-- If relevant, include terms and calculations in this section that can help readers understand the model or model card. -->
223
+
224
+ [More Information Needed]
225
+
226
+ ## More Information [optional]
227
+
228
+ [More Information Needed]
229
+
230
+ ## Model Card Authors [optional]
231
+
232
+ [More Information Needed]
233
+
234
+ ## Model Card Contact
235
+
236
+ [More Information Needed]
base/convnext_tiny/convnext_tiny_base.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a5630e12bd9e1a749bb7582906632bc5729f39ff6c0c3778bf6d4a00cad1f21c
3
+ size 111353138
base/convnext_tiny/convnext_tiny_base.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0551357284d36b50d964def3f8910ea047bbb80647baee087125d2b59b7abc9f
3
+ size 111286724
base/enet_b0/enet_b0_base.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:07515b6d3968deb03ff654ef7b4f7717e3cf1d8150eefc580c8ce41d471542a6
3
+ size 16023020
base/enet_b0/enet_b0_base.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7fe26ca7697ebf2064c1eced7866e31e1b6225c685d25b1e5b2156869eb318f3
3
+ size 16238684
base/enet_b3/enet_b3_base.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:23f5321a72e10a6f3ebdcf51137669b3d3f076da487c83faeb3cc5b604863b11
3
+ size 42733583
base/enet_b3/enet_b3_base.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e68dc9870d1c3589e35390ae433d5c43eeebf9005b2399bdd7d6c0ee9019d590
3
+ size 43197740
base/enet_b7/enet_b7_base.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:20d0d19e6df3482854eda5c297f3a05aa49ff6c45e657ee84e09409e3d166654
3
+ size 254785573
base/enet_b7/enet_b7_base.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e6f46777f6d28b652ad1e83d3bbf8a33e15eadfdf6c18ad3bb6b5ef00eba9265
3
+ size 256524508
base/mlp_dend/mlp_dend_base.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d13823b81798ffae5a4cae026a6ab65c07009279eb235eea6c3ed2b6597326e2
3
+ size 76559
base/mlp_dend/mlp_dend_base.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:302e24376e0c459b4c7989eca39a09e52a3bd455c91eb50b35eb6db1e4b87cab
3
+ size 76124
base/mlp_full/mlp_full_base.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:70ae9dd8b401e4c5992390d4634a27c9e87efc27f9fb863646b66e07090f1c96
3
+ size 203539
base/mlp_full/mlp_full_base.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:257ecba2a29380bb9996bcff2f293a666a418a6f9541010bbac6f5f16d5fcd2b
3
+ size 203124
base/mlp_o1/mlp_o1_3d_pretrain_300_unfreeze_all.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e71ccd93151cd158dee6e41456cb8d21a893f367c4a3bd0927c460172197d0d1
3
+ size 74511
base/mlp_o1/mlp_o1_3d_pretrain_300_unfreeze_all.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:65c15a72b808418f92164a1c01550c9070bc25bac4f754e91afb7ad8b0065c0b
3
+ size 74076
base/mlp_o1/mlp_o1_base.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c5ec791f3288e7f620faac21424616f5d9f076ed8de0dcf7c6cde438dfed43d0
3
+ size 74511
base/mlp_o1/mlp_o1_base.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:efb4f86e381dc59bd0586674a7905a5124497ea26960a33190aed90b57be1bac
3
+ size 74076
base/resnet_152/resnet_152_base.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:26e83ab0b93023a40a23771999ef46cf10b0071c38e924f5a4949f3467986d06
3
+ size 232317981
base/resnet_152/resnet_152_base.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4cde5578dd31e177789eea1c073039ef566ca772a2117dc5b9dd768634f59be8
3
+ size 233245860
base/resnet_18/resnet_18_base.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:caa4816f3191b19770ec71333a3cd1d694371429c6b412a212cea1416d3d27d1
3
+ size 44663281
base/resnet_18/resnet_18_base.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:94e3cc71115b126ff41213ea633196eeea0fe7799af5a1796388e56b66e9878c
3
+ size 44723124
base/resnet_50/resnet_50_base.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:895e5cf66a159bd51e5f70a4c1f9bf4bebde9f69cfb572e2e0826f36dffba3bf
3
+ size 93923245
base/resnet_50/resnet_50_base.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ad3f40f46be13f68448d6b87f4b6c7631fb886e187a16e3e7c62278ffe196b8e
3
+ size 94248660
hyperparameters/best_params_convnext_tiny.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "hyperparameters": {
3
+ "learning_rate": 0.23699388000283336,
4
+ "weight_decay": 0.0003795214141463416,
5
+ "kernel_size": 1,
6
+ "stride": 2,
7
+ "padding": 1,
8
+ "batch_size": 32,
9
+ "scheduler_factor": 0.10407032558978876,
10
+ "scheduler_patience": 14,
11
+ "scheduler_threshold": 0.0007639430825545345
12
+ },
13
+ "validation_loss": 0.36920997500419617
14
+ }
hyperparameters/best_params_enet_b0.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "hyperparameters": {
3
+ "learning_rate": 0.0015801849950581874,
4
+ "weight_decay": 1.235158048935322e-05,
5
+ "kernel_size": 1,
6
+ "stride": 2,
7
+ "padding": 0,
8
+ "batch_size": 64,
9
+ "scheduler_factor": 0.11559915010662485,
10
+ "scheduler_patience": 15,
11
+ "scheduler_threshold": 0.0003021977576971474
12
+ },
13
+ "validation_loss": 0.0038186332676559687
14
+ }
hyperparameters/best_params_enet_b3.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "hyperparameters": {
3
+ "learning_rate": 0.0011140616389973715,
4
+ "weight_decay": 7.02753409648415e-05,
5
+ "kernel_size": 5,
6
+ "stride": 1,
7
+ "padding": 2,
8
+ "batch_size": 32,
9
+ "scheduler_factor": 0.16322446851765238,
10
+ "scheduler_patience": 7,
11
+ "scheduler_threshold": 0.0038049686341583267
12
+ },
13
+ "validation_loss": 0.004008469637483358
14
+ }
hyperparameters/best_params_enet_b7.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "hyperparameters": {
3
+ "learning_rate": 0.0012199668475623272,
4
+ "weight_decay": 0.00032379826052113,
5
+ "kernel_size": 3,
6
+ "stride": 2,
7
+ "padding": 2,
8
+ "batch_size": 32,
9
+ "scheduler_factor": 0.11590671587549593,
10
+ "scheduler_patience": 10,
11
+ "scheduler_threshold": 0.0017160400686953745
12
+ },
13
+ "validation_loss": 0.002957067685201764
14
+ }
hyperparameters/best_params_mlp.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "hyperparameters": {
3
+ "hidden_size": 1480,
4
+ "num_layers": 1,
5
+ "lr": 0.0008591530783482852,
6
+ "weight_decay": 0.00012686372039020111,
7
+ "batch_size": 32,
8
+ "scheduler_factor": 0.12387065250955309,
9
+ "scheduler_patience": 10,
10
+ "scheduler_threshold": 0.0001725777162252396
11
+ },
12
+ "validation_loss": 0.003614193992689252
13
+ }
hyperparameters/best_params_mlp_dend.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "hyperparameters": {
3
+ "hidden_size": 1072,
4
+ "num_layers": 1,
5
+ "lr": 0.0006490624870220825,
6
+ "weight_decay": 0.0003579389623468425,
7
+ "batch_size": 32,
8
+ "scheduler_factor": 0.15137349637223427,
9
+ "scheduler_patience": 11,
10
+ "scheduler_threshold": 0.0002335875429607458
11
+ },
12
+ "validation_loss": 0.001131717232055962
13
+ }
hyperparameters/best_params_mlp_o1.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "hyperparameters": {
3
+ "hidden_size": 1480,
4
+ "num_layers": 1,
5
+ "lr": 0.0008591530783482852,
6
+ "weight_decay": 0.00012686372039020111,
7
+ "batch_size": 32,
8
+ "scheduler_factor": 0.12387065250955309,
9
+ "scheduler_patience": 10,
10
+ "scheduler_threshold": 0.0001725777162252396
11
+ },
12
+ "validation_loss": 0.002175817731767893
13
+ }
hyperparameters/best_params_resnet_152.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "hyperparameters": {
3
+ "learning_rate": 0.0012199668475623272,
4
+ "weight_decay": 0.00032379826052113,
5
+ "kernel_size": 3,
6
+ "stride": 2,
7
+ "padding": 2,
8
+ "batch_size": 32,
9
+ "scheduler_factor": 0.11590671587549593,
10
+ "scheduler_patience": 10,
11
+ "scheduler_threshold": 0.0017160400686953745
12
+ },
13
+ "validation_loss": 0.0016866237856447697
14
+ }
hyperparameters/best_params_resnet_18.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "hyperparameters": {
3
+ "learning_rate": 0.0012199668475623272,
4
+ "weight_decay": 0.00032379826052113,
5
+ "kernel_size": 3,
6
+ "stride": 2,
7
+ "padding": 2,
8
+ "batch_size": 32,
9
+ "scheduler_factor": 0.11590671587549593,
10
+ "scheduler_patience": 10,
11
+ "scheduler_threshold": 0.0017160400686953745
12
+ },
13
+ "validation_loss": 0.002738025737926364
14
+ }
hyperparameters/best_params_resnet_50.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "hyperparameters": {
3
+ "learning_rate": 0.0012199668475623272,
4
+ "weight_decay": 0.00032379826052113,
5
+ "kernel_size": 3,
6
+ "stride": 2,
7
+ "padding": 2,
8
+ "batch_size": 32,
9
+ "scheduler_factor": 0.11590671587549593,
10
+ "scheduler_patience": 10,
11
+ "scheduler_threshold": 0.0017160400686953745
12
+ },
13
+ "validation_loss": 0.002920560771599412
14
+ }
model_classes/ConvNeXt.py ADDED
@@ -0,0 +1,528 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import Optional, List, Dict, Tuple, Any
3
+ import numpy as np
4
+ import pandas as pd
5
+ import piexif
6
+ from sklearn.preprocessing import StandardScaler
7
+ from PIL import Image
8
+ import torch
9
+ from torch.optim.lr_scheduler import ReduceLROnPlateau
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from torch.utils.data import Dataset, TensorDataset, DataLoader, random_split
13
+ from torchvision.io import decode_image, read_file, image
14
+ from torchvision.transforms import v2
15
+ import torchvision.models as models
16
+ import lightning as L
17
+ from lightning.pytorch.callbacks.early_stopping import EarlyStopping
18
+ import torchmetrics
19
+ from lightning.pytorch.loggers import WandbLogger
20
+ from lightning.pytorch import Trainer, seed_everything
21
+ import wandb
22
+ import lmdb
23
+ import msgpack
24
+ import sys
25
+ import torchvision
26
+
27
+ class ConvNeXtLarge(L.LightningModule):
28
+ def __init__(
29
+ self,
30
+ learning_rate: float=1e-3,
31
+ weight_decay: float=1e-2,
32
+ kernel_size: int=3,
33
+ stride: int=1,
34
+ padding: int=0,
35
+ use_weights: bool=True,
36
+ scheduler_factor: float=0.1,
37
+ scheduler_patience: int=10,
38
+ scheduler_threshold: float=1e-4
39
+ ):
40
+ '''
41
+ Class to load the ConvNeXt-Large architecture from PyTorch's torchvision library.
42
+
43
+ Parameters:
44
+ learning_rate (float): Learning rate. Defaults to 1e-3.
45
+ weight_decay (float): Weight decay for AdamW optimizer. Defaults to 1e-2.
46
+ kernel_size (int): Kernel size for convolutional filters. Defaults to 3.
47
+ stride (int): Stride for convolutional filters. Defaults to 1.
48
+ padding (int): Padding for convolutional filters. Defaults to 0.
49
+ use_weights (bool): Whether or not to use pretrained weights from ImageNet. Defaults to True.
50
+ scheduler_factor (float): Factor for ReduceLROnPlateau. Defaults to 0.1.
51
+ scheduler_patience (int): Patience for ReduceLROnPlateau. Defaults to 10.
52
+ scheduler_threshold (float): Threshold for ReduceLROnPlateau. Defaults to 1e-4.
53
+
54
+ Methods:
55
+ All of the methods within this class are subclassed from PyTorch Lightning's LightningModule. Their documentation for each of these methods can be found here: https://lightning.ai/docs/pytorch/stable/common/lightning_module.html
56
+ '''
57
+ super().__init__()
58
+ self.save_hyperparameters()
59
+
60
+ # Transforms flag to perform image augmentations
61
+ # self.use_transforms = use_transforms
62
+
63
+ # Save predictions for later
64
+ self.test_preds = []
65
+ self.test_labels = []
66
+
67
+ self.learning_rate = learning_rate
68
+ self.weight_decay = weight_decay
69
+ self.kernel_size = kernel_size
70
+ self.stride = stride
71
+ self.padding = padding
72
+ self.use_weights = use_weights
73
+ self.scheduler_factor = scheduler_factor
74
+ self.scheduler_patience = scheduler_patience
75
+ self.scheduler_threshold = scheduler_threshold
76
+
77
+ if use_weights==True:
78
+ self.model = models.convnext_large(weights='DEFAULT')
79
+ else:
80
+ self.model = models.convnext_large()
81
+
82
+ # Modify first conv. layer to accept grayscale/1 channel inputs
83
+ self.model.features[0][0] = nn.Conv2d(
84
+ in_channels=1,
85
+ out_channels=192,
86
+ kernel_size=kernel_size,
87
+ stride=stride,
88
+ padding=padding
89
+ )
90
+
91
+ # Modify classifier for regression output
92
+ num_features = self.model.classifier[-1].in_features
93
+ self.model.classifier[-1] = nn.Linear(num_features, 1) # Single output for regression
94
+
95
+ # Create dictionary of metrics to track for training, validation, and testing
96
+ self.train_metrics = torchmetrics.MetricCollection(
97
+ {
98
+ 'MAE': torchmetrics.regression.MeanAbsoluteError(num_outputs=1),
99
+ 'RMSE': torchmetrics.regression.MeanSquaredError(squared=False, num_outputs=1),
100
+ 'MSE': torchmetrics.regression.MeanSquaredError(squared=True, num_outputs=1),
101
+ 'r_squared': torchmetrics.regression.R2Score()
102
+ },
103
+ prefix='train_'
104
+ )
105
+
106
+ self.valid_metrics = self.train_metrics.clone(prefix='valid_')
107
+ self.test_metrics = self.train_metrics.clone(prefix='test_')
108
+
109
+
110
+ def forward(self, x):
111
+ return self.model(x).squeeze(-1) # Remove extra dimension
112
+
113
+ # Reset metrics
114
+ def on_train_epoch_start(self):
115
+ self.train_metrics.reset()
116
+
117
+ def training_step(self, batch, batch_idx):
118
+ x, y = batch # Get inputs and labels
119
+ y_pred = self(x) # Forward pass (call model's forward method)
120
+
121
+ loss = F.mse_loss(y_pred, y)
122
+ self.log('train_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True) # Log MSE loss for monitoring
123
+
124
+ # Log metrics
125
+ batch_values = self.train_metrics(y_pred, y)
126
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
127
+ return loss
128
+
129
+ # Reset metrics
130
+ def on_validation_epoch_start(self):
131
+ self.valid_metrics.reset()
132
+
133
+ def validation_step(self, batch, batch_idx):
134
+ x, y = batch # Get features and labels
135
+ y_pred = self(x)
136
+ loss = F.mse_loss(y_pred, y)
137
+ self.log('val_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
138
+
139
+ # Update validation metrics
140
+ batch_values = self.valid_metrics(y_pred, y)
141
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
142
+
143
+ return loss
144
+
145
+ # Reset metrics
146
+ def on_test_epoch_start(self):
147
+ self.test_metrics.reset()
148
+
149
+ def test_step(self, batch, batch_idx):
150
+ x, y = batch # Get features and labels
151
+ y_pred = self(x)
152
+ loss = F.mse_loss(y_pred, y)
153
+ self.log('test_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
154
+
155
+ # Update validation metrics
156
+ batch_values = self.test_metrics(y_pred, y)
157
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
158
+
159
+ # Store predictions and labels
160
+ self.test_preds.append(y_pred.cpu())
161
+ self.test_labels.append(y.cpu())
162
+
163
+ return loss
164
+
165
+ def on_test_epoch_end(self):
166
+ self.test_preds = torch.cat([pred.float() for pred in self.test_preds], dim=0).numpy()
167
+ self.test_labels = torch.cat([label.float() for label in self.test_labels], dim=0).numpy()
168
+
169
+ # Log transform test predictions and labels
170
+ self.test_preds = np.exp(self.test_preds)
171
+ self.test_labels = np.exp(self.test_labels)
172
+
173
+ # Store results for access after trainer.test()
174
+ self.test_results = {'preds': self.test_preds, 'labels': self.test_labels}
175
+
176
+ def configure_optimizers(self):
177
+ optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
178
+ scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='min', factor=self.scheduler_factor, patience=self.scheduler_patience, threshold=self.scheduler_threshold)
179
+
180
+ return {'optimizer': optimizer,
181
+ 'lr_scheduler': scheduler,
182
+ 'monitor': 'val_loss'}
183
+
184
+ # NOTE: pin_memory=True calls in the next three defs should be monitored for performance. Can easily set to false.
185
+ def train_dataloader(self):
186
+ return DataLoader(self.train_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=True, pin_memory=True)
187
+
188
+ def val_dataloader(self):
189
+ return DataLoader(self.val_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
190
+
191
+ def test_dataloader(self):
192
+ return DataLoader(self.test_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
193
+
194
+
195
+ class ConvNeXtSmall(L.LightningModule):
196
+ def __init__(
197
+ self,
198
+ learning_rate: float=1e-3,
199
+ weight_decay: float=1e-2,
200
+ kernel_size: int=3,
201
+ stride: int=1,
202
+ padding: int=0,
203
+ use_weights: bool=True,
204
+ scheduler_factor: float=0.1,
205
+ scheduler_patience: int=10,
206
+ scheduler_threshold: float=1e-4
207
+ ):
208
+ '''
209
+ Class to load the ConvNeXt-Small architecture from PyTorch's torchvision library.
210
+
211
+ Parameters:
212
+ learning_rate (float): Learning rate. Defaults to 1e-3.
213
+ weight_decay (float): Weight decay for AdamW optimizer. Defaults to 1e-2.
214
+ kernel_size (int): Kernel size for convolutional filters. Defaults to 3.
215
+ stride (int): Stride for convolutional filters. Defaults to 1.
216
+ padding (int): Padding for convolutional filters. Defaults to 0.
217
+ use_weights (bool): Whether or not to use pretrained weights from ImageNet. Defaults to True.
218
+ scheduler_factor (float): Factor for ReduceLROnPlateau. Defaults to 0.1.
219
+ scheduler_patience (int): Patience for ReduceLROnPlateau. Defaults to 10.
220
+ scheduler_threshold (float): Threshold for ReduceLROnPlateau. Defaults to 1e-4.
221
+
222
+ Methods:
223
+ All of the methods within this class are subclassed from PyTorch Lightning's LightningModule. Their documentation for each of these methods can be found here: https://lightning.ai/docs/pytorch/stable/common/lightning_module.html
224
+ '''
225
+ super().__init__()
226
+ self.save_hyperparameters()
227
+
228
+ # Transforms flag to perform image augmentations
229
+ # self.use_transforms = use_transforms
230
+
231
+ # Save predictions for later
232
+ self.test_preds = []
233
+ self.test_labels = []
234
+
235
+ self.learning_rate = learning_rate
236
+ self.weight_decay = weight_decay
237
+ self.kernel_size = kernel_size
238
+ self.stride = stride
239
+ self.padding = padding
240
+ self.use_weights = use_weights
241
+ self.scheduler_factor = scheduler_factor
242
+ self.scheduler_patience = scheduler_patience
243
+ self.scheduler_threshold = scheduler_threshold
244
+
245
+ if use_weights==True:
246
+ self.model = models.convnext_small(weights='DEFAULT')
247
+ else:
248
+ self.model = models.convnext_small()
249
+
250
+ # Modify first conv. layer to accept grayscale/1 channel inputs
251
+ self.model.features[0][0] = nn.Conv2d(
252
+ in_channels=1,
253
+ out_channels=96,
254
+ kernel_size=kernel_size,
255
+ stride=stride,
256
+ padding=padding
257
+ )
258
+
259
+ # Modify classifier for regression output
260
+ num_features = self.model.classifier[-1].in_features
261
+ self.model.classifier[-1] = nn.Linear(num_features, 1) # Single output for regression
262
+
263
+ # Create dictionary of metrics to track for training, validation, and testing
264
+ self.train_metrics = torchmetrics.MetricCollection(
265
+ {
266
+ 'MAE': torchmetrics.regression.MeanAbsoluteError(num_outputs=1),
267
+ 'RMSE': torchmetrics.regression.MeanSquaredError(squared=False, num_outputs=1),
268
+ 'MSE': torchmetrics.regression.MeanSquaredError(squared=True, num_outputs=1),
269
+ 'r_squared': torchmetrics.regression.R2Score()
270
+ },
271
+ prefix='train_'
272
+ )
273
+
274
+ self.valid_metrics = self.train_metrics.clone(prefix='valid_')
275
+ self.test_metrics = self.train_metrics.clone(prefix='test_')
276
+
277
+
278
+ def forward(self, x):
279
+ return self.model(x).squeeze(-1) # Remove extra dimension
280
+
281
+ # Reset metrics
282
+ def on_train_epoch_start(self):
283
+ self.train_metrics.reset()
284
+
285
+ def training_step(self, batch, batch_idx):
286
+ x, y = batch # Get inputs and labels
287
+ y_pred = self(x) # Forward pass (call model's forward method)
288
+
289
+ loss = F.mse_loss(y_pred, y)
290
+ self.log('train_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True) # Log MSE loss for monitoring
291
+
292
+ # Log metrics
293
+ batch_values = self.train_metrics(y_pred, y)
294
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
295
+ return loss
296
+
297
+ # Reset metrics
298
+ def on_validation_epoch_start(self):
299
+ self.valid_metrics.reset()
300
+
301
+ def validation_step(self, batch, batch_idx):
302
+ x, y = batch # Get features and labels
303
+ y_pred = self(x)
304
+ loss = F.mse_loss(y_pred, y)
305
+ self.log('val_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
306
+
307
+ # Update validation metrics
308
+ batch_values = self.valid_metrics(y_pred, y)
309
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
310
+
311
+ return loss
312
+
313
+ # Reset metrics
314
+ def on_test_epoch_start(self):
315
+ self.test_metrics.reset()
316
+
317
+ def test_step(self, batch, batch_idx):
318
+ x, y = batch # Get features and labels
319
+ y_pred = self(x)
320
+ loss = F.mse_loss(y_pred, y)
321
+ self.log('test_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
322
+
323
+ # Update validation metrics
324
+ batch_values = self.test_metrics(y_pred, y)
325
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
326
+
327
+ # Store predictions and labels
328
+ self.test_preds.append(y_pred.cpu())
329
+ self.test_labels.append(y.cpu())
330
+
331
+ return loss
332
+
333
+ def on_test_epoch_end(self):
334
+ self.test_preds = torch.cat([pred.float() for pred in self.test_preds], dim=0).numpy()
335
+ self.test_labels = torch.cat([label.float() for label in self.test_labels], dim=0).numpy()
336
+
337
+ # Log transform test predictions and labels
338
+ self.test_preds = np.exp(self.test_preds)
339
+ self.test_labels = np.exp(self.test_labels)
340
+
341
+ # Store results for access after trainer.test()
342
+ self.test_results = {'preds': self.test_preds, 'labels': self.test_labels}
343
+
344
+ def configure_optimizers(self):
345
+ optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
346
+ scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='min', factor=self.scheduler_factor, patience=self.scheduler_patience, threshold=self.scheduler_threshold)
347
+
348
+ return {'optimizer': optimizer,
349
+ 'lr_scheduler': scheduler,
350
+ 'monitor': 'val_loss'}
351
+
352
+ # NOTE: pin_memory=True calls in the next three defs should be monitored for performance. Can easily set to false.
353
+ def train_dataloader(self):
354
+ return DataLoader(self.train_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=True, pin_memory=True)
355
+
356
+ def val_dataloader(self):
357
+ return DataLoader(self.val_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
358
+
359
+ def test_dataloader(self):
360
+ return DataLoader(self.test_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
361
+
362
+
363
+ class ConvNeXtTiny(L.LightningModule):
364
+ def __init__(
365
+ self,
366
+ learning_rate: float=1e-3,
367
+ weight_decay: float=1e-2,
368
+ kernel_size: int=3,
369
+ stride: int=1,
370
+ padding: int=0,
371
+ use_weights: bool=True,
372
+ scheduler_factor: float=0.1,
373
+ scheduler_patience: int=10,
374
+ scheduler_threshold: float=1e-4
375
+ ):
376
+ '''
377
+ Class to load the ConvNeXt-Tiny architecture from PyTorch's torchvision library.
378
+
379
+ Parameters:
380
+ learning_rate (float): Learning rate. Defaults to 1e-3.
381
+ weight_decay (float): Weight decay for AdamW optimizer. Defaults to 1e-2.
382
+ kernel_size (int): Kernel size for convolutional filters. Defaults to 3.
383
+ stride (int): Stride for convolutional filters. Defaults to 1.
384
+ padding (int): Padding for convolutional filters. Defaults to 0.
385
+ use_weights (bool): Whether or not to use pretrained weights from ImageNet. Defaults to True.
386
+ scheduler_factor (float): Factor for ReduceLROnPlateau. Defaults to 0.1.
387
+ scheduler_patience (int): Patience for ReduceLROnPlateau. Defaults to 10.
388
+ scheduler_threshold (float): Threshold for ReduceLROnPlateau. Defaults to 1e-4.
389
+
390
+ Methods:
391
+ All of the methods within this class are subclassed from PyTorch Lightning's LightningModule. Their documentation for each of these methods can be found here: https://lightning.ai/docs/pytorch/stable/common/lightning_module.html
392
+ '''
393
+ super().__init__()
394
+ self.save_hyperparameters()
395
+
396
+ # Transforms flag to perform image augmentations
397
+ # self.use_transforms = use_transforms
398
+
399
+ # Save predictions for later
400
+ self.test_preds = []
401
+ self.test_labels = []
402
+
403
+ self.learning_rate = learning_rate
404
+ self.weight_decay = weight_decay
405
+ self.kernel_size = kernel_size
406
+ self.stride = stride
407
+ self.padding = padding
408
+ self.use_weights = use_weights
409
+ self.scheduler_factor = scheduler_factor
410
+ self.scheduler_patience = scheduler_patience
411
+ self.scheduler_threshold = scheduler_threshold
412
+
413
+ if use_weights==True:
414
+ self.model = models.convnext_tiny(weights='DEFAULT')
415
+ else:
416
+ self.model = models.convnext_tiny()
417
+
418
+ # Modify first conv. layer to accept grayscale/1 channel inputs
419
+ self.model.features[0][0] = nn.Conv2d(
420
+ in_channels=1,
421
+ out_channels=96,
422
+ kernel_size=kernel_size,
423
+ stride=stride,
424
+ padding=padding
425
+ )
426
+
427
+ # Modify classifier for regression output
428
+ num_features = self.model.classifier[-1].in_features
429
+ self.model.classifier[-1] = nn.Linear(num_features, 1) # Single output for regression
430
+
431
+ # Create dictionary of metrics to track for training, validation, and testing
432
+ self.train_metrics = torchmetrics.MetricCollection(
433
+ {
434
+ 'MAE': torchmetrics.regression.MeanAbsoluteError(num_outputs=1),
435
+ 'RMSE': torchmetrics.regression.MeanSquaredError(squared=False, num_outputs=1),
436
+ 'MSE': torchmetrics.regression.MeanSquaredError(squared=True, num_outputs=1),
437
+ 'r_squared': torchmetrics.regression.R2Score()
438
+ },
439
+ prefix='train_'
440
+ )
441
+
442
+ self.valid_metrics = self.train_metrics.clone(prefix='valid_')
443
+ self.test_metrics = self.train_metrics.clone(prefix='test_')
444
+
445
+
446
+ def forward(self, x):
447
+ return self.model(x).squeeze(-1) # Remove extra dimension
448
+
449
+ # Reset metrics
450
+ def on_train_epoch_start(self):
451
+ self.train_metrics.reset()
452
+
453
+ def training_step(self, batch, batch_idx):
454
+ x, y = batch # Get inputs and labels
455
+ y_pred = self(x) # Forward pass (call model's forward method)
456
+
457
+ loss = F.mse_loss(y_pred, y)
458
+ self.log('train_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True) # Log MSE loss for monitoring
459
+
460
+ # Log metrics
461
+ batch_values = self.train_metrics(y_pred, y)
462
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
463
+ return loss
464
+
465
+ # Reset metrics
466
+ def on_validation_epoch_start(self):
467
+ self.valid_metrics.reset()
468
+
469
+ def validation_step(self, batch, batch_idx):
470
+ x, y = batch # Get features and labels
471
+ y_pred = self(x)
472
+ loss = F.mse_loss(y_pred, y)
473
+ self.log('val_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
474
+
475
+ # Update validation metrics
476
+ batch_values = self.valid_metrics(y_pred, y)
477
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
478
+
479
+ return loss
480
+
481
+ # Reset metrics
482
+ def on_test_epoch_start(self):
483
+ self.test_metrics.reset()
484
+
485
+ def test_step(self, batch, batch_idx):
486
+ x, y = batch # Get features and labels
487
+ y_pred = self(x)
488
+ loss = F.mse_loss(y_pred, y)
489
+ self.log('test_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
490
+
491
+ # Update validation metrics
492
+ batch_values = self.test_metrics(y_pred, y)
493
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
494
+
495
+ # Store predictions and labels
496
+ self.test_preds.append(y_pred.cpu())
497
+ self.test_labels.append(y.cpu())
498
+
499
+ return loss
500
+
501
+ def on_test_epoch_end(self):
502
+ self.test_preds = torch.cat([pred.float() for pred in self.test_preds], dim=0).numpy()
503
+ self.test_labels = torch.cat([label.float() for label in self.test_labels], dim=0).numpy()
504
+
505
+ # Log transform test predictions and labels
506
+ self.test_preds = np.exp(self.test_preds)
507
+ self.test_labels = np.exp(self.test_labels)
508
+
509
+ # Store results for access after trainer.test()
510
+ self.test_results = {'preds': self.test_preds, 'labels': self.test_labels}
511
+
512
+ def configure_optimizers(self):
513
+ optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
514
+ scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='min', factor=self.scheduler_factor, patience=self.scheduler_patience, threshold=self.scheduler_threshold)
515
+
516
+ return {'optimizer': optimizer,
517
+ 'lr_scheduler': scheduler,
518
+ 'monitor': 'val_loss'}
519
+
520
+ # NOTE: pin_memory=True calls in the next three defs should be monitored for performance. Can easily set to false.
521
+ def train_dataloader(self):
522
+ return DataLoader(self.train_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=True, pin_memory=True)
523
+
524
+ def val_dataloader(self):
525
+ return DataLoader(self.val_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
526
+
527
+ def test_dataloader(self):
528
+ return DataLoader(self.test_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
model_classes/EfficientNets.py ADDED
@@ -0,0 +1,512 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import Optional, List, Dict, Tuple, Any
3
+ import numpy as np
4
+ import pandas as pd
5
+ import piexif
6
+ from sklearn.preprocessing import StandardScaler
7
+ from PIL import Image
8
+ import torch
9
+ from torch.optim.lr_scheduler import ReduceLROnPlateau
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from torch.utils.data import Dataset, TensorDataset, DataLoader, random_split
13
+ from torchvision.io import decode_image, read_file, image
14
+ from torchvision.transforms import v2
15
+ import torchvision.models as models
16
+ import lightning as L
17
+ from lightning.pytorch.callbacks.early_stopping import EarlyStopping
18
+ import torchmetrics
19
+ from lightning.pytorch.loggers import WandbLogger
20
+ from lightning.pytorch import Trainer, seed_everything
21
+ import wandb
22
+ import lmdb
23
+ import msgpack
24
+ import sys
25
+ import torchvision
26
+
27
+ # Dynamically construct the path based on the user's home directory
28
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__name__), '..')))
29
+
30
+ from utils import export_cnn, test_report
31
+
32
+ torch.set_float32_matmul_precision('highest') # Options are medium, high, highest
33
+
34
+ tensor_dtype = torch.bfloat16 # Can change to torch.bfloat16
35
+
36
+ # For training on AMD GPUs, as bfloat16 isn't supported
37
+ # tensor_dtype = torch.float16
38
+
39
+ # EfficientNet B0 architecture
40
+ class ENetB0(L.LightningModule):
41
+ def __init__(
42
+ self,
43
+ learning_rate: float=1e-3,
44
+ weight_decay: float=1e-2,
45
+ kernel_size: int=3,
46
+ stride: int=1,
47
+ padding: int=0,
48
+ use_weights: bool=True,
49
+ scheduler_factor: float=0.1,
50
+ scheduler_patience: int=10,
51
+ scheduler_threshold: float=1e-4
52
+ ):
53
+ '''
54
+ Class to load the EfficientNet B0 architecture from PyTorch's torchvision library.
55
+
56
+ Parameters:
57
+ learning_rate (float): Learning rate. Defaults to 1e-3.
58
+ weight_decay (float): Weight decay for AdamW optimizer. Defaults to 1e-2.
59
+ kernel_size (int): Kernel size for convolutional filters. Defaults to 3.
60
+ stride (int): Stride for convolutional filters. Defaults to 1.
61
+ padding (int): Padding for convolutional filters. Defaults to 0.
62
+ use_weights (bool): Whether or not to use pretrained weights from ImageNet. Defaults to True.
63
+ scheduler_factor (float): Factor for ReduceLROnPlateau. Defaults to 0.1.
64
+ scheduler_patience (int): Patience for ReduceLROnPlateau. Defaults to 10.
65
+ scheduler_threshold (float): Threshold for ReduceLROnPlateau. Defaults to 1e-4.
66
+
67
+ Methods:
68
+ All of the methods within this class are subclassed from PyTorch Lightning's LightningModule. Their documentation for each of these methods can be found here: https://lightning.ai/docs/pytorch/stable/common/lightning_module.html
69
+ '''
70
+ super().__init__()
71
+ self.save_hyperparameters()
72
+
73
+ # Transforms flag to perform image augmentations
74
+ # self.use_transforms = use_transforms
75
+
76
+ # Save predictions for later
77
+ self.test_preds = []
78
+ self.test_labels = []
79
+
80
+ self.learning_rate = learning_rate
81
+ self.weight_decay = weight_decay
82
+ self.kernel_size = kernel_size
83
+ self.stride = stride
84
+ self.padding = padding
85
+ self.use_weights = use_weights
86
+ self.scheduler_factor = scheduler_factor
87
+ self.scheduler_patience = scheduler_patience
88
+ self.scheduler_threshold = scheduler_threshold
89
+
90
+ if use_weights==True:
91
+ self.model = models.efficientnet_b0(weights='DEFAULT')
92
+ else:
93
+ self.model = models.efficientnet_b0()
94
+
95
+ # Modify first conv. layer to accept grayscale/1 channel inputs
96
+ self.model.features[0][0] = nn.Conv2d(
97
+ in_channels=1,
98
+ out_channels=32,
99
+ kernel_size=kernel_size,
100
+ stride=stride,
101
+ padding=padding
102
+ )
103
+
104
+ # Modify classifier for regression output
105
+ num_features = self.model.classifier[-1].in_features
106
+ self.model.classifier[-1] = nn.Linear(num_features, 1) # Single output for regression
107
+
108
+ # Create dictionary of metrics to track for training, validation, and testing
109
+ self.train_metrics = torchmetrics.MetricCollection(
110
+ {
111
+ 'MAE': torchmetrics.regression.MeanAbsoluteError(num_outputs=1),
112
+ 'RMSE': torchmetrics.regression.MeanSquaredError(squared=False, num_outputs=1),
113
+ 'MSE': torchmetrics.regression.MeanSquaredError(squared=True, num_outputs=1),
114
+ 'r_squared': torchmetrics.regression.R2Score()
115
+ },
116
+ prefix='train_'
117
+ )
118
+
119
+ self.valid_metrics = self.train_metrics.clone(prefix='valid_')
120
+ self.test_metrics = self.train_metrics.clone(prefix='test_')
121
+
122
+
123
+ def forward(self, x):
124
+ return self.model(x).squeeze(-1) # Remove extra dimension
125
+
126
+ # Reset metrics
127
+ def on_train_epoch_start(self):
128
+ self.train_metrics.reset()
129
+
130
+ def training_step(self, batch, batch_idx):
131
+ x, y = batch # Get inputs and labels
132
+ y_pred = self(x) # Forward pass (call model's forward method)
133
+
134
+ loss = F.mse_loss(y_pred, y)
135
+ self.log('train_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True) # Log MSE loss for monitoring
136
+
137
+ # Log metrics
138
+ batch_values = self.train_metrics(y_pred, y)
139
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
140
+ return loss
141
+
142
+ # Reset metrics
143
+ def on_validation_epoch_start(self):
144
+ self.valid_metrics.reset()
145
+
146
+ def validation_step(self, batch, batch_idx):
147
+ x, y = batch # Get features and labels
148
+ y_pred = self(x)
149
+ loss = F.mse_loss(y_pred, y)
150
+ self.log('val_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
151
+
152
+ # Update validation metrics
153
+ batch_values = self.valid_metrics(y_pred, y)
154
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
155
+
156
+ return loss
157
+
158
+ # Reset metrics
159
+ def on_test_epoch_start(self):
160
+ self.test_metrics.reset()
161
+
162
+ def test_step(self, batch, batch_idx):
163
+ x, y = batch # Get features and labels
164
+ y_pred = self(x)
165
+ loss = F.mse_loss(y_pred, y)
166
+ self.log('test_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
167
+
168
+ # Update validation metrics
169
+ batch_values = self.test_metrics(y_pred, y)
170
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
171
+
172
+ # Store predictions and labels
173
+ self.test_preds.append(y_pred.cpu())
174
+ self.test_labels.append(y.cpu())
175
+
176
+ return loss
177
+
178
+ def on_test_epoch_end(self):
179
+ self.test_preds = torch.cat([pred.float() for pred in self.test_preds], dim=0).numpy()
180
+ self.test_labels = torch.cat([label.float() for label in self.test_labels], dim=0).numpy()
181
+
182
+ # Log transform test predictions and labels
183
+ self.test_preds = np.exp(self.test_preds)
184
+ self.test_labels = np.exp(self.test_labels)
185
+
186
+ # Store results for access after trainer.test()
187
+ self.test_results = {'preds': self.test_preds, 'labels': self.test_labels}
188
+
189
+ def configure_optimizers(self):
190
+ optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
191
+ scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='min', factor=self.scheduler_factor, patience=self.scheduler_patience, threshold=self.scheduler_threshold)
192
+
193
+ return {'optimizer': optimizer,
194
+ 'lr_scheduler': scheduler,
195
+ 'monitor': 'val_loss'}
196
+
197
+ # EfficientNet B3 architecture
198
+ class ENetB3(L.LightningModule):
199
+ def __init__(
200
+ self,
201
+ learning_rate: float=1e-3,
202
+ weight_decay: float=1e-2,
203
+ kernel_size: int=3,
204
+ stride: int=1,
205
+ padding: int=0,
206
+ use_weights: bool=True,
207
+ scheduler_factor: float=0.1,
208
+ scheduler_patience: int=10,
209
+ scheduler_threshold: float=1e-4
210
+ ):
211
+ '''
212
+ Class to load the EfficientNet B3 architecture from PyTorch's torchvision library.
213
+
214
+ Parameters:
215
+ learning_rate (float): Learning rate. Defaults to 1e-3.
216
+ weight_decay (float): Weight decay for AdamW optimizer. Defaults to 1e-2.
217
+ kernel_size (int): Kernel size for convolutional filters. Defaults to 3.
218
+ stride (int): Stride for convolutional filters. Defaults to 1.
219
+ padding (int): Padding for convolutional filters. Defaults to 0.
220
+ use_weights (bool): Whether or not to use pretrained weights from ImageNet. Defaults to True.
221
+ scheduler_factor (float): Factor for ReduceLROnPlateau. Defaults to 0.1.
222
+ scheduler_patience (int): Patience for ReduceLROnPlateau. Defaults to 10.
223
+ scheduler_threshold (float): Threshold for ReduceLROnPlateau. Defaults to 1e-4.
224
+
225
+ Methods:
226
+ All of the methods within this class are subclassed from PyTorch Lightning's LightningModule. Their documentation for each of these methods can be found here: https://lightning.ai/docs/pytorch/stable/common/lightning_module.html
227
+ '''
228
+ super().__init__()
229
+ self.save_hyperparameters()
230
+
231
+ # Transforms flag to perform image augmentations
232
+ # self.use_transforms = use_transforms
233
+
234
+ # Save predictions for later
235
+ self.test_preds = []
236
+ self.test_labels = []
237
+
238
+ self.learning_rate = learning_rate
239
+ self.weight_decay = weight_decay
240
+ self.kernel_size = kernel_size
241
+ self.stride = stride
242
+ self.padding = padding
243
+ self.use_weights = use_weights
244
+ self.scheduler_factor = scheduler_factor
245
+ self.scheduler_patience = scheduler_patience
246
+ self.scheduler_threshold = scheduler_threshold
247
+
248
+ if use_weights==True:
249
+ self.model = models.efficientnet_b3(weights='DEFAULT')
250
+ else:
251
+ self.model = models.efficientnet_b3()
252
+
253
+ # Modify first conv. layer to accept grayscale/1 channel inputs
254
+ self.model.features[0][0] = nn.Conv2d(
255
+ in_channels=1,
256
+ out_channels=40,
257
+ kernel_size=kernel_size,
258
+ stride=stride,
259
+ padding=padding
260
+ )
261
+
262
+ # Modify classifier for regression output
263
+ num_features = self.model.classifier[-1].in_features
264
+ self.model.classifier[-1] = nn.Linear(num_features, 1) # Single output for regression
265
+
266
+ # Create dictionary of metrics to track for training, validation, and testing
267
+ self.train_metrics = torchmetrics.MetricCollection(
268
+ {
269
+ 'MAE': torchmetrics.regression.MeanAbsoluteError(num_outputs=1),
270
+ 'RMSE': torchmetrics.regression.MeanSquaredError(squared=False, num_outputs=1),
271
+ 'MSE': torchmetrics.regression.MeanSquaredError(squared=True, num_outputs=1),
272
+ 'r_squared': torchmetrics.regression.R2Score()
273
+ },
274
+ prefix='train_'
275
+ )
276
+
277
+ self.valid_metrics = self.train_metrics.clone(prefix='valid_')
278
+ self.test_metrics = self.train_metrics.clone(prefix='test_')
279
+
280
+
281
+ def forward(self, x):
282
+ return self.model(x).squeeze(-1) # Remove extra dimension
283
+
284
+ # Reset metrics
285
+ def on_train_epoch_start(self):
286
+ self.train_metrics.reset()
287
+
288
+ def training_step(self, batch, batch_idx):
289
+ x, y = batch # Get inputs and labels
290
+ y_pred = self(x) # Forward pass (call model's forward method)
291
+
292
+ loss = F.mse_loss(y_pred, y)
293
+ self.log('train_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True) # Log MSE loss for monitoring
294
+
295
+ # Log metrics
296
+ batch_values = self.train_metrics(y_pred, y)
297
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
298
+ return loss
299
+
300
+ # Reset metrics
301
+ def on_validation_epoch_start(self):
302
+ self.valid_metrics.reset()
303
+
304
+ def validation_step(self, batch, batch_idx):
305
+ x, y = batch # Get features and labels
306
+ y_pred = self(x)
307
+ loss = F.mse_loss(y_pred, y)
308
+ self.log('val_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
309
+
310
+ # Update validation metrics
311
+ batch_values = self.valid_metrics(y_pred, y)
312
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
313
+
314
+ return loss
315
+
316
+ # Reset metrics
317
+ def on_test_epoch_start(self):
318
+ self.test_metrics.reset()
319
+
320
+ def test_step(self, batch, batch_idx):
321
+ x, y = batch # Get features and labels
322
+ y_pred = self(x)
323
+ loss = F.mse_loss(y_pred, y)
324
+ self.log('test_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
325
+
326
+ # Update validation metrics
327
+ batch_values = self.test_metrics(y_pred, y)
328
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
329
+
330
+ # Store predictions and labels
331
+ self.test_preds.append(y_pred.cpu())
332
+ self.test_labels.append(y.cpu())
333
+
334
+ return loss
335
+
336
+ def on_test_epoch_end(self):
337
+ self.test_preds = torch.cat([pred.float() for pred in self.test_preds], dim=0).numpy()
338
+ self.test_labels = torch.cat([label.float() for label in self.test_labels], dim=0).numpy()
339
+
340
+ # Log transform test predictions and labels
341
+ self.test_preds = np.exp(self.test_preds)
342
+ self.test_labels = np.exp(self.test_labels)
343
+
344
+ # Store results for access after trainer.test()
345
+ self.test_results = {'preds': self.test_preds, 'labels': self.test_labels}
346
+
347
+ def configure_optimizers(self):
348
+ optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
349
+ scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='min', factor=self.scheduler_factor, patience=self.scheduler_patience, threshold=self.scheduler_threshold)
350
+
351
+ return {'optimizer': optimizer,
352
+ 'lr_scheduler': scheduler,
353
+ 'monitor': 'val_loss'}
354
+
355
+ # EfficientNet B7 architecture
356
+ class ENetB7(L.LightningModule):
357
+ def __init__(
358
+ self,
359
+ learning_rate: float=1e-3,
360
+ weight_decay: float=1e-2,
361
+ kernel_size: int=3,
362
+ stride: int=1,
363
+ padding: int=0,
364
+ use_weights: bool=True,
365
+ scheduler_factor: float=0.1,
366
+ scheduler_patience: int=10,
367
+ scheduler_threshold: float=1e-4
368
+ ):
369
+ '''
370
+ Class to load the EfficientNet B7 architecture from PyTorch's torchvision library.
371
+
372
+ Parameters:
373
+ learning_rate (float): Learning rate. Defaults to 1e-3.
374
+ weight_decay (float): Weight decay for AdamW optimizer. Defaults to 1e-2.
375
+ kernel_size (int): Kernel size for convolutional filters. Defaults to 3.
376
+ stride (int): Stride for convolutional filters. Defaults to 1.
377
+ padding (int): Padding for convolutional filters. Defaults to 0.
378
+ use_weights (bool): Whether or not to use pretrained weights from ImageNet. Defaults to True.
379
+ scheduler_factor (float): Factor for ReduceLROnPlateau. Defaults to 0.1.
380
+ scheduler_patience (int): Patience for ReduceLROnPlateau. Defaults to 10.
381
+ scheduler_threshold (float): Threshold for ReduceLROnPlateau. Defaults to 1e-4.
382
+
383
+ Methods:
384
+ All of the methods within this class are subclassed from PyTorch Lightning's LightningModule. Their documentation for each of these methods can be found here: https://lightning.ai/docs/pytorch/stable/common/lightning_module.html
385
+ '''
386
+ super().__init__()
387
+ self.save_hyperparameters()
388
+
389
+ # Transforms flag to perform image augmentations
390
+ # self.use_transforms = use_transforms
391
+
392
+ # Save predictions for later
393
+ self.test_preds = []
394
+ self.test_labels = []
395
+
396
+ self.learning_rate = learning_rate
397
+ self.weight_decay = weight_decay
398
+ self.kernel_size = kernel_size
399
+ self.stride = stride
400
+ self.padding = padding
401
+ self.use_weights = True
402
+ self.scheduler_factor = scheduler_factor
403
+ self.scheduler_patience = scheduler_patience
404
+ self.scheduler_threshold = scheduler_threshold
405
+
406
+ if use_weights==True:
407
+ self.model = models.efficientnet_b7(weights='DEFAULT')
408
+ else:
409
+ self.model = models.efficientnet_b7()
410
+
411
+ # Modify first conv. layer to accept grayscale/1 channel inputs
412
+ self.model.features[0][0] = nn.Conv2d(
413
+ in_channels=1,
414
+ out_channels=64,
415
+ kernel_size=kernel_size,
416
+ stride=stride,
417
+ padding=padding
418
+ )
419
+
420
+ # Modify classifier for regression output
421
+ num_features = self.model.classifier[-1].in_features
422
+ self.model.classifier[-1] = nn.Linear(num_features, 1) # Single output for regression
423
+
424
+ # Create dictionary of metrics to track for training, validation, and testing
425
+ self.train_metrics = torchmetrics.MetricCollection(
426
+ {
427
+ 'MAE': torchmetrics.regression.MeanAbsoluteError(num_outputs=1),
428
+ 'RMSE': torchmetrics.regression.MeanSquaredError(squared=False, num_outputs=1),
429
+ 'MSE': torchmetrics.regression.MeanSquaredError(squared=True, num_outputs=1),
430
+ 'r_squared': torchmetrics.regression.R2Score()
431
+ },
432
+ prefix='train_'
433
+ )
434
+
435
+ self.valid_metrics = self.train_metrics.clone(prefix='valid_')
436
+ self.test_metrics = self.train_metrics.clone(prefix='test_')
437
+
438
+
439
+ def forward(self, x):
440
+ return self.model(x).squeeze(-1) # Remove extra dimension
441
+
442
+ # Reset metrics
443
+ def on_train_epoch_start(self):
444
+ self.train_metrics.reset()
445
+
446
+ def training_step(self, batch, batch_idx):
447
+ x, y = batch # Get inputs and labels
448
+ y_pred = self(x) # Forward pass (call model's forward method)
449
+
450
+ loss = F.mse_loss(y_pred, y)
451
+ self.log('train_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True) # Log MSE loss for monitoring
452
+
453
+ # Log metrics
454
+ batch_values = self.train_metrics(y_pred, y)
455
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
456
+ return loss
457
+
458
+ # Reset metrics
459
+ def on_validation_epoch_start(self):
460
+ self.valid_metrics.reset()
461
+
462
+ def validation_step(self, batch, batch_idx):
463
+ x, y = batch # Get features and labels
464
+ y_pred = self(x)
465
+ loss = F.mse_loss(y_pred, y)
466
+ self.log('val_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
467
+
468
+ # Update validation metrics
469
+ batch_values = self.valid_metrics(y_pred, y)
470
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
471
+
472
+ return loss
473
+
474
+ # Reset metrics
475
+ def on_test_epoch_start(self):
476
+ self.test_metrics.reset()
477
+
478
+ def test_step(self, batch, batch_idx):
479
+ x, y = batch # Get features and labels
480
+ y_pred = self(x)
481
+ loss = F.mse_loss(y_pred, y)
482
+ self.log('test_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
483
+
484
+ # Update validation metrics
485
+ batch_values = self.test_metrics(y_pred, y)
486
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
487
+
488
+ # Store predictions and labels
489
+ self.test_preds.append(y_pred.cpu())
490
+ self.test_labels.append(y.cpu())
491
+
492
+ return loss
493
+
494
+ def on_test_epoch_end(self):
495
+ self.test_preds = torch.cat([pred.float() for pred in self.test_preds], dim=0).numpy()
496
+ self.test_labels = torch.cat([label.float() for label in self.test_labels], dim=0).numpy()
497
+
498
+ # Log transform test predictions and labels
499
+ self.test_preds = np.exp(self.test_preds)
500
+ self.test_labels = np.exp(self.test_labels)
501
+
502
+ # Store results for access after trainer.test()
503
+ self.test_results = {'preds': self.test_preds, 'labels': self.test_labels}
504
+
505
+ def configure_optimizers(self):
506
+ optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
507
+ scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='min', factor=self.scheduler_factor, patience=self.scheduler_patience, threshold=self.scheduler_threshold)
508
+
509
+ return {'optimizer': optimizer,
510
+ 'lr_scheduler': scheduler,
511
+ 'monitor': 'val_loss'}
512
+
model_classes/MLP.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import Optional, List, Dict, Tuple, Any
3
+ import numpy as np
4
+ import pandas as pd
5
+ import piexif
6
+ from sklearn.preprocessing import StandardScaler
7
+ from PIL import Image
8
+ import torch
9
+ from torch.optim.lr_scheduler import ReduceLROnPlateau
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from torch.utils.data import Dataset, TensorDataset, DataLoader, random_split
13
+ from torchvision.io import decode_image, read_file, image
14
+ from torchvision.transforms import v2
15
+ import torchvision.models as models
16
+ import lightning as L
17
+ from lightning.pytorch.callbacks.early_stopping import EarlyStopping
18
+ import torchmetrics
19
+ from lightning.pytorch.loggers import WandbLogger
20
+ from lightning.pytorch import Trainer, seed_everything
21
+ import wandb
22
+ import lmdb
23
+ import msgpack
24
+ import sys
25
+ import torchvision
26
+
27
+ # Dynamically construct the path based on the user's home directory
28
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__name__), '..')))
29
+
30
+ from utils import export_mlp, test_report
31
+
32
+ torch.set_float32_matmul_precision('highest') # Options are medium, high, highest
33
+
34
+ tensor_dtype = torch.bfloat16 # Can change to torch.bfloat16
35
+
36
+ # For training on AMD GPUs, as bfloat16 isn't supported
37
+ # tensor_dtype = torch.float16
38
+
39
+ class MLP(L.LightningModule):
40
+ def __init__(
41
+ self,
42
+ input_size: int,
43
+ hidden_size: int=128,
44
+ num_layers: int=2,
45
+ learning_rate: float=1e-3,
46
+ weight_decay: float=1e-2,
47
+ scheduler_factor: float=0.1,
48
+ scheduler_patience: int=10,
49
+ scheduler_threshold: float=1e-4
50
+ ):
51
+ '''
52
+ Class to create a simple multi-layered perceptron (MLP) model for tabular data.
53
+
54
+ Parameters:
55
+ input_size (int): Size of the input data.
56
+ hidden_size (int): Number of neurons for the hidden layers. Defaults to 100.
57
+ num_layers (int): Number of hidden layers. Defaults to 2.
58
+ learning_rate (float): Learning rate. Defaults to 1e-3
59
+ weight_decay (float): Weight decay for AdamW optimizer. Defaults to 1e-5
60
+ scheduler_factor (float): Factor for ReduceLROnPlateau. Defaults to 0.1.
61
+ scheduler_patience (int): Patience for ReduceLROnPlateau. Defaults to 10.
62
+ scheduler_threshold (float): Threshold for ReduceLROnPlateau. Defaults to 1e-4.
63
+
64
+ Methods:
65
+ All of the methods within this class are subclassed from PyTorch Lightning's LightningModule. Their documentation for each of these methods can be found here: https://lightning.ai/docs/pytorch/stable/common/lightning_module.html
66
+ '''
67
+ super().__init__()
68
+ self.save_hyperparameters() # Save model hyperparameters for checkpointing
69
+
70
+ self.input_size = input_size
71
+ self.hidden_size = hidden_size
72
+ self.num_layers = num_layers
73
+ self.learning_rate = learning_rate
74
+ self.weight_decay = weight_decay
75
+ self.input_size = input_size
76
+ self.scheduler_factor = scheduler_factor
77
+ self.scheduler_patience = scheduler_patience
78
+ self.scheduler_threshold = scheduler_threshold
79
+
80
+ # Save predictions for later
81
+ self.test_preds = []
82
+ self.test_labels = []
83
+
84
+ # Define model layers
85
+ layers = []
86
+
87
+ layers.append(nn.Linear(self.input_size, hidden_size))
88
+ layers.append(nn.ReLU())
89
+
90
+ # Set number of hidden layers dynamically via class definition
91
+ for _ in range(num_layers - 1):
92
+ layers.append(nn.Linear(hidden_size, hidden_size))
93
+ layers.append(nn.BatchNorm1d(num_features=hidden_size))
94
+ layers.append(nn.ReLU())
95
+
96
+ layers.append(nn.Linear(hidden_size, 1)) # Output layer for regression and permeability
97
+
98
+ self.model = nn.Sequential(*layers) # Build model
99
+
100
+ # Create dictionary of metrics to track for training, validation, and testing
101
+ self.train_metrics = torchmetrics.MetricCollection(
102
+ {
103
+ 'MAE': torchmetrics.regression.MeanAbsoluteError(num_outputs=1),
104
+ 'RMSE': torchmetrics.regression.MeanSquaredError(squared=False, num_outputs=1),
105
+ 'MSE': torchmetrics.regression.MeanSquaredError(squared=True, num_outputs=1),
106
+ 'r_squared': torchmetrics.regression.R2Score()
107
+ },
108
+ prefix='train_'
109
+ )
110
+
111
+ self.valid_metrics = self.train_metrics.clone(prefix='valid_')
112
+ self.test_metrics = self.train_metrics.clone(prefix='test_')
113
+
114
+ def forward(self, x):
115
+ return self.model(x)
116
+
117
+ # Reset metrics
118
+ def on_train_epoch_start(self):
119
+ self.train_metrics.reset()
120
+
121
+ def training_step(self, batch, batch_idx):
122
+ x, y = batch # Get inputs and labels
123
+ y_pred = self(x) # Forward pass (call model's forward method)
124
+
125
+ loss = F.mse_loss(y_pred, y)
126
+ self.log('train_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True) # Log MSE loss for monitoring
127
+
128
+ # Log metrics
129
+ batch_values = self.train_metrics(y_pred, y)
130
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
131
+ return loss
132
+
133
+ # Reset metrics
134
+ def on_validation_epoch_start(self):
135
+ self.valid_metrics.reset()
136
+
137
+ def validation_step(self, batch, batch_idx):
138
+ x, y = batch # Get features and labels
139
+ y_pred = self(x)
140
+ loss = F.mse_loss(y_pred, y)
141
+ self.log('val_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
142
+
143
+ # Update validation metrics
144
+ batch_values = self.valid_metrics(y_pred, y)
145
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
146
+
147
+ return loss
148
+
149
+ # Reset metrics
150
+ def on_test_epoch_start(self):
151
+ self.test_metrics.reset()
152
+
153
+ def test_step(self, batch, batch_idx):
154
+ x, y = batch # Get features and labels
155
+ y_pred = self(x)
156
+ loss = F.mse_loss(y_pred, y)
157
+ self.log('test_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
158
+
159
+ # Update validation metrics
160
+ batch_values = self.test_metrics(y_pred, y)
161
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
162
+
163
+ # Store predictions and labels
164
+ self.test_preds.append(y_pred.cpu())
165
+ self.test_labels.append(y.cpu())
166
+
167
+ return loss
168
+
169
+ def on_test_epoch_end(self):
170
+ self.test_preds = torch.cat([pred.float() for pred in self.test_preds], dim=0).numpy()
171
+ self.test_labels = torch.cat([label.float() for label in self.test_labels], dim=0).numpy()
172
+
173
+ # Log transform test predictions and labels
174
+ self.test_preds = np.exp(self.test_preds)
175
+ self.test_labels = np.exp(self.test_labels)
176
+
177
+ # Store results for access after trainer.test()
178
+ self.test_results = {'preds': self.test_preds, 'labels': self.test_labels}
179
+
180
+ def configure_optimizers(self):
181
+ optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
182
+ scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='min', factor=self.scheduler_factor, patience=self.scheduler_patience, threshold=self.scheduler_threshold)
183
+
184
+ return {'optimizer': optimizer,
185
+ 'lr_scheduler': scheduler,
186
+ 'monitor': 'val_loss'}
model_classes/ResNets.py ADDED
@@ -0,0 +1,542 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import Optional, List, Dict, Tuple, Any
3
+ import numpy as np
4
+ import pandas as pd
5
+ import piexif
6
+ from sklearn.preprocessing import StandardScaler
7
+ from PIL import Image
8
+ import torch
9
+ from torch.optim.lr_scheduler import ReduceLROnPlateau
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from torch.utils.data import Dataset, TensorDataset, DataLoader, random_split
13
+ from torchvision.io import decode_image, read_file, image
14
+ from torchvision.transforms import v2
15
+ import torchvision.models as models
16
+ import lightning as L
17
+ from lightning.pytorch.callbacks.early_stopping import EarlyStopping
18
+ import torchmetrics
19
+ from lightning.pytorch.loggers import WandbLogger
20
+ from lightning.pytorch import Trainer, seed_everything
21
+ import wandb
22
+ import lmdb
23
+ import msgpack
24
+ import sys
25
+ import torchvision
26
+
27
+ # Dynamically construct the path based on the user's home directory
28
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__name__), '..')))
29
+
30
+ from utils import export_cnn, test_report
31
+
32
+ torch.set_float32_matmul_precision('highest') # Options are medium, high, highest
33
+
34
+ tensor_dtype = torch.bfloat16 # Can change to torch.bfloat16
35
+
36
+ # For training on AMD GPUs, as bfloat16 isn't supported
37
+ # tensor_dtype = torch.float16
38
+
39
+ # ResNet-18 model architecture
40
+ class ResNet18(L.LightningModule):
41
+ def __init__(
42
+ self,
43
+ learning_rate: float=1e-3,
44
+ weight_decay: float=1e-2,
45
+ kernel_size: int=3,
46
+ stride: int=1,
47
+ padding: int=0,
48
+ use_weights: bool=True,
49
+ scheduler_factor: float=0.1,
50
+ scheduler_patience: int=10,
51
+ scheduler_threshold: float=1e-4
52
+ ):
53
+ '''
54
+ Class to load the ResNet-50 architecture from PyTorch's torchvision library.
55
+
56
+ Parameters:
57
+ learning_rate (float): Learning rate. Defaults to 1e-3.
58
+ weight_decay (float): Weight decay for AdamW optimizer. Defaults to 1e-2.
59
+ kernel_size (int): Kernel size for convolutional filters. Defaults to 3.
60
+ stride (int): Stride for convolutional filters. Defaults to 1.
61
+ padding (int): Padding for convolutional filters. Defaults to 0.
62
+ use_weights (bool): Whether or not to use pretrained weights from ImageNet. Defaults to True.
63
+ scheduler_factor (float): Factor for ReduceLROnPlateau. Defaults to 0.1.
64
+ scheduler_patience (int): Patience for ReduceLROnPlateau. Defaults to 10.
65
+ scheduler_threshold (float): Threshold for ReduceLROnPlateau. Defaults to 1e-4.
66
+
67
+ Methods:
68
+ All of the methods within this class are subclassed from PyTorch Lightning's LightningModule. Their documentation for each of these methods can be found here: https://lightning.ai/docs/pytorch/stable/common/lightning_module.html
69
+ '''
70
+ super().__init__()
71
+ self.save_hyperparameters()
72
+
73
+ # Transforms flag to perform image augmentations
74
+ # self.use_transforms = use_transforms
75
+
76
+ # Save predictions for later
77
+ self.test_preds = []
78
+ self.test_labels = []
79
+
80
+ self.learning_rate = learning_rate
81
+ self.weight_decay = weight_decay
82
+ self.kernel_size = kernel_size
83
+ self.stride = stride
84
+ self.padding = padding
85
+ self.use_weights = use_weights
86
+ self.scheduler_factor = scheduler_factor
87
+ self.scheduler_patience = scheduler_patience
88
+ self.scheduler_threshold = scheduler_threshold
89
+
90
+ if use_weights==True:
91
+ self.model = models.resnet18(weights='DEFAULT')
92
+ else:
93
+ self.model = models.resnet18()
94
+
95
+ # Modify first conv. layer to accept grayscale/1 channel inputs
96
+ self.model.conv1 = nn.Conv2d(
97
+ in_channels=1,
98
+ out_channels=64,
99
+ kernel_size=kernel_size,
100
+ stride=stride,
101
+ padding=padding
102
+ )
103
+
104
+ # Modify classifier for regression output
105
+ num_features = self.model.fc.in_features
106
+ self.model.fc = nn.Linear(num_features, 1) # Single output for regression
107
+
108
+ # Create dictionary of metrics to track for training, validation, and testing
109
+ self.train_metrics = torchmetrics.MetricCollection(
110
+ {
111
+ 'MAE': torchmetrics.regression.MeanAbsoluteError(num_outputs=1),
112
+ 'RMSE': torchmetrics.regression.MeanSquaredError(squared=False, num_outputs=1),
113
+ 'MSE': torchmetrics.regression.MeanSquaredError(squared=True, num_outputs=1),
114
+ 'r_squared': torchmetrics.regression.R2Score()
115
+ },
116
+ prefix='train_'
117
+ )
118
+
119
+ self.valid_metrics = self.train_metrics.clone(prefix='valid_')
120
+ self.test_metrics = self.train_metrics.clone(prefix='test_')
121
+
122
+
123
+ def forward(self, x):
124
+ return self.model(x).squeeze(-1) # Remove extra dimension
125
+
126
+ # Reset metrics
127
+ def on_train_epoch_start(self):
128
+ self.train_metrics.reset()
129
+
130
+ def training_step(self, batch, batch_idx):
131
+ x, y = batch # Get inputs and labels
132
+ y_pred = self(x) # Forward pass (call model's forward method)
133
+
134
+ loss = F.mse_loss(y_pred, y)
135
+ self.log('train_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True) # Log MSE loss for monitoring
136
+
137
+ # Log metrics
138
+ batch_values = self.train_metrics(y_pred, y)
139
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
140
+ return loss
141
+
142
+ # Reset metrics
143
+ def on_validation_epoch_start(self):
144
+ self.valid_metrics.reset()
145
+
146
+ def validation_step(self, batch, batch_idx):
147
+ x, y = batch # Get features and labels
148
+ y_pred = self(x)
149
+ loss = F.mse_loss(y_pred, y)
150
+ self.log('val_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
151
+
152
+ # Update validation metrics
153
+ batch_values = self.valid_metrics(y_pred, y)
154
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
155
+
156
+ return loss
157
+
158
+ # Reset metrics
159
+ def on_test_epoch_start(self):
160
+ self.test_metrics.reset()
161
+
162
+ def test_step(self, batch, batch_idx):
163
+ x, y = batch # Get features and labels
164
+ y_pred = self(x)
165
+ loss = F.mse_loss(y_pred, y)
166
+ self.log('test_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
167
+
168
+ # Update validation metrics
169
+ batch_values = self.test_metrics(y_pred, y)
170
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
171
+
172
+ # Store predictions and labels
173
+ self.test_preds.append(y_pred.cpu())
174
+ self.test_labels.append(y.cpu())
175
+
176
+ return loss
177
+
178
+ def on_test_epoch_end(self):
179
+ self.test_preds = torch.cat([pred.float() for pred in self.test_preds], dim=0).numpy()
180
+ self.test_labels = torch.cat([label.float() for label in self.test_labels], dim=0).numpy()
181
+
182
+ # Log transform test predictions and labels
183
+ self.test_preds = np.exp(self.test_preds)
184
+ self.test_labels = np.exp(self.test_labels)
185
+
186
+ # Store results for access after trainer.test()
187
+ self.test_results = {'preds': self.test_preds, 'labels': self.test_labels}
188
+
189
+ def configure_optimizers(self):
190
+ optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
191
+ scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='min', factor=self.scheduler_factor, patience=self.scheduler_patience, threshold=self.scheduler_threshold)
192
+
193
+ return {'optimizer': optimizer,
194
+ 'lr_scheduler': scheduler,
195
+ 'monitor': 'val_loss'}
196
+
197
+ # NOTE: pin_memory=True calls in the next three defs should be monitored for performance. Can easily set to false.
198
+ def train_dataloader(self):
199
+ return DataLoader(self.train_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=True, pin_memory=True)
200
+
201
+ def val_dataloader(self):
202
+ return DataLoader(self.val_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
203
+
204
+ def test_dataloader(self):
205
+ return DataLoader(self.test_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
206
+
207
+ # ResNet-50 model architecture
208
+ class ResNet50(L.LightningModule):
209
+ def __init__(
210
+ self,
211
+ learning_rate: float=1e-3,
212
+ weight_decay: float=1e-2,
213
+ kernel_size: int=3,
214
+ stride: int=1,
215
+ padding: int=0,
216
+ use_weights: bool=True,
217
+ scheduler_factor: float=0.1,
218
+ scheduler_patience: int=10,
219
+ scheduler_threshold: float=1e-4
220
+ ):
221
+ '''
222
+ Class to load the ResNet-50 architecture from PyTorch's torchvision library.
223
+
224
+ Parameters:
225
+ learning_rate (float): Learning rate. Defaults to 1e-3.
226
+ weight_decay (float): Weight decay for AdamW optimizer. Defaults to 1e-2.
227
+ kernel_size (int): Kernel size for convolutional filters. Defaults to 3.
228
+ stride (int): Stride for convolutional filters. Defaults to 1.
229
+ padding (int): Padding for convolutional filters. Defaults to 0.
230
+ use_weights (bool): Whether or not to use pretrained weights from ImageNet. Defaults to True.
231
+ scheduler_factor (float): Factor for ReduceLROnPlateau. Defaults to 0.1.
232
+ scheduler_patience (int): Patience for ReduceLROnPlateau. Defaults to 10.
233
+ scheduler_threshold (float): Threshold for ReduceLROnPlateau. Defaults to 1e-4.
234
+
235
+ Methods:
236
+ All of the methods within this class are subclassed from PyTorch Lightning's LightningModule. Their documentation for each of these methods can be found here: https://lightning.ai/docs/pytorch/stable/common/lightning_module.html
237
+ '''
238
+ super().__init__()
239
+ self.save_hyperparameters()
240
+
241
+ # Transforms flag to perform image augmentations
242
+ # self.use_transforms = use_transforms
243
+
244
+ # Save predictions for later
245
+ self.test_preds = []
246
+ self.test_labels = []
247
+
248
+ self.learning_rate = learning_rate
249
+ self.weight_decay = weight_decay
250
+ self.kernel_size = kernel_size
251
+ self.stride = stride
252
+ self.padding = padding
253
+ self.use_weights = use_weights
254
+ self.scheduler_factor = scheduler_factor
255
+ self.scheduler_patience = scheduler_patience
256
+ self.scheduler_threshold = scheduler_threshold
257
+
258
+ if use_weights==True:
259
+ self.model = models.resnet50(weights='DEFAULT')
260
+ else:
261
+ self.model = models.resnet50()
262
+
263
+ # Modify first conv. layer to accept grayscale/1 channel inputs
264
+ self.model.conv1 = nn.Conv2d(
265
+ in_channels=1,
266
+ out_channels=64,
267
+ kernel_size=kernel_size,
268
+ stride=stride,
269
+ padding=padding
270
+ )
271
+
272
+ # Modify classifier for regression output
273
+ num_features = self.model.fc.in_features
274
+ self.model.fc = nn.Linear(num_features, 1) # Single output for regression
275
+
276
+ # Create dictionary of metrics to track for training, validation, and testing
277
+ self.train_metrics = torchmetrics.MetricCollection(
278
+ {
279
+ 'MAE': torchmetrics.regression.MeanAbsoluteError(num_outputs=1),
280
+ 'RMSE': torchmetrics.regression.MeanSquaredError(squared=False, num_outputs=1),
281
+ 'MSE': torchmetrics.regression.MeanSquaredError(squared=True, num_outputs=1),
282
+ 'r_squared': torchmetrics.regression.R2Score()
283
+ },
284
+ prefix='train_'
285
+ )
286
+
287
+ self.valid_metrics = self.train_metrics.clone(prefix='valid_')
288
+ self.test_metrics = self.train_metrics.clone(prefix='test_')
289
+
290
+
291
+ def forward(self, x):
292
+ return self.model(x).squeeze(-1) # Remove extra dimension
293
+
294
+ # Reset metrics
295
+ def on_train_epoch_start(self):
296
+ self.train_metrics.reset()
297
+
298
+ def training_step(self, batch, batch_idx):
299
+ x, y = batch # Get inputs and labels
300
+ y_pred = self(x) # Forward pass (call model's forward method)
301
+
302
+ loss = F.mse_loss(y_pred, y)
303
+ self.log('train_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True) # Log MSE loss for monitoring
304
+
305
+ # Log metrics
306
+ batch_values = self.train_metrics(y_pred, y)
307
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
308
+ return loss
309
+
310
+ # Reset metrics
311
+ def on_validation_epoch_start(self):
312
+ self.valid_metrics.reset()
313
+
314
+ def validation_step(self, batch, batch_idx):
315
+ x, y = batch # Get features and labels
316
+ y_pred = self(x)
317
+ loss = F.mse_loss(y_pred, y)
318
+ self.log('val_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
319
+
320
+ # Update validation metrics
321
+ batch_values = self.valid_metrics(y_pred, y)
322
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
323
+
324
+ return loss
325
+
326
+ # Reset metrics
327
+ def on_test_epoch_start(self):
328
+ self.test_metrics.reset()
329
+
330
+ def test_step(self, batch, batch_idx):
331
+ x, y = batch # Get features and labels
332
+ y_pred = self(x)
333
+ loss = F.mse_loss(y_pred, y)
334
+ self.log('test_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
335
+
336
+ # Update validation metrics
337
+ batch_values = self.test_metrics(y_pred, y)
338
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
339
+
340
+ # Store predictions and labels
341
+ self.test_preds.append(y_pred.cpu())
342
+ self.test_labels.append(y.cpu())
343
+
344
+ return loss
345
+
346
+ def on_test_epoch_end(self):
347
+ self.test_preds = torch.cat([pred.float() for pred in self.test_preds], dim=0).numpy()
348
+ self.test_labels = torch.cat([label.float() for label in self.test_labels], dim=0).numpy()
349
+
350
+ # Log transform test predictions and labels
351
+ self.test_preds = np.exp(self.test_preds)
352
+ self.test_labels = np.exp(self.test_labels)
353
+
354
+ # Store results for access after trainer.test()
355
+ self.test_results = {'preds': self.test_preds, 'labels': self.test_labels}
356
+
357
+ def configure_optimizers(self):
358
+ optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
359
+ scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='min', factor=self.scheduler_factor, patience=self.scheduler_patience, threshold=self.scheduler_threshold)
360
+
361
+ return {'optimizer': optimizer,
362
+ 'lr_scheduler': scheduler,
363
+ 'monitor': 'val_loss'}
364
+
365
+ # NOTE: pin_memory=True calls in the next three defs should be monitored for performance. Can easily set to false.
366
+ def train_dataloader(self):
367
+ return DataLoader(self.train_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=True, pin_memory=True)
368
+
369
+ def val_dataloader(self):
370
+ return DataLoader(self.val_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
371
+
372
+ def test_dataloader(self):
373
+ return DataLoader(self.test_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
374
+
375
+ # ResNet-152 architecture
376
+ class ResNet152(L.LightningModule):
377
+ def __init__(
378
+ self,
379
+ learning_rate: float=1e-3,
380
+ weight_decay: float=1e-2,
381
+ kernel_size: int=3,
382
+ stride: int=1,
383
+ padding: int=0,
384
+ use_weights: bool=True,
385
+ scheduler_factor: float=0.1,
386
+ scheduler_patience: int=10,
387
+ scheduler_threshold: float=1e-4
388
+ ):
389
+ '''
390
+ Class to load the EfficientNet B0 architecture from PyTorch's torchvision library.
391
+
392
+ Parameters:
393
+ learning_rate (float): Learning rate. Defaults to 1e-3.
394
+ weight_decay (float): Weight decay for AdamW optimizer. Defaults to 1e-2.
395
+ kernel_size (int): Kernel size for convolutional filters. Defaults to 3.
396
+ stride (int): Stride for convolutional filters. Defaults to 1.
397
+ padding (int): Padding for convolutional filters. Defaults to 0.
398
+ use_weights (bool): Whether or not to use pretrained weights from ImageNet. Defaults to True.
399
+ scheduler_factor (float): Factor for ReduceLROnPlateau. Defaults to 0.1.
400
+ scheduler_patience (int): Patience for ReduceLROnPlateau. Defaults to 10.
401
+ scheduler_threshold (float): Threshold for ReduceLROnPlateau. Defaults to 1e-4.
402
+
403
+ Methods:
404
+ All of the methods within this class are subclassed from PyTorch Lightning's LightningModule. Their documentation for each of these methods can be found here: https://lightning.ai/docs/pytorch/stable/common/lightning_module.html
405
+ '''
406
+ super().__init__()
407
+ self.save_hyperparameters()
408
+
409
+ # Transforms flag to perform image augmentations
410
+ # self.use_transforms = use_transforms
411
+
412
+ # Save predictions for later
413
+ self.test_preds = []
414
+ self.test_labels = []
415
+
416
+ self.learning_rate = learning_rate
417
+ self.weight_decay = weight_decay
418
+ self.kernel_size = kernel_size
419
+ self.stride = stride
420
+ self.padding = padding
421
+ self.use_weights = use_weights
422
+ self.scheduler_factor = scheduler_factor
423
+ self.scheduler_patience = scheduler_patience
424
+ self.scheduler_threshold = scheduler_threshold
425
+
426
+ if use_weights==True:
427
+ self.model = models.resnet152(weights='DEFAULT')
428
+ else:
429
+ self.model = models.resnet152()
430
+
431
+ # Modify first conv. layer to accept grayscale/1 channel inputs
432
+ self.model.conv1 = nn.Conv2d(
433
+ in_channels=1,
434
+ out_channels=64,
435
+ kernel_size=kernel_size,
436
+ stride=stride,
437
+ padding=padding
438
+ )
439
+
440
+ # Modify classifier for regression output
441
+ num_features = self.model.fc.in_features
442
+ self.model.fc = nn.Linear(num_features, 1) # Single output for regression
443
+
444
+ # Create dictionary of metrics to track for training, validation, and testing
445
+ self.train_metrics = torchmetrics.MetricCollection(
446
+ {
447
+ 'MAE': torchmetrics.regression.MeanAbsoluteError(num_outputs=1),
448
+ 'RMSE': torchmetrics.regression.MeanSquaredError(squared=False, num_outputs=1),
449
+ 'MSE': torchmetrics.regression.MeanSquaredError(squared=True, num_outputs=1),
450
+ 'r_squared': torchmetrics.regression.R2Score()
451
+ },
452
+ prefix='train_'
453
+ )
454
+
455
+ self.valid_metrics = self.train_metrics.clone(prefix='valid_')
456
+ self.test_metrics = self.train_metrics.clone(prefix='test_')
457
+
458
+
459
+ def forward(self, x):
460
+ return self.model(x).squeeze(-1) # Remove extra dimension
461
+
462
+ # Reset metrics
463
+ def on_train_epoch_start(self):
464
+ self.train_metrics.reset()
465
+
466
+ def training_step(self, batch, batch_idx):
467
+ x, y = batch # Get inputs and labels
468
+ y_pred = self(x) # Forward pass (call model's forward method)
469
+
470
+ loss = F.mse_loss(y_pred, y)
471
+ self.log('train_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True) # Log MSE loss for monitoring
472
+
473
+ # Log metrics
474
+ batch_values = self.train_metrics(y_pred, y)
475
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
476
+ return loss
477
+
478
+ # Reset metrics
479
+ def on_validation_epoch_start(self):
480
+ self.valid_metrics.reset()
481
+
482
+ def validation_step(self, batch, batch_idx):
483
+ x, y = batch # Get features and labels
484
+ y_pred = self(x)
485
+ loss = F.mse_loss(y_pred, y)
486
+ self.log('val_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
487
+
488
+ # Update validation metrics
489
+ batch_values = self.valid_metrics(y_pred, y)
490
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
491
+
492
+ return loss
493
+
494
+ # Reset metrics
495
+ def on_test_epoch_start(self):
496
+ self.test_metrics.reset()
497
+
498
+ def test_step(self, batch, batch_idx):
499
+ x, y = batch # Get features and labels
500
+ y_pred = self(x)
501
+ loss = F.mse_loss(y_pred, y)
502
+ self.log('test_loss', loss, on_step=True, on_epoch=True, logger=True, sync_dist=True)
503
+
504
+ # Update validation metrics
505
+ batch_values = self.test_metrics(y_pred, y)
506
+ self.log_dict(batch_values, on_step=True, on_epoch=True, sync_dist=True)
507
+
508
+ # Store predictions and labels
509
+ self.test_preds.append(y_pred.cpu())
510
+ self.test_labels.append(y.cpu())
511
+
512
+ return loss
513
+
514
+ def on_test_epoch_end(self):
515
+ self.test_preds = torch.cat([pred.float() for pred in self.test_preds], dim=0).numpy()
516
+ self.test_labels = torch.cat([label.float() for label in self.test_labels], dim=0).numpy()
517
+
518
+ # Log transform test predictions and labels
519
+ self.test_preds = np.exp(self.test_preds)
520
+ self.test_labels = np.exp(self.test_labels)
521
+
522
+ # Store results for access after trainer.test()
523
+ self.test_results = {'preds': self.test_preds, 'labels': self.test_labels}
524
+
525
+ def configure_optimizers(self):
526
+ optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
527
+ scheduler = ReduceLROnPlateau(optimizer=optimizer, mode='min', factor=self.scheduler_factor, patience=self.scheduler_patience, threshold=self.scheduler_threshold)
528
+
529
+ return {'optimizer': optimizer,
530
+ 'lr_scheduler': scheduler,
531
+ 'monitor': 'val_loss'}
532
+
533
+ # NOTE: pin_memory=True calls in the next three defs should be monitored for performance. Can easily set to false.
534
+ def train_dataloader(self):
535
+ return DataLoader(self.train_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=True, pin_memory=True)
536
+
537
+ def val_dataloader(self):
538
+ return DataLoader(self.val_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
539
+
540
+ def test_dataloader(self):
541
+ return DataLoader(self.test_set, batch_size=self.batch_size, num_workers=self.num_workers, shuffle=False, pin_memory=True)
542
+
model_classes/__init__.py ADDED
File without changes
model_classes/__pycache__/ConvNeXt.cpython-311.pyc ADDED
Binary file (25.6 kB). View file
 
model_classes/__pycache__/ConvNeXt_Large.cpython-311.pyc ADDED
Binary file (11.6 kB). View file
 
model_classes/__pycache__/EfficientNets.cpython-311.pyc ADDED
Binary file (23.4 kB). View file
 
model_classes/__pycache__/MLP.cpython-311.pyc ADDED
Binary file (11 kB). View file
 
model_classes/__pycache__/MLP_drop.cpython-311.pyc ADDED
Binary file (11.3 kB). View file
 
model_classes/__pycache__/ResNets.cpython-311.pyc ADDED
Binary file (24 kB). View file
 
model_classes/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (159 Bytes). View file