This notebooks presents simple Multi-Layer Perceptron in PyTorch model to solve College Admissions problem
Contents
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import torch
import torch.nn as nn
Load and show raw, unprocessed data
dataset_file = '../Datasets/college-admissions/college_admissions.csv'
df = pd.read_csv(dataset_file)
df.head()
Preprocess dataset
# Create dummies
temp = pd.get_dummies(df['rank'], prefix='rank')
data = pd.concat([df, temp], axis=1)
data.drop(columns='rank', inplace=True)
# Normalize
for col in ['gre', 'gpa']:
mean, std = data[col].mean(), data[col].std()
# data.loc[:, col] = (data[col]-mean) / std
data[col] = (data[col]-mean) / std
# Split off random 20% of the data for testing
np.random.seed(0) # for reproducibility
sample = np.random.choice(data.index, size=int(len(data)*0.9), replace=False)
data, test_data = data.iloc[sample], data.drop(sample)
# Split into features and targets
features_train = data.drop('admit', axis=1)
targets_train = data['admit']
features_test = test_data.drop('admit', axis=1)
targets_test = test_data['admit']
# Convert to numpy
x_train = features_train.values # features train set (numpy)
y_train = targets_train.values[:,None] # targets train set (numpy)
x_test = features_test.values # features validation set (numpy)
y_test = targets_test.values[:,None] # targets validation set (numpy)
# Assert shapes came right way around
assert x_train.shape == (360, 6)
assert y_train.shape == (360, 1)
assert x_test.shape == (40, 6)
assert y_test.shape == (40, 1)
Train data looks like this
x_train[0:6].round(2)
y_train[0:6]
Helper function, returns tensor
def accuracy(pred, tar):
return (pred == tar).float().mean() # tensor!!
Model with one hidden, one output layer
model = nn.Sequential(
nn.Linear(in_features=6, out_features=128),
nn.Sigmoid(),
nn.Linear(in_features=128, out_features=1)) # note there is no sigmoid at the output
criterion = nn.BCEWithLogitsLoss() # this expects logits and is more numerically stable
optimizer = torch.optim.Adam(model.parameters())
print(model)
Convert dataset to tensors
x = torch.tensor(x_train, dtype=torch.float32)
y = torch.tensor(y_train, dtype=torch.float32)
Train model
hist = { 'loss':[], 'acc':[] }
for epoch in range(500): # loop over the dataset multiple times
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = model(x)
loss = criterion(outputs, y)
loss.backward()
optimizer.step()
with torch.no_grad():
probabilities = torch.sigmoid(outputs)
predictions = probabilities.round()
hist['acc'].append( accuracy(predictions, y).item() )
hist['loss'].append( loss.item() )
Show final results
with torch.no_grad():
outputs = model(x)
probabilities = torch.sigmoid(outputs)
predictions = probabilities.data.round()
acc = accuracy(predictions, y).item()
print(f'Accuracy on train set: {acc:.2f}')
x = torch.tensor(x_test, dtype=torch.float32)
y = torch.tensor(y_test, dtype=torch.float32)
with torch.no_grad():
outputs = model(x)
probabilities = torch.sigmoid(outputs)
predictions = probabilities.data.round()
acc = accuracy(predictions, y).item()
print(f'Accuracy on test set: {acc:.2f}')
plt.plot(hist['loss'], label='loss')
plt.plot(hist['acc'], label='acc', color='red')
plt.legend();