Skip to content

Instantly share code, notes, and snippets.

@alonsoir
Last active October 20, 2023 10:27
Show Gist options
  • Save alonsoir/26c8d084125acf587bc6078eb67a2bd7 to your computer and use it in GitHub Desktop.
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.
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
# 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.")
#
# 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.")
@alonsoir
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment