StarNet88 commited on
Commit
1a8b056
·
verified ·
1 Parent(s): b74b7b0

Upload model_development.py

Browse files
Files changed (1) hide show
  1. model_development.py +647 -0
model_development.py ADDED
@@ -0,0 +1,647 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """Model_Development
3
+
4
+ Automatically generated by Colab.
5
+
6
+ Original file is located at
7
+ https://colab.research.google.com/drive/1BPWPi-oYa82w42fjYxMY7SVOU2XwedyW
8
+ """
9
+
10
+ import tensorflow as tf
11
+ from tensorflow.keras.models import Sequential
12
+ from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
13
+ from tensorflow.keras.preprocessing.image import ImageDataGenerator
14
+ from tensorflow.keras.utils import image_dataset_from_directory
15
+ import os
16
+ import numpy as np
17
+ import keras
18
+ from keras import layers
19
+ from tensorflow import data as tf_data
20
+ import matplotlib.pyplot as plt
21
+
22
+ !unzip "/content/drive/MyDrive/Caitlin Bodzy/Data/constellations.zip" -d "/content"
23
+
24
+
25
+
26
+ # Preparing our data
27
+ directory = "/content/content/constellations2"
28
+ image_size = (128, 128)
29
+ batch_size = 64
30
+
31
+ train_ds, val_ds = image_dataset_from_directory(
32
+ directory,
33
+ validation_split=0.2,
34
+ subset="both",
35
+ seed=1337,
36
+ image_size=image_size,
37
+ batch_size=batch_size,
38
+
39
+ )
40
+
41
+ plt.figure(figsize=(10, 10))
42
+ for images, labels in train_ds.take(1):
43
+ for i in range(9):
44
+ ax = plt.subplot(3, 3, i + 1)
45
+ plt.imshow(np.array(images[i]).astype("uint8"))
46
+ plt.title(int(labels[i]))
47
+ plt.axis("off")
48
+
49
+ def make_model(input_shape, num_classes):
50
+ inputs = keras.Input(shape=input_shape)
51
+
52
+ # Entry block
53
+ x = layers.Rescaling(1.0 / 255)(inputs)
54
+ x = layers.Conv2D(128, 3, strides=2, padding="same")(x)
55
+ x = layers.BatchNormalization()(x)
56
+ x = layers.Activation("relu")(x)
57
+
58
+ previous_block_activation = x # Set aside residual
59
+
60
+ for size in [256, 512, 728]:
61
+ x = layers.Activation("relu")(x)
62
+ x = layers.SeparableConv2D(size, 3, padding="same")(x)
63
+ x = layers.BatchNormalization()(x)
64
+
65
+ x = layers.Activation("relu")(x)
66
+ x = layers.SeparableConv2D(size, 3, padding="same")(x)
67
+ x = layers.BatchNormalization()(x)
68
+
69
+ x = layers.MaxPooling2D(3, strides=2, padding="same")(x)
70
+
71
+ # Project residual
72
+ residual = layers.Conv2D(size, 1, strides=2, padding="same")(
73
+ previous_block_activation
74
+ )
75
+ x = layers.add([x, residual]) # Add back residual
76
+ previous_block_activation = x # Set aside next residual
77
+
78
+ x = layers.SeparableConv2D(1024, 3, padding="same")(x)
79
+ x = layers.BatchNormalization()(x)
80
+ x = layers.Activation("relu")(x)
81
+
82
+ x = layers.GlobalAveragePooling2D()(x)
83
+ if num_classes == 2:
84
+ units = 1
85
+ else:
86
+ units = num_classes
87
+
88
+ x = layers.Dropout(0.25)(x)
89
+ # We specify activation=None so as to return logits
90
+ outputs = layers.Dense(units, activation=None)(x)
91
+ return keras.Model(inputs, outputs)
92
+
93
+ num_classes = 89
94
+ model = make_model(input_shape=image_size + (3,), num_classes=num_classes)
95
+ keras.utils.plot_model(model, show_shapes=True)
96
+
97
+ epochs = 25
98
+
99
+ callbacks = [
100
+ keras.callbacks.ModelCheckpoint("save_at_{epoch}.keras"),
101
+ ]
102
+ model.compile(
103
+ optimizer='adam',
104
+ loss='sparse_categorical_crossentropy',
105
+ metrics=['accuracy']
106
+ )
107
+ model.fit(
108
+ train_ds,
109
+ epochs=epochs,
110
+ callbacks=callbacks,
111
+ validation_data=val_ds,
112
+
113
+ )
114
+
115
+ """#Pytorch time"""
116
+
117
+ import os
118
+ import torch
119
+ import pandas as pd
120
+ from skimage import io, transform
121
+ import numpy as np
122
+ import matplotlib.pyplot as plt
123
+ from torch.utils.data import Dataset, DataLoader
124
+ from torchvision import transforms, utils
125
+ from torchvision.datasets import ImageFolder
126
+ from torchvision import datasets, models, transforms
127
+ from tqdm import tqdm
128
+ import torch.optim as optim
129
+ import pickle
130
+
131
+ transform = transforms.Compose(
132
+ [transforms.ToTensor(),
133
+ transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
134
+
135
+ # can use ImageFolderDataset
136
+ path = "/content/content/constellations2"
137
+ dataset = ImageFolder(path, transform = transform)
138
+
139
+ train_dataset, test_dataset = torch.utils.data.random_split(dataset, [0.8, 0.2])
140
+
141
+ batch_size = 64
142
+ trainloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size,
143
+ shuffle=True, num_workers=2)
144
+ testloader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size,
145
+ shuffle=False, num_workers=2)
146
+
147
+ def train_model(model, train_loader, val_loader, criterion, optimizer, num_epochs=10, device="cuda"):
148
+ """
149
+ Trains a PyTorch model and prints training + validation loss/accuracy each epoch.
150
+
151
+ Args:
152
+ model: nn.Module - your model
153
+ train_loader: DataLoader - training data
154
+ val_loader: DataLoader - validation data
155
+ criterion: loss function (e.g. nn.CrossEntropyLoss)
156
+ optimizer: optimizer (e.g. Adam, SGD)
157
+ num_epochs: int - number of training epochs
158
+ device: 'cuda' or 'cpu'
159
+ """
160
+
161
+ model.to(device)
162
+ # Initialize history dictionary
163
+ history = {
164
+ "train_loss": [],
165
+ "train_acc": [],
166
+ "val_loss": [],
167
+ "val_acc": []
168
+ }
169
+ best_accuracy = 0
170
+ for epoch in range(num_epochs):
171
+ # --- Training phase ---
172
+ model.train() # set model to training mode
173
+ running_loss = 0.0
174
+ correct = 0
175
+ total = 0
176
+ print(f"\nEpoch [{epoch+1}/{num_epochs}]")
177
+ train_pbar = tqdm(train_loader, desc="Training", leave=False)
178
+ for inputs, labels in train_pbar:
179
+ # Move data to GPU/CPU
180
+ inputs, labels = inputs.to(device), labels.to(device)
181
+
182
+ # Zero gradients for this batch
183
+ optimizer.zero_grad()
184
+
185
+ # Forward pass
186
+ outputs = model(inputs)
187
+ loss = criterion(outputs, labels)
188
+
189
+ # Backward pass + optimization
190
+ loss.backward()
191
+ optimizer.step()
192
+
193
+ # Update training loss
194
+ running_loss += loss.item() * inputs.size(0)
195
+
196
+ # Get predictions (highest logit = predicted class)
197
+ _, predicted = torch.max(outputs, 1)
198
+ total += labels.size(0)
199
+ correct += (predicted == labels).sum().item()
200
+ # live update in progress bar
201
+ train_pbar.set_postfix(loss=loss.item())
202
+ epoch_train_loss = running_loss / len(train_loader.dataset)
203
+ epoch_train_acc = 100 * correct / total
204
+ history["train_loss"].append(epoch_train_loss)
205
+ history["train_acc"].append(epoch_train_acc)
206
+ # --- Validation phase ---
207
+ model.eval()
208
+ val_loss, val_correct, val_total = 0.0, 0, 0
209
+
210
+ val_pbar = tqdm(val_loader, desc="Validating", leave=False)
211
+ with torch.no_grad():
212
+ for inputs, labels in val_pbar:
213
+ inputs, labels = inputs.to(device), labels.to(device)
214
+ outputs = model(inputs)
215
+ loss = criterion(outputs, labels)
216
+
217
+ val_loss += loss.item() * inputs.size(0)
218
+ _, predicted = torch.max(outputs, 1)
219
+ val_total += labels.size(0)
220
+ val_correct += (predicted == labels).sum().item()
221
+
222
+ # live update in progress bar
223
+ val_pbar.set_postfix(loss=loss.item())
224
+
225
+ epoch_val_loss = val_loss / len(val_loader.dataset)
226
+ epoch_val_acc = 100 * val_correct / val_total
227
+ if epoch_val_acc > best_accuracy:
228
+ best_accuracy = epoch_val_acc
229
+ torch.save(model.state_dict(), "best_model_params.pt")
230
+ history["val_loss"].append(epoch_val_loss)
231
+ history["val_acc"].append(epoch_val_acc)
232
+ # --- Print results at end of epoch ---
233
+ print(f"Epoch [{epoch+1}/{num_epochs}] "
234
+ f"Train Loss: {epoch_train_loss:.4f}, Train Acc: {epoch_train_acc:.2f}% "
235
+ f"| Val Loss: {epoch_val_loss:.4f}, Val Acc: {epoch_val_acc:.2f}%")
236
+ print("\n✅ Training complete.")
237
+ return model, history
238
+
239
+ import torch.nn as nn
240
+ import torch.nn.functional as F
241
+
242
+
243
+ class Net(nn.Module):
244
+ def __init__(self):
245
+ super().__init__()
246
+ self.conv1 = nn.Conv2d(3, 32, 5, stride=2, padding=2) # downsample early
247
+ self.conv2 = nn.Conv2d(32, 64, 3, stride=2, padding=1)
248
+ self.conv3 = nn.Conv2d(64, 128, 3, stride=2, padding=1)
249
+ self.conv4 = nn.Conv2d(128, 256, 3, stride=2, padding=1)
250
+
251
+ # Global average pooling (output shape = batch × 256)
252
+ self.gap = nn.AdaptiveAvgPool2d((1, 1))
253
+
254
+ # Small fully connected head
255
+ self.fc1 = nn.Linear(256, 128)
256
+ self.fc2 = nn.Linear(128, 89)
257
+
258
+ def forward(self, x):
259
+ x = F.relu(self.conv1(x))
260
+ x = F.relu(self.conv2(x))
261
+ x = F.relu(self.conv3(x))
262
+ x = F.relu(self.conv4(x))
263
+ x = self.gap(x) # -> (batch, 256, 1, 1)
264
+ x = torch.flatten(x, 1) # -> (batch, 256)
265
+ x = F.relu(self.fc1(x))
266
+ x = self.fc2(x)
267
+ return x
268
+
269
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
270
+ print("Using device:", device)
271
+ model = Net().to(device)
272
+ criterion = nn.CrossEntropyLoss()
273
+ optimizer = optim.Adam(model.parameters(), lr=1e-3)
274
+ num_epochs = 50
275
+ model, history = train_model(model, trainloader, testloader, criterion, optimizer, num_epochs=num_epochs, device=device)
276
+
277
+ with open('custom_cnn_history.pkl', 'wb') as f:
278
+ pickle.dump(history, f)
279
+
280
+ """Results for 50 epochs:
281
+
282
+ Using device: cuda
283
+
284
+ Epoch [1/50]
285
+ Epoch [1/50] Train Loss: 4.3550, Train Acc: 1.81% | Val Loss: 4.0249, Val Acc: 2.54%
286
+
287
+ Epoch [2/50]
288
+ Epoch [2/50] Train Loss: 3.8108, Train Acc: 3.31% | Val Loss: 3.6244, Val Acc: 3.45%
289
+
290
+ Epoch [3/50]
291
+ Epoch [3/50] Train Loss: 3.4859, Train Acc: 6.98% | Val Loss: 3.3346, Val Acc: 5.63%
292
+
293
+ Epoch [4/50]
294
+ Epoch [4/50] Train Loss: 3.2355, Train Acc: 8.43% | Val Loss: 3.1397, Val Acc: 12.89%
295
+
296
+ Epoch [5/50]
297
+ Epoch [5/50] Train Loss: 3.0890, Train Acc: 11.51% | Val Loss: 3.0306, Val Acc: 12.16%
298
+
299
+ Epoch [6/50]
300
+ Epoch [6/50] Train Loss: 3.1845, Train Acc: 9.11% | Val Loss: 3.0034, Val Acc: 19.60%
301
+
302
+ Epoch [7/50]
303
+ Epoch [7/50] Train Loss: 2.8859, Train Acc: 15.45% | Val Loss: 2.6902, Val Acc: 15.97%
304
+
305
+ Epoch [8/50]
306
+ Epoch [8/50] Train Loss: 2.7958, Train Acc: 16.54% | Val Loss: 2.7449, Val Acc: 16.70%
307
+
308
+ Epoch [9/50]
309
+ Epoch [9/50] Train Loss: 2.5519, Train Acc: 22.34% | Val Loss: 2.7096, Val Acc: 17.79%
310
+
311
+ Epoch [10/50]
312
+ Epoch [10/50] Train Loss: 2.4776, Train Acc: 23.33% | Val Loss: 2.4054, Val Acc: 24.68%
313
+
314
+ Epoch [11/50]
315
+ Epoch [11/50] Train Loss: 2.2965, Train Acc: 29.50% | Val Loss: 2.2966, Val Acc: 23.96%
316
+
317
+ Epoch [12/50]
318
+ Epoch [12/50] Train Loss: 2.0906, Train Acc: 33.57% | Val Loss: 2.0627, Val Acc: 36.30%
319
+
320
+ Epoch [13/50]
321
+ Epoch [13/50] Train Loss: 2.0251, Train Acc: 37.52% | Val Loss: 1.9627, Val Acc: 37.57%
322
+
323
+ Epoch [14/50]
324
+ Epoch [14/50] Train Loss: 1.7805, Train Acc: 44.09% | Val Loss: 1.8681, Val Acc: 40.83%
325
+
326
+ Epoch [15/50]
327
+ Epoch [15/50] Train Loss: 1.7417, Train Acc: 43.04% | Val Loss: 1.5517, Val Acc: 51.36%
328
+
329
+ Epoch [16/50]
330
+ Epoch [16/50] Train Loss: 1.5492, Train Acc: 47.80% | Val Loss: 1.5065, Val Acc: 51.18%
331
+
332
+ Epoch [17/50]
333
+ Epoch [17/50] Train Loss: 1.5765, Train Acc: 48.39% | Val Loss: 1.4849, Val Acc: 52.99%
334
+
335
+ Epoch [18/50]
336
+ Epoch [18/50] Train Loss: 1.3129, Train Acc: 57.68% | Val Loss: 1.1928, Val Acc: 58.62%
337
+
338
+ Epoch [19/50]
339
+ Epoch [19/50] Train Loss: 1.6431, Train Acc: 46.35% | Val Loss: 1.3933, Val Acc: 54.81%
340
+
341
+ Epoch [20/50]
342
+ Epoch [20/50] Train Loss: 1.1105, Train Acc: 64.20% | Val Loss: 1.2303, Val Acc: 57.89%
343
+
344
+ Epoch [21/50]
345
+ Epoch [21/50] Train Loss: 1.1097, Train Acc: 61.53% | Val Loss: 0.9919, Val Acc: 65.88%
346
+
347
+ Epoch [22/50]
348
+ Epoch [22/50] Train Loss: 0.9873, Train Acc: 66.65% | Val Loss: 0.9837, Val Acc: 65.52%
349
+
350
+ Epoch [23/50]
351
+ Epoch [23/50] Train Loss: 0.8362, Train Acc: 70.00% | Val Loss: 1.1519, Val Acc: 62.61%
352
+
353
+ Epoch [24/50]
354
+ Epoch [24/50] Train Loss: 0.9181, Train Acc: 67.47% | Val Loss: 0.9100, Val Acc: 70.05%
355
+
356
+ Epoch [25/50]
357
+ Epoch [25/50] Train Loss: 1.0156, Train Acc: 65.52% | Val Loss: 0.9139, Val Acc: 67.70%
358
+
359
+ Epoch [26/50]
360
+ Epoch [26/50] Train Loss: 0.7847, Train Acc: 73.72% | Val Loss: 0.6174, Val Acc: 82.94%
361
+
362
+ Epoch [27/50]
363
+ Epoch [27/50] Train Loss: 0.8881, Train Acc: 70.41% | Val Loss: 1.0006, Val Acc: 60.80%
364
+
365
+ Epoch [28/50]
366
+ Epoch [28/50] Train Loss: 0.9419, Train Acc: 69.05% | Val Loss: 0.6462, Val Acc: 83.85%
367
+
368
+ Epoch [29/50]
369
+ Epoch [29/50] Train Loss: 0.6375, Train Acc: 78.84% | Val Loss: 0.6832, Val Acc: 76.23%
370
+
371
+ Epoch [30/50]
372
+ Epoch [30/50] Train Loss: 0.5708, Train Acc: 78.66% | Val Loss: 0.6045, Val Acc: 78.04%
373
+
374
+ Epoch [31/50]
375
+ Epoch [31/50] Train Loss: 0.5209, Train Acc: 81.15% | Val Loss: 0.8075, Val Acc: 76.77%
376
+
377
+ Epoch [32/50]
378
+ Epoch [32/50] Train Loss: 0.6596, Train Acc: 77.03% | Val Loss: 0.5404, Val Acc: 82.21%
379
+
380
+ Epoch [33/50]
381
+ Epoch [33/50] Train Loss: 0.4934, Train Acc: 84.05% | Val Loss: 0.3702, Val Acc: 87.66%
382
+
383
+ Epoch [34/50]
384
+ Epoch [34/50] Train Loss: 0.5477, Train Acc: 79.97% | Val Loss: 0.4291, Val Acc: 85.48%
385
+
386
+ Epoch [35/50]
387
+ Epoch [35/50] Train Loss: 0.4817, Train Acc: 83.55% | Val Loss: 0.6402, Val Acc: 76.23%
388
+
389
+ Epoch [36/50]
390
+ Epoch [36/50] Train Loss: 0.7414, Train Acc: 73.95% | Val Loss: 0.7658, Val Acc: 74.23%
391
+
392
+ Epoch [37/50]
393
+ Epoch [37/50] Train Loss: 0.4875, Train Acc: 83.64% | Val Loss: 0.5194, Val Acc: 79.13%
394
+
395
+ Epoch [38/50]
396
+ Epoch [38/50] Train Loss: 0.7001, Train Acc: 74.94% | Val Loss: 0.4669, Val Acc: 82.40%
397
+
398
+ Epoch [39/50]
399
+ Epoch [39/50] Train Loss: 0.4260, Train Acc: 86.27% | Val Loss: 0.4313, Val Acc: 84.21%
400
+
401
+ Epoch [40/50]
402
+ Epoch [40/50] Train Loss: 0.4358, Train Acc: 84.05% | Val Loss: 1.0168, Val Acc: 66.79%
403
+
404
+ Epoch [41/50]
405
+ Epoch [41/50] Train Loss: 0.4003, Train Acc: 85.50% | Val Loss: 0.4285, Val Acc: 85.12%
406
+
407
+ Epoch [42/50]
408
+ Epoch [42/50] Train Loss: 0.3837, Train Acc: 86.91% | Val Loss: 0.6751, Val Acc: 78.40%
409
+
410
+ Epoch [43/50]
411
+ Epoch [43/50] Train Loss: 0.4011, Train Acc: 85.46% | Val Loss: 1.9752, Val Acc: 55.54%
412
+
413
+ Epoch [44/50]
414
+ Epoch [44/50] Train Loss: 0.9230, Train Acc: 73.18% | Val Loss: 0.4821, Val Acc: 84.94%
415
+
416
+ Epoch [45/50]
417
+ Epoch [45/50] Train Loss: 0.3531, Train Acc: 89.13% | Val Loss: 0.3267, Val Acc: 90.38%
418
+
419
+ Epoch [46/50]
420
+ Epoch [46/50] Train Loss: 0.3086, Train Acc: 89.40% | Val Loss: 0.3978, Val Acc: 85.30%
421
+
422
+ Epoch [47/50]
423
+ Epoch [47/50] Train Loss: 0.3021, Train Acc: 89.49% | Val Loss: 0.3236, Val Acc: 88.02%
424
+
425
+ Epoch [48/50]
426
+ Epoch [48/50] Train Loss: 0.3974, Train Acc: 85.27% | Val Loss: 0.3593, Val Acc: 87.11%
427
+
428
+ Epoch [49/50]
429
+ Epoch [49/50] Train Loss: 0.2615, Train Acc: 90.39% | Val Loss: 0.2154, Val Acc: 92.38%
430
+
431
+ Epoch [50/50]
432
+ Epoch [50/50] Train Loss: 0.2437, Train Acc: 92.03% | Val Loss: 0.3268, Val Acc: 88.38%
433
+
434
+ ✅ Training complete.
435
+ """
436
+
437
+ import matplotlib.pyplot as plt
438
+
439
+ # summarize history for accuracy
440
+ plt.plot(history['train_acc'])
441
+ plt.plot(history['val_acc'])
442
+ plt.title('custom cnn model accuracy')
443
+ plt.ylabel('accuracy')
444
+ plt.xlabel('epoch')
445
+ plt.legend(['Train', 'Validation'], loc='upper left')
446
+ plt.show()
447
+ # summarize history for loss
448
+ plt.plot(history['train_loss'])
449
+ plt.plot(history['val_loss'])
450
+ plt.title('custom cnn model loss')
451
+ plt.ylabel('loss')
452
+ plt.xlabel('epoch')
453
+ plt.legend(['Train', 'Validation'], loc='upper left')
454
+ plt.show()
455
+
456
+ """#resnet"""
457
+
458
+ #Different model
459
+ model_ft = models.resnet18(weights='IMAGENET1K_V1')
460
+ num_ftrs = model_ft.fc.in_features
461
+ # Here the size of each output sample is set to 2.
462
+ # Alternatively, it can be generalized to ``nn.Linear(num_ftrs, len(class_names))``.
463
+ model_ft.fc = nn.Linear(num_ftrs, 89)
464
+
465
+ from torchvision.datasets import ImageFolder
466
+ import torchvision.transforms as transforms
467
+ import torch
468
+
469
+ # Standard ResNet preprocessing
470
+ image_transforms = transforms.Compose([
471
+ transforms.Resize((224, 224)),
472
+ transforms.ToTensor(),
473
+ transforms.Normalize([0.485, 0.456, 0.406],
474
+ [0.229, 0.224, 0.225]) # ImageNet stats
475
+ ])
476
+ batch_size = 64
477
+ # can use ImageFolderDataset
478
+ path = "/content/content/constellations2"
479
+ dataset = ImageFolder(path, transform = image_transforms)
480
+ train_dataset, test_dataset = torch.utils.data.random_split(dataset, [0.8, 0.2])
481
+ trainloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size,
482
+ shuffle=True, num_workers=2)
483
+ testloader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size,
484
+ shuffle=False, num_workers=2)
485
+
486
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
487
+ print("Using device:", device)
488
+ model = Net().to(device)
489
+ criterion = nn.CrossEntropyLoss()
490
+ optimizer = optim.Adam(model.parameters(), lr=1e-3)
491
+ model, history = train_model(model_ft, trainloader, testloader, criterion, optimizer, num_epochs=50, device=device)
492
+
493
+ # summarize history for accuracy
494
+ plt.plot(history['train_acc'])
495
+ plt.plot(history['val_acc'])
496
+ plt.title('resnet model accuracy')
497
+ plt.ylabel('accuracy')
498
+ plt.xlabel('epoch')
499
+ plt.legend(['Train', 'Validation'], loc='upper left')
500
+ plt.show()
501
+ # summarize history for loss
502
+ plt.plot(history['train_loss'])
503
+ plt.plot(history['val_loss'])
504
+ plt.title('resnet model loss')
505
+ plt.ylabel('loss')
506
+ plt.xlabel('epoch')
507
+ plt.legend(['Train', 'Validation'], loc='upper left')
508
+ plt.show()
509
+
510
+ """Chat gpt improved resnet18 model"""
511
+
512
+ # ==== Imports ====
513
+ import torch
514
+ import torch.nn as nn
515
+ import torch.optim as optim
516
+ from torchvision import models, transforms
517
+ from torchvision.datasets import ImageFolder
518
+ from torch.utils.data import DataLoader, random_split
519
+ from tqdm import tqdm
520
+ import matplotlib.pyplot as plt
521
+
522
+ # ==== 1. Device setup ====
523
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
524
+ print("Using device:", device)
525
+
526
+ # ==== 2. Data setup with augmentations ====
527
+ path = "/content/content/constellations2"
528
+
529
+ image_transforms = transforms.Compose([
530
+ transforms.Resize((224, 224)),
531
+ transforms.RandomHorizontalFlip(),
532
+ transforms.RandomRotation(10),
533
+ transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
534
+ transforms.ToTensor(),
535
+ transforms.Normalize([0.485, 0.456, 0.406],
536
+ [0.229, 0.224, 0.225]) # ImageNet normalization
537
+ ])
538
+
539
+ dataset = ImageFolder(path, transform=image_transforms)
540
+
541
+ # Split dataset into train/test
542
+ train_size = int(0.8 * len(dataset))
543
+ test_size = len(dataset) - train_size
544
+ train_dataset, test_dataset = random_split(dataset, [train_size, test_size])
545
+
546
+ # DataLoaders
547
+ batch_size = 64
548
+ trainloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=2)
549
+ testloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=2)
550
+
551
+ # ==== 3. Model setup ====
552
+ model_ft = models.resnet18(weights='IMAGENET1K_V1')
553
+ num_ftrs = model_ft.fc.in_features
554
+ model_ft.fc = nn.Linear(num_ftrs, 89) # 89 output classes
555
+ model_ft = model_ft.to(device)
556
+
557
+ # ==== 4. Loss and optimizer ====
558
+ criterion = nn.CrossEntropyLoss()
559
+ optimizer = optim.Adam(model_ft.parameters(), lr=1e-4, weight_decay=1e-4)
560
+ scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5)
561
+
562
+ # ==== 5. Training function ====
563
+ def train_model(model, train_loader, val_loader, criterion, optimizer, scheduler, num_epochs, device):
564
+ history = {'train_loss': [], 'val_loss': [], 'train_acc': [], 'val_acc': []}
565
+
566
+ for epoch in range(num_epochs):
567
+ print(f"\nEpoch [{epoch+1}/{num_epochs}]")
568
+ model.train()
569
+ train_loss, correct, total = 0.0, 0, 0
570
+
571
+ for inputs, labels in tqdm(train_loader, desc="Training", leave=False):
572
+ inputs, labels = inputs.to(device), labels.to(device)
573
+ optimizer.zero_grad()
574
+ outputs = model(inputs)
575
+ loss = criterion(outputs, labels)
576
+ loss.backward()
577
+ optimizer.step()
578
+
579
+ train_loss += loss.item() * inputs.size(0)
580
+ _, predicted = torch.max(outputs, 1)
581
+ total += labels.size(0)
582
+ correct += (predicted == labels).sum().item()
583
+
584
+ scheduler.step()
585
+
586
+ train_acc = 100 * correct / total
587
+ val_loss, val_acc = evaluate(model, val_loader, criterion, device)
588
+
589
+ history['train_loss'].append(train_loss / len(train_loader.dataset))
590
+ history['val_loss'].append(val_loss)
591
+ history['train_acc'].append(train_acc)
592
+ history['val_acc'].append(val_acc)
593
+
594
+ print(f"Train Loss: {train_loss/len(train_loader.dataset):.4f} | "
595
+ f"Train Acc: {train_acc:.2f}% | "
596
+ f"Val Loss: {val_loss:.4f} | "
597
+ f"Val Acc: {val_acc:.2f}%")
598
+
599
+ return model, history
600
+
601
+ # ==== 6. Validation function ====
602
+ def evaluate(model, loader, criterion, device):
603
+ model.eval()
604
+ loss_total, correct, total = 0.0, 0, 0
605
+ with torch.no_grad():
606
+ for inputs, labels in loader:
607
+ inputs, labels = inputs.to(device), labels.to(device)
608
+ outputs = model(inputs)
609
+ loss = criterion(outputs, labels)
610
+ loss_total += loss.item() * inputs.size(0)
611
+ _, predicted = torch.max(outputs, 1)
612
+ total += labels.size(0)
613
+ correct += (predicted == labels).sum().item()
614
+ avg_loss = loss_total / len(loader.dataset)
615
+ acc = 100 * correct / total
616
+ return avg_loss, acc
617
+
618
+ # ==== 7. Train model ====
619
+ model_ft, history = train_model(
620
+ model_ft,
621
+ trainloader,
622
+ testloader,
623
+ criterion,
624
+ optimizer,
625
+ scheduler,
626
+ num_epochs=30,
627
+ device=device
628
+ )
629
+
630
+ # ==== 8. Visualization ====
631
+ plt.figure(figsize=(10,5))
632
+ plt.plot(history['train_acc'], label='Train Accuracy')
633
+ plt.plot(history['val_acc'], label='Validation Accuracy')
634
+ plt.title('ResNet18 Model Accuracy')
635
+ plt.xlabel('Epoch')
636
+ plt.ylabel('Accuracy (%)')
637
+ plt.legend()
638
+ plt.show()
639
+
640
+ plt.figure(figsize=(10,5))
641
+ plt.plot(history['train_loss'], label='Train Loss')
642
+ plt.plot(history['val_loss'], label='Validation Loss')
643
+ plt.title('ResNet18 Model Loss')
644
+ plt.xlabel('Epoch')
645
+ plt.ylabel('Loss')
646
+ plt.legend()
647
+ plt.show()