makiisthebes's picture
Upload 18 files
4ec6f12 verified
from torchvision.transforms import ToTensor
from torchvision.transforms import v2
from torchvision import transforms
import matplotlib.pyplot as plt
from time import time
from torch import nn
import pandas as pd
import numpy as np
import torch, os
from torch.optim.lr_scheduler import ReduceLROnPlateau
from tqdm import tqdm
# Going to be using keras
input_shape = (224, 224, 3)
device = (
"cuda"
if torch.cuda.is_available()
else "mps"
if torch.backends.mps.is_available()
else "cpu"
)
class MakiAlexNet(nn.Module):
def __init__(self, num_classes=2):
super(MakiAlexNet, self).__init__()
self.num_classes = num_classes
self.conv1 = nn.Conv2d(in_channels=3, out_channels=96, kernel_size=11, stride=4, padding=1) # LazyConv2d determine the input channels automatically.
self.conv2 = nn.Conv2d(in_channels=96, out_channels=256, kernel_size=5, padding=2)
self.conv3 = nn.Conv2d(in_channels=256, out_channels=384, kernel_size=3, padding=1) # 256, 384
self.conv4 = nn.Conv2d(in_channels=384, out_channels=384, kernel_size=3, padding=1) # 384,384
self.conv5 = nn.Conv2d(in_channels=384, out_channels=256, kernel_size=3, padding=1) # 384, 256
self.activation = nn.ReLU()
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2)
self.dropout = nn.Dropout(p=0.5)
self.f_linear = nn.Linear(256, self.num_classes)
# Replace Flatten with GlobalAvgPool2d
self.gap = nn.AvgPool2d(5) # Adjust output size if needed
# In this case LazyLinear is really useful after flattening,
# such that abstraction is made from the initial output layer and the linear layer nodes.
# Create an empty dictionary to store layer outputs
self.layer_outputs = {}
# Register hooks for desired layers
self.conv5.register_forward_hook(self._save_layer_output)
self.f_linear.register_forward_hook(self._save_layer_output)
def _save_to_output_weights(self, module, input, output):
self.layer_outputs[module.__class__.__name__] = {"input": input, "output": output, "weights": module.weight.data}
def _save_layer_output(self, module, input, output):
self.layer_outputs[module.__class__.__name__] = output
def forward(self, x):
"""Defined forward pass of AlexNet for learning left or right prediction."""
x = self.conv1(x) # wider
x = self.activation(x)
x = self.maxpool(x) # down sample.
x = self.conv2(x) # wider.
x = self.activation(x)
x = self.maxpool(x) # down sample.
x = self.conv3(x) # wider.
x = self.activation(x)
x = self.conv4(x)
x = self.activation(x)
x = self.conv5(x)
x = self.activation(x)
x = self.maxpool(x) # down sample.
x = self.gap(x).squeeze(-1).squeeze(-1)
# x = self.activation(x)
x = self.dropout(x)
x = self.f_linear(x)
return x
if __name__ == "__main__":
from dataset_creation import test_loader, train_loader # Initiate the custom dataloaders and datasets here.
# Running the model to learn, also introducing good features to make it learn better like a cosine scheduler for the learning rate.
EPOCH = 35
model = MakiAlexNet()
model.to(device)
print(model)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.00001 * 5, weight_decay=0.0001, momentum=0.9)
scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=3)
if os.path.exists("best_model_2.0.txt"):
with open("best_model_2.0.txt", "r") as file:
best_accuracy = float(file.read())
else:
best_accuracy = 0.0
# create a new file
with open("best_model_2.0.txt", "w") as file:
file.write(f"{best_accuracy}")
for epoch in tqdm(range(EPOCH), desc="Training Epoch Cycle"):
model.train() # Set model to training mode
running_loss = 0.0
for i, data in enumerate(train_loader, 0):
if i % 10 == 0:
print(f"Internal Loop of batches: {i}")
inputs, labels = data
# print(type(labels), labels)
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
train_loss = running_loss / len(train_loader)
print(f'Epoch [{epoch + 1}] training loss: {train_loss:.3f}')
# Validation phase
model.eval() # Set model to evaluation mode
val_running_loss = 0.0
val_correct = 0
val_total = 0
with torch.no_grad():
for data in test_loader: # Assuming test_loader is used as a validation loader
inputs, labels = data
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
loss = criterion(outputs, labels)
val_running_loss += loss.item()
_, predicted = torch.max(outputs.data, 1)
val_total += labels.size(0)
val_correct += (predicted == labels).sum().item()
val_loss = val_running_loss / len(test_loader)
val_accuracy = 100 * val_correct / val_total
print(f'Epoch [{epoch + 1}] validation loss: {val_loss:.3f}, accuracy: {val_accuracy:.2f}%')
if val_accuracy > best_accuracy:
best_accuracy = val_accuracy
torch.save(model.state_dict(), "alexnet_2.0.pth")
with open("best_model_2.0.txt", "w") as file:
file.write(f"{best_accuracy}")
# Update the LR scheduler with validation loss
scheduler.step(val_loss)