added more models for testing
This commit is contained in:
16
.gitignore
vendored
16
.gitignore
vendored
@@ -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
11
Tune.py
@@ -8,7 +8,7 @@ from IdentitySubset import IdentitySubset
|
|||||||
from architectures.Model import Model, Architecture
|
from architectures.Model import Model, Architecture
|
||||||
|
|
||||||
# numbre of classes
|
# numbre of classes
|
||||||
CLASS_SIZE = 20
|
CLASS_SIZE = 50
|
||||||
# batch
|
# batch
|
||||||
BATCH_SIZE = 16
|
BATCH_SIZE = 16
|
||||||
|
|
||||||
@@ -34,7 +34,9 @@ RESOLUTION = 224
|
|||||||
# - DENSENET121
|
# - DENSENET121
|
||||||
# - INCEPTION
|
# - INCEPTION
|
||||||
# - GOOGLENET
|
# - GOOGLENET
|
||||||
arch = Architecture.EFFICIENTNET
|
# - EFFICIENTNET
|
||||||
|
# - SHUFFLENET
|
||||||
|
arch = Architecture.GOOGLENET
|
||||||
|
|
||||||
# DATA PREPARATION
|
# DATA PREPARATION
|
||||||
# load data set and prepare
|
# load data set and prepare
|
||||||
@@ -93,9 +95,12 @@ model.train(
|
|||||||
rate = LR_RATE)
|
rate = LR_RATE)
|
||||||
|
|
||||||
# save.
|
# save.
|
||||||
|
model.save(filename=arch.name.lower())
|
||||||
|
'''
|
||||||
torch.save(
|
torch.save(
|
||||||
model.get().state_dict(),
|
model.get().state_dict(),
|
||||||
f'{arch.name.lower()}.pth')
|
f'trained/{arch.name.lower()}.pth'
|
||||||
|
)'''
|
||||||
|
|
||||||
# done tuning
|
# done tuning
|
||||||
print('Model saved!')
|
print('Model saved!')
|
||||||
|
|||||||
@@ -12,4 +12,4 @@ class DenseNet121(Model):
|
|||||||
num_ftrs = m.classifier.in_features
|
num_ftrs = m.classifier.in_features
|
||||||
m.classifier = nn.Linear(num_ftrs, self.size)
|
m.classifier = nn.Linear(num_ftrs, self.size)
|
||||||
|
|
||||||
return m.to(self.device)
|
return m
|
||||||
19
architectures/EfficentNet.py
Normal file
19
architectures/EfficentNet.py
Normal 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
|
||||||
14
architectures/GoogleNet.py
Normal file
14
architectures/GoogleNet.py
Normal 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
|
||||||
@@ -10,12 +10,12 @@ from architectures.Model import Model
|
|||||||
|
|
||||||
class Inception(Model):
|
class Inception(Model):
|
||||||
def get(self):
|
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():
|
#for param in model.parameters():
|
||||||
# param.requires_grad = False
|
# param.requires_grad = False
|
||||||
model.fc = nn.Linear(model.fc.in_features, self.size)
|
m.AuxLogits.fc = nn.Linear(m.AuxLogits.fc.in_features, self.size)
|
||||||
model.AuxLogits.fc = nn.Linear(model.AuxLogits.fc.in_features, self.size)
|
m.fc = nn.Linear(m.fc.in_features, self.size)
|
||||||
return model.to(self.device)
|
return m
|
||||||
|
|
||||||
def train(self, epochs, loader, rate):
|
def train(self, epochs, loader, rate):
|
||||||
# Override because Inception returns a tuple (main, aux)
|
# Override because Inception returns a tuple (main, aux)
|
||||||
|
|||||||
@@ -6,17 +6,18 @@ import torch.optim as optim
|
|||||||
import time
|
import time
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from sklearn.metrics import classification_report
|
from sklearn.metrics import classification_report
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
class Model(ABC):
|
class Model(ABC):
|
||||||
def __init__(self, device, size):
|
def __init__(self, device, size):
|
||||||
self.device = device
|
self.device = device
|
||||||
self.size = size
|
self.size = size
|
||||||
self.model = self.get()
|
self.model = self.get().to(self.device)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get(self):
|
def get(self):
|
||||||
# return the model
|
# return the model
|
||||||
return self.model
|
pass
|
||||||
|
|
||||||
def train(self, epochs, loader, rate):
|
def train(self, epochs, loader, rate):
|
||||||
criterion = nn.CrossEntropyLoss()
|
criterion = nn.CrossEntropyLoss()
|
||||||
@@ -60,6 +61,21 @@ class Model(ABC):
|
|||||||
print(classification_report(all_labels, all_preds, zero_division=0))
|
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
|
# Using the factory patern here
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(arch, device, size):
|
def create(arch, device, size):
|
||||||
@@ -74,8 +90,8 @@ class Model(ABC):
|
|||||||
|
|
||||||
# ResNet50
|
# ResNet50
|
||||||
case Architecture.RESNET50:
|
case Architecture.RESNET50:
|
||||||
from architectures.ResNet18 import ResNet18
|
from architectures.ResNet50 import ResNet50
|
||||||
return ResNet18(device, size)
|
return ResNet50(device, size)
|
||||||
|
|
||||||
# INCEPTION
|
# INCEPTION
|
||||||
case Architecture.INCEPTION:
|
case Architecture.INCEPTION:
|
||||||
@@ -94,6 +110,14 @@ class Model(ABC):
|
|||||||
case Architecture.EFFICIENTNET:
|
case Architecture.EFFICIENTNET:
|
||||||
from architectures.EfficentNet import EfficientNet
|
from architectures.EfficentNet import EfficientNet
|
||||||
return EfficientNet(device, size)
|
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 _:
|
case _:
|
||||||
raise ValueError(f"Unknown model: {arch}")
|
raise ValueError(f"Unknown model: {arch}")
|
||||||
|
|
||||||
@@ -107,3 +131,5 @@ class Architecture(Enum):
|
|||||||
DENSENET121 = auto()
|
DENSENET121 = auto()
|
||||||
GOOGLENET = auto()
|
GOOGLENET = auto()
|
||||||
EFFICIENTNET = auto()
|
EFFICIENTNET = auto()
|
||||||
|
SHUFFLENET = auto()
|
||||||
|
WIDE_RESNET = auto()
|
||||||
@@ -11,12 +11,12 @@ class ResNet18(Model):
|
|||||||
m = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
|
m = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
|
||||||
|
|
||||||
# freez all layers
|
# freez all layers
|
||||||
#for param in m.parameters():
|
for param in m.parameters():
|
||||||
# param.requires_grad = False
|
param.requires_grad = False
|
||||||
|
|
||||||
# unfreez the last two
|
# unfreez the last two
|
||||||
#for param in m.layer3.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
|
for param in m.layer4.parameters(): param.requires_grad = True
|
||||||
|
|
||||||
m.fc = nn.Linear(m.fc.in_features, self.size)
|
m.fc = nn.Linear(m.fc.in_features, self.size)
|
||||||
return m.to(self.device)
|
return m
|
||||||
@@ -6,6 +6,18 @@ from torchvision import models
|
|||||||
from architectures.Model import Model
|
from architectures.Model import Model
|
||||||
|
|
||||||
class ResNet50(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):
|
def get(self):
|
||||||
m = models.resnet50(weights=models.ResNet50_Weights.DEFAULT)
|
m = models.resnet50(weights=models.ResNet50_Weights.DEFAULT)
|
||||||
@@ -15,8 +27,10 @@ class ResNet50(Model):
|
|||||||
param.requires_grad = False
|
param.requires_grad = False
|
||||||
|
|
||||||
# unfreez the last two
|
# 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.layer3.parameters(): param.requires_grad = True
|
||||||
for param in m.layer4.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)
|
m.fc = nn.Linear(m.fc.in_features, self.size)
|
||||||
return m.to(self.device)
|
return m
|
||||||
17
architectures/ShuffleNet.py
Normal file
17
architectures/ShuffleNet.py
Normal 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
|
||||||
15
architectures/WideResNet.py
Normal file
15
architectures/WideResNet.py
Normal 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
|
||||||
Reference in New Issue
Block a user