Skip to content

Commit

Permalink
added initial pass at the machine learning project
Browse files Browse the repository at this point in the history
  • Loading branch information
JasonGibson274 committed Sep 6, 2020
1 parent 449d363 commit fdd3bcc
Show file tree
Hide file tree
Showing 4 changed files with 337 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ projects/.c9/*
*.idea
cmake-build-debug
build
data

120 changes: 120 additions & 0 deletions assignments/week_1/project1.4/ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Project 1.4
Welcome to this first robotics themed projects of the RoboJackets software training
curriculum. The point of these projects is to give you hands on experience playing
around with code related to a robotics topic that we have covered in lecture.
I hope you enjoy this one

# Project Objective
During this project we will be training a Neural Network on the MNIST dataset.
This is the canonical hello world of the machine learning world. The goal is to
classify images of handwritten digits into what it is. We will be using a
convolutional neural network in order to effectively process the image data.

# Starter Code
We will be using something called Google Colab. This allows you to run a python notebook
on google servers using their GPU's. Often GPU setup is nontrivial and this allows us to
get up an running almost immediately. You would not want to use this for more general
work unless you do not have another option. Open up the file here and click the button
to add it to your own drive. There is also a complete version of the code that can be found
here in script form.

Today we will be using Python but you *DO NOT NEED TO KNOW PYTHON*. A lot of machine
learning libraries are implemented with python wrappers, hence why we are using python.
Don't worry though, you won't have to edit any of the code that isn't very explicit.

## Python Notebooks Basics

Each block is of the same code, just press the play button to run that section of code.
The results from each section are kept in memory, this allows you to run a further
along section of the code multiple times without constantly rerunning the initial sections.
If you change a section above another you will have to rerun it.

## Part 1
For this section you should run the entire notebook step by step. I would recommend
using the button at the top pictured here in order to make it easier on yourself.

You should see output similar to this, the instructions inside the notebook should
cover any questions you might have about what each section of code is doing.
You should not read over each line of code unless instructed to do so, you won't
need to know how any of the code works in order to complete the exercise (I wrote
it and I barely know how it works).

You should see a graph similar to the one below at the final output.

## Part 2
Now that we can train a simple model we want to try to increase out accuracy. Remember
how we discussed underfitting the model previously. Now our model has enough room to
accurate model the data (trust me on this one). So what else could we look at in order to
get a better model for the data? Consider the graph at the end, what should be
happening to know that we have maxed out our accuracy?

Remember that you should only have to change locations where it says change me.
I have also provided bounds on how much you should change certain variables, this
is mostly so you don't spend hours on this part.
Which one of those locations in the code listed below would be the right place
to solve this issue?

````python
learning_rate = 1e-6 # <=================== CHANGE ME HERE range:[1e-8, 1e-1]
num_epochs = 3 # <=================== CHANGE ME HERE range:[1, 20]
````

<details>
<summary>Answer</summary>
That graph tells me that we should be training for longer, out error curve
has not leveled out yet, maybe just increasing
the number of epochs would significantly improve out network.
</details>

<details>
<summary>Answer</summary>
That graph tells me that we should be training for longer, out error curve
has not leveled out yet, maybe just increasing
the number of epochs would significantly improve out network.
</details>

## Part 3
Now that we have gotten better results could we have gotten here faster? Try
thinking about what we should change in order to converge faster. Let's really put
the speed to the test and use the lower upper limit here. Are your results any better?
If results are bad, try starting at a known good value and increasing until
the performance starts to degrade significantly.

You should be getting accuracy above 90%.

## Part 4
Now that we have a beautiful neural network for the current dataset let us try
something a little more difficult. We will be using KMNIST, a dataset very similar to MNIST.

TODO include graphic

Go back to the section where we loaded in the dataset and change the lines to be

````python
## download and load training dataset
trainset = torchvision.datasets.KMNIST(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=BATCH_SIZE,
shuffle=True, num_workers=2)

## download and load testing dataset
testset = torchvision.datasets.KMNIST(root='./data', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=BATCH_SIZE,
shuffle=False, num_workers=2)
````

Now try playing around with the new dataset and see if you can change values
to give accuracy above 91%.
[Training](https://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.reddit.com%2Fr%2FProgrammerHumor%2Fcomments%2F9cu51a%2Fshamelessly_stolen_from_xkcd_credit_where_is_due%2F&psig=AOvVaw00gXQw1TnbHykteNddM-rV&ust=1599439002194000&source=images&cd=vfe&ved=0CAIQjRxqFwoTCNjm5-Ck0-sCFQAAAAAdAAAAABAg)
is a good time to check out the videos below
that give a better intuition into what is happening with these neural networks. This
guy has some fancy visualizations.

Here are the links to some videos

[This series](https://www.youtube.com/watch?v=aircAruvnKk&list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi)
of videos will cover what we covered in this presentation in video 1 and 2.
Three and four go into how backpropagation actually works, be warned there is math.


1 change: 1 addition & 0 deletions assignments/week_1/project1.4/RoboJackets_MNIST.ipynb

Large diffs are not rendered by default.

215 changes: 215 additions & 0 deletions assignments/week_1/project1.4/mnist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms

BATCH_SIZE=32

## transformations
transform = transforms.Compose(
[transforms.ToTensor()])

## download and load training dataset
trainset = torchvision.datasets.MNIST(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=BATCH_SIZE,
shuffle=True, num_workers=2)

## download and load testing dataset
testset = torchvision.datasets.MNIST(root='./data', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=BATCH_SIZE,
shuffle=False, num_workers=2)

# ====================================================================

import matplotlib.pyplot as plt
import numpy as np


## functions to show an image
def imshow(img):
#img = img / 2 + 0.5 # unnormalize
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()

## get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()

## show images
#imshow(torchvision.utils.make_grid(images)) TODO

# ====================================================================

class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()

# 28x28x1 => 26x26x32
self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3)
self.d1 = nn.Linear(26 * 26 * 32, 128)
self.d2 = nn.Linear(128, 10)

def forward(self, x):
# 32x1x28x28 => 32x32x26x26
x = self.conv1(x)
x = F.relu(x)

# flatten => 32 x (32*26*26)
x = x.flatten(start_dim = 1)

# 32 x (32*26*26) => 32x128
x = self.d1(x)
x = F.relu(x)

# logits => 32x10
logits = self.d2(x)
out = F.softmax(logits, dim=1)
return out

# ====================================================================

# run the random model through the data to make sure our ins and outs correspond to each other
#model = MyModel()
#for images, labels in trainloader:
# print("batch size:", images.shape)
# out = model(images)
# print(out.shape)
# break

# ====================================================================

## compute accuracy
def get_accuracy(logit, target, batch_size):
''' Obtain accuracy for training round '''
corrects = (torch.max(logit, 1)[1].view(target.size()).data == target.data).sum()
accuracy = 100.0 * corrects/batch_size
return accuracy.item()


def insepct_detection(image, output):
fig, axs = plt.subplots(2)
fig.suptitle('Plots')
axs[0].set_title("Image")
image = np.transpose(image.numpy(), (1,2,0))
#print(np.transpose(image.numpy(), (1,2,0)).shape)
#imshow(image)
axs[0].imshow(image)
axs[1].bar(range(0,10), sample_output)
axs[1].legend(loc='upper right', frameon=False)
axs[1].set_title("Probability of digit")
plt.show()

# ====================================================================

# possible exercises
# not running long enough
# learning rate = 1e-6
# num_epochs = 3

# run for longer
# num_epochs = 20

# Increase the learning rate
# learning_rate = 1e-1
# num_epochs = 3

# decrease the learning rate to get a better result on 3 epochs (> 90% accuracy)
# learning_rate = 1e-3
# num_epochs = 3

# increase the number of epochs, can we learn more?
# num_epochs = 20

# give them KMNIST and then have then see if they can beat my top accuracy
# 91

learning_rate = 1e-3 # <=================== CHANGE ME HERE
num_epochs = 50 # <=================== CHANGE ME HERE

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = MyModel()
model = model.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)


training_loss_plot = []
training_accuracy_plot = []
test_accuracy_plot = []

test_acc = 0.0
for i, (images, labels) in enumerate(testloader, 0):
images = images.to(device)
labels = labels.to(device)
outputs = model(images)
test_acc += get_accuracy(outputs, labels, BATCH_SIZE)
if i == 0:
image = torchvision.utils.make_grid(images.cpu()[0])
sample_output = outputs[0].cpu().detach().numpy()
insepct_detection(image, sample_output)


print('Initial Test Accuracy: %.2f'%( test_acc/i))

for epoch in range(num_epochs):
train_running_loss = 0.0
train_acc = 0.0

model = model.train()

## training step
for i, (images, labels) in enumerate(trainloader):

images = images.to(device)
labels = labels.to(device)

## forward + backprop + loss
logits = model(images)
loss = criterion(logits, labels)
optimizer.zero_grad()
loss.backward()

## update model params
optimizer.step()

train_running_loss += loss.detach().item()
train_acc += get_accuracy(logits, labels, BATCH_SIZE)

model.eval()
average_train_loss = train_running_loss / i
average_train_accuracy = train_acc / i
training_loss_plot.append(100 - average_train_loss)
training_accuracy_plot.append(100 - average_train_accuracy)
print('Epoch: %d | Loss: %.4f | Train Accuracy: %.2f' \
%(epoch, average_train_loss, average_train_accuracy))


test_acc = 0.0
for i, (images, labels) in enumerate(testloader, 0):
images = images.to(device)
labels = labels.to(device)
outputs = model(images)
test_acc += get_accuracy(outputs, labels, BATCH_SIZE)
# only show result on the last epoch
if i == 0 and (epoch+1 is num_epochs or epoch == 0):
image = torchvision.utils.make_grid(images.cpu()[0])
sample_output = outputs[0].cpu().detach().numpy()
insepct_detection(image, sample_output)
test_accuracy_plot.append(100 - test_acc/i)
print('Test Accuracy: %.2f'%( test_acc/i))

# ====================================================================

plt.title("Training vs Test accuracy")
plt.plot(range(1,num_epochs+1), training_accuracy_plot, label='Training Error (%)')
plt.plot(range(1,num_epochs+1), test_accuracy_plot, label='Testing Error (%)')
plt.legend(loc='upper right', frameon=False)
plt.show()

# ====================================================================


0 comments on commit fdd3bcc

Please sign in to comment.