Skip to content
Snippets Groups Projects
Commit 01d3b99a authored by Chan, Ho Tung Jeremy's avatar Chan, Ho Tung Jeremy
Browse files

2022 version cleanup

parent be2062f3
No related branches found
No related tags found
No related merge requests found
# Task 1: Tutorial of using a [Pytorch](https://pytorch.org/get-started/locally/ "Pytorch") and [Optuna](https://optuna.readthedocs.io/en/stable/tutorial/index.html "Optuna") to create a NN classifier for the dataset USPS
# Task 1: Tutorial of using [Pytorch](https://pytorch.org/get-started/locally/ "Pytorch") and [Optuna](https://optuna.readthedocs.io/en/stable/tutorial/index.html "Optuna") to create a NN classifier for the dataset USPS
Follow the walkthrough of *assignment1.ipynb* and complete the *TODOs* within the python notebook.
Watch the support video and follow along with *walkthrough.ipynb*.
Complete *assignment1.ipynb* by completing the *TODOs* within the python notebook.
Upon completion, save the notebook as html in the following format: Task1-*your_student_number*.html
![image-1.png](./image-1.png)
%% Cell type:code id:c87bb09d tags:
``` python
#sanity checks
```
%% Cell type:code id:1d33b1e0 tags:
``` python
import torch
from scipy.io import loadmat
import numpy as np
```
%% Cell type:code id:9be97462 tags:
``` python
print(torch.__version__)
DEVICE= torch.device("cuda" if torch.cuda.is_available() else "cpu")
```
%% Cell type:code id:5cb63935 tags:
``` python
mat = loadmat('../data/USPS.mat')
```
%% Cell type:markdown id:4729badd tags:
## Section 1: Introduction
%% Cell type:code id:ac3ad9f3 tags:
``` python
mat = loadmat('../data/USPS.mat')
mat["Y"]= mat["Y"].reshape(-1)
```
%% Cell type:code id:cf1ae235 tags:
``` python
# Data
mat["X"]
```
%% Cell type:code id:172df00d tags:
``` python
# label
mat["Y"]
```
%% Cell type:code id:bab9478b tags:
``` python
# unique labels before
np.unique(mat["Y"])
```
%% Cell type:code id:139dd608 tags:
``` python
#TODO: Reformat labels such that
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] --> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Hint below...
```
%% Cell type:code id:6d648157 tags:
``` python
# mat["Y"]==1 # returns a bool array for indexes where y is 1
```
%% Cell type:code id:d270dd28 tags:
``` python
# mat["Y"][mat["Y"]==1]=0 # replacing y as 0 for the indexes where y is 1
```
%% Cell type:code id:9bf58254 tags:
``` python
# mat["Y"]==0 # returns a bool array for indexes where y is 0 (should be the same as when y was 1)
```
%% Cell type:code id:91709907 tags:
``` python
old_labels=
new_labels=
for old, new in zip(old_labels, new_labels):
print(f"old: {old}, new: {new}")
# mat["Y"][mat["Y"]==...]=...
```
%% Cell type:code id:d7ac36a1 tags:
``` python
# unique labels after
np.unique(mat["Y"])
```
%% Cell type:code id:0a4c67d9 tags:
``` python
# Create torch compatible dataset for dataloader
class ScikitFeatDataset(torch.utils.data.Dataset):
def __init__(self, X:np.array, y:np.array):
self.X= X.astype(float)
self.y= y.astype(int)
def __len__(self):
return len(self.X)
def __getitem__(self, idx):
return self.X[idx], self.y[idx]
dataset= ScikitFeatDataset(mat["X"], mat["Y"])
dataloader=torch.utils.data.DataLoader(dataset)
```
%% Cell type:code id:f19e01c9 tags:
``` python
# for i,j in dataloader:
# print(i.shape,j)
# break
```
%% Cell type:code id:8b118a3f tags:
``` python
# TODO: split the data into a training and validation split
# 60% of data to be used for training, 40% of data to be used for validation
# Hint below...
```
%% Cell type:code id:30c2ec5f tags:
``` python
len(mat["X"]) # total length
```
%% Cell type:code id:aea249e2 tags:
``` python
split= int(len(mat["X"]) * 0.1) # 10% of data
len(mat["X"][:split]) # split length
```
%% Cell type:code id:bf07f533 tags:
``` python
len(mat["X"][split:]) # total length - split length
```
%% Cell type:code id:274f1bc0 tags:
``` python
# random shuffling the data
# indexes=[i for i in range(len(mat["X"]))]
# np.random.shuffle(indexes)
# mat["X"][indexes[:split]], mat["Y"][indexes[:split]]
```
%% Cell type:code id:3a10f3bc tags:
``` python
train_dataset= ScikitFeatDataset( , ) # <-- TODO: input the split defined from above
val_dataset= ScikitFeatDataset( , ) # <---
batch_size=1
train_dataloader= torch.utils.data.DataLoader(train_dataset, batch_size=batch_size)
val_dataloader= torch.utils.data.DataLoader(val_dataset, batch_size=batch_size)
```
%% Cell type:code id:ae3329bf tags:
``` python
```
%% Cell type:code id:a0f18535 tags:
``` python
# shape of X, unique labels
print(mat["X"].shape, np.unique(mat["Y"]))
```
%% Cell type:code id:fa87a3d3 tags:
``` python
# TODO: creating a simple sequential NN
# https://pytorch.org/docs/stable/generated/torch.nn.Sequential.html
input_units= # <-- number of features for each data instance
output_units= # <-- number of unique classes within data
layer=[torch.nn.Linear(input_units,output_units), torch.nn.Softmax(dim=1)]
model= torch.nn.Sequential(*layer).to(DEVICE)
loss_function= torch.nn.CrossEntropyLoss()
optimiser= torch.optim.Adam(model.parameters(), lr=0.001)
```
%% Cell type:code id:40f4a746 tags:
``` python
# dataloader provides a batch
# default setting of loss_function takes the average loss from the batch
# --> loss= batch_loss/ num_in_batch
# the average loss from all instances is better for tracking the model's performance
# --> running_loss_from_each_batch += batch_loss * num_in_batch
# --> final_loss_for_epoch = running_loss_loss_from_each_batch / total_num_of_data_instances
```
%% Cell type:code id:fc6a32e7 tags:
``` python
# TODO: create training and validation function
def train(model, train_dataloader, loss_function, optimiser):
# https://pytorch.org/tutorials/beginner/introyt/trainingyt.html#the-training-loop
model.train()
running_loss= 0
for X, y in train_dataloader:
optimiser.zero_grad()
X= X.to(DEVICE, dtype=torch.float)
y= y.to(DEVICE, dtype=torch.long)
###### TODO
######
print(f"Loss: {running_loss/ len(train_dataloader)}")
EPOCHS=1
for i in range(EPOCHS):
train(model, train_dataloader, loss_function, optimiser)
def val(model, val_dataloader, loss_function):
# https://learn.microsoft.com/en-us/windows/ai/windows-ml/tutorials/pytorch-analysis-train-model#train-the-model-on-the-training-data
model.eval()
y_real= []
outputs= []
running_loss= 0
with torch.no_grad():
for X, y in val_dataloader:
X = X.to(DEVICE, dtype=torch.float)
y = y.to(DEVICE, dtype=torch.long)
##### TODO
#####
outputs += [output.argmax(dim=1).cpu().detach().numpy()]
y_real += [y.cpu().detach().numpy()]
validation_loss= running_loss / len(val_dataloader)
return validation_loss, outputs, y_real
validation_loss, outputs, y_real= val(model, val_dataloader, loss_function)
```
%% Cell type:code id:1e9e2371 tags:
``` python
import sklearn.metrics
# https://scikit-learn.org/stable/modules/classes.html#classification-metrics
sklearn.metrics.accuracy_score(y_real, outputs)
```
%% Cell type:code id:b2574d49 tags:
``` python
dictionary=sklearn.metrics.classification_report(y_real, outputs, output_dict=True)
dictionary
```
%% Cell type:code id:860ea084 tags:
``` python
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
plt.figure(figsize=(8,6))
sns.heatmap(pd.DataFrame(dictionary).iloc[:-1, :-3].T, annot=True)
plt.show()
```
%% Cell type:markdown id:4d51d393 tags:
## Section 2: Finetuning with Optuna
%% Cell type:code id:8b438cec tags:
``` python
import optuna
import torch
```
%% Cell type:code id:47a39e72 tags:
``` python
# https://optuna.readthedocs.io/en/stable/reference/generated/optuna.study.create_study.html#optuna.study.create_study
study= optuna.create_study(direction="minimize")
```
%% Cell type:code id:784d0713 tags:
``` python
# https://optuna.readthedocs.io/en/stable/reference/generated/optuna.trial.Trial.html#optuna.trial.Trial
def define_model(trial):
layers= []
# TODO: add to the activation function selections
# consider https://pytorch.org/docs/stable/nn.html#non-linear-activations-weighted-sum-nonlinearity
activation_function_selections= {"ReLU":torch.nn.ReLU(),"None":None}
input_units= #<-- number of features
n_layers= trial.suggest_int("n_layers", 0, 1) # TODO: define a new range that is not between 0-1 layers
for i in range(n_layers):
units= trial.suggest_int(f"layer{i}_units", 1,2) # TODO: define a new range that is not between 1-2 units
layers.append(torch.nn.Linear(input_units, units))
activation_function= activation_function_selections[trial.suggest_categorical(f"layer{i}_activation", activation_function_selections.keys())]
if activation_function != None:
layers.append(activation_function)
input_units= units
classes= # <-- number of classes within the data
output_activation= torch.nn.Softmax(dim=1)
output_layer= torch.nn.Linear(input_units, classes)
layers.append(output_layer)
layers.append(output_activation)
return torch.nn.Sequential(*layers)
```
%% Cell type:code id:54e38659 tags:
``` python
EPOCHS=1
def objective(trial):
model= define_model(trial).to(DEVICE)
loss_function= torch.nn.CrossEntropyLoss()
learning_rate= trial.suggest_float("lr", 1e-5, 1e-3)
# TODO: add more optimisers
# consider https://pytorch.org/docs/stable/optim.html#algorithms
optimiser_selections={"Adam": torch.optim.Adam(model.parameters(), lr=learning_rate)}
optimiser= optimiser_selections[trial.suggest_categorical("optim", optimiser_selections.keys())]
print(model)
for i in range(EPOCHS):
train(model, train_dataloader, loss_function, optimiser)
validation_loss, outputs, y_real= val(model, val_dataloader, loss_function)
# TODO: use alternate objective metrics to optimise the optuna study
# Note: MINIMIZE validation_loss, MAXIMISE accuracy
# Hint: change direction of optuna study object
return validation_loss
```
%% Cell type:code id:b13b6082 tags:
``` python
study.optimize(objective, n_trials=3)
```
%% Cell type:code id:6a991683 tags:
``` python
study.best_trial
```
%% Cell type:code id:ecc600aa tags:
``` python
study.best_trial.values
```
%% Cell type:code id:9d8f257e tags:
``` python
# TODO: extract parameters from study.best_trial
```
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment