Perceptron Activities
Unit 7
Single Perceptron
This exercise demonstrates the basic operations of a single perceptron: calculating the dot product as a weighted sum of inputs and passing it through a step function as the activation mechanism.
# Importing NumPy
import numpy as np
# Exercise 1: Dot Product and Step Function
print("---- Exercise 1 ----")
# Inputs and weights for the perceptron
# Inputs represent features, and weights represent their importance.
inputs = np.array([45, 25])
weights = np.array([0.7, 0.1])
# Dot product simulates the sum function in a perceptron
sum_func = np.dot(inputs, weights)
# Step function simulates the perceptron's activation function
# If the weighted sum is greater than or equal to a threshold, it activates (returns 1).
def step_function(value):
return 1 if value >= 1 else 0
result_step = step_function(sum_func)
print(f"Sum: {sum_func}, Step Function Result: {result_step}")
Training a Perceptron (AND Operator)
This follow up exercise introduces training a perceptron to learn the logic of an AND gate. The weights are adjusted iteratively based on errors until the perceptron accurately models the desired behavior.
# Exercise 2: Training a Perceptron
print("\n---- Exercise 2 ----")
# Inputs and expected outputs for an AND gate
# Each row in inputs represents a data point, and outputs is the target result.
inputs = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
outputs = np.array([0, 0, 0, 1]) # AND gate logic
# Initialize weights to zero and set a learning rate
weights = np.array([0.0, 0.0])
learning_rate = 0.1
# Perceptron training function
# Adjusts weights based on errors to learn the AND gate logic.
def train_perceptron():
global weights
for _ in range(10): # Fixed number of epochs (iterations over the data)
total_error = 0
for i in range(len(outputs)):
# Calculate the perceptron's prediction
prediction = step_function(np.dot(inputs[i], weights))
# Error is the difference between the target and the prediction
error = outputs[i] - prediction
# Update weights based on the error and learning rate
weights += learning_rate * inputs[i] * error
# Track total error to decide when to stop
total_error += abs(error)
# Stop early if the perceptron has no errors
if total_error == 0:
break
print(f"Trained Weights: {weights}")
train_perceptron()
Multilayer Perceptron
Finally, this experiment implements a simple artificial neural network to solve the XOR problem, which cannot be addressed by a single perceptron. The network uses a sigmoid activation function, forward propagation, and backpropagation to adjust weights over multiple epochs.
# Exercise 3: Simple Artificial Neural Network
print("\n---- Exercise 3 ----")
# Define sigmoid activation function
# Maps any real value into the range (0, 1), enabling the ANN to handle non-linear problems.
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# Derivative of sigmoid (used during backpropagation)
def sigmoid_derivative(x):
return x * (1 - x)
# Inputs and outputs for XOR gate
# XOR cannot be solved by a single perceptron, hence a neural network is needed.
inputs = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
outputs = np.array([[0], [1], [1], [0]])
# Initialize weights randomly for input-to-hidden and hidden-to-output layers
weights_0 = np.random.uniform(-1, 1, (2, 3)) # 2 inputs, 3 hidden neurons
weights_1 = np.random.uniform(-1, 1, (3, 1)) # 3 hidden neurons, 1 output
# Learning rate controls the size of weight updates
learning_rate = 0.1
# Train the neural network
for epoch in range(10000): # Number of training iterations
# Forward pass: compute the outputs of each layer
hidden_layer_input = np.dot(inputs, weights_0)
hidden_layer_output = sigmoid(hidden_layer_input)
final_layer_input = np.dot(hidden_layer_output, weights_1)
final_output = sigmoid(final_layer_input)
# Calculate error at the output layer
error = outputs - final_output
# Backpropagation: compute adjustments for weights
final_output_delta = error * sigmoid_derivative(final_output)
hidden_layer_error = final_output_delta.dot(weights_1.T)
hidden_layer_delta = hidden_layer_error * sigmoid_derivative(hidden_layer_output)
# Update weights based on deltas
weights_1 += hidden_layer_output.T.dot(final_output_delta) * learning_rate
weights_0 += inputs.T.dot(hidden_layer_delta) * learning_rate
# Optional: Print the error every 1000 epochs for monitoring
if epoch % 1000 == 0:
print(f"Epoch {epoch}, Error: {np.mean(np.abs(error))}")
# Final predictions after training
print("\nFinal Predictions:")
for i, input_val in enumerate(inputs):
hidden = sigmoid(np.dot(input_val, weights_0))
output = sigmoid(np.dot(hidden, weights_1))
print(f"Input: {input_val}, Predicted: {output.round()}")