Last active
October 20, 2023 10:27
-
-
Save alonsoir/26c8d084125acf587bc6078eb67a2bd7 to your computer and use it in GitHub Desktop.
The Fashion MNIST Datasets contain a set of 28x28 grayscale images of clotes. Our goal is building a neural network using Pytorch and then training the network to predict clothes. 84% max. First python Without REFACTOR. Third is refactored.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from torch import nn | |
from torch.nn import functional as F | |
class Classifier(nn.Module): | |
def __init__(self): | |
super().__init__() | |
self.fc1 = nn.Linear(784, 120) | |
self.fc2 = nn.Linear(120, 120) | |
self.fc3 = nn.Linear(120, 10) | |
# self.fc4 = nn.Linear(64,10) | |
# defining the 20% dropout | |
self.dropout = nn.Dropout(0.2) | |
def forward(self, x): | |
x = x.view(x.shape[0], -1) | |
x = self.dropout(F.relu(self.fc1(x))) | |
x = self.dropout(F.relu(self.fc2(x))) | |
# x = self.dropout(F.relu(self.fc3(x))) | |
# not using dropout on output layer | |
x = F.log_softmax(self.fc3(x), dim=1) | |
return x |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# importing required libraries.. | |
import torch | |
import numpy as np | |
import torch.nn as nn | |
import torch.optim as optim | |
import matplotlib.pyplot as plt | |
from torchvision import datasets, transforms | |
from torch.utils.data.sampler import SubsetRandomSampler # for validation test | |
from Classifier import Classifier | |
# Define a transform to convert to images to tensor and normalize | |
transform = transforms.Compose( | |
[ | |
transforms.ToTensor(), | |
transforms.Normalize( | |
(0.5,), | |
(0.5,), | |
), | |
] | |
) # mean and std have to be sequences (e.g., tuples), | |
# therefore we should add a comma after the values | |
# Load the data: train and test sets | |
trainset = datasets.FashionMNIST( | |
"~/.pytorch/F_MNIST_data", download=True, train=True, transform=transform | |
) | |
testset = datasets.FashionMNIST( | |
"~/.pytorch/F_MNIST_data", download=True, train=False, transform=transform | |
) | |
# Preparing for validaion test | |
indices = list(range(len(trainset))) | |
np.random.shuffle(indices) | |
# to get 20% of the train set | |
split = int(np.floor(0.2 * len(trainset))) | |
train_sample = SubsetRandomSampler(indices[:split]) | |
valid_sample = SubsetRandomSampler(indices[split:]) | |
# Data Loader | |
trainloader = torch.utils.data.DataLoader(trainset, sampler=train_sample, batch_size=64) | |
validloader = torch.utils.data.DataLoader(trainset, sampler=valid_sample, batch_size=64) | |
testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=True) | |
dataiter = iter(trainloader) | |
print(len(dataiter)) | |
# images, labels = dataiter.next() | |
images, labels = dataiter.__next__() | |
fig = plt.figure(figsize=(15, 5)) | |
for idx in np.arange(20): | |
# xticks=[], yticks=[] is empty to print the images without any ticks around them | |
# np.sqeeze : Remove single-dimensional entries from the shape of an array. | |
ax = fig.add_subplot(4, 5, idx + 1, xticks=[], yticks=[]) | |
ax.imshow(np.squeeze(images[idx]), cmap="gray") | |
# .item() gets the value contained in a Tensor | |
ax.set_title(labels[idx].item()) | |
fig.tight_layout() | |
model = Classifier() | |
# defining the loss function | |
criterion = nn.NLLLoss() | |
optimizer = optim.SGD(model.parameters(), lr=0.01) | |
valid_loss_min = ( | |
np.Inf | |
) # using this high value to make sure the update the weight first time | |
epochs = 40 | |
steps = 0 | |
model.train() # prep model for training | |
train_losses, valid_losses = [], [] | |
for e in range(epochs): | |
running_loss = 0 | |
valid_loss = 0 | |
# train the model # | |
for images, labels in trainloader: | |
optimizer.zero_grad() | |
log_ps = model(images) | |
loss = criterion(log_ps, labels) | |
loss.backward() | |
optimizer.step() | |
running_loss += loss.item() * images.size(0) | |
for images, labels in validloader: | |
log_ps = model(images) | |
loss = criterion(log_ps, labels) | |
valid_loss += loss.item() * images.size(0) | |
running_loss = running_loss / len(trainloader.sampler) | |
valid_loss = valid_loss / len(validloader.sampler) | |
train_losses.append(running_loss) | |
valid_losses.append(valid_loss) | |
print( | |
"Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}".format( | |
e + 1, running_loss, valid_loss | |
) | |
) | |
if valid_loss <= valid_loss_min: | |
print( | |
"validation loss decreased({:.6f} -->{:.6f}). Saving Model ...".format( | |
valid_loss_min, valid_loss | |
) | |
) | |
torch.save(model.state_dict(), "model.pt") | |
valid_loss_min = valid_loss | |
plt.plot(train_losses, label="Train Loss") | |
plt.plot(valid_losses, label="Valid Loss") | |
plt.legend("Train Loss/Valid Loss") | |
plt.show() | |
model.load_state_dict(torch.load("model.pt")) | |
# track the test loss | |
test_loss = 0 | |
class_correct = list(0.0 for i in range(10)) | |
class_total = list(0.0 for i in range(10)) | |
model.eval() | |
for images, labels in testloader: | |
# forword pass | |
output = model(images) | |
# calculate the loss | |
loss = criterion(output, labels) | |
# update the test loss | |
test_loss += loss.item() * images.size(0) | |
# convert output probabilities to predicted class | |
_, pred = torch.max(output, 1) | |
# compare predictions to the true labes | |
correct = np.squeeze(pred.eq(labels.data.view_as(pred))) | |
# calculate test accuracy for each object class | |
for i in range(len(labels)): | |
label = labels.data[i] | |
class_correct[label] += correct[i].item() | |
class_total[label] += 1 | |
# calculate and prınt test loss | |
test_loss = test_loss / len(testloader.sampler) | |
print("Test Loss: {:.6f}\n".format(test_loss)) | |
for i in range(10): | |
if class_total[i] > 0: | |
print( | |
"Test Accuracy of %5s: %2d%% (%2d/%2d)" | |
% ( | |
str(i), | |
100 * class_correct[i] / class_total[i], | |
np.sum(class_correct[i]), | |
np.sum(class_total[i]), | |
) | |
) | |
else: | |
print("Test Accuracy of %5s: N/A(no training examples)" % class_total[i]) | |
print( | |
"\nTest Accuracy (Overall): %2d%% (%2d/%2d)" | |
% ( | |
100.0 * np.sum(class_correct) / np.sum(class_total), | |
np.sum(class_correct), | |
np.sum(class_total), | |
) | |
) | |
# obtain one batch of test images | |
dataiter = iter(testloader) | |
images, labels = dataiter.__next__() | |
# get sample outputs | |
output = model(images) | |
# convert output probabilities to predicted class | |
_, preds = torch.max(output, 1) | |
# prep images for display | |
images = images.numpy() | |
# plot the images in the batch, along with predicted and true labels | |
fig = plt.figure(figsize=(25, 4)) | |
for idx in np.arange(20): | |
ax = fig.add_subplot(2, 10, idx + 1, xticks=[], yticks=[]) | |
ax.imshow(np.squeeze(images[idx]), cmap="gray") | |
ax.set_title( | |
"{} ({})".format(str(preds[idx].item()), str(labels[idx].item())), | |
color=("green" if preds[idx] == labels[idx] else "red"), | |
) | |
plt.show() | |
print("Done!. There is a trained model named model.pt in this folder.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# importing required libraries.. | |
import torch | |
import numpy as np | |
import torch.nn as nn | |
import torch.optim as optim | |
import matplotlib.pyplot as plt | |
from torchvision import datasets, transforms | |
from torch.utils.data.sampler import SubsetRandomSampler # for validation test | |
from Classifier import Classifier | |
# Load and Visualize the Data | |
# Define a transform to convert to images to tensor and normalize | |
def define_a_transform_to_convert_to_images_to_tensor_and_normalize(): | |
global trainloader, validloader, testloader | |
transform = transforms.Compose( | |
[ | |
transforms.ToTensor(), | |
transforms.Normalize( | |
(0.5,), | |
(0.5,), | |
), | |
] | |
) # mean and std have to be sequences (e.g., tuples), | |
# therefore we should add a comma after the values | |
# Load the data: train and test sets | |
trainset = datasets.FashionMNIST( | |
"~/.pytorch/F_MNIST_data", download=True, train=True, transform=transform | |
) | |
testset = datasets.FashionMNIST( | |
"~/.pytorch/F_MNIST_data", download=True, train=False, transform=transform | |
) | |
# Preparing for validaion test | |
indices = list(range(len(trainset))) | |
np.random.shuffle(indices) | |
# to get 20% of the train set | |
split = int(np.floor(0.2 * len(trainset))) | |
train_sample = SubsetRandomSampler(indices[:split]) | |
valid_sample = SubsetRandomSampler(indices[split:]) | |
# Data Loader | |
trainloader = torch.utils.data.DataLoader( | |
trainset, sampler=train_sample, batch_size=64 | |
) | |
validloader = torch.utils.data.DataLoader( | |
trainset, sampler=valid_sample, batch_size=64 | |
) | |
testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=True) | |
# Visualize a Batch of Training Data | |
def visualize_a_Batch_of_Training_Data(): | |
global trainloader | |
dataiter = iter(trainloader) | |
print(len(dataiter)) | |
# images, labels = dataiter.next() | |
images, labels = dataiter.__next__() | |
fig = plt.figure(figsize=(15, 5)) | |
for idx in np.arange(20): | |
# xticks=[], yticks=[] is empty to print the images without any ticks around them | |
# np.sqeeze : Remove single-dimensional entries from the shape of an array. | |
ax = fig.add_subplot(4, 5, idx + 1, xticks=[], yticks=[]) | |
ax.imshow(np.squeeze(images[idx]), cmap="gray") | |
# .item() gets the value contained in a Tensor | |
ax.set_title(labels[idx].item()) | |
fig.tight_layout() | |
# Building the Network | |
def building_the_Network(): | |
global validloader, trainloader | |
global model | |
global criterion | |
model = Classifier() | |
# defining the loss function | |
criterion = nn.NLLLoss() | |
optimizer = optim.SGD(model.parameters(), lr=0.01) | |
valid_loss_min = ( | |
np.Inf | |
) # using this high value to make sure the update the weight first time | |
epochs = 40 | |
steps = 0 | |
model.train() # prep model for training | |
train_losses, valid_losses = [], [] | |
for e in range(epochs): | |
running_loss = 0 | |
valid_loss = 0 | |
# train the model # | |
for images, labels in trainloader: | |
optimizer.zero_grad() | |
log_ps = model(images) | |
loss = criterion(log_ps, labels) | |
loss.backward() | |
optimizer.step() | |
running_loss += loss.item() * images.size(0) | |
for images, labels in validloader: | |
log_ps = model(images) | |
loss = criterion(log_ps, labels) | |
valid_loss += loss.item() * images.size(0) | |
running_loss = running_loss / len(trainloader.sampler) | |
valid_loss = valid_loss / len(validloader.sampler) | |
train_losses.append(running_loss) | |
valid_losses.append(valid_loss) | |
print( | |
"Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}".format( | |
e + 1, running_loss, valid_loss | |
) | |
) | |
global title | |
if valid_loss <= valid_loss_min: | |
title = ( | |
"validation loss decreased({:.6f} -->{:.6f}). Saving Model ...".format( | |
valid_loss_min, valid_loss | |
) | |
) | |
print(title) | |
torch.save(model.state_dict(), "model.pt") | |
valid_loss_min = valid_loss | |
plt.ion() | |
plt.plot(train_losses, label="Train Loss") | |
plt.plot(valid_losses, label="Valid Loss") | |
plt.legend("Train Loss/Valid Loss") | |
plt.show() | |
plt.savefig(title) | |
# Load the Model with the Lowest Validation Loss | |
def load_the_Model_with_the_Lowest_Validation_Loss(): | |
global model | |
model.load_state_dict(torch.load("model.pt")) | |
# Test The Train Network | |
def test_The_Train_Network(): | |
global criterion | |
# track the test loss | |
test_loss = 0 | |
class_correct = list(0.0 for i in range(10)) | |
class_total = list(0.0 for i in range(10)) | |
model.eval() | |
for images, labels in testloader: | |
# forword pass | |
output = model(images) | |
# calculate the loss | |
loss = criterion(output, labels) | |
# update the test loss | |
test_loss += loss.item() * images.size(0) | |
# convert output probabilities to predicted class | |
_, pred = torch.max(output, 1) | |
# compare predictions to the true labes | |
correct = np.squeeze(pred.eq(labels.data.view_as(pred))) | |
# calculate test accuracy for each object class | |
for i in range(len(labels)): | |
label = labels.data[i] | |
class_correct[label] += correct[i].item() | |
class_total[label] += 1 | |
# calculate and prınt test loss | |
test_loss = test_loss / len(testloader.sampler) | |
print("Test Loss: {:.6f}\n".format(test_loss)) | |
for i in range(10): | |
if class_total[i] > 0: | |
print( | |
"Test Accuracy of %5s: %2d%% (%2d/%2d)" | |
% ( | |
str(i), | |
100 * class_correct[i] / class_total[i], | |
np.sum(class_correct[i]), | |
np.sum(class_total[i]), | |
) | |
) | |
else: | |
print("Test Accuracy of %5s: N/A(no training examples)" % class_total[i]) | |
print( | |
"\nTest Accuracy (Overall): %2d%% (%2d/%2d)" | |
% ( | |
100.0 * np.sum(class_correct) / np.sum(class_total), | |
np.sum(class_correct), | |
np.sum(class_total), | |
) | |
) | |
# obtain one batch of test images | |
dataiter = iter(testloader) | |
images, labels = dataiter.__next__() | |
# get sample outputs | |
output = model(images) | |
# convert output probabilities to predicted class | |
_, preds = torch.max(output, 1) | |
# prep images for display | |
images = images.numpy() | |
# plot the images in the batch, along with predicted and true labels | |
fig = plt.figure(figsize=(25, 4)) | |
for idx in np.arange(20): | |
ax = fig.add_subplot(2, 10, idx + 1, xticks=[], yticks=[]) | |
ax.imshow(np.squeeze(images[idx]), cmap="gray") | |
ax.set_title( | |
"{} ({})".format(str(preds[idx].item()), str(labels[idx].item())), | |
color=("green" if preds[idx] == labels[idx] else "red"), | |
) | |
plt.show() | |
if __name__ == "__main__": | |
define_a_transform_to_convert_to_images_to_tensor_and_normalize() | |
visualize_a_Batch_of_Training_Data() | |
building_the_Network() | |
load_the_Model_with_the_Lowest_Validation_Loss() | |
test_The_Train_Network() | |
print("Done!. There is a trained model named model.pt in this folder.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
From https://medium.com/@aaysbt/fashion-mnist-data-training-using-pytorch-7f6ad71e96f4
The original code worked in Jupyter, now it is python code, refactored. I had to change something here and there in order to get it running, but it works.
Between 81% and 84% performance. I think the model can perform better.
Kudos for https://medium.com/@aaysbt