added more models for testing

This commit is contained in:
2026-05-05 21:04:33 +02:00
parent 1c04344ad6
commit 4cc9fa2bac
11 changed files with 143 additions and 21 deletions

16
.gitignore vendored
View File

@@ -1,2 +1,14 @@
# Created by venv; see https://docs.python.org/3/library/venv.html
*
# Virtual Environment (the folders Git saw)
bin/
lib/
share/
pyvenv.cfg
include/
# Data and Models
data/
trained_models/
# Python cache
__pycache__/
*.py[cod]

11
Tune.py
View File

@@ -8,7 +8,7 @@ from IdentitySubset import IdentitySubset
from architectures.Model import Model, Architecture
# numbre of classes
CLASS_SIZE = 20
CLASS_SIZE = 50
# batch
BATCH_SIZE = 16
@@ -34,7 +34,9 @@ RESOLUTION = 224
# - DENSENET121
# - INCEPTION
# - GOOGLENET
arch = Architecture.EFFICIENTNET
# - EFFICIENTNET
# - SHUFFLENET
arch = Architecture.GOOGLENET
# DATA PREPARATION
# load data set and prepare
@@ -93,9 +95,12 @@ model.train(
rate = LR_RATE)
# save.
model.save(filename=arch.name.lower())
'''
torch.save(
model.get().state_dict(),
f'{arch.name.lower()}.pth')
f'trained/{arch.name.lower()}.pth'
)'''
# done tuning
print('Model saved!')

View File

@@ -12,4 +12,4 @@ class DenseNet121(Model):
num_ftrs = m.classifier.in_features
m.classifier = nn.Linear(num_ftrs, self.size)
return m.to(self.device)
return m

View File

@@ -0,0 +1,19 @@
import torch.nn as nn
from torchvision import models
# Base model
from architectures.Model import Model
class EfficientNet(Model):
def get(self):
m = models.efficientnet_b1(weights=models.EfficientNet_B1_Weights.DEFAULT)
# Unfreeze the last block for a lighter touch
for param in m.features[-1].parameters(): param.requires_grad = True
# Standard classifier fix
m.classifier[1] = nn.Linear(m.classifier[1].in_features, self.size)
return m

View File

@@ -0,0 +1,14 @@
import torch.nn as nn
from torchvision import models
# Base model
from architectures.Model import Model
class GoogleNet(Model):
def get(self):
m = models.googlenet(weights = models.GoogLeNet_Weights.DEFAULT)
m.fc = nn.Linear(m.fc.in_features, self.size)
return m

View File

@@ -10,12 +10,12 @@ from architectures.Model import Model
class Inception(Model):
def get(self):
model = models.inception_v3(weights=models.Inception_V3_Weights.DEFAULT)
m = models.inception_v3(weights=models.Inception_V3_Weights.DEFAULT)
#for param in model.parameters():
# param.requires_grad = False
model.fc = nn.Linear(model.fc.in_features, self.size)
model.AuxLogits.fc = nn.Linear(model.AuxLogits.fc.in_features, self.size)
return model.to(self.device)
m.AuxLogits.fc = nn.Linear(m.AuxLogits.fc.in_features, self.size)
m.fc = nn.Linear(m.fc.in_features, self.size)
return m
def train(self, epochs, loader, rate):
# Override because Inception returns a tuple (main, aux)

View File

