Skip to content

Instantly share code, notes, and snippets.

@mpds
Last active October 13, 2021 02:19
Show Gist options
  • Save mpds/1abec0ba2debfd224b2b225c06701f70 to your computer and use it in GitHub Desktop.
Save mpds/1abec0ba2debfd224b2b225c06701f70 to your computer and use it in GitHub Desktop.
Item 1 - Perceptron
import numpy as np
def generate_dataset(N: int, p1: list, p2: list, seed: int = 42):
"""Generate a random dataset with size N from p1 and p2."""
p1_ = np.tile(p1, reps=int(N // 2)).reshape(N // 2, 2)
p2_ = np.tile(p2, reps=int(N // 2)).reshape(N // 2, 2)
rng = np.random.default_rng(seed) # random number generator
X = np.concatenate((p1_, p2_)) + rng.standard_normal((N, 2)) # examples
Y = np.concatenate((np.tile(+1, p1_.shape[0]), np.tile(-1, p2_.shape[0]))) # labels
return (X, Y)
def split_dataset(dataset, train_split_percentage: float, seed: int = 42):
"""Shuffle and split dataset."""
X, Y = dataset
rng = np.random.default_rng(seed) # random number generator
idx = rng.permutation(X.shape[0])
x, y = X[idx], Y[idx]
n_train = int(X.shape[0] * train_split_percentage)
x_train, y_train = x[:n_train], y[:n_train]
x_test, y_test = x[n_train:], y[n_train:]
return (x_train, y_train), (x_test, y_test)
class Perceptron:
def __init__(self, lr: float = 1):
self.weights = np.array([0.0, 0.0])
self.bias = 0.0
self.lr = lr # learning rate
def activation(self, z: np.ndarray):
"""Implement the signal function.
Returns 1 if x > 0, -1 otherwise.
"""
return np.where(z > 0, 1, -1)
def forward(self, x: np.ndarray):
"""Perform a forward pass."""
z = np.dot(x, self.weights) + self.bias # induced field
ypred = self.activation(z) # activation function
return ypred
def loss(self, y: float, ypred: float):
"""Calculate the loss."""
return y - ypred
def step(self, x: np.ndarray, y: float):
"""Perform a forward pass and update weights and biases.
x : np.ndarray
An example of the dataset.
y : float
Ground truth label.
"""
ypred = self.forward(x) # forward step calculation
# update weights and bias
delta = self.lr * self.loss(y, ypred)
self.weights = self.weights + (delta * x)
self.bias = self.bias + delta
if __name__ == "__main__":
dataset = generate_dataset(100, p1=[-1, 1], p2=[1, -3])
train, test = split_dataset(dataset, train_split_percentage=0.7)
X, Y = 0, 1 # indices that correspond to examples/labels respectively
# hyperparams
epoch, max_epochs = 1, 1000
loss = 1
tol = 1e-8
model = Perceptron()
# training loop
while loss > tol and epoch < max_epochs:
for x, y in zip(
train[X], train[Y]
): # loop through dataset, one ex. per iteration
model.step(x, y)
preds = model.forward(train[X]) # predictions over training set
loss = np.mean(np.abs(model.loss(train[Y], preds))) # average abs loss
epoch += 1
print("Épocas:", epoch)
print("Valor dos pesos:", model.weights)
print("Valor do bias:", model.bias)
acc = (preds == train[Y]).sum() / train[Y].shape[0] * 100
print(f"Acurácia no treinamento: {acc:.2f}%")
yhat = model.forward(test[X])
print(f"Acurácia no teste: {(yhat == test[Y]).sum() / yhat.shape[0] * 100:.2f}%")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment