jrrade's picture
added necessary files for app to run on HF
74c02ff
import torch
import torch.nn as nn
import torchvision.models as models
from torchvision.models import VGG16_Weights
class VGG16Model(nn.Module):
def __init__(self, num_classes=4):
super(VGG16Model, self).__init__()
#self.vgg16 = models.vgg16(pretrained=True)
# Replace pretrained=True with weights=VGG16_Weights.DEFAULT
#self.vgg16 = models.vgg16(weights=VGG16_Weights.DEFAULT)
# Manually load the weights
self.vgg16 = models.vgg16()
# state_dict = torch.load("/work/mech-ai/angona3/Trial/vgg16_weights.pth", map_location=torch.device("cpu"))
# self.vgg16.load_state_dict(state_dict)
self.vgg16.classifier[6] = nn.Linear(4096, num_classes) ##In PyTorch CrossEntropyLoss Handles Softmax Internally
###Adding an explicit softmax layer would create numerical instability by double-applying softmax (once in your model, once in the loss),
# leading to incorrect gradient calculations during training.
self.vgg16.classifier[2] = nn.Dropout(p=0.6) # or 0.7 ##introducing dropout for regularization
self.vgg16.classifier[5] = nn.Dropout(p=0.6) # or 0.7
# Freeze all the convolutional layers (feature extractor part)
# The classifier layers (fully connected layers) remain trainable
for param in self.vgg16.features.parameters():
param.requires_grad = False
#param.requires_grad = True # Unfreeze the last two fully connected layers
# Unfreeze Conv Block 4 and Conv Block 5 (512 filters, 3x3 filters, same padding)
# best: conv_layers_to_unfreeze = [17, 19, 21, 24, 26, 28]
conv_layers_to_unfreeze = [17, 19, 21, 24, 26, 28]
for layer_idx in conv_layers_to_unfreeze:
for param in self.vgg16.features[layer_idx].parameters():
param.requires_grad = True
# Unfreeze the last two fully connected layers
# Unfreeze all fully connected layers
for param in self.vgg16.classifier.parameters():
param.requires_grad = True
def forward(self, x):
return self.vgg16(x)
#Fine-tuning the entire network can lead to better performance compared to freezing layers
##because the model can adjust both the feature extractor and classifier to your specific dataset.
##Yes, nn.CrossEntropyLoss in PyTorch is explicitly designed to handle raw logits (ranging from −∞to +∞) directly and efficiently.
##CrossEntropyLoss=Softmax(logits)+Log+NLLLoss
##### In newer versions of torchvision, the weights argument replaces pretrained.
# #The VGG16_Weights.DEFAULT is the new way to specify that anyone want the pretrained weights, and it is the preferred method.
##Deprecation Warning Fix: Replace pretrained=True with weights=VGG16_Weights.DEFAULT.
##Security Warning Fix: You don't need to use torch.load in this case because you're not loading a pre-trained model from a .pth file.
##from torchvision.models import VGG16_Weights
## self.vgg16 = models.vgg16(weights=VGG16_Weights.DEFAULT)
## adding dropout to VGG16
#class VGG16Model(nn.Module):
# def __init__(self, num_classes=4):
# super(VGG16Model, self).__init__()
# self.vgg16 = models.vgg16(pretrained=True)
# self.vgg16.classifier[6] = nn.Sequential(
# nn.Linear(4096, 1024), # First layer reduces dimensions to 1024
# nn.ReLU(), # Adds non-linearity to increase learning capacity
# nn.Dropout(0.5), # Introduces dropout for regularization
# nn.Linear(1024, num_classes) # Second layer maps to the desired number of classes
# )
# def forward(self, x):
# return self.vgg16(x)
#import torch.nn as nn
#from torchvision import models
#def get_resnet18_model(num_classes):
# model = models.resnet18(pretrained=True)
# model.fc = nn.Linear(model.fc.in_features, num_classes)
# return model
##VGG16 structure
#(vgg16.classifier): Sequential(
# (0): Linear(25088, 4096)
# (1): ReLU(inplace=True)
# (2): Dropout(p=0.5, inplace=False)
# (3): Linear(4096, 4096)
# (4): ReLU(inplace=True)
# (5): Dropout(p=0.5, inplace=False)
# (6): Linear(4096, num_classes)
#)