Simple binary classification

The code below solves the sklearn make_circles problem. It also provide pseudo animation of the development of the solution. For make_moons and spirals see https://github.com/talasinski/Pytorch-Neural-Net-Playground. Modified version of this code was used for the Boston Housing problem, see my comments to
PyTorch fails to (over)fit Boston housing dataset

original code for make_moons from

#https://www.datahubbs.com/deep-learning-101-first-neural-network-with-pytorch/
#Modified by Tom Lasinski for the make_circles problem and spitals.
#Also added “animation” to show optimizer fitting the training data.

see https://github.com/talasinski/Pytorch-Neural-Net-Playground

import numpy as np
from sklearn.datasets import make_circles
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import torch
import torch.nn as nn

def boundary(X): # determine boundary between different colored dots
x_min, x_max = X[:, 0].min()-0.1, X[:, 0].max()+0.1
y_min, y_max = X[:, 1].min()-0.1, X[:, 1].max()+0.1
spacing = min(x_max - x_min, y_max - y_min) / 100
XX, YY = np.meshgrid(np.arange(x_min, x_max, spacing),np.arange(y_min, y_max, spacing))
data = np.hstack((XX.ravel().reshape(-1,1),YY.ravel().reshape(-1,1)))
data_t = torch.FloatTensor(data)
db_prob = net(data_t)
clf = np.where(db_prob<0.5,0,1)
Z = clf.reshape(XX.shape)
return(plt.contourf(XX, YY, Z, cmap=plt.cm.Accent, alpha=0.6))

print(“Using PyTorch Version %s” %torch.version)
np.random.seed(0)
torch.manual_seed(0)
X, Y = make_circles(n_samples=2000, noise=0.15, factor = 0.1, random_state=1)
X_train, X_test, Y_train, Y_test = train_test_split(X, Y,test_size=0.75, random_state=73)

fig, ax = plt.subplots(1, 2, figsize=(6,4))
ax[0].set_title(‘Total Circles Data’)
ax[0].scatter(X[:,0], X[:,1], c=Y)
ax[1].set_title(‘Training Circles Data’)
ax[1].scatter(X_train[:,0], X_train[:,1], c=Y_train)
#print(’ train shape’, X_train.shape, Y_train.shape)
plt.tight_layout()
plt.show()

Define network dimensions

n_input_dim = X_train.shape[1]

Layer size

n_hidden2 = 40
n_hidden = 20 # Number of hidden nodes
n_output = 1 # Number of output nodes = for binary classifier
net = nn.Sequential(
nn.Linear(n_input_dim, n_hidden),
nn.ELU(),
nn.Linear(n_hidden, n_hidden2),
nn.ELU(),
nn.Linear(n_hidden2, n_output), nn.Sigmoid()
)

loss_func = nn.BCELoss()
learning_rate = 0.005
optimizer = torch.optim.Adam(net.parameters(), lr=learning_rate)

train_loss = []
train_accuracy = []
iters = 300
print('Shapes: ', Y_train.shape, Y_train.reshape(-1,1).shape)
Y_train_t = torch.FloatTensor(Y_train).reshape(-1, 1)
plot_iter = 100
plot_now = 1
X_train_t = torch.FloatTensor(X_train)
print('Shapes: ',X_train_t.shape, Y_train_t.shape)
for i in range(iters):

X_train_t = torch.FloatTensor(X_train)

y_hat = net(X_train_t)    #this is how you make predictions.
y_hat_round = y_hat.round()

loss = loss_func(y_hat, Y_train_t)
loss.backward()
optimizer.step()
optimizer.zero_grad()
y_hat_class = np.where(y_hat.detach().numpy()<0.5, 0, 1)
accuracy = np.sum(Y_train.reshape(-1,1)==y_hat_class) / len(Y_train)
train_accuracy.append(accuracy)
train_loss.append(loss.item())

if i%plot_now == 0:
	print(' Iteration: ', i, ' loss: {:.4f}'.format(loss.item()),' accuracy:', accuracy)
	y_hat_final =  y_hat_round.detach().numpy().reshape(500)
	string = 'Iteration = {}'.format(i)
	plt.figure(figsize=(5,5))
	plt.title(string)
	_ = boundary(X)
	plt.scatter(X_train [:,0], X_train [:,1], c=y_hat_final) #y_hat_class

	plt.show(block=False)
	plt.pause(0.2)
	plt.close()
	if i > plot_iter : plot_now = 100

#summary of results
X_test_t = torch.FloatTensor(X_test)
Y_test_t = torch.FloatTensor(Y_test).reshape(-1, 1)
y_hat_test = net(X_test_t)
y_hat = net(X_test_t)
loss_test =loss_func(y_hat,Y_test_t)
y_hat_test_class = np.where(y_hat_test.detach().numpy()<0.5, 0, 1) # torch Mickey
test_accuracy = np.sum(Y_test.reshape(-1,1)==y_hat_test_class) / len(Y_test) # torch Mickey
print(“Test Accuracy {:.3f}”.format(test_accuracy))
print(‘Loss for Test Set: {:.4f}’.format(loss_test.item()))
y_hat_round = y_hat_test.round()
y_hat_final = y_hat_round.detach().numpy().reshape(1500) # torch Mickey

plt.figure(figsize=(12,6))
plt.subplot(1,2,1)
plt.title(‘Training Accuracy:{:.3f}’.format(accuracy))

_ = boundary(X_train)
plt.scatter(X_train[:,0], X_train[:,1], c=Y_train,cmap=plt.cm.Accent)

plt.subplot(1,2,2)
plt.title(‘Prediction Test Set: {:.3f} Loss’.format(loss_test))

_ = boundary(X_test)
plt.scatter(X_test[:,0], X_test[:,1], c=y_hat_final,cmap=plt.cm.Accent)
plt.tight_layout()
plt.show()