Image from: https://datascientest.com/en/perceptron-definition-and-use-cases
In this post we include a perceptron implementation using NumPy and using PyTorch.
The Main Code
We use input data from this location. The input structure is as follows:
The main code does the following:
- Reads the data
- Split to training data and testing data
- Creates and trains a single perceptron
- Validates the training results vs. the testing data
def prepare_input(x, y):
samples_number = y.shape[0]
indices = np.arange(samples_number)
random_state = np.random.RandomState(RANDOM_SEED)
random_state.shuffle(indices)
x, y = x[indices], y[indices]
train_factor = 0.7
train_size = int(train_factor * samples_number)
x_train, x_test = x[:train_size], x[train_size:]
y_train, y_test = y[:train_size], y[train_size:]
print('train shape', x_train.shape, y_train.shape)
print('test shape', x_test.shape, y_test.shape)
return x_train, y_train, x_test, y_test
def normalize_input(mean, std, data):
return (data - mean) / std
def plot_xy_by_classes(samples, labels, file_name, added_line=None):
class1_indices = labels == 0
class2_indices = labels == 1
class1_x = samples[class1_indices, 0]
class1_y = samples[class1_indices, 1]
class2_x = samples[class2_indices, 0]
class2_y = samples[class2_indices, 1]
plt.clf()
if added_line:
line_x, line_y = added_line
plt.plot(line_x, line_y)
plt.scatter(class1_x, class1_y, label='class1', marker='o')
plt.scatter(class2_x, class2_y, label='class2', marker='s')
plt.legend()
plt.savefig(f'output/{file_name}.pdf')
def main():
x, y = read_input()
plot_xy_by_classes(x, y, 'original')
x_train, y_train, x_test, y_test = prepare_input(x, y)
mean = x_train.mean(axis=0)
std = x_train.std(axis=0)
x_train = normalize_input(mean, std, x_train)
x_test = normalize_input(mean, std, x_test)
plot_xy_by_classes(x_train, y_train, 'train')
plot_xy_by_classes(x_test, y_test, 'test')
perceptron = Perceptron(2)
perceptron.train(x_train, y_train, 10)
perceptron.describe()
accuracy = perceptron.evaluate(x_test, y_test)
print('accuracy', accuracy)
plot_xy_by_classes(x_train, y_train, 'train_with_model', added_line=perceptron.model_line())
plot_xy_by_classes(x_test, y_test, 'test_with_model', added_line=perceptron.model_line())
main()
Perceptron Using NumPy
NumPy requires the following dependecies:
pip3 install numpy
pip3 install mathplotlib
And the Perceptron code is:
class Perceptron:
def __init__(self, features_number):
self.features_number = features_number
self.weights_vector = np.zeros((features_number, 1), dtype=np.float32)
self.bias = np.zeros(1, dtype=np.float32)
def forward(self, x):
z = x @ self.weights_vector + self.bias
predictions = np.where(z > 0., 1, 0)
return predictions
def backward(self, x, y):
predictions = self.forward(x)
errors = y - predictions
return errors
def train(self, x, y, epochs_number):
for epoch_index in range(epochs_number):
for sample_index in range(y.shape[0]):
sample_x = x[sample_index]
sample_label = y[sample_index]
errors = self.backward(sample_x, sample_label)
correction = errors * sample_x
correction = correction.reshape(self.features_number, 1)
self.weights_vector += correction
self.bias += errors
def evaluate(self, x, y):
predictions = self.forward(x).flatten()
correct = predictions == y
accuracy = np.sum(correct) / y.shape[0]
return accuracy
def describe(self):
print('weights', self.weights_vector.flatten())
print('bias', self.bias)
def model_line(self):
x1 = -2
x2 = 2
y1 = -(self.bias + x1 * self.weights_vector[0]) / self.weights_vector[1]
y2 = -(self.bias + x2 * self.weights_vector[0]) / self.weights_vector[1]
line_x = [x1, x2]
line_y = [y1, y2]
return line_x, line_y
Perceptron Using PyTorch
PyTorch requires the following dependencies:
pip3 install numpy
pip3 install mathplotlib
pip3 install torch
And the Perceptron code is:
class Perceptron:
def __init__(self, features_number):
self.device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
self.features_number = features_number
self.weights_vector = torch.zeros(features_number, 1, dtype=torch.float32, device=self.device)
self.bias = torch.zeros(1, dtype=torch.float32, device=self.device)
self.ones = torch.ones(1)
self.zeros = torch.zeros(1)
def forward(self, x):
z = x @ self.weights_vector + self.bias
predictions = torch.where(z > 0., self.ones, self.zeros)
return predictions
def backward(self, x, y):
predictions = self.forward(x)
errors = y - predictions
return errors
def train(self, x, y, epochs_number):
x = torch.tensor(x, dtype=torch.float32, device=self.device)
y = torch.tensor(y, dtype=torch.float32, device=self.device)
for epoch_index in range(epochs_number):
for sample_index in range(y.shape[0]):
sample_x = x[sample_index]
sample_label = y[sample_index]
errors = self.backward(sample_x, sample_label)
correction = errors * sample_x
correction = correction.reshape(self.features_number, 1)
self.weights_vector += correction
self.bias += errors
def evaluate(self, x, y):
x = torch.tensor(x, dtype=torch.float32, device=self.device)
y = torch.tensor(y, dtype=torch.float32, device=self.device)
predictions = self.forward(x).flatten()
correct = predictions == y
accuracy = torch.sum(correct).float() / y.shape[0]
return accuracy
def describe(self):
print('weights', self.weights_vector.flatten())
print('bias', self.bias)
def model_line(self):
x1 = -2
x2 = 2
y1 = -(self.bias + x1 * self.weights_vector[0]) / self.weights_vector[1]
y2 = -(self.bias + x2 * self.weights_vector[0]) / self.weights_vector[1]
line_x = [x1, x2]
line_y = [y1, y2]
return line_x, line_y
Run Results
Plotting the reuslts, we can see the model in the training data:
And the model over the test data:
No comments:
Post a Comment