@@ -6,17 +6,18 @@ import torch.optim as optim
import time
import numpy as np
from sklearn.metrics import classification_report
from pathlib import Path
class Model(ABC):
def __init__(self, device, size):
self.device = device
self.size = size
self.model = self.get()
self.model = self.get().to(self.device)
@abstractmethod
def get(self):
# return the model
return self.model
pass
def train(self, epochs, loader, rate):
criterion = nn.CrossEntropyLoss()
@@ -60,6 +61,21 @@ class Model(ABC):
print(classification_report(all_labels, all_preds, zero_division=0))
def save(self, filename=None):
"""
Saves the model state_dict. Creates the directory if it doesn't exist.
"""
save_dir = Path("trained_models")
save_dir.mkdir(parents=True, exist_ok=True)
# 2. Determine filename (Default to class name if not provided)
if filename is None:
filename = f"{self.__class__.__name__.lower()}.pth"
save_path = save_dir / filename
torch.save(self.model.state_dict(), save_path)
# Using the factory patern here
@staticmethod
def create(arch, device, size):
@@ -74,8 +90,8 @@ class Model(ABC):
# ResNet50
case Architecture.RESNET50:
from architectures.ResNet18 import ResNet18
return ResNet18(device, size)
from architectures.ResNet50 import ResNet50
return ResNet50(device, size)
# INCEPTION
case Architecture.INCEPTION:
@@ -94,6 +110,14 @@ class Model(ABC):
case Architecture.EFFICIENTNET:
from architectures.EfficentNet import EfficientNet
return EfficientNet(device, size)
#ShuffleNet
case Architecture.SHUFFLENET:
from architectures.ShuffleNet import ShuffleNet
return ShuffleNet(device, size)
# wide ResNet
case Architecture.WIDE_RESNET:
from architectures.WideResNet import WideResNet
return WideResNet(device, size)
case _:
raise ValueError(f"Unknown model: {arch}")
@@ -106,4 +130,6 @@ class Architecture(Enum):
INCEPTION = auto()
DENSENET121 = auto()
GOOGLENET = auto()
EFFICIENTNET = auto()
EFFICIENTNET = auto()
SHUFFLENET = auto()
WIDE_RESNET = auto()

View File

@@ -11,12 +11,12 @@ class ResNet18(Model):
m = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
# freez all layers
#for param in m.parameters():
# param.requires_grad = False
for param in m.parameters():
param.requires_grad = False
# unfreez the last two
#for param in m.layer3.parameters(): param.requires_grad = True
#for param in m.layer4.parameters(): param.requires_grad = True
for param in m.layer3.parameters(): param.requires_grad = True
for param in m.layer4.parameters(): param.requires_grad = True
m.fc = nn.Linear(m.fc.in_features, self.size)
return m.to(self.device)
return m

View File

@@ -6,6 +6,18 @@ from torchvision import models
from architectures.Model import Model
class ResNet50(Model):
# NOTE:
# This model had it's best performance with the following configs
# numbre of classes
# CLASS_SIZE = 20
# BATCH_SIZE = 16
# SAMPLE_SIZE = 30
# TRAINING_SMPLE = 28
# LR_RATE = 0.0001
# EPOCHS = 15
# RESOLUTION = 224
# NOTE: But it may be a one time thing.
# because testing again didn't repeat
def get(self):
m = models.resnet50(weights=models.ResNet50_Weights.DEFAULT)
@@ -15,8 +27,10 @@ class ResNet50(Model):
param.requires_grad = False
# unfreez the last two
# NOTE: Freezing everything and unfrizing the last 3 yeilded the best performance
for param in m.layer2.parameters(): param.requires_grad = True
for param in m.layer3.parameters(): param.requires_grad = True
for param in m.layer4.parameters(): param.requires_grad = True
m.fc = nn.Linear(m.fc.in_features, self.size)
return m.to(self.device)
return m

View File

@@ -0,0 +1,17 @@
import torch.nn as nn
from torchvision import models
# Base model
from architectures.Model import Model
class ShuffleNet(Model):
def get(self):
m = models.shufflenet_v2_x1_0(weights=models.ShuffleNet_V2_X1_0_Weights.DEFAULT)
num_ftrs = m.fc.in_features
m.fc = nn.Linear(num_ftrs, self.size)
return m

View File

@@ -0,0 +1,15 @@
import torch.nn as nn
from torchvision import models
# Base model
from architectures.Model import Model
class WideResNet(Model):
def get(self):
# wide_resnet50_2 is a common high-performance choice
m = models.wide_resnet50_2(weights=models.Wide_ResNet50_2_Weights.DEFAULT)
m.fc = nn.Linear(m.fc.in_features, self.size)
return m