cycool29 commited on
Commit
73666ad
Β·
1 Parent(s): 0dc855f
__pycache__/augment.cpython-311.pyc ADDED
Binary file (3.71 kB). View file
 
__pycache__/configs.cpython-310.pyc ADDED
Binary file (1.94 kB). View file
 
__pycache__/configs.cpython-311.pyc ADDED
Binary file (17.2 kB). View file
 
__pycache__/data_loader.cpython-310.pyc ADDED
Binary file (1.22 kB). View file
 
__pycache__/data_loader.cpython-311.pyc ADDED
Binary file (1.97 kB). View file
 
__pycache__/ensemble.cpython-311.pyc ADDED
Binary file (12.6 kB). View file
 
__pycache__/extract.cpython-310.pyc ADDED
Binary file (1.95 kB). View file
 
__pycache__/lime_eval.cpython-310.pyc ADDED
Binary file (2.15 kB). View file
 
__pycache__/models.cpython-310.pyc ADDED
Binary file (1.14 kB). View file
 
__pycache__/models.cpython-311.pyc ADDED
Binary file (4.38 kB). View file
 
__pycache__/predict.cpython-310.pyc ADDED
Binary file (1.55 kB). View file
 
__pycache__/shap.cpython-310.pyc ADDED
Binary file (2.85 kB). View file
 
__pycache__/swa.cpython-311.pyc ADDED
Binary file (18.5 kB). View file
 
__pycache__/weight_averaging.cpython-311.pyc ADDED
Binary file (9.65 kB). View file
 
app.py CHANGED
@@ -1,7 +1,7 @@
1
  import gradio as gr
2
  import predict as predict
3
- import extract as extract
4
- import lime_eval as lime_eval
5
 
6
 
7
  def upload_file(files):
@@ -24,33 +24,17 @@ def process_file(
24
  result.append(f"{class_label}: {class_prob}%")
25
  result = result[:4]
26
  if gradcam_toggle == True:
27
- cam = extract.extract_gradcam(upload_filepath, save_path="gradcam.jpg")
28
  result.append("gradcam.jpg")
29
  else:
30
  result.append(None)
31
  if lime_toggle == True:
32
- lime = lime_eval.generate_lime(upload_filepath, save_path="lime.jpg")
33
  result.append("lime.jpg")
34
  else:
35
  result.append(None)
36
  return result
37
- # else:
38
- # sorted_classes = predict.predict_image(upload_filepath)
39
- # for class_label, class_prob in sorted_classes:
40
- # class_prob = class_prob.item().__round__(2)
41
- # result.append(f"{class_label}: {class_prob}%")
42
- # result = result[:4]
43
- # if gradcam_toggle == 1:
44
- # cam = extract.extract_gradcam(upload_filepath, save_path="gradcam.jpg")
45
- # result.append("gradcam.jpg")
46
- # if lime_toggle == 1:
47
- # lime = lime_eval.generate_lime(upload_filepath, save_path="lime.jpg")
48
- # result.append("lime.jpg")
49
- # return result
50
-
51
-
52
- # Prerun to innitialize the model
53
- # process_file(None, r"data\test\Task 1\Dystonia\0c08d2ea-8e1c-4ac6-92db-a752388b30cf.png")
54
 
55
  css = """
56
  .block {
@@ -108,21 +92,10 @@ with block as demo:
108
  with gr.Column():
109
  gr.Label("SpiralSense", elem_id="title-label", show_label=False)
110
  gr.Label(
111
- "Cost-Effective, Portable And Stressless Spiral Drawing Analysing Web Application for Early Detection of Multiple Neurological Disorders with 96% Accuracy",
112
  elem_id="desc-label",
113
- show_label=False
114
  )
115
- # gr.Markdown(
116
- # """
117
- # <h1 style="text-align: center;">SpiralSense</h1>
118
- # <h4 style="text-align: center;">Cost-Effective, Portable And Stressless Spiral Drawing Analysing Web Application for Early Detection of Multiple Neurological Disorders with 96% Accuracy</h4>
119
- # """
120
- # )
121
- # gr.Markdown(
122
- # """
123
- # <h4 style="text-align: center;">------------------------------------------</h4>
124
- # """
125
- # )
126
  with gr.Row():
127
  image_input = gr.Image(
128
  type="filepath",
@@ -147,11 +120,6 @@ with block as demo:
147
  with gr.Row():
148
  submit_button = gr.Button(value="Submit")
149
  gr.Markdown("<br>")
150
- # cancel_button = gr.Button(value="Cancel")
151
- # theme="gradio/soft",
152
- # fn=process_file,
153
- # title="HANDETECT",
154
- # outputs=[
155
  with gr.Row():
156
  prob1_textbox = gr.outputs.Textbox(label="Probability 1")
157
  prob2_textbox = gr.outputs.Textbox(label="Probability 2")
@@ -184,7 +152,6 @@ with block as demo:
184
  show_progress="minimal",
185
  preprocess=upload_file,
186
  scroll_to_output=True,
187
- # cancels=[cancel_button],
188
  )
189
 
190
 
 
1
  import gradio as gr
2
  import predict as predict
3
+ import extract_gradcam as extract_gradcam
4
+ import extract_lime as extract_lime
5
 
6
 
7
  def upload_file(files):
 
24
  result.append(f"{class_label}: {class_prob}%")
25
  result = result[:4]
26
  if gradcam_toggle == True:
27
+ cam = extract_gradcam.extract_gradcam(upload_filepath, save_path="gradcam.jpg")
28
  result.append("gradcam.jpg")
29
  else:
30
  result.append(None)
31
  if lime_toggle == True:
32
+ lime = extract_lime.generate_lime(upload_filepath, save_path="lime.jpg")
33
  result.append("lime.jpg")
34
  else:
35
  result.append(None)
36
  return result
37
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
  css = """
40
  .block {
 
92
  with gr.Column():
93
  gr.Label("SpiralSense", elem_id="title-label", show_label=False)
94
  gr.Label(
95
+ "A Stress-free, Portable, and Cost-effective Machine Learning-Powered Web Application for Early Detection of Multiple Neurological Disorders through Spiral Drawing Analysis",
96
  elem_id="desc-label",
97
+ show_label=False,
98
  )
 
 
 
 
 
 
 
 
 
 
 
99
  with gr.Row():
100
  image_input = gr.Image(
101
  type="filepath",
 
120
  with gr.Row():
121
  submit_button = gr.Button(value="Submit")
122
  gr.Markdown("<br>")
 
 
 
 
 
123
  with gr.Row():
124
  prob1_textbox = gr.outputs.Textbox(label="Probability 1")
125
  prob2_textbox = gr.outputs.Textbox(label="Probability 2")
 
152
  show_progress="minimal",
153
  preprocess=upload_file,
154
  scroll_to_output=True,
 
155
  )
156
 
157
 
compute_mean_std.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torchvision
2
+ from torchvision import transforms
3
+ from torch.utils.data import DataLoader
4
+ import torch
5
+ from configs import *
6
+
7
+ def main():
8
+ data_path = COMBINED_DATA_DIR + str(TASK)
9
+
10
+ transform_img = transforms.Compose(
11
+ [
12
+ transforms.Resize((224, 224)),
13
+ transforms.ToTensor(), # Convert to tensor
14
+ transforms.Grayscale(num_output_channels=3), # Convert to 3 channels
15
+ ]
16
+ )
17
+
18
+ image_data = torchvision.datasets.ImageFolder(root=data_path, transform=transform_img)
19
+
20
+ batch_size = BATCH_SIZE
21
+
22
+ loader = DataLoader(image_data, batch_size=batch_size, num_workers=1)
23
+
24
+ def batch_mean_and_sd(loader):
25
+ cnt = 0
26
+ fst_moment = torch.empty(3)
27
+ snd_moment = torch.empty(3)
28
+
29
+ for images, _ in loader:
30
+ b, c, h, w = images.shape
31
+ nb_pixels = b * h * w
32
+ sum_ = torch.sum(images, dim=[0, 2, 3])
33
+ sum_of_square = torch.sum(images**2, dim=[0, 2, 3])
34
+ fst_moment = (cnt * fst_moment + sum_) / (cnt + nb_pixels)
35
+ snd_moment = (cnt * snd_moment + sum_of_square) / (cnt + nb_pixels)
36
+ cnt += nb_pixels
37
+
38
+ mean, std = fst_moment, torch.sqrt(snd_moment - fst_moment**2)
39
+ return mean, std
40
+
41
+ mean, std = batch_mean_and_sd(loader)
42
+ print("mean and std: \n", mean, std)
43
+
44
+ if __name__ == '__main__':
45
+ main()
configs.py CHANGED
@@ -1,39 +1,7 @@
1
- import os
2
  import torch
3
  from torchvision import transforms
4
  from torch.utils.data import Dataset
5
  from models import *
6
- import torch.nn as nn
7
- from torchvision.models import (
8
- squeezenet1_0,
9
- SqueezeNet1_0_Weights,
10
- squeezenet1_1,
11
- SqueezeNet1_1_Weights,
12
- shufflenet_v2_x2_0,
13
- ShuffleNet_V2_X2_0_Weights,
14
- mobilenet_v3_small,
15
- MobileNet_V3_Small_Weights,
16
- efficientnet_v2_s,
17
- EfficientNet_V2_S_Weights,
18
- efficientnet_b0,
19
- EfficientNet_B0_Weights,
20
- efficientnet_b1,
21
- EfficientNet_B1_Weights,
22
- efficientnet_b2,
23
- EfficientNet_B2_Weights,
24
- efficientnet_b3,
25
- EfficientNet_B3_Weights,
26
- mobilenet_v3_small,
27
- MobileNet_V3_Small_Weights,
28
- mobilenet_v3_large,
29
- MobileNet_V3_Large_Weights,
30
- googlenet,
31
- GoogLeNet_Weights,
32
- MobileNet_V2_Weights,
33
- mobilenet_v2,
34
- )
35
-
36
- import torch.nn.functional as F
37
 
38
  # Constants
39
  RANDOM_SEED = 123
@@ -44,8 +12,8 @@ LEARNING_RATE = 0.0001
44
  STEP_SIZE = 10
45
  GAMMA = 0.3
46
  CUTMIX_ALPHA = 0.3
47
- DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
48
- # DEVICE = torch.device("cpu")
49
  NUM_PRINT = 100
50
  TASK = 1
51
  WARMUP_EPOCHS = 5
@@ -69,235 +37,13 @@ CLASSES = [
69
  ]
70
 
71
 
72
- class SE_Block(nn.Module):
73
- def __init__(self, channel, reduction=16):
74
- super(SE_Block, self).__init__()
75
- self.avg_pool = nn.AdaptiveAvgPool2d(1)
76
- self.fc = nn.Sequential(
77
- nn.Linear(channel, channel // reduction, bias=False),
78
- nn.ReLU(inplace=True),
79
- nn.Linear(channel // reduction, channel, bias=False),
80
- nn.Sigmoid(), # Sigmoid activation to produce attention scores
81
- )
82
-
83
- def forward(self, x):
84
- b, c, _, _ = x.size()
85
- y = self.avg_pool(x).view(b, c)
86
- y = self.fc(y).view(b, c, 1, 1)
87
- return x * y.expand_as(x)
88
-
89
-
90
- class SqueezeNet1_0WithSE(nn.Module):
91
- def __init__(self, num_classes, dropout_prob=0.5):
92
- super(SqueezeNet1_0WithSE, self).__init__()
93
- squeezenet = squeezenet1_0(weights=SqueezeNet1_0_Weights.DEFAULT)
94
- self.features = squeezenet.features
95
- self.classifier = nn.Sequential(
96
- nn.Conv2d(512, num_classes, kernel_size=1),
97
- nn.BatchNorm2d(num_classes), # add batch normalization
98
- nn.ReLU(inplace=True),
99
- nn.AdaptiveAvgPool2d((1, 1)),
100
- )
101
- self.dropout = nn.Dropout(
102
- dropout_prob
103
- ) # Add dropout layer with the specified probability
104
-
105
- # Adjust channel for SqueezeNet1.0 (original SqueezeNet1.0 has 1000 classes)
106
- num_classes_squeezenet1_0 = 7
107
-
108
- # Add Squeeze-and-Excitation block
109
- self.se_block = SE_Block(
110
- channel=num_classes_squeezenet1_0
111
- ) # Adjust channel as needed
112
-
113
- def forward(self, x):
114
- x = self.features(x)
115
- x = self.classifier(x)
116
- # x = self.se_block(x) # Apply the SE block
117
- x = F.dropout(x, training=self.training) # Apply dropout during training
118
- x = torch.flatten(x, 1)
119
- return x
120
-
121
-
122
- class SqueezeNet1_1WithSE(nn.Module):
123
- def __init__(self, num_classes, dropout_prob=0.2):
124
- super(SqueezeNet1_1WithSE, self).__init__()
125
- squeezenet = squeezenet1_1(weights=SqueezeNet1_1_Weights.DEFAULT)
126
- self.features = squeezenet.features
127
- self.classifier = nn.Sequential(
128
- nn.Conv2d(512, num_classes, kernel_size=1),
129
- nn.BatchNorm2d(num_classes), # add batch normalization
130
- nn.ReLU(inplace=True),
131
- nn.AdaptiveAvgPool2d((1, 1)),
132
- )
133
- self.dropout = nn.Dropout(
134
- dropout_prob
135
- ) # Add dropout layer with the specified probability
136
-
137
- # Add Squeeze-and-Excitation block
138
- self.se_block = SE_Block(channel=num_classes) # Adjust channel as needed
139
-
140
- def forward(self, x):
141
- x = self.features(x)
142
- x = self.classifier(x)
143
- x = self.se_block(x) # Apply the SE block
144
- x = F.dropout(x, training=self.training) # Apply dropout during training
145
- x = torch.flatten(x, 1)
146
- return x
147
-
148
-
149
- class EfficientNetB2WithDropout(nn.Module):
150
- # 0.00022015769999619205
151
- def __init__(self, num_classes, dropout_prob=0.2):
152
- super(EfficientNetB2WithDropout, self).__init__()
153
- efficientnet = efficientnet_b2(weights=EfficientNet_B2_Weights.DEFAULT)
154
- self.features = efficientnet.features
155
- self.classifier = nn.Sequential(
156
- nn.Conv2d(1408, num_classes, kernel_size=1),
157
- nn.BatchNorm2d(num_classes), # add batch normalization
158
- nn.ReLU(inplace=True),
159
- nn.AdaptiveAvgPool2d((1, 1)),
160
- )
161
- self.dropout = nn.Dropout(
162
- dropout_prob
163
- ) # Add dropout layer with the specified probability
164
-
165
- def forward(self, x):
166
- x = self.features(x)
167
- x = self.classifier(x)
168
- x = F.dropout(x, training=self.training) # Apply dropout during training
169
- x = torch.flatten(x, 1)
170
- return x
171
-
172
-
173
- class EfficientNetB3WithDropout(nn.Module):
174
- def __init__(self, num_classes, dropout_prob=0.2):
175
- super(EfficientNetB3WithDropout, self).__init__()
176
- efficientnet = efficientnet_b3(weights=EfficientNet_B3_Weights.DEFAULT)
177
- self.features = efficientnet.features
178
- self.classifier = nn.Sequential(
179
- nn.Conv2d(1536, num_classes, kernel_size=1),
180
- nn.BatchNorm2d(num_classes), # add batch normalization
181
- nn.ReLU(inplace=True),
182
- nn.AdaptiveAvgPool2d((1, 1)),
183
- )
184
- self.dropout = nn.Dropout(
185
- dropout_prob
186
- ) # Add dropout layer with the specified probability
187
-
188
- def forward(self, x):
189
- x = self.features(x)
190
- x = self.classifier(x)
191
- x = F.dropout(x, training=self.training) # Apply dropout during training
192
- x = torch.flatten(x, 1)
193
- return x
194
-
195
-
196
- class ResNet18WithNorm(nn.Module):
197
- def __init__(self, num_classes=1000):
198
- super(ResNet18WithNorm, self).__init__()
199
- resnet = resnet18(pretrained=False)
200
-
201
- # Remove the last block (Block 4)
202
- self.features = nn.Sequential(
203
- *list(resnet.children())[:-1] # Exclude the last block
204
- )
205
-
206
- self.classifier = nn.Sequential(
207
- nn.AdaptiveAvgPool2d((1, 1)),
208
- nn.Flatten(),
209
- nn.Linear(
210
- 512, num_classes
211
- ), # Adjust input size for the fully connected layer
212
- nn.BatchNorm1d(num_classes), # Add batch normalization
213
- )
214
-
215
- def forward(self, x):
216
- x = self.features(x)
217
- x = self.classifier(x)
218
- x = torch.flatten(x, 1)
219
- return x
220
-
221
-
222
- class MobileNetV3LargeWithDropout(nn.Module):
223
- def __init__(self, num_classes, dropout_prob=0.2):
224
- super(MobileNetV3LargeWithDropout, self).__init__()
225
- mobilenet = mobilenet_v3_large(weights=MobileNet_V3_Large_Weights.DEFAULT)
226
- self.features = mobilenet.features
227
- self.classifier = nn.Sequential(
228
- nn.Conv2d(960, num_classes, kernel_size=1),
229
- nn.BatchNorm2d(num_classes), # add batch normalization
230
- nn.ReLU(inplace=True),
231
- nn.AdaptiveAvgPool2d((1, 1)),
232
- )
233
- self.dropout = nn.Dropout(
234
- dropout_prob
235
- ) # Add dropout layer with the specified probability
236
-
237
- def forward(self, x):
238
- x = self.features(x)
239
- x = self.classifier(x)
240
- x = F.dropout(x, training=self.training) # Apply dropout during training
241
- x = torch.flatten(x, 1)
242
- return x
243
-
244
-
245
- class GoogLeNetWithSE(nn.Module):
246
- def __init__(self, num_classes):
247
- super(GoogLeNetWithSE, self).__init__()
248
- googlenet = googlenet(weights=GoogLeNet_Weights.DEFAULT)
249
- # self.features = googlenet.features
250
- self.classifier = nn.Sequential(
251
- nn.Conv2d(1024, num_classes, kernel_size=1),
252
- nn.BatchNorm2d(num_classes), # add batch normalization
253
- nn.ReLU(inplace=True),
254
- nn.AdaptiveAvgPool2d((1, 1)),
255
- )
256
-
257
- # Add Squeeze-and-Excitation block
258
- self.se_block = SE_Block(channel=num_classes) # Adjust channel as needed
259
-
260
- def forward(self, x):
261
- # x = self.features(x)
262
- x = self.classifier(x)
263
- x = self.se_block(x) # Apply the SE block
264
- x = torch.flatten(x, 1)
265
- return x
266
-
267
-
268
- class MobileNetV2WithDropout(nn.Module):
269
- def __init__(self, num_classes, dropout_prob=0.2):
270
- super(MobileNetV2WithDropout, self).__init__()
271
- mobilenet = mobilenet_v2(weights=MobileNet_V2_Weights.DEFAULT)
272
- self.features = mobilenet.features
273
- self.classifier = nn.Sequential(
274
- nn.Conv2d(1280, num_classes, kernel_size=1),
275
- nn.BatchNorm2d(num_classes), # add batch normalization
276
- nn.ReLU(inplace=True),
277
- nn.AdaptiveAvgPool2d((1, 1)),
278
- )
279
- self.dropout = nn.Dropout(
280
- dropout_prob
281
- ) # Add dropout layer with the specified probability
282
-
283
- def forward(self, x):
284
- x = self.features(x)
285
- x = self.classifier(x)
286
- x = F.dropout(x, training=self.training) # Apply dropout during training
287
- x = torch.flatten(x, 1)
288
- return x
289
-
290
-
291
- MODEL = EfficientNetB3WithDropout(num_classes=NUM_CLASSES)
292
  MODEL_SAVE_PATH = r"output/checkpoints/" + MODEL.__class__.__name__ + ".pth"
293
- # MODEL_SAVE_PATH = r"C:\Users\User\Downloads\bestsqueezenetSE.pth"
294
  preprocess = transforms.Compose(
295
  [
296
  transforms.Resize((224, 224)),
297
  transforms.ToTensor(), # Convert to tensor
298
- transforms.Grayscale(num_output_channels=3), # Convert to 3 channels
299
- # Normalize 3 channels
300
- transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
301
  ]
302
  )
303
 
@@ -313,14 +59,3 @@ class CustomDataset(Dataset):
313
  def __getitem__(self, idx):
314
  img, label = self.data[idx]
315
  return img, label
316
-
317
-
318
- def ensemble_predictions(models, image):
319
- all_predictions = []
320
-
321
- with torch.no_grad():
322
- for model in models:
323
- output = model(image)
324
- all_predictions.append(output)
325
-
326
- return torch.stack(all_predictions, dim=0).mean(dim=0)
 
 
1
  import torch
2
  from torchvision import transforms
3
  from torch.utils.data import Dataset
4
  from models import *
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
  # Constants
7
  RANDOM_SEED = 123
 
12
  STEP_SIZE = 10
13
  GAMMA = 0.3
14
  CUTMIX_ALPHA = 0.3
15
+ # DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
16
+ DEVICE = torch.device("cpu")
17
  NUM_PRINT = 100
18
  TASK = 1
19
  WARMUP_EPOCHS = 5
 
37
  ]
38
 
39
 
40
+ MODEL = EfficientNetB3WithNorm(num_classes=NUM_CLASSES)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  MODEL_SAVE_PATH = r"output/checkpoints/" + MODEL.__class__.__name__ + ".pth"
 
42
  preprocess = transforms.Compose(
43
  [
44
  transforms.Resize((224, 224)),
45
  transforms.ToTensor(), # Convert to tensor
46
+ transforms.Normalize(0.8289, 0.2006),
 
 
47
  ]
48
  )
49
 
 
59
  def __getitem__(self, idx):
60
  img, label = self.data[idx]
61
  return img, label
 
 
 
 
 
 
 
 
 
 
 
convert.py DELETED
@@ -1,17 +0,0 @@
1
- import torch
2
- import onnx2tf
3
- from configs import *
4
-
5
- torch.onnx.export(
6
- model=model,
7
- args=torch.randn(1, 3, 64, 64),
8
- f="output/checkpoints/model.onnx",
9
- verbose=True,
10
- input_names=["input"],
11
- output_names=["output"],
12
- )
13
-
14
- onnx2tf.convert(
15
- input_onnx_file_path="output/checkpoints/model.onnx",
16
- output_folder_path="output/checkpoints/converted/",
17
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data-splitting.py β†’ data_splitting.py RENAMED
File without changes
ensemble.py DELETED
@@ -1,249 +0,0 @@
1
- import matplotlib.pyplot as plt
2
- from torch.optim.lr_scheduler import CosineAnnealingLR
3
- import torch
4
- import torch.nn as nn
5
- from torchvision.datasets import ImageFolder
6
- from torch.utils.data import DataLoader
7
- from data_loader import load_data, load_test_data
8
- from configs import *
9
- import numpy as np
10
-
11
- torch.cuda.empty_cache()
12
-
13
- #
14
-
15
-
16
- class MLP(nn.Module):
17
- def __init__(self, num_classes, num_models):
18
- super(MLP, self).__init__()
19
- self.layers = nn.Sequential(
20
- nn.Linear(num_classes * num_models, 1024),
21
- nn.LayerNorm(1024),
22
- nn.LeakyReLU(negative_slope=0.01, inplace=True),
23
- nn.Dropout(0.8),
24
- nn.Linear(1024, 2048),
25
- nn.LeakyReLU(negative_slope=0.01, inplace=True),
26
- nn.Dropout(0.5),
27
- nn.Linear(2048, 2048),
28
- nn.LeakyReLU(negative_slope=0.01, inplace=True),
29
- nn.Dropout(0.5),
30
- nn.Linear(2048, num_classes),
31
- )
32
-
33
- def forward(self, x):
34
- x = x.view(x.size(0), -1)
35
- x = self.layers(x)
36
- return x
37
-
38
-
39
- def mlp_meta(num_classes, num_models):
40
- model = MLP(num_classes, num_models)
41
- return model
42
-
43
-
44
- # Hyperparameters
45
- input_dim = 3 * 224 * 224 # Modify this based on your input size
46
- hidden_dim = 256
47
- output_dim = NUM_CLASSES
48
-
49
- # Create the data loaders using your data_loader functions50
50
- train_loader, val_loader = load_data(COMBINED_DATA_DIR + "1", preprocess, BATCH_SIZE)
51
- test_loader = load_test_data("data/test/Task 1", preprocess, BATCH_SIZE)
52
-
53
- model_paths = [
54
- "output/checkpoints/bestsqueezenetSE3.pth",
55
- "output/checkpoints/EfficientNetB3WithDropout.pth",
56
- "output/checkpoints/MobileNetV2WithDropout2.pth",
57
- ]
58
-
59
-
60
- # Define a function to load pretrained models
61
- def load_pretrained_model(path, model):
62
- model.load_state_dict(torch.load(path))
63
- return model.to(DEVICE)
64
-
65
-
66
- def rand_bbox(size, lam):
67
- W = size[2]
68
- H = size[3]
69
- cut_rat = np.sqrt(1.0 - lam)
70
- cut_w = np.int_(W * cut_rat)
71
- cut_h = np.int_(H * cut_rat)
72
-
73
- # uniform
74
- cx = np.random.randint(W)
75
- cy = np.random.randint(H)
76
-
77
- bbx1 = np.clip(cx - cut_w // 2, 0, W)
78
- bby1 = np.clip(cy - cut_h // 2, 0, H)
79
- bbx2 = np.clip(cx + cut_w // 2, 0, W)
80
- bby2 = np.clip(cy + cut_h // 2, 0, H)
81
-
82
- return bbx1, bby1, bbx2, bby2
83
-
84
-
85
- def cutmix_data(input, target, alpha=1.0):
86
- if alpha > 0:
87
- lam = np.random.beta(alpha, alpha)
88
- else:
89
- lam = 1
90
-
91
- batch_size = input.size()[0]
92
- index = torch.randperm(batch_size)
93
- rand_index = torch.randperm(input.size()[0])
94
-
95
- bbx1, bby1, bbx2, bby2 = rand_bbox(input.size(), lam)
96
- input[:, :, bbx1:bbx2, bby1:bby2] = input[rand_index, :, bbx1:bbx2, bby1:bby2]
97
-
98
- lam = 1 - ((bbx2 - bbx1) * (bby2 - bby1) / (input.size()[-1] * input.size()[-2]))
99
- targets_a = target
100
- targets_b = target[rand_index]
101
-
102
- return input, targets_a, targets_b, lam
103
-
104
-
105
- def cutmix_criterion(criterion, outputs, targets_a, targets_b, lam):
106
- return lam * criterion(outputs, targets_a) + (1 - lam) * criterion(
107
- outputs, targets_b
108
- )
109
-
110
-
111
- # Load pretrained models
112
- model1 = load_pretrained_model(
113
- model_paths[0], SqueezeNet1_0WithSE(num_classes=NUM_CLASSES)
114
- ).to(DEVICE)
115
- model2 = load_pretrained_model(
116
- model_paths[1], EfficientNetB3WithDropout(num_classes=NUM_CLASSES)
117
- ).to(DEVICE)
118
- model3 = load_pretrained_model(
119
- model_paths[2], MobileNetV2WithDropout(num_classes=NUM_CLASSES)
120
- ).to(DEVICE)
121
-
122
- models = [model1, model2, model3]
123
-
124
- # Create the meta learner
125
- meta_learner_model = mlp_meta(NUM_CLASSES, len(models)).to(DEVICE)
126
- meta_optimizer = torch.optim.Adam(meta_learner_model.parameters(), lr=0.001)
127
- meta_loss_fn = torch.nn.CrossEntropyLoss()
128
-
129
- # Define the Cosine Annealing Learning Rate Scheduler
130
- scheduler = CosineAnnealingLR(
131
- meta_optimizer, T_max=700
132
- ) # T_max is the number of epochs for the cosine annealing.
133
-
134
- # Define loss function and optimizer for the meta learner
135
- criterion = nn.CrossEntropyLoss().to(DEVICE)
136
-
137
- # Record learning rate
138
- lr_hist = []
139
-
140
- # Training loop
141
- num_epochs = 160
142
- for epoch in range(num_epochs):
143
- print("[Epoch: {}]".format(epoch + 1))
144
- print("Total number of batches: {}".format(len(train_loader)))
145
- for batch_idx, data in enumerate(train_loader, 0):
146
- print("Batch: {}".format(batch_idx + 1))
147
- inputs, labels = data
148
- inputs, labels = inputs.to(DEVICE), labels.to(DEVICE)
149
- inputs, targets_a, targets_b, lam = cutmix_data(inputs, labels, alpha=1)
150
-
151
- # Forward pass through the three pretrained models
152
- features1 = model1(inputs)
153
- features2 = model2(inputs)
154
- features3 = model3(inputs)
155
-
156
- # Stack the features from the three models
157
- stacked_features = torch.cat((features1, features2, features3), dim=1).to(
158
- DEVICE
159
- )
160
-
161
- # Forward pass through the meta learner
162
- meta_output = meta_learner_model(stacked_features)
163
-
164
- # Compute the loss
165
- loss = cutmix_criterion(criterion, meta_output, targets_a, targets_b, lam)
166
-
167
- # Compute the accuracy
168
- _, predicted = torch.max(meta_output, 1)
169
- total = labels.size(0)
170
- correct = (predicted == labels).sum().item()
171
-
172
- # Backpropagation and optimization
173
- meta_optimizer.zero_grad()
174
- loss.backward()
175
- meta_optimizer.step()
176
-
177
- lr_hist.append(meta_optimizer.param_groups[0]["lr"])
178
-
179
- scheduler.step()
180
-
181
- print("Train Loss: {}".format(loss.item()))
182
- print("Train Accuracy: {}%".format(100 * correct / total))
183
-
184
- # Validation
185
- meta_learner_model.eval()
186
- correct = 0
187
- total = 0
188
- val_loss = 0
189
- with torch.no_grad():
190
- for data in val_loader:
191
- inputs, labels = data
192
- inputs, labels = inputs.to(DEVICE), labels.to(DEVICE)
193
- features1 = model1(inputs)
194
- features2 = model2(inputs)
195
- features3 = model3(inputs)
196
- stacked_features = torch.cat((features1, features2, features3), dim=1).to(
197
- DEVICE
198
- )
199
- outputs = meta_learner_model(stacked_features)
200
- loss = criterion(outputs, labels) # Use the validation loss
201
- val_loss += loss.item()
202
- _, predicted = torch.max(outputs, 1)
203
- total += labels.size(0)
204
- correct += (predicted == labels).sum().item()
205
-
206
- print(
207
- "Validation Loss: {}".format(val_loss / len(val_loader))
208
- ) # Calculate the average loss
209
- print("Validation Accuracy: {}%".format(100 * correct / total))
210
-
211
-
212
- print("Finished Training")
213
-
214
- # Test the ensemble
215
- print("Testing the ensemble")
216
- meta_learner_model.eval()
217
- correct = 0
218
- total = 0
219
- with torch.no_grad():
220
- for data in test_loader:
221
- inputs, labels = data
222
- inputs, labels = inputs.to(DEVICE), labels.to(DEVICE)
223
- features1 = model1(inputs)
224
- features2 = model2(inputs)
225
- features3 = model3(inputs)
226
- stacked_features = torch.cat((features1, features2, features3), dim=1)
227
- outputs = meta_learner_model(stacked_features)
228
- _, predicted = torch.max(outputs, 1)
229
- total += labels.size(0)
230
- correct += (predicted == labels).sum().item()
231
-
232
- print(
233
- "Accuracy of the ensemble network on the test images: {}%".format(
234
- 100 * correct / total
235
- )
236
- )
237
-
238
-
239
- # Plot the learning rate history
240
-
241
- plt.plot(lr_hist)
242
- plt.xlabel("Iterations")
243
- plt.ylabel("Learning Rate")
244
- plt.title("Learning Rate History")
245
- plt.show()
246
-
247
-
248
- # Save the model
249
- torch.save(meta_learner_model.state_dict(), "output/checkpoints/ensemble.pth")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eval.py DELETED
@@ -1,190 +0,0 @@
1
- import os
2
- import torch
3
- import numpy as np
4
- import pathlib
5
- from PIL import Image
6
- import matplotlib.pyplot as plt
7
- from sklearn.metrics import (
8
- classification_report,
9
- precision_recall_curve,
10
- accuracy_score,
11
- f1_score,
12
- confusion_matrix,
13
- ConfusionMatrixDisplay,
14
- )
15
- from sklearn.preprocessing import label_binarize
16
- from torchvision import transforms
17
- from configs import *
18
-
19
- # EfficientNet: 0.901978973407545
20
- # MobileNet: 0.8731189445475158
21
- # SquuezeNet: 0.8559218559218559
22
-
23
-
24
- # Constants
25
- DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
26
- NUM_AUGMENTATIONS = 10 # Number of augmentations to perform
27
-
28
- model2 = EfficientNetB2WithDropout(num_classes=NUM_CLASSES).to(DEVICE)
29
- model2.load_state_dict(torch.load("output/checkpoints/EfficientNetB2WithDropout.pth"))
30
- model1 = SqueezeNet1_0WithSE(num_classes=NUM_CLASSES).to(DEVICE)
31
- model1.load_state_dict(torch.load("output/checkpoints/SqueezeNet1_0WithSE.pth"))
32
- model3 = MobileNetV2WithDropout(num_classes=NUM_CLASSES).to(DEVICE)
33
- model3.load_state_dict(torch.load("output\checkpoints\MobileNetV2WithDropout.pth"))
34
-
35
- best_weights = [0.901978973407545, 0.8731189445475158, 0.8559218559218559]
36
-
37
- # Load the model
38
- model = WeightedVoteEnsemble([model1, model2, model3], best_weights)
39
- # model.load_state_dict(torch.load(MODEL_SAVE_PATH, map_location=DEVICE))
40
- model.load_state_dict(torch.load('output/checkpoints/WeightedVoteEnsemble.pth', map_location=DEVICE))
41
- model.eval()
42
-
43
- # define augmentations for TTA
44
- tta_transforms = transforms.Compose(
45
- [
46
- transforms.RandomHorizontalFlip(p=0.5),
47
- transforms.RandomVerticalFlip(p=0.5),
48
- ]
49
- )
50
-
51
-
52
- def perform_tta(model, image, tta_transforms):
53
- augmented_predictions = []
54
- augmented_scores = []
55
-
56
- for _ in range(NUM_AUGMENTATIONS):
57
- augmented_image = tta_transforms(image)
58
- output = model(augmented_image)
59
- predicted_class = torch.argmax(output, dim=1).item()
60
- augmented_predictions.append(predicted_class)
61
- augmented_scores.append(output.softmax(dim=1).cpu().numpy())
62
-
63
- # max voting
64
- final_predicted_class_max = max(
65
- set(augmented_predictions), key=augmented_predictions.count
66
- )
67
-
68
- # average probabilities
69
- final_predicted_scores_avg = np.mean(np.array(augmented_scores), axis=0)
70
-
71
- # rotate and average probabilities
72
- rotation_transforms = [
73
- transforms.RandomRotation(degrees=i) for i in range(0, 360, 30)
74
- ]
75
- rotated_scores = []
76
- for rotation_transform in rotation_transforms:
77
- augmented_image = rotation_transform(image)
78
- output = model(augmented_image)
79
- rotated_scores.append(output.softmax(dim=1).cpu().numpy())
80
-
81
- final_predicted_scores_rotation = np.mean(np.array(rotated_scores), axis=0)
82
-
83
- return (
84
- final_predicted_class_max,
85
- final_predicted_scores_avg,
86
- final_predicted_scores_rotation,
87
- )
88
-
89
-
90
- def predict_image_with_tta(image_path, model, transform, tta_transforms):
91
- model.eval()
92
- correct_predictions = 0
93
- true_classes = []
94
- predicted_labels_max = []
95
- predicted_labels_avg = []
96
- predicted_labels_rotation = []
97
-
98
- with torch.no_grad():
99
- images = list(pathlib.Path(image_path).rglob("*.png"))
100
- total_predictions = len(images)
101
-
102
- for image_file in images:
103
- true_class = CLASSES.index(image_file.parts[-2])
104
-
105
- original_image = Image.open(image_file).convert("RGB")
106
- original_image = transform(original_image).unsqueeze(0)
107
- original_image = original_image.to(DEVICE)
108
-
109
- # Perform TTA with different strategies
110
- final_predicted_class_max, _, _ = perform_tta(
111
- model, original_image, tta_transforms
112
- )
113
- _, final_predicted_scores_avg, _ = perform_tta(
114
- model, original_image, tta_transforms
115
- )
116
- _, _, final_predicted_scores_rotation = perform_tta(
117
- model, original_image, tta_transforms
118
- )
119
-
120
- true_classes.append(true_class)
121
- predicted_labels_max.append(final_predicted_class_max)
122
- predicted_labels_avg.append(np.argmax(final_predicted_scores_avg))
123
- predicted_labels_rotation.append(np.argmax(final_predicted_scores_rotation))
124
-
125
- if final_predicted_class_max == true_class:
126
- correct_predictions += 1
127
-
128
- # accuracy for each strategy
129
- accuracy_max = accuracy_score(true_classes, predicted_labels_max)
130
- accuracy_avg = accuracy_score(true_classes, predicted_labels_avg)
131
- accuracy_rotation = accuracy_score(true_classes, predicted_labels_rotation)
132
-
133
- print("Accuracy (Max Voting):", accuracy_max)
134
- print("Accuracy (Average Probabilities):", accuracy_avg)
135
- print("Accuracy (Rotation and Average):", accuracy_rotation)
136
-
137
- # final prediction using ensemble (choose the strategy with the highest accuracy)
138
- final_predicted_labels = []
139
- for i in range(len(true_classes)):
140
- max_strategy_accuracy = max(accuracy_max, accuracy_avg, accuracy_rotation)
141
- if accuracy_max == max_strategy_accuracy:
142
- final_predicted_labels.append(predicted_labels_max[i])
143
- elif accuracy_avg == max_strategy_accuracy:
144
- final_predicted_labels.append(predicted_labels_avg[i])
145
- else:
146
- final_predicted_labels.append(predicted_labels_rotation[i])
147
-
148
- # calculate accuracy and f1 score(ensemble)
149
- accuracy_ensemble = accuracy_score(true_classes, final_predicted_labels)
150
- f1_ensemble = f1_score(true_classes, final_predicted_labels, average="weighted")
151
-
152
- print("Ensemble Accuracy:", accuracy_ensemble)
153
- print("Ensemble Weighted F1 Score:", f1_ensemble)
154
-
155
- # Classification report
156
- class_names = [str(cls) for cls in range(NUM_CLASSES)]
157
- report = classification_report(
158
- true_classes, final_predicted_labels, target_names=class_names
159
- )
160
- print("Classification Report of", MODEL.__class__.__name__, ":\n", report)
161
-
162
- # confusion matrix and classification report for the ensemble
163
- conf_matrix_ensemble = confusion_matrix(true_classes, final_predicted_labels)
164
- ConfusionMatrixDisplay(
165
- confusion_matrix=conf_matrix_ensemble, display_labels=range(NUM_CLASSES)
166
- ).plot(cmap=plt.cm.Blues)
167
- plt.title("Confusion Matrix (Ensemble)")
168
- plt.show()
169
-
170
- class_names = [str(cls) for cls in range(NUM_CLASSES)]
171
- report_ensemble = classification_report(
172
- true_classes, final_predicted_labels, target_names=class_names
173
- )
174
- print("Classification Report (Ensemble):\n", report_ensemble)
175
-
176
- # Calculate precision and recall for each class
177
- true_classes_binary = label_binarize(true_classes, classes=range(NUM_CLASSES))
178
- precision, recall, _ = precision_recall_curve(
179
- true_classes_binary.ravel(), np.array(final_predicted_scores_rotation).ravel()
180
- )
181
-
182
- # Plot precision-recall curve
183
- plt.figure(figsize=(10, 6))
184
- plt.plot(recall, precision)
185
- plt.title("Precision-Recall Curve")
186
- plt.xlabel("Recall")
187
- plt.ylabel("Precision")
188
- plt.show()
189
-
190
- predict_image_with_tta("data/test/Task 1/", model, preprocess, tta_transforms)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eval_orig.py β†’ evaluate.py RENAMED
@@ -1,6 +1,3 @@
1
- import os
2
- import torchvision
3
- import shap
4
  import torch
5
  import numpy as np
6
  import pathlib
@@ -19,14 +16,10 @@ from sklearn.metrics import (
19
  auc,
20
  average_precision_score,
21
  cohen_kappa_score,
 
22
  )
23
  from sklearn.preprocessing import label_binarize
24
  from configs import *
25
- from data_loader import load_data # Import the load_data function
26
-
27
- # MobileNet: 0.8731189445475158
28
- # EfficientNet: 0.873118944547516
29
- # SquuezeNet: 0.8865856365856365
30
 
31
 
32
  rcParams["font.family"] = "Times New Roman"
@@ -126,7 +119,7 @@ def predict_image(image_path, model, transform):
126
  plt.title("Confusion Matrix")
127
  manager = plt.get_current_fig_manager()
128
  manager.full_screen_toggle()
129
- plt.savefig("docs/efficientnet/confusion_matrix.png")
130
  plt.show()
131
 
132
  # Classification report
@@ -170,7 +163,7 @@ def predict_image(image_path, model, transform):
170
  "AUC-PRC = {:.3f}".format(auc_prc),
171
  bbox=dict(boxstyle="round", facecolor="white", alpha=0.8),
172
  )
173
- plt.savefig("docs/efficientnet/prc.png")
174
  plt.show()
175
 
176
  # Plot ROC curve
@@ -186,7 +179,7 @@ def predict_image(image_path, model, transform):
186
  "AUC-ROC = {:.3f}".format(auc_roc),
187
  bbox=dict(boxstyle="round", facecolor="white", alpha=0.8),
188
  )
189
- plt.savefig("docs/efficientnet/roc.png")
190
  plt.show()
191
 
192
 
 
 
 
 
1
  import torch
2
  import numpy as np
3
  import pathlib
 
16
  auc,
17
  average_precision_score,
18
  cohen_kappa_score,
19
+
20
  )
21
  from sklearn.preprocessing import label_binarize
22
  from configs import *
 
 
 
 
 
23
 
24
 
25
  rcParams["font.family"] = "Times New Roman"
 
119
  plt.title("Confusion Matrix")
120
  manager = plt.get_current_fig_manager()
121
  manager.full_screen_toggle()
122
+ plt.savefig("docs/evaluation/confusion_matrix.png")
123
  plt.show()
124
 
125
  # Classification report
 
163
  "AUC-PRC = {:.3f}".format(auc_prc),
164
  bbox=dict(boxstyle="round", facecolor="white", alpha=0.8),
165
  )
166
+ plt.savefig("docs/evaluation/prc.png")
167
  plt.show()
168
 
169
  # Plot ROC curve
 
179
  "AUC-ROC = {:.3f}".format(auc_roc),
180
  bbox=dict(boxstyle="round", facecolor="white", alpha=0.8),
181
  )
182
+ plt.savefig("docs/evaluation/roc.png")
183
  plt.show()
184
 
185
 
extract-ensemble.py DELETED
@@ -1,110 +0,0 @@
1
- from pytorch_grad_cam import GradCAMPlusPlus
2
- from pytorch_grad_cam.utils.image import show_cam_on_image, preprocess_image
3
- import cv2
4
- import numpy as np
5
- import torch
6
- import torch.nn as nn # Replace with your model
7
- from configs import *
8
-
9
- # Load your model (change this according to your model definition)
10
- model2 = EfficientNetB2WithDropout(num_classes=NUM_CLASSES).to(DEVICE)
11
- model2.load_state_dict(torch.load("output/checkpoints/EfficientNetB2WithDropout.pth"))
12
- model1 = SqueezeNet1_0WithSE(num_classes=NUM_CLASSES).to(DEVICE)
13
- model1.load_state_dict(torch.load("output/checkpoints/SqueezeNet1_0WithSE.pth"))
14
- model3 = MobileNetV2WithDropout(num_classes=NUM_CLASSES).to(DEVICE)
15
- model3.load_state_dict(torch.load("output\checkpoints\MobileNetV2WithDropout.pth"))
16
-
17
- model1.eval()
18
- model2.eval()
19
- model3.eval()
20
-
21
-
22
- # Find the target layer (modify this based on your model architecture)
23
- # EfficientNetB2WithDropout - model.features[-1]
24
- # SqueezeNet1_0WithSE - model.features
25
- # MobileNetV2WithDropout - model.features[-1]
26
-
27
- target_layer_efficientnet = None
28
- for child in model2.features[-1]:
29
- if isinstance(child, nn.Conv2d):
30
- target_layer_efficientnet = child
31
-
32
- if target_layer_efficientnet is None:
33
- raise ValueError(
34
- "Invalid EfficientNet layer name: {}".format(target_layer_efficientnet)
35
- )
36
-
37
- target_layer_squeezenet = None
38
- for child in model1.features:
39
- if isinstance(child, nn.Conv2d):
40
- target_layer_squeezenet = child
41
-
42
- if target_layer_squeezenet is None:
43
- raise ValueError(
44
- "Invalid SqueezeNet layer name: {}".format(target_layer_squeezenet)
45
- )
46
-
47
- target_layer_mobilenet = None
48
- for child in model3.features[-1]:
49
- if isinstance(child, nn.Conv2d):
50
- target_layer_mobilenet = child
51
-
52
- if target_layer_mobilenet is None:
53
- raise ValueError("Invalid MobileNet layer name: {}".format(target_layer_mobilenet))
54
-
55
- # Load and preprocess the image
56
- image_path = r"data\test\Task 1\Cerebral Palsy\89.png"
57
- rgb_img = cv2.imread(image_path, 1)
58
- rgb_img = np.float32(rgb_img) / 255
59
- input_tensor = preprocess_image(rgb_img, mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
60
- input_tensor = input_tensor.to(DEVICE)
61
- input_tensor.requires_grad = True # Enable gradients for the input tensor
62
-
63
-
64
- # Create a GradCAMPlusPlus object
65
- efficientnet_cam = GradCAMPlusPlus(model=model2, target_layers=[target_layer_efficientnet], use_cuda=True)
66
- squeezenet_cam = GradCAMPlusPlus(model=model1, target_layers=[target_layer_squeezenet], use_cuda=True)
67
- mobilenet_cam = GradCAMPlusPlus(model=model3, target_layers=[target_layer_mobilenet], use_cuda=True)
68
-
69
-
70
- efficientnet_grayscale_cam = efficientnet_cam(input_tensor=input_tensor)[0]
71
- squeezenet_grayscale_cam = squeezenet_cam(input_tensor=input_tensor)[0]
72
- mobilenet_grayscale_cam = mobilenet_cam(input_tensor=input_tensor)[0]
73
-
74
- # Apply a colormap to the grayscale heatmap
75
- efficientnet_heatmap_colored = cv2.applyColorMap(np.uint8(255 * efficientnet_grayscale_cam), cv2.COLORMAP_JET)
76
- squeezenet_heatmap_colored = cv2.applyColorMap(np.uint8(255 * squeezenet_grayscale_cam), cv2.COLORMAP_JET)
77
- mobilenet_heatmap_colored = cv2.applyColorMap(np.uint8(255 * mobilenet_grayscale_cam), cv2.COLORMAP_JET)
78
-
79
- # normalized_efficientnet_heatmap = efficientnet_heatmap_colored / np.max(efficientnet_heatmap_colored)
80
- # normalized_squeezenet_heatmap = squeezenet_heatmap_colored / np.max(squeezenet_heatmap_colored)
81
- # normalized_mobilenet_heatmap = mobilenet_heatmap_colored / np.max(mobilenet_heatmap_colored)
82
-
83
- # # Ensure heatmap_colored has the same dtype as rgb_img
84
- # normalized_efficientnet_heatmap = normalized_efficientnet_heatmap.astype(np.float32) / 255
85
- # normalized_squeezenet_heatmap = normalized_squeezenet_heatmap.astype(np.float32) / 255
86
- # normalized_mobilenet_heatmap = normalized_mobilenet_heatmap.astype(np.float32) / 255
87
-
88
- efficientnet_heatmap_colored = efficientnet_heatmap_colored.astype(np.float32) / 255
89
- squeezenet_heatmap_colored = squeezenet_heatmap_colored.astype(np.float32) / 255
90
- mobilenet_heatmap_colored = mobilenet_heatmap_colored.astype(np.float32) / 255
91
-
92
- # Adjust the alpha value to control transparency
93
- alpha = (
94
- 0.1 # You can change this value to make the original image more or less transparent
95
- )
96
-
97
-
98
- # [0.38, 0.34, 0.28]
99
- weighted_heatmap = (
100
- efficientnet_heatmap_colored * 0.38
101
- + squeezenet_heatmap_colored * 0.34
102
- + mobilenet_heatmap_colored * 0.28
103
- )
104
-
105
-
106
- # Overlay the colored heatmap on the original image
107
- final_output = cv2.addWeighted(rgb_img, 0.3, weighted_heatmap, 0.7, 0)
108
-
109
- # Save the final output
110
- cv2.imwrite("cam.jpg", (final_output * 255).astype(np.uint8))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
extract.py β†’ extract_gradcam.py RENAMED
@@ -3,6 +3,7 @@ from pytorch_grad_cam.utils.image import show_cam_on_image, preprocess_image
3
  import cv2
4
  import numpy as np
5
  import torch
 
6
  import torch.nn as nn # Replace with your model
7
  from configs import *
8
  import os, random
@@ -21,30 +22,36 @@ for child in model.features[-1]:
21
  if target_layer is None:
22
  raise ValueError("Invalid layer name: {}".format(target_layer))
23
 
24
-
25
 
26
  def extract_gradcam(image_path=None, save_path=None):
27
  if image_path is None:
28
  for disease in CLASSES:
29
  print("Processing", disease)
30
- for image_path in os.listdir(r'data\test\Task 1\{}'.format(disease)):
31
  print("Processing", image_path)
32
- image_path = r'data\test\Task 1\{}\{}'.format(disease, image_path)
33
- image_name = image_path.split('.')[0].split('\\')[-1]
34
- print("Processing", image_name)
35
  rgb_img = cv2.imread(image_path, 1)
36
  rgb_img = np.float32(rgb_img) / 255
37
- input_tensor = preprocess_image(rgb_img, mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
 
 
38
  input_tensor = input_tensor.to(DEVICE)
 
39
 
40
  # Create a GradCAMPlusPlus object
41
- cam = GradCAMPlusPlus(model=model, target_layers=[target_layer], use_cuda=True)
 
 
42
 
43
  # Generate the GradCAM heatmap
44
  grayscale_cam = cam(input_tensor=input_tensor)[0]
45
 
46
  # Apply a colormap to the grayscale heatmap
47
- heatmap_colored = cv2.applyColorMap(np.uint8(255 * grayscale_cam), cv2.COLORMAP_JET)
 
 
48
 
49
  # Ensure heatmap_colored has the same dtype as rgb_img
50
  heatmap_colored = heatmap_colored.astype(np.float32) / 255
@@ -56,34 +63,46 @@ def extract_gradcam(image_path=None, save_path=None):
56
  final_output = cv2.addWeighted(rgb_img, 0.3, heatmap_colored, 0.7, 0)
57
 
58
  # Save the final output
59
- os.makedirs(f'docs/efficientnet/gradcam/{disease}', exist_ok=True)
60
- cv2.imwrite(f'docs/efficientnet/gradcam/{disease}/{image_name}.jpg', (final_output * 255).astype(np.uint8))
 
 
 
61
  else:
62
- rgb_img = cv2.imread(image_path, 1)
63
- rgb_img = np.float32(rgb_img) / 255
64
- input_tensor = preprocess_image(rgb_img, mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
65
- input_tensor = input_tensor.to(DEVICE)
 
 
 
 
 
 
 
 
 
66
 
67
- # Create a GradCAMPlusPlus object
68
- cam = GradCAMPlusPlus(model=model, target_layers=[target_layer])
 
 
69
 
70
- # Generate the GradCAM heatmap
71
- grayscale_cam = cam(input_tensor=input_tensor)[0]
72
 
73
- # Apply a colormap to the grayscale heatmap
74
- heatmap_colored = cv2.applyColorMap(np.uint8(255 * grayscale_cam), cv2.COLORMAP_JET)
75
 
76
- # Ensure heatmap_colored has the same dtype as rgb_img
77
- heatmap_colored = heatmap_colored.astype(np.float32) / 255
78
 
79
- # Adjust the alpha value to control transparency
80
- alpha = 0.3 # You can change this value to make the original image more or less transparent
81
 
82
- # Overlay the colored heatmap on the original image
83
- final_output = cv2.addWeighted(rgb_img, 0.3, heatmap_colored, 0.7, 0)
84
 
85
- # Save the final output
86
- cv2.imwrite(save_path, (final_output * 255).astype(np.uint8))
87
-
88
- return save_path
89
-
 
3
  import cv2
4
  import numpy as np
5
  import torch
6
+ import time
7
  import torch.nn as nn # Replace with your model
8
  from configs import *
9
  import os, random
 
22
  if target_layer is None:
23
  raise ValueError("Invalid layer name: {}".format(target_layer))
24
 
25
+ print(target_layer)
26
 
27
  def extract_gradcam(image_path=None, save_path=None):
28
  if image_path is None:
29
  for disease in CLASSES:
30
  print("Processing", disease)
31
+ for image_path in os.listdir(r"data\test\Task 1\{}".format(disease)):
32
  print("Processing", image_path)
33
+ image_path = r"data\test\Task 1\{}\{}".format(disease, image_path)
34
+ image_name = image_path.split(".")[0].split("\\")[-1]
 
35
  rgb_img = cv2.imread(image_path, 1)
36
  rgb_img = np.float32(rgb_img) / 255
37
+ input_tensor = preprocess_image(
38
+ rgb_img, mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]
39
+ )
40
  input_tensor = input_tensor.to(DEVICE)
41
+ input_tensor.requires_grad = True
42
 
43
  # Create a GradCAMPlusPlus object
44
+ cam = GradCAMPlusPlus(
45
+ model=model, target_layers=[target_layer], use_cuda=True
46
+ )
47
 
48
  # Generate the GradCAM heatmap
49
  grayscale_cam = cam(input_tensor=input_tensor)[0]
50
 
51
  # Apply a colormap to the grayscale heatmap
52
+ heatmap_colored = cv2.applyColorMap(
53
+ np.uint8(255 * grayscale_cam), cv2.COLORMAP_JET
54
+ )
55
 
56
  # Ensure heatmap_colored has the same dtype as rgb_img
57
  heatmap_colored = heatmap_colored.astype(np.float32) / 255
 
63
  final_output = cv2.addWeighted(rgb_img, 0.3, heatmap_colored, 0.7, 0)
64
 
65
  # Save the final output
66
+ os.makedirs(f"docs/evaluation/gradcam/{disease}", exist_ok=True)
67
+ cv2.imwrite(
68
+ f"docs/evaluation/gradcam/{disease}/{image_name}.jpg",
69
+ (final_output * 255).astype(np.uint8),
70
+ )
71
  else:
72
+ rgb_img = cv2.imread(image_path, 1)
73
+ rgb_img = np.float32(rgb_img) / 255
74
+ input_tensor = preprocess_image(
75
+ rgb_img, mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]
76
+ )
77
+ input_tensor = input_tensor.to(DEVICE)
78
+ input_tensor.requires_grad = True
79
+
80
+ # Create a GradCAMPlusPlus object
81
+ cam = GradCAMPlusPlus(model=model, target_layers=[target_layer])
82
+
83
+ # Generate the GradCAM heatmap
84
+ grayscale_cam = cam(input_tensor=input_tensor)[0]
85
 
86
+ # Apply a colormap to the grayscale heatmap
87
+ heatmap_colored = cv2.applyColorMap(
88
+ np.uint8(255 * grayscale_cam), cv2.COLORMAP_JET
89
+ )
90
 
91
+ # Ensure heatmap_colored has the same dtype as rgb_img
92
+ heatmap_colored = heatmap_colored.astype(np.float32) / 255
93
 
94
+ # Adjust the alpha value to control transparency
95
+ alpha = 0.3 # You can change this value to make the original image more or less transparent
96
 
97
+ # Overlay the colored heatmap on the original image
98
+ final_output = cv2.addWeighted(rgb_img, 0.3, heatmap_colored, 0.7, 0)
99
 
100
+ # Save the final output
101
+ cv2.imwrite(save_path, (final_output * 255).astype(np.uint8))
102
 
103
+ return save_path
 
104
 
105
+ # start = time.time()
106
+ # extract_gradcam()
107
+ # end = time.time()
108
+ # print("Time taken:", end - start)
 
lime_eval.py β†’ extract_lime.py RENAMED
@@ -1,12 +1,11 @@
 
1
  import numpy as np
2
  from lime.lime_image import LimeImageExplainer
3
  from PIL import Image
4
  import torch
5
- import torchvision.transforms as transforms
6
  import matplotlib.pyplot as plt
7
- from matplotlib.colors import Normalize
8
  from configs import *
9
- from sklearn.preprocessing import minmax_scale
10
 
11
 
12
  model = MODEL.to(DEVICE)
@@ -34,7 +33,6 @@ def generate_lime(image_path=None, save_path=None):
34
  print("Processing", image_path)
35
  image_path = r"data\test\Task 1\{}\{}".format(disease, image_path)
36
  image_name = image_path.split(".")[0].split("\\")[-1]
37
- print("Processing", image_name)
38
  image = Image.open(image_path).convert("RGB")
39
  image = preprocess(image)
40
  image = image.unsqueeze(0) # Add batch dimension
@@ -67,9 +65,9 @@ def generate_lime(image_path=None, save_path=None):
67
  image = (image - np.min(image)) / (np.max(image) - np.min(image))
68
 
69
  # image = Image.fromarray(image)
70
- os.makedirs(f"docs/efficientnet/lime/{disease}", exist_ok=True)
71
- # image.save(f'docs/efficientnet/lime/{disease}/{image_name}.jpg')
72
- plt.imsave(f"docs/efficientnet/lime/{disease}/{image_name}.jpg", image)
73
 
74
  else:
75
  image = None
@@ -103,6 +101,15 @@ def generate_lime(image_path=None, save_path=None):
103
  image = (image - np.min(image)) / (np.max(image) - np.min(image))
104
 
105
  # image = Image.fromarray(image)
106
- # os.makedirs(f"docs/efficientnet/lime/{disease}", exist_ok=True)
107
- # image.save(f'docs/efficientnet/lime/{disease}/{image_name}.jpg')
108
  plt.imsave(save_path, image)
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
  import numpy as np
3
  from lime.lime_image import LimeImageExplainer
4
  from PIL import Image
5
  import torch
 
6
  import matplotlib.pyplot as plt
 
7
  from configs import *
8
+ import time
9
 
10
 
11
  model = MODEL.to(DEVICE)
 
33
  print("Processing", image_path)
34
  image_path = r"data\test\Task 1\{}\{}".format(disease, image_path)
35
  image_name = image_path.split(".")[0].split("\\")[-1]
 
36
  image = Image.open(image_path).convert("RGB")
37
  image = preprocess(image)
38
  image = image.unsqueeze(0) # Add batch dimension
 
65
  image = (image - np.min(image)) / (np.max(image) - np.min(image))
66
 
67
  # image = Image.fromarray(image)
68
+ os.makedirs(f"docs/evaluation/lime/{disease}", exist_ok=True)
69
+ # image.save(f'docs/evaluation/lime/{disease}/{image_name}.jpg')
70
+ plt.imsave(f"docs/evaluation/lime/{disease}/{image_name}.jpg", image)
71
 
72
  else:
73
  image = None
 
101
  image = (image - np.min(image)) / (np.max(image) - np.min(image))
102
 
103
  # image = Image.fromarray(image)
104
+ # os.makedirs(f"docs/evaluation/lime/{disease}", exist_ok=True)
105
+ # image.save(f'docs/evaluation/lime/{disease}/{image_name}.jpg')
106
  plt.imsave(save_path, image)
107
+
108
+
109
+ # start = time.time()
110
+
111
+ # generate_lime()
112
+
113
+ # end = time.time()
114
+
115
+ # print("Time taken:", end - start)
genetric_algorithm.py CHANGED
@@ -1,34 +1,38 @@
1
  import os
2
  import optuna
3
- from optuna.trial import TrialState
4
  import torch
5
  import torch.nn as nn
6
  import torch.optim as optim
 
7
  from configs import *
8
  import data_loader
9
  from torch.utils.tensorboard import SummaryWriter
 
10
  import numpy as np
11
- import pygad
12
- import pygad.torchga
13
 
14
  torch.cuda.empty_cache()
15
- model = MODEL.to(DEVICE)
 
 
 
 
 
 
 
16
 
17
- EPOCHS = 10
18
- N_TRIALS = 20
19
- TIMEOUT = 1800
20
- EARLY_STOPPING_PATIENCE = (
21
- 4 # Number of epochs with no improvement to trigger early stopping
22
- )
23
- NUM_GENERATIONS = 10
24
- SOL_PER_POP = 10 # Number of solutions in the population
25
- NUM_GENES = 2
26
- NUM_PARENTS_MATING = 4
27
 
 
 
 
28
  # Create a TensorBoard writer
29
  writer = SummaryWriter(log_dir="output/tensorboard/tuning")
30
 
31
-
32
  # Function to create or modify data loaders with the specified batch size
33
  def create_data_loaders(batch_size):
34
  train_loader, valid_loader = data_loader.load_data(
@@ -38,211 +42,204 @@ def create_data_loaders(batch_size):
38
  )
39
  return train_loader, valid_loader
40
 
 
 
 
 
41
 
42
- # Objective function for optimization
43
- def objective(trial):
44
- global data_inputs, data_outputs
45
-
46
- batch_size = trial.suggest_categorical("batch_size", [16, 32, 64])
47
- train_loader, valid_loader = create_data_loaders(batch_size)
48
-
49
- lr = trial.suggest_float("lr", 1e-5, 1e-3, log=True)
50
  optimizer = optim.Adam(model.parameters(), lr=lr)
51
  criterion = nn.CrossEntropyLoss()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
- gamma = trial.suggest_float("gamma", 0.1, 0.9, step=0.1)
54
- scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=EPOCHS)
 
55
 
56
- past_trials = 0 # Number of trials already completed
 
57
 
58
- # Print best hyperparameters:
59
- if past_trials > 0:
60
- print("\nBest Hyperparameters:")
61
- print(f"{study.best_trial.params}")
62
 
63
- print(f"\n[INFO] Trial: {trial.number}")
64
- print(f"Batch Size: {batch_size}")
65
- print(f"Learning Rate: {lr}")
66
- print(f"Gamma: {gamma}\n")
67
 
68
- early_stopping_counter = 0
69
- best_accuracy = 0.0
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  for epoch in range(EPOCHS):
72
  model.train()
73
  for batch_idx, (data, target) in enumerate(train_loader, 0):
74
  data, target = data.to(DEVICE), target.to(DEVICE)
75
  optimizer.zero_grad()
76
- output = model(data)
77
- loss = criterion(output, target)
 
 
 
 
 
78
  loss.backward()
79
  optimizer.step()
80
 
81
- scheduler.step()
82
-
83
  model.eval()
84
  correct = 0
85
  with torch.no_grad():
86
  for batch_idx, (data, target) in enumerate(valid_loader, 0):
87
  data, target = data.to(DEVICE), target.to(DEVICE)
 
88
  output = model(data)
89
  pred = output.argmax(dim=1, keepdim=True)
90
  correct += pred.eq(target.view_as(pred)).sum().item()
91
 
92
  accuracy = correct / len(valid_loader.dataset)
93
 
94
- # Log hyperparameters and accuracy to TensorBoard
95
- writer.add_scalar("Accuracy", accuracy, trial.number)
96
- writer.add_hparams(
97
- {"batch_size": batch_size, "lr": lr, "gamma": gamma},
98
- {"accuracy": accuracy},
99
- )
100
-
101
- print(f"[EPOCH {epoch + 1}] Accuracy: {accuracy:.4f}")
102
-
103
- trial.report(accuracy, epoch)
104
-
105
- if accuracy > best_accuracy:
106
- best_accuracy = accuracy
107
- early_stopping_counter = 0
108
- else:
109
- early_stopping_counter += 1
110
-
111
- # Early stopping check
112
- if early_stopping_counter >= EARLY_STOPPING_PATIENCE:
113
- print(f"\nEarly stopping at epoch {epoch + 1}")
114
- break
115
-
116
- if trial.number > 10 and trial.params["lr"] < 1e-3 and best_accuracy < 0.7:
117
- return float("inf")
118
-
119
- past_trials += 1
120
-
121
- return best_accuracy
122
-
123
-
124
- # Custom genetic algorithm
125
- def run_genetic_algorithm(fitness_func):
126
- # Initial population
127
- population = np.random.rand(SOL_PER_POP, NUM_GENES) # Random initialization
128
-
129
- # Run for a fixed number of generations
130
- for generation in range(NUM_GENERATIONS):
131
- # Calculate fitness for each solution in the population
132
- fitness = np.array(
133
- [fitness_func(solution, idx) for idx, solution in enumerate(population)]
134
- )
135
-
136
- # Get the index of the best solution
137
- best_idx = np.argmax(fitness)
138
- best_solution = population[best_idx]
139
- best_fitness = fitness[best_idx]
140
-
141
- # Print the best solution and fitness for this generation
142
- print(f"Generation {generation + 1}:")
143
- print("Best Solution:")
144
- print("Learning Rate = {lr}".format(lr=best_solution[0]))
145
- print("Gamma = {gamma}".format(gamma=best_solution[1]))
146
- print("Best Fitness = {fitness}".format(fitness=best_fitness))
147
-
148
- # Perform selection and crossover to create the next generation
149
- population = selection_and_crossover(population, fitness)
150
-
151
-
152
- # Selection and crossover logic
153
- def selection_and_crossover(population, fitness):
154
- # Perform tournament selection
155
- parents = []
156
- for _ in range(SOL_PER_POP):
157
- tournament_idxs = np.random.choice(range(SOL_PER_POP), NUM_PARENTS_MATING)
158
- tournament_fitness = [fitness[idx] for idx in tournament_idxs]
159
- selected_parent_idx = tournament_idxs[np.argmax(tournament_fitness)]
160
- parents.append(population[selected_parent_idx])
161
-
162
- # Perform single-point crossover
163
- offspring = []
164
- for i in range(0, SOL_PER_POP, 2):
165
- if i + 1 < SOL_PER_POP:
166
- crossover_point = np.random.randint(0, NUM_GENES)
167
- offspring.extend(
168
- [
169
- np.concatenate(
170
- (parents[i][:crossover_point], parents[i + 1][crossover_point:])
171
- )
172
- ]
173
- )
174
- offspring.extend(
175
- [
176
- np.concatenate(
177
- (parents[i + 1][:crossover_point], parents[i][crossover_point:])
178
- )
179
- ]
180
- )
181
-
182
- return np.array(offspring)
183
-
184
-
185
- # Modify callback function to log best accuracy
186
- def callback_generation(ga_instance):
187
- global study
188
-
189
- # Fetch the parameters of the best solution
190
- solution, solution_fitness, _ = ga_instance.best_solution()
191
- best_learning_rate, best_gamma = solution
192
-
193
- # Report the best accuracy to Optuna study
194
- study.set_user_attr("best_accuracy", solution_fitness)
195
-
196
- # Print generation number and best fitness
197
- print(
198
- "Generation = {generation}".format(generation=ga_instance.generations_completed)
199
- )
200
- print("Best Fitness = {fitness}".format(fitness=solution_fitness))
201
- print("Best Learning Rate = {lr}".format(lr=best_learning_rate))
202
- print("Best Gamma = {gamma}".format(gamma=best_gamma))
203
 
 
 
204
 
205
  if __name__ == "__main__":
206
- global study
207
  pruner = optuna.pruners.HyperbandPruner()
 
 
208
  study = optuna.create_study(
209
  direction="maximize",
210
  pruner=pruner,
211
- study_name="hyperparameter_tuning",
 
212
  )
213
 
214
- # Define data_inputs and data_outputs
215
- # You need to populate these with your own data
216
 
217
- # Define the loss function
218
- loss_function = nn.CrossEntropyLoss()
219
 
220
- def fitness_func(solution, sol_idx):
221
- global data_inputs, data_outputs, model, loss_function
222
 
223
- learning_rate, momentum = solution
 
 
 
 
 
 
224
 
225
- # Update optimizer with the current learning rate and momentum
226
- optimizer = torch.optim.SGD(
227
- model.parameters(), lr=learning_rate, momentum=momentum
228
- )
229
 
230
- # Load the model weights
231
- model_weights_dict = pygad.torchga.model_weights_as_dict(
232
- model=model, weights_vector=solution
233
- )
234
- model.load_state_dict(model_weights_dict)
235
 
236
- # Forward pass
237
- predictions = model(data_inputs)
238
 
239
- # Calculate cross-entropy loss
240
- loss = loss_function(predictions, data_outputs)
241
 
242
- # Higher fitness for lower loss
243
- solution_fitness = 1.0 / (loss.detach().numpy() + 1e-8)
244
 
245
- return solution_fitness
 
 
 
246
 
247
- # Run the custom genetic algorithm
248
- run_genetic_algorithm(fitness_func)
 
 
1
  import os
2
  import optuna
 
3
  import torch
4
  import torch.nn as nn
5
  import torch.optim as optim
6
+ import torch.utils.data
7
  from configs import *
8
  import data_loader
9
  from torch.utils.tensorboard import SummaryWriter
10
+ import time
11
  import numpy as np
12
+ import random
 
13
 
14
  torch.cuda.empty_cache()
15
+ RANDOM_SEED1=42
16
+ random.seed(RANDOM_SEED1)
17
+ torch.cuda.manual_seed(RANDOM_SEED1)
18
+ torch.manual_seed(RANDOM_SEED1)
19
+ print("PyTorch Seed:", torch.initial_seed())
20
+ print("Random Seed:", random.getstate()[1][0])
21
+ print("PyTorch CUDA Seed:", torch.cuda.initial_seed())
22
+
23
 
24
+ # Define the constants for genetic algorithm
25
+ POPULATION_SIZE = 5
26
+ MUTATION_RATE = 0.05
27
+ CROSSOVER_RATE = 0.7
28
+ NUM_GENERATIONS = 5
 
 
 
 
 
29
 
30
+ EPOCHS = 5
31
+
32
+ EARLY_STOPPING_PATIENCE = 4
33
  # Create a TensorBoard writer
34
  writer = SummaryWriter(log_dir="output/tensorboard/tuning")
35
 
 
36
  # Function to create or modify data loaders with the specified batch size
37
  def create_data_loaders(batch_size):
38
  train_loader, valid_loader = data_loader.load_data(
 
42
  )
43
  return train_loader, valid_loader
44
 
45
+ # Create a TensorBoard writer
46
+ writer = SummaryWriter(log_dir="output/tensorboard/tuning")
47
+ model = MODEL.to(DEVICE)
48
+ # model.load_state_dict(torch.load(MODEL_SAVE_PATH, map_location=DEVICE))
49
 
50
+ def fitness_function(individual,model):
51
+ batch_size, lr,= individual
52
+
53
+ # Assuming you have a model, optimizer, and loss function defined
54
+ model = model.to(DEVICE)
 
 
 
55
  optimizer = optim.Adam(model.parameters(), lr=lr)
56
  criterion = nn.CrossEntropyLoss()
57
+ scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=NUM_EPOCHS)
58
+ # Define your data loaders using the given batch_size
59
+ train_loader, valid_loader = create_data_loaders(batch_size)
60
+
61
+ # Training loop
62
+ for epoch in range(EPOCHS):
63
+ model.train()
64
+ for batch_idx, (data, target) in enumerate(train_loader, 0):
65
+ data, target = data.to(DEVICE), target.to(DEVICE)
66
+ optimizer.zero_grad()
67
+ if model.__class__.__name__ == "GoogLeNet":
68
+ output = model(data).logits
69
+ else:
70
+ output = model(data)
71
+ loss = criterion(output, target)
72
+ loss.backward()
73
+ optimizer.step()
74
+ scheduler.step()
75
+ # Validation loop
76
+ model.eval()
77
+ correct = 0
78
+ with torch.no_grad():
79
+ for batch_idx, (data, target) in enumerate(valid_loader, 0):
80
+ data, target = data.to(DEVICE), target.to(DEVICE)
81
+ data, targets_a, targets_b, lam = cutmix_data(data, target, alpha=1)
82
+ output = model(data)
83
+ pred = output.argmax(dim=1, keepdim=True)
84
+ correct += pred.eq(target.view_as(pred)).sum().item()
85
+
86
+ accuracy = correct / len(valid_loader.dataset)
87
+ print(f"Epoch {epoch + 1}/{EPOCHS}, Accuracy: {accuracy:.4f}")
88
+ return accuracy,
89
+
90
+ def rand_bbox(size, lam):
91
+ W = size[2]
92
+ H = size[3]
93
+ cut_rat = np.sqrt(1.0 - lam)
94
+ cut_w = np.int_(W * cut_rat)
95
+ cut_h = np.int_(H * cut_rat)
96
+
97
+ # uniform
98
+ cx = np.random.randint(W)
99
+ cy = np.random.randint(H)
100
+
101
+ bbx1 = np.clip(cx - cut_w // 2, 0, W)
102
+ bby1 = np.clip(cy - cut_h // 2, 0, H)
103
+ bbx2 = np.clip(cx + cut_w // 2, 0, W)
104
+ bby2 = np.clip(cy + cut_h // 2, 0, H)
105
+
106
+ return bbx1, bby1, bbx2, bby2
107
+
108
+ def cutmix_data(input, target, alpha=1.0):
109
+ if alpha > 0:
110
+ lam = np.random.beta(alpha, alpha)
111
+ else:
112
+ lam = 1
113
 
114
+ batch_size = input.size()[0]
115
+ index = torch.randperm(batch_size)
116
+ rand_index = torch.randperm(input.size()[0])
117
 
118
+ bbx1, bby1, bbx2, bby2 = rand_bbox(input.size(), lam)
119
+ input[:, :, bbx1:bbx2, bby1:bby2] = input[rand_index, :, bbx1:bbx2, bby1:bby2]
120
 
121
+ lam = 1 - ((bbx2 - bbx1) * (bby2 - bby1) / (input.size()[-1] * input.size()[-2]))
122
+ targets_a = target
123
+ targets_b = target[rand_index]
 
124
 
125
+ return input, targets_a, targets_b, lam
 
 
 
126
 
127
+ def cutmix_criterion(criterion, outputs, targets_a, targets_b, lam):
128
+ return lam * criterion(outputs, targets_a) + (1 - lam) * criterion(outputs, targets_b)
129
 
130
+ # Function to create or modify data loaders with the specified batch size
131
+ def create_data_loaders(batch_size):
132
+ print(f"Batch Size (before conversion): {batch_size}")
133
+ batch_size = int(batch_size) # Ensure batch_size is an integer
134
+ print(f"Batch Size (after conversion): {batch_size}")
135
+ train_loader, valid_loader = data_loader.load_data(
136
+ COMBINED_DATA_DIR + "1",
137
+ preprocess,
138
+ batch_size=batch_size,
139
+ )
140
+ return train_loader, valid_loader
141
+
142
+ # Genetic algorithm initialization functions
143
+ def create_individual():
144
+ lr = abs(np.random.uniform(0.0006, 0.0009))
145
+ print(f"Generated lr: {lr}")
146
+ return creator.Individual([
147
+ int(np.random.choice([32])), # Choose a valid batch size
148
+ lr, # lr in log scale between 1e-4 and 1e-2
149
+ ])
150
+ # Genetic algorithm evaluation function
151
+ def evaluate_individual(individual, model=MODEL):
152
+ batch_size, lr, = individual
153
+ lr=abs(lr)
154
+ # Assuming you have a model, optimizer, and loss function defined
155
+ model = model.to(DEVICE)
156
+ optimizer = optim.Adam(model.parameters(), lr=lr)
157
+ criterion = nn.CrossEntropyLoss()
158
+
159
+ # Define your data loaders using the given batch_size
160
+ train_loader, valid_loader = create_data_loaders(batch_size)
161
+
162
+ # Training loop
163
  for epoch in range(EPOCHS):
164
  model.train()
165
  for batch_idx, (data, target) in enumerate(train_loader, 0):
166
  data, target = data.to(DEVICE), target.to(DEVICE)
167
  optimizer.zero_grad()
168
+ # Apply CutMix
169
+ data, targets_a, targets_b, lam = cutmix_data(data, target, alpha=1)
170
+ if model.__class__.__name__ == "GoogLeNet":
171
+ output = model(data).logits
172
+ else:
173
+ output = model(data)
174
+ loss = cutmix_criterion(criterion, output, targets_a, targets_b, lam)
175
  loss.backward()
176
  optimizer.step()
177
 
178
+ # Validation loop
 
179
  model.eval()
180
  correct = 0
181
  with torch.no_grad():
182
  for batch_idx, (data, target) in enumerate(valid_loader, 0):
183
  data, target = data.to(DEVICE), target.to(DEVICE)
184
+ data, targets_a, targets_b, lam = cutmix_data(data, target, alpha=1)
185
  output = model(data)
186
  pred = output.argmax(dim=1, keepdim=True)
187
  correct += pred.eq(target.view_as(pred)).sum().item()
188
 
189
  accuracy = correct / len(valid_loader.dataset)
190
 
191
+ # Log accuracy or other metrics as needed
192
+ writer.add_scalar("Accuracy", accuracy, epoch)
193
+
194
+ print(f"Epoch {epoch + 1}/{EPOCHS}, Accuracy: {accuracy:.4f}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
 
196
+ # Return the accuracy (or any other metric you want to optimize)
197
+ return (accuracy,)
198
 
199
  if __name__ == "__main__":
 
200
  pruner = optuna.pruners.HyperbandPruner()
201
+
202
+ start_time = time.time()
203
  study = optuna.create_study(
204
  direction="maximize",
205
  pruner=pruner,
206
+ study_name="hyperparameter_optimization",
207
+ storage="sqlite:///" + MODEL.__class__.__name__ + ".sqlite3",
208
  )
209
 
210
+ from deap import base, creator, tools, algorithms
 
211
 
212
+ creator.create("FitnessMax", base.Fitness, weights=(1.0,))
 
213
 
214
+ creator.create("Individual", list, fitness=creator.FitnessMax)
 
215
 
216
+ toolbox = base.Toolbox()
217
+ toolbox.register("individual", create_individual)
218
+ toolbox.register("population", tools.initRepeat, list, toolbox.individual)
219
+ toolbox.register("evaluate", fitness_function, model=model)
220
+ toolbox.register("mate", tools.cxTwoPoint)
221
+ toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=0.1, indpb=MUTATION_RATE)
222
+ toolbox.register("select", tools.selTournament, tournsize=3)
223
 
224
+ population = toolbox.population(n=POPULATION_SIZE)
 
 
 
225
 
226
+ for ind in population:
227
+ print(type(ind))
228
+ fitness_value = evaluate_individual(ind, model)
229
+ ind.fitness.values = (fitness_value[0],)
 
230
 
231
+ algorithms.eaSimple(population, toolbox, cxpb=CROSSOVER_RATE, mutpb=MUTATION_RATE, ngen=NUM_GENERATIONS, stats=None, halloffame=None, verbose=True)
 
232
 
233
+ best_individual = tools.selBest(population, 1)[0]
234
+ best_batch_size, best_lr = best_individual
235
 
236
+ best_accuracy = evaluate_individual(best_individual, model)
 
237
 
238
+ print("Best Hyperparameters:")
239
+ print(f"Batch Size: {best_batch_size}")
240
+ print(f"Learning Rate: {best_lr}")
241
+ print(f"Best Accuracy: {best_accuracy[0]}")
242
 
243
+ end_time = time.time()
244
+ tuning_duration = end_time - start_time
245
+ print(f"Hyperparameter optimization took {tuning_duration:.2f} seconds.")
lazy_predict.py DELETED
@@ -1,60 +0,0 @@
1
- import os
2
- import torch
3
- import torch.nn as nn
4
- import torch.optim as optim
5
- import matplotlib.pyplot as plt
6
- from models import *
7
- from torch.utils.tensorboard import SummaryWriter
8
- from configs import *
9
- import data_loader
10
- import numpy as np
11
- from lazypredict.Supervised import LazyClassifier
12
- from sklearn.utils import shuffle
13
-
14
- def extract_features_labels(loader):
15
- data = []
16
- labels = []
17
- for inputs, labels_batch in loader:
18
- for img in inputs:
19
- data.append(img.view(-1).numpy())
20
- labels.extend(labels_batch.numpy())
21
- return np.array(data), np.array(labels)
22
-
23
- def load_and_preprocess_data():
24
- train_loader, valid_loader = data_loader.load_data(
25
- RAW_DATA_DIR + str(TASK),
26
- AUG_DATA_DIR + str(TASK),
27
- EXTERNAL_DATA_DIR + str(TASK),
28
- preprocess,
29
- )
30
- return train_loader, valid_loader
31
-
32
- def initialize_model_optimizer_scheduler(train_loader, valid_loader):
33
- model = MODEL.to(DEVICE)
34
- criterion = nn.CrossEntropyLoss()
35
- optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE)
36
- scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=NUM_EPOCHS)
37
- return model, criterion, optimizer, scheduler
38
-
39
- # Load and preprocess data
40
- train_loader, valid_loader = load_and_preprocess_data()
41
-
42
- # Initialize the model, criterion, optimizer, and scheduler
43
- model, criterion, optimizer, scheduler = initialize_model_optimizer_scheduler(train_loader, valid_loader)
44
-
45
- # Extract features and labels
46
- X_train, y_train = extract_features_labels(train_loader)
47
- X_valid, y_valid = extract_features_labels(valid_loader)
48
-
49
- # LazyClassifier
50
- clf = LazyClassifier(verbose=0, ignore_warnings=True, custom_metric=None)
51
- models, predictions = clf.fit(X_train, X_valid, y_train, y_valid)
52
-
53
- print("Models:", models)
54
- print("Predictions:", predictions)
55
-
56
-
57
-
58
-
59
-
60
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lrp-eval.py DELETED
@@ -1,16 +0,0 @@
1
- import torch
2
- from torchvision.models import vgg16, VGG16_Weights
3
- from src.lrp import LRPModel
4
- from configs import *
5
- from PIL import Image
6
-
7
-
8
- image = Image.open(r'data\test\Task 1\Alzheimer Disease\0d846ee1-c90d-4ed5-8467-3550dd653858.png').convert("RGB")
9
- image = preprocess(image).unsqueeze(0)
10
- image = image.to(DEVICE)
11
- model = MODEL.to(DEVICE)
12
- print(dict(model.named_modules()))
13
- model.load_state_dict(torch.load(MODEL_SAVE_PATH, map_location=DEVICE))
14
- model.eval()
15
- lrp_model = LRPModel(model)
16
- r = lrp_model.forward(image)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
models.py CHANGED
@@ -1,69 +1,22 @@
1
- #######################################################
2
- # This file stores all the models used in the project.#
3
- #######################################################
4
-
5
- # Import all models from torchvision.models
6
- from torchvision.models import resnet50
7
- from torchvision.models import resnet18
8
- from torchvision.models import squeezenet1_0
9
- from torchvision.models import vgg16
10
- from torchvision.models import alexnet
11
- from torchvision.models import densenet121
12
- from torchvision.models import googlenet
13
- from torchvision.models import inception_v3
14
- from torchvision.models import mobilenet_v2
15
- from torchvision.models import mobilenet_v3_small
16
- from torchvision.models import mobilenet_v3_large
17
- from torchvision.models import shufflenet_v2_x0_5
18
- from torchvision.models import vgg11
19
- from torchvision.models import vgg11_bn
20
- from torchvision.models import vgg13
21
- from torchvision.models import vgg13_bn
22
- from torchvision.models import vgg16_bn
23
- from torchvision.models import vgg19_bn
24
- from torchvision.models import vgg19
25
- from torchvision.models import wide_resnet50_2
26
- from torchvision.models import wide_resnet101_2
27
- from torchvision.models import mnasnet0_5
28
- from torchvision.models import mnasnet0_75
29
- from torchvision.models import mnasnet1_0
30
- from torchvision.models import mnasnet1_3
31
- from torchvision.models import resnext50_32x4d
32
- from torchvision.models import resnext101_32x8d
33
- from torchvision.models import shufflenet_v2_x1_0
34
- from torchvision.models import shufflenet_v2_x1_5
35
- from torchvision.models import shufflenet_v2_x2_0
36
- from torchvision.models import squeezenet1_1
37
- from torchvision.models import efficientnet_v2_s
38
- from torchvision.models import efficientnet_v2_m
39
- from torchvision.models import efficientnet_v2_l
40
- from torchvision.models import efficientnet_b0
41
- from torchvision.models import efficientnet_b1
42
  import torch
43
  import torch.nn as nn
44
 
45
- class WeightedVoteEnsemble(nn.Module):
46
- def __init__(self, models, weights):
47
- super(WeightedVoteEnsemble, self).__init__()
48
- self.models = models
49
- self.weights = weights
50
 
51
- def forward(self, x):
52
- predictions = [model(x) for model in self.models]
53
- weighted_predictions = torch.stack(
54
- [w * pred for w, pred in zip(self.weights, predictions)], dim=0
 
 
 
 
 
 
55
  )
56
- avg_predictions = weighted_predictions.sum(dim=0)
57
- return avg_predictions
58
-
59
-
60
- def ensemble_predictions(models, image):
61
- all_predictions = []
62
-
63
- with torch.no_grad():
64
- for model in models:
65
- output = model(image)
66
- all_predictions.append(output)
67
-
68
- return torch.stack(all_predictions, dim=0).mean(dim=0)
69
 
 
 
 
 
 
 
1
+ from torchvision.models import efficientnet_b3, EfficientNet_B3_Weights
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import torch
3
  import torch.nn as nn
4
 
 
 
 
 
 
5
 
6
+ class EfficientNetB3WithNorm(nn.Module):
7
+ def __init__(self, num_classes):
8
+ super(EfficientNetB3WithNorm, self).__init__()
9
+ efficientnet = efficientnet_b3(weights=EfficientNet_B3_Weights.DEFAULT)
10
+ self.features = efficientnet.features
11
+ self.classifier = nn.Sequential(
12
+ nn.Conv2d(1536, num_classes, kernel_size=1),
13
+ nn.BatchNorm2d(num_classes), # add batch normalization
14
+ nn.ReLU(inplace=True),
15
+ nn.AdaptiveAvgPool2d((1, 1)),
16
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
+ def forward(self, x):
19
+ x = self.features(x)
20
+ x = self.classifier(x)
21
+ x = torch.flatten(x, 1)
22
+ return x
tuning.py β†’ optuna_unused.py RENAMED
File without changes
plot-gradcam.py DELETED
@@ -1,65 +0,0 @@
1
- # Plot a table, each column is a test image, separate to 7 tables (one for each disease), each column have 4 rows, one is disease name, one is gradcam, one is lime, one is original image
2
-
3
- import os
4
- import cv2
5
- import numpy as np
6
- import torch
7
- import torchvision.transforms as transforms
8
- import matplotlib.pyplot as plt
9
- from matplotlib.colors import Normalize
10
- from configs import *
11
- from sklearn.preprocessing import minmax_scale
12
-
13
- plt.rcParams["font.family"] = "Times New Roman"
14
-
15
- # Plot a table, each column is a test image, separate to 7 plot (one for each disease), each column have 4 rows, one is disease name, one is gradcam, one is lime, one is original image, the images are in 'docs/efficientnet/gradcam' and 'docs/efficientnet/lime' and 'data/test/Task 1'
16
-
17
-
18
- def plot_table():
19
- diseases = CLASSES
20
- diseases.sort()
21
- # diseases = ["Atelectasis", "Cardiomegaly", "Consolidation", "Edema", "Effusion", "Emphysema", "Fibrosis", "Hernia", "Infiltration", "Mass", "Nodule", "Pleural_Thickening", "Pneumonia", "Pneumothorax"]
22
- print(diseases)
23
- fig, axs = plt.subplots(4, 14, figsize=(20, 10))
24
- fig.tight_layout()
25
- for i, disease in enumerate(diseases):
26
- # Create a new plot
27
- print("Processing", disease)
28
- axs[0, i].axis("off")
29
- axs[0, i].set_title(disease)
30
- axs[1, i].axis("off")
31
- axs[1, i].set_title("GradCAM")
32
- axs[2, i].axis("off")
33
- axs[2, i].set_title("LIME")
34
- axs[3, i].axis("off")
35
- axs[3, i].set_title("Original")
36
- # For each image in test folder, there are corresponding ones in gradcam folder and lime folder, plot it accordingly
37
- for j, image_path in enumerate(os.listdir(r"data\test\Task 1\{}".format(disease))):
38
- print("Processing", image_path)
39
- image_path = r"data\test\Task 1\{}\{}".format(disease, image_path)
40
- image_name = image_path.split(".")[0].split("\\")[-1]
41
- print("Processing", image_name)
42
- # Plot the original image
43
- image = cv2.imread(image_path, 1)
44
- image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
45
- axs[3, i].imshow(image)
46
- # Plot the gradcam image
47
- image = cv2.imread(
48
- f"docs/efficientnet/gradcam/{disease}/{image_name}.jpg", 1
49
- )
50
- image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
51
- axs[1, i].imshow(image)
52
- # Plot the lime image
53
- image = cv2.imread(
54
- f"docs/efficientnet/lime/{disease}/{image_name}.jpg", 1
55
- )
56
- image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
57
- axs[2, i].imshow(image)
58
- # # Plot the disease name
59
- # axs[0, i].text(0.5, 0.5, disease, horizontalalignment="center")
60
- plt.savefig("docs/efficientnet/table.png")
61
- plt.show()
62
-
63
- if __name__ == "__main__":
64
- plot_table()
65
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
plot_structure.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # from torchview import draw_graph
2
+ from torchviz import make_dot
3
+ from configs import *
4
+ import os
5
+ # import graphviz
6
+
7
+ # when running on VSCode run the below command
8
+ # svg format on vscode does not give desired result
9
+ # graphviz.set_jupyter_format("png")
10
+
11
+ model = EfficientNetB3WithNorm(num_classes=7)
12
+
13
+ batch_size = 2
14
+ # device='meta' -> no memory is consumed for visualization
15
+ # model_graph = draw_graph(model, input_size=(32, 3, 224, 224), save_graph=True, filename="model_graph.png")
16
+ # model_graph.visual_graph
17
+
18
+ model_graph = make_dot(
19
+ model(torch.randn(batch_size, 3, 224, 224)), params=dict(model.named_parameters())
20
+ ).render("torchviz", format="png")
plot_training_metrics.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import matplotlib.pyplot as plt
3
+
4
+ # Load data from the CSV file
5
+ df = pd.read_csv('training_metrics.csv')
6
+
7
+ # Extract data
8
+ epochs = df['Epoch']
9
+ train_loss = df['Train Loss']
10
+ train_accuracy = df['Train Accuracy']
11
+ validation_loss = df['Validation Loss']
12
+ validation_accuracy = df['Validation Accuracy']
13
+
14
+ # Create subplots for loss and accuracy
15
+ plt.figure(figsize=(12, 5))
16
+
17
+ # Loss subplot
18
+ plt.subplot(1, 2, 1)
19
+ plt.plot(epochs, train_loss, label='Train Loss', marker='o')
20
+ plt.plot(epochs, validation_loss, label='Validation Loss', marker='o')
21
+ plt.title('Training and Validation Loss')
22
+ plt.xlabel('Epoch')
23
+ plt.ylabel('Loss')
24
+ plt.legend()
25
+
26
+ # Accuracy subplot
27
+ plt.subplot(1, 2, 2)
28
+ plt.plot(epochs, train_accuracy, label='Train Accuracy', marker='o')
29
+ plt.plot(epochs, validation_accuracy, label='Validation Accuracy', marker='o')
30
+ plt.title('Training and Validation Accuracy')
31
+ plt.xlabel('Epoch')
32
+ plt.ylabel('Accuracy')
33
+ plt.legend()
34
+
35
+ plt.tight_layout()
36
+ plt.show()
requirements.txt CHANGED
Binary files a/requirements.txt and b/requirements.txt differ
 
shap_eval.py DELETED
@@ -1,37 +0,0 @@
1
- # Import necessary libraries
2
- import shap
3
- import torch
4
- import numpy as np
5
-
6
- # Load your EfficientNetB3 model
7
- from torchvision import models
8
-
9
- # Load your test data
10
- from data_loader import load_test_data # Replace with your actual data loader function
11
- from configs import *
12
-
13
- # Define your EfficientNetB3 model and load its pre-trained weights
14
- model = MODEL
15
-
16
- # Set your model to evaluation mode
17
- model.eval()
18
-
19
- # Load your test data using your data loader
20
- test_loader = load_test_data(TEST_DATA_DIR + "1", preprocess) # Replace with your test data loader
21
-
22
- # Choose a specific image from the test dataset
23
- image, _ = next(iter(test_loader))
24
-
25
- # Make sure your model and input data are on the same device (CPU or GPU)
26
- device = DEVICE
27
- model = model.to(device)
28
- image = image.to(device)
29
-
30
- # Initialize an explainer for your model using SHAP's DeepExplainer
31
- explainer = shap.DeepExplainer(model, data=test_loader)
32
-
33
- # Calculate SHAP values for your chosen image
34
- shap_values = explainer(image)
35
-
36
- # Summarize the feature importance for the specific image
37
- shap.summary_plot(shap_values, image)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test.py DELETED
@@ -1,223 +0,0 @@
1
- import sys
2
- import torch
3
- import torch.nn as nn
4
- from PIL import Image
5
- import os
6
- from configs import *
7
- from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
8
- import matplotlib.pyplot as plt
9
- import random
10
- from itertools import product
11
-
12
- random.seed(RANDOM_SEED)
13
- torch.cuda.manual_seed(RANDOM_SEED)
14
- torch.manual_seed(RANDOM_SEED)
15
- print("PyTorch Seed:", torch.initial_seed())
16
- print("Random Seed:", random.getstate()[1][0])
17
- print("PyTorch CUDA Seed:", torch.cuda.initial_seed())
18
-
19
- # Define your model paths
20
- # Load your pre-trained models
21
- model2 = EfficientNetB2WithDropout(num_classes=NUM_CLASSES).to(DEVICE)
22
- model2.load_state_dict(torch.load("output/checkpoints/EfficientNetB2WithDropout.pth"))
23
- model1 = SqueezeNet1_0WithSE(num_classes=NUM_CLASSES).to(DEVICE)
24
- model1.load_state_dict(torch.load("output/checkpoints/SqueezeNet1_0WithSE.pth"))
25
- model3 = MobileNetV2WithDropout(num_classes=NUM_CLASSES).to(DEVICE)
26
- model3.load_state_dict(torch.load("output\checkpoints\MobileNetV2WithDropout.pth"))
27
-
28
- # Define the class labels
29
- class_labels = CLASSES
30
-
31
- # Define your test data folder path
32
- test_data_folder = "data/test/Task 1/"
33
-
34
-
35
- # Put models in evaluation mode
36
- def set_models_eval(models):
37
- for model in models:
38
- model.eval()
39
-
40
-
41
- # Define the ensemble model using a list of models
42
- class WeightedVoteEnsemble(nn.Module):
43
- def __init__(self, models, weights):
44
- super(WeightedVoteEnsemble, self).__init__()
45
- self.models = models
46
- self.weights = weights
47
-
48
- def forward(self, x):
49
- predictions = [model(x) for model in self.models]
50
- weighted_predictions = torch.stack(
51
- [w * pred for w, pred in zip(self.weights, predictions)], dim=0
52
- )
53
- avg_predictions = weighted_predictions.sum(dim=0)
54
- return avg_predictions
55
-
56
-
57
- def ensemble_predictions(models, image):
58
- all_predictions = []
59
-
60
- with torch.no_grad():
61
- for model in models:
62
- output = model(image)
63
- all_predictions.append(output)
64
-
65
- return torch.stack(all_predictions, dim=0).mean(dim=0)
66
-
67
-
68
- # Load a single image and make predictions
69
- def evaluate_image(models, image_path, transform=preprocess):
70
- image = Image.open(image_path).convert("RGB")
71
- image = transform(image).unsqueeze(0)
72
- image = image.to(DEVICE)
73
- outputs = ensemble_predictions(models, image)
74
-
75
- return outputs.argmax(dim=1).item()
76
-
77
-
78
- # Evaluate and plot a confusion matrix for an ensemble of models
79
- def evaluate_and_plot_confusion_matrix(models, test_data_folder):
80
- all_predictions = []
81
- true_labels = []
82
-
83
- with torch.no_grad():
84
- for class_label in class_labels:
85
- class_path = os.path.join(test_data_folder, class_label)
86
- for image_file in os.listdir(class_path):
87
- image_path = os.path.join(class_path, image_file)
88
- # print(image_path)
89
- predicted_label = evaluate_image(models, image_path, preprocess)
90
- all_predictions.append(predicted_label)
91
- true_labels.append(class_labels.index(class_label))
92
-
93
- # Print accuracy
94
- accuracy = (
95
- (torch.tensor(all_predictions) == torch.tensor(true_labels)).float().mean()
96
- )
97
- print("Accuracy:", accuracy)
98
-
99
- # Create the confusion matrix
100
- cm = confusion_matrix(true_labels, all_predictions)
101
-
102
- # Plot the confusion matrix
103
- display = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=class_labels)
104
- display.plot(cmap=plt.cm.Blues, values_format="d")
105
-
106
- # Show the plot
107
- plt.show()
108
-
109
- return accuracy
110
-
111
- # Set the models to evaluation mode
112
- set_models_eval([model1, model2, model3])
113
-
114
- # Define different weight configurations
115
- # [SqueezeNet, EfficientNetB2WithDropout, MobileNetV2WithDropout]
116
- weights_configurations = [
117
- # Random set of weights using random.random() and all weights sum to 1
118
- [
119
- random.randrange(1, 10) / 10,
120
- random.randrange(1, 10) / 10,
121
- random.randrange(1, 10) / 10,
122
- ],
123
- ]
124
-
125
-
126
- ## NOTE OF PREVIOUS WEIGHTS
127
- # Best weights: [0.2, 0.3, 0.5] with accuracy: 0.9428571462631226 at iteration: 15 with torch seed: 28434738589300 and random seed: 3188652458777471118 and torch cuda seed: None
128
-
129
-
130
- best_weights = {
131
- "weights": 0,
132
- "accuracy": 0,
133
- "iteration": 0,
134
- "torch_seed": 0,
135
- "random_seed": 0,
136
- "torch_cuda_seed": 0,
137
- }
138
-
139
- i = 0
140
-
141
- # weights_hist = []
142
-
143
- target_sum = 1.0
144
- number_of_numbers = 3
145
- lower_limit = 0.20
146
- upper_limit = 0.9
147
- step = 0.1
148
-
149
- valid_combinations = []
150
-
151
- # Generate all unique combinations of three numbers with values to two decimal places
152
- range_values = list(range(int(lower_limit * 100), int(upper_limit * 100) + 1))
153
- for combo in product(range_values, repeat=number_of_numbers):
154
- combo_float = [x / 100.0 for x in combo]
155
-
156
- # Check if the sum of the numbers is equal to 1
157
- if sum(combo_float) == target_sum:
158
- valid_combinations.append(combo_float)
159
-
160
- # Calculate the total number of possibilities
161
- total_possibilities = len(valid_combinations)
162
-
163
- print("Total number of possibilities:", total_possibilities)
164
-
165
- valid_combinations = [[0.37, 0.34, 0.29]]
166
-
167
- for weights in valid_combinations:
168
- # while True:
169
- print("---------------------------")
170
- print("Iteration:", i)
171
- # Should iterate until all possible weights are exhausted
172
- # Create an ensemble model with weighted voting
173
-
174
- random.seed(RANDOM_SEED)
175
- torch.cuda.manual_seed(RANDOM_SEED)
176
- torch.manual_seed(RANDOM_SEED)
177
- # print("PyTorch Seed:", torch.initial_seed())
178
- # weights_hist.append(weights)
179
- weighted_vote_ensemble_model = WeightedVoteEnsemble(
180
- # [model1, model2, model3], weights
181
- [model1, model2, model3],
182
- weights,
183
- )
184
- # print("Weights:", weights)
185
- print("Weights:", weights)
186
- # Call the evaluate_and_plot_confusion_matrix function with your models and test data folder
187
- accuracy = evaluate_and_plot_confusion_matrix(
188
- [weighted_vote_ensemble_model], test_data_folder
189
- )
190
- # Convert tensor to float
191
- accuracy = accuracy.item()
192
- if accuracy > best_weights["accuracy"]:
193
- # best_weights["weights"] = weights
194
- best_weights["weights"] = weights
195
- best_weights["accuracy"] = accuracy
196
- best_weights["iteration"] = i
197
- best_weights["torch_seed"] = torch.initial_seed()
198
- seed = random.randrange(sys.maxsize)
199
- rng = random.Random(seed)
200
- best_weights["random_seed"] = seed
201
- best_weights["torch_cuda_seed"] = torch.cuda.initial_seed()
202
-
203
- print(
204
- "Best weights:",
205
- best_weights["weights"],
206
- "with accuracy:",
207
- best_weights["accuracy"],
208
- "at iteration:",
209
- best_weights["iteration"],
210
- "with torch seed:",
211
- best_weights["torch_seed"],
212
- "and random seed:",
213
- best_weights["random_seed"],
214
- "and torch cuda seed:",
215
- best_weights["torch_cuda_seed"],
216
- )
217
- i += 1
218
-
219
-
220
- torch.save(
221
- weighted_vote_ensemble_model.state_dict(),
222
- "output/checkpoints/WeightedVoteEnsemble.pth",
223
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test-speed.py β†’ test_speed.py RENAMED
@@ -1,3 +1,4 @@
 
1
  from gradio_client import Client
2
  import time
3
  import csv
@@ -6,7 +7,7 @@ from matplotlib import rcParams
6
  from configs import *
7
  from PIL import Image
8
 
9
- client = Client("https://cycool29-handetect.hf.space/")
10
 
11
  list_of_times = []
12
 
@@ -25,33 +26,35 @@ for disease in CLASSES:
25
  image_path = r"data\test\Task 1\{}\{}".format(disease, image_path)
26
  start_time = time.time()
27
  result = client.predict(
28
- image_path,
29
- api_name="/predict"
 
 
30
  )
31
  time_taken = time.time() - start_time
32
  list_of_times.append(time_taken)
33
  print("Time taken:", time_taken)
34
 
35
  # Log to csv
36
- with open('log.csv', 'a', newline='') as file:
37
  writer = csv.writer(file)
38
  writer.writerow([disease])
39
  writer.writerow([image_path])
40
  writer.writerow([time_taken])
41
-
42
 
43
- print("Average time taken:", sum(list_of_times)/len(list_of_times))
 
44
  print("Max time taken:", max(list_of_times))
45
  print("Min time taken:", min(list_of_times))
46
  print("Total time taken:", sum(list_of_times))
47
- print("Median time taken:", sorted(list_of_times)[len(list_of_times)//2])
48
 
49
  # Plot the histogram
50
  plt.hist(list_of_times, bins=10)
51
  plt.xlabel("Time taken (s)")
52
  plt.ylabel("Frequency")
53
- plt.title("Time taken to process each image")
54
- plt.savefig("docs/efficientnet/time_taken_for_web.png")
55
 
56
 
57
  # Now is local
@@ -72,22 +75,22 @@ for disease in CLASSES:
72
  print("Time taken:", time_taken)
73
 
74
  # Log to csv
75
- with open('log.csv', 'a', newline='') as file:
76
  writer = csv.writer(file)
77
  writer.writerow([disease])
78
  writer.writerow([image_path])
79
  writer.writerow([time_taken])
80
 
81
 
82
- print("Average time taken local:", sum(list_of_times)/len(list_of_times))
83
  print("Max time taken local:", max(list_of_times))
84
  print("Min time taken local:", min(list_of_times))
85
  print("Total time taken local:", sum(list_of_times))
86
- print("Median time taken local:", sorted(list_of_times)[len(list_of_times)//2])
87
 
88
  # Plot the histogram
89
  plt.hist(list_of_times, bins=10)
90
- plt.xlabel("Time taken (s) local")
91
- plt.ylabel("Frequency local")
92
- plt.title("Time taken to process each image local")
93
- plt.savefig("docs/efficientnet/time_taken_for_local.png")
 
1
+ import os
2
  from gradio_client import Client
3
  import time
4
  import csv
 
7
  from configs import *
8
  from PIL import Image
9
 
10
+ client = Client("https://cycool29-spiralsense.hf.space/")
11
 
12
  list_of_times = []
13
 
 
26
  image_path = r"data\test\Task 1\{}\{}".format(disease, image_path)
27
  start_time = time.time()
28
  result = client.predict(
29
+ image_path,
30
+ False,
31
+ False,
32
+ fn_index=0,
33
  )
34
  time_taken = time.time() - start_time
35
  list_of_times.append(time_taken)
36
  print("Time taken:", time_taken)
37
 
38
  # Log to csv
39
+ with open("log.csv", "a", newline="") as file:
40
  writer = csv.writer(file)
41
  writer.writerow([disease])
42
  writer.writerow([image_path])
43
  writer.writerow([time_taken])
 
44
 
45
+
46
+ print("Average time taken:", sum(list_of_times) / len(list_of_times))
47
  print("Max time taken:", max(list_of_times))
48
  print("Min time taken:", min(list_of_times))
49
  print("Total time taken:", sum(list_of_times))
50
+ print("Median time taken:", sorted(list_of_times)[len(list_of_times) // 2])
51
 
52
  # Plot the histogram
53
  plt.hist(list_of_times, bins=10)
54
  plt.xlabel("Time taken (s)")
55
  plt.ylabel("Frequency")
56
+ plt.title("Time Taken to Process Each Image (Web)")
57
+ plt.savefig("docs/evaluation/time_taken_for_web.png")
58
 
59
 
60
  # Now is local
 
75
  print("Time taken:", time_taken)
76
 
77
  # Log to csv
78
+ with open("log.csv", "a", newline="") as file:
79
  writer = csv.writer(file)
80
  writer.writerow([disease])
81
  writer.writerow([image_path])
82
  writer.writerow([time_taken])
83
 
84
 
85
+ print("Average time taken local:", sum(list_of_times) / len(list_of_times))
86
  print("Max time taken local:", max(list_of_times))
87
  print("Min time taken local:", min(list_of_times))
88
  print("Total time taken local:", sum(list_of_times))
89
+ print("Median time taken local:", sorted(list_of_times)[len(list_of_times) // 2])
90
 
91
  # Plot the histogram
92
  plt.hist(list_of_times, bins=10)
93
+ plt.xlabel("Time taken (s)")
94
+ plt.ylabel("Frequency")
95
+ plt.title("Time taken to Process Each Image (Local)")
96
+ plt.savefig("docs/evaluation/time_taken_for_local.png")
train-svm.py DELETED
@@ -1,101 +0,0 @@
1
- import os
2
- import numpy as np
3
- from sklearn import svm
4
- from sklearn.model_selection import train_test_split
5
- from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
6
- from skimage.io import imread
7
- from skimage.transform import resize
8
- from sklearn.model_selection import train_test_split, RandomizedSearchCV
9
- from scipy.stats import uniform
10
- from configs import *
11
-
12
- # Set the path to your dataset folder, where each subfolder represents a class
13
- dataset_path = COMBINED_DATA_DIR + str(1)
14
-
15
-
16
- # Function to load, resize, and convert images to grayscale
17
- def load_resize_and_convert_to_gray(folder, target_size=(100, 100)):
18
- images = []
19
- for filename in os.listdir(folder):
20
- img_path = os.path.join(folder, filename)
21
- if os.path.isfile(img_path):
22
- img = imread(img_path, as_gray=True)
23
- img = resize(img, target_size, anti_aliasing=True)
24
- images.append(img)
25
- return images
26
-
27
-
28
- # Load, resize, and convert images to grayscale from folders
29
- X = [] # List to store images
30
- y = [] # List to store corresponding labels
31
-
32
- class_folders = os.listdir(dataset_path)
33
- class_folders.sort() # Sort the class folders to ensure consistent class ordering
34
-
35
- for class_folder in class_folders:
36
- class_path = os.path.join(dataset_path, class_folder)
37
- if os.path.isdir(class_path):
38
- images = load_resize_and_convert_to_gray(class_path)
39
- X.extend(images)
40
- y.extend([class_folder] * len(images)) # Assign labels based on folder name
41
-
42
- # Convert data to NumPy arrays
43
- X = np.array(X)
44
- y = np.array(y)
45
-
46
- # Split the dataset into training and testing sets
47
- X_train, X_test, y_train, y_test = train_test_split(
48
- X, y, test_size=0.2, random_state=42
49
- )
50
-
51
- # Define the parameter distributions for random search
52
- param_dist = {
53
- "C": uniform(loc=0, scale=10), # Randomly sample from [0, 10]
54
- "kernel": ["linear", "rbf", "poly"],
55
- "gamma": uniform(loc=0.001, scale=0.1), # Randomly sample from [0.001, 0.1]
56
- }
57
-
58
- # Flatten the images to a 1D array
59
- X_train_flat = X_train.reshape(X_train.shape[0], -1)
60
- X_test_flat = X_test.reshape(X_test.shape[0], -1)
61
-
62
- # Create an SVM classifier
63
- svm_classifier = svm.SVC()
64
-
65
- # Perform Randomized Search with cross-validation
66
- random_search = RandomizedSearchCV(
67
- svm_classifier,
68
- param_distributions=param_dist,
69
- n_iter=50,
70
- cv=5,
71
- n_jobs=-1,
72
- verbose=2,
73
- random_state=42,
74
- )
75
-
76
- # Fit the Randomized Search on the training data
77
- random_search.fit(X_train_flat, y_train)
78
-
79
- # Print the best hyperparameters
80
- print("Best Hyperparameters:")
81
- print(random_search.best_params_)
82
-
83
- # Get the best SVM model with the tuned hyperparameters
84
- best_svm_model = random_search.best_estimator_
85
-
86
- # Evaluate the best model on the test set
87
- y_pred = best_svm_model.predict(X_test_flat)
88
-
89
- # Calculate accuracy and other metrics
90
- accuracy = accuracy_score(y_test, y_pred)
91
- print("Accuracy:", accuracy)
92
-
93
- # Confusion Matrix
94
- conf_matrix = confusion_matrix(y_test, y_pred)
95
- print("Confusion Matrix:\n", conf_matrix)
96
-
97
- # You can also print other classification metrics like precision, recall, and F1-score
98
- from sklearn.metrics import classification_report
99
-
100
- report = classification_report(y_test, y_pred)
101
- print("Classification Report:\n", report)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
weight_averaging.py DELETED
@@ -1,235 +0,0 @@
1
- import sys
2
- import torch
3
- import torch.nn as nn
4
- from PIL import Image
5
- import os
6
- from configs import *
7
- from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
8
- import matplotlib.pyplot as plt
9
- import random
10
- from itertools import product
11
-
12
- random.seed(RANDOM_SEED)
13
- torch.cuda.manual_seed(RANDOM_SEED)
14
- torch.manual_seed(RANDOM_SEED)
15
- print("PyTorch Seed:", torch.initial_seed())
16
- print("Random Seed:", random.getstate()[1][0])
17
- print("PyTorch CUDA Seed:", torch.cuda.initial_seed())
18
-
19
- print("DEVICE:", DEVICE)
20
-
21
- # Define your model paths
22
- # Load your pre-trained models
23
- model2 = EfficientNetB3WithDropout(num_classes=NUM_CLASSES).to(DEVICE)
24
- model2.load_state_dict(torch.load("output/checkpoints/EfficientNetB3WithDropout.pth"))
25
- model1 = SqueezeNet1_0WithSE(num_classes=NUM_CLASSES).to(DEVICE)
26
- model1.load_state_dict(torch.load("output/checkpoints/SqueezeNet1_0WithSE.pth"))
27
- model3 = MobileNetV2WithDropout(num_classes=NUM_CLASSES).to(DEVICE)
28
- model3.load_state_dict(torch.load("output\checkpoints\MobileNetV2WithDropout.pth"))
29
- model4 = EfficientNetB2WithDropout(num_classes=NUM_CLASSES).to(DEVICE)
30
- model4.load_state_dict(torch.load("output\checkpoints\EfficientNetB2WithDropout.pth"))
31
-
32
- models = [model1, model2, model3, model4]
33
-
34
- # Define the class labels
35
- class_labels = CLASSES
36
-
37
- # Define your test data folder path
38
- test_data_folder = "data/test/Task 1/"
39
-
40
-
41
- # Put models in evaluation mode
42
- def set_models_eval(models):
43
- for model in models:
44
- model.eval()
45
-
46
-
47
- # Define the ensemble model using a list of models
48
- class WeightedVoteEnsemble(nn.Module):
49
- def __init__(self, models, weights):
50
- super(WeightedVoteEnsemble, self).__init__()
51
- self.models = models
52
- self.weights = weights
53
-
54
- def forward(self, x):
55
- predictions = [model(x) for model in self.models]
56
- weighted_predictions = torch.stack(
57
- [w * pred for w, pred in zip(self.weights, predictions)], dim=0
58
- )
59
- avg_predictions = weighted_predictions.sum(dim=0)
60
- return avg_predictions
61
-
62
-
63
- def ensemble_predictions(models, image):
64
- all_predictions = []
65
-
66
- with torch.no_grad():
67
- for model in models:
68
- output = model(image)
69
- all_predictions.append(output)
70
-
71
- return torch.stack(all_predictions, dim=0).mean(dim=0)
72
-
73
-
74
- # Load a single image and make predictions
75
- def evaluate_image(models, image_path, transform=preprocess):
76
- image = Image.open(image_path).convert("RGB")
77
- image = transform(image).unsqueeze(0)
78
- image = image.to(DEVICE)
79
- outputs = ensemble_predictions(models, image)
80
-
81
- return outputs.argmax(dim=1).item()
82
-
83
-
84
- # Evaluate and plot a confusion matrix for an ensemble of models
85
- def evaluate_and_plot_confusion_matrix(models, test_data_folder):
86
- all_predictions = []
87
- true_labels = []
88
-
89
- with torch.no_grad():
90
- for class_label in class_labels:
91
- class_path = os.path.join(test_data_folder, class_label)
92
- for image_file in os.listdir(class_path):
93
- image_path = os.path.join(class_path, image_file)
94
- # print(image_path)
95
- predicted_label = evaluate_image(models, image_path, preprocess)
96
- all_predictions.append(predicted_label)
97
- true_labels.append(class_labels.index(class_label))
98
-
99
- # Print accuracy
100
- accuracy = (
101
- (torch.tensor(all_predictions) == torch.tensor(true_labels)).float().mean()
102
- )
103
- print("Accuracy:", accuracy)
104
-
105
- # Create the confusion matrix
106
- # cm = confusion_matrix(true_labels, all_predictions)
107
-
108
- # # Plot the confusion matrix
109
- # display = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=class_labels)
110
- # display.plot(cmap=plt.cm.Blues, values_format="d")
111
-
112
- # # Show the plot
113
- # plt.show()
114
-
115
- return accuracy
116
-
117
- # Set the models to evaluation mode
118
- set_models_eval(models)
119
-
120
- # Define different weight configurations
121
- # [SqueezeNet, EfficientNetB2WithDropout, MobileNetV2WithDropout]
122
- weights_configurations = [
123
- # Random set of weights using random.random() and all weights sum to 1
124
- [
125
- random.randrange(1, 10) / 10,
126
- random.randrange(1, 10) / 10,
127
- random.randrange(1, 10) / 10,
128
- ],
129
- ]
130
-
131
-
132
- ## NOTE OF PREVIOUS WEIGHTS
133
- # Best weights: [0.2, 0.3, 0.5] with accuracy: 0.9428571462631226 at iteration: 15 with torch seed: 28434738589300 and random seed: 3188652458777471118 and torch cuda seed: None
134
-
135
-
136
- best_weights = {
137
- "weights": 0,
138
- "accuracy": 0,
139
- "iteration": 0,
140
- "torch_seed": 0,
141
- "random_seed": 0,
142
- "torch_cuda_seed": 0,
143
- }
144
-
145
- i = 0
146
-
147
- # weights_hist = []
148
-
149
- target_sum = 1.0
150
- number_of_numbers = 4
151
- lower_limit = 0.2
152
- upper_limit = 0.8
153
- step = 0.01
154
-
155
- valid_combinations = []
156
-
157
- # Generate all unique combinations of four numbers with values to two decimal places
158
- for combination in product(
159
- *[range(int(lower_limit * 100), int(upper_limit * 100) + 1)] * number_of_numbers
160
- ):
161
- # Convert the combination to a list of floats
162
- combination = [float(number) / 100 for number in combination]
163
- # Check if the sum of the combination is equal to the target sum
164
- if sum(combination) == target_sum:
165
- # Add the combination to the list of valid combinations
166
- valid_combinations.append(combination)
167
-
168
-
169
- # Calculate the total number of possibilities
170
- total_possibilities = len(valid_combinations)
171
-
172
- print("Total number of possibilities:", total_possibilities)
173
-
174
- # valid_combinations = [[0.3, 0.5, 0.2]]
175
- # 0.38 for SqueezeNet, 0.34 for EfficientNetB2WithDropout, 0.28 for MobileNetV2WithDropout
176
- best_weighted_vote_ensemble_model = None
177
-
178
- for weights in valid_combinations:
179
- # while True:
180
- print("---------------------------")
181
- print("Iteration:", i)
182
- # Should iterate until all possible weights are exhausted
183
- # Create an ensemble model with weighted voting
184
-
185
- random.seed(RANDOM_SEED)
186
- torch.cuda.manual_seed(RANDOM_SEED)
187
- torch.manual_seed(RANDOM_SEED)
188
- # print("PyTorch Seed:", torch.initial_seed())
189
- # weights_hist.append(weights)
190
- weighted_vote_ensemble_model = WeightedVoteEnsemble(
191
- # [model1, model2, model3], weights
192
- models,
193
- weights,
194
- )
195
- # print("Weights:", weights)
196
- print("Weights:", weights)
197
- # Call the evaluate_and_plot_confusion_matrix function with your models and test data folder
198
- accuracy = evaluate_and_plot_confusion_matrix(
199
- [weighted_vote_ensemble_model], test_data_folder
200
- )
201
- # Convert tensor to float
202
- accuracy = accuracy.item()
203
- if accuracy > best_weights["accuracy"]:
204
- # best_weights["weights"] = weights
205
- best_weights["weights"] = weights
206
- best_weights["accuracy"] = accuracy
207
- best_weights["iteration"] = i
208
- best_weights["torch_seed"] = torch.initial_seed()
209
- seed = random.randrange(sys.maxsize)
210
- rng = random.Random(seed)
211
- best_weights["random_seed"] = seed
212
- best_weights["torch_cuda_seed"] = torch.cuda.initial_seed()
213
- best_weighted_vote_ensemble_model = weighted_vote_ensemble_model
214
-
215
- print(
216
- "Best weights:",
217
- best_weights["weights"],
218
- "with accuracy:",
219
- best_weights["accuracy"],
220
- "at iteration:",
221
- best_weights["iteration"],
222
- "with torch seed:",
223
- best_weights["torch_seed"],
224
- "and random seed:",
225
- best_weights["random_seed"],
226
- "and torch cuda seed:",
227
- best_weights["torch_cuda_seed"],
228
- )
229
- i += 1
230
-
231
-
232
- torch.save(
233
- best_weighted_vote_ensemble_model.state_dict(),
234
- "output/checkpoints/WeightedVoteEnsemble.pth",
235
- )