| title: “Multi-Layer Perceptron in R” |
| author: “Harsh Sharma” |
| output: html_document |
This document demonstrates the creation and training of a multi-layer perceptron (MLP) in R using basic functions.
library(DiagrammeR) # For visualizing the neural network structure
library(datasets) # Contains the iris dataset
Define Activation Functions and Weight Initialization
# Sigmoid function
sigmoid <- function(x) {
return(1 / (1 + exp(-x)))
}
# Derivative of sigmoid for backpropagation
sigmoid_derivative <- function(x) {
return(x * (1 - x))
}
# Initialize weights randomly for each layer
initialize_weights <- function(n_input, n_hidden1, n_hidden2, n_output) {
list(
w1 = matrix(runif(n_input * n_hidden1, min = -1, max = 1), nrow = n_input, ncol = n_hidden1),
w2 = matrix(runif(n_hidden1 * n_hidden2, min = -1, max = 1), nrow = n_hidden1, ncol = n_hidden2),
w3 = matrix(runif(n_hidden2 * n_output, min = -1, max = 1), nrow = n_hidden2, ncol = n_output)
)
}
Define Forward and Backward Propagation Functions
# Forward propagation through the network
forward_propagation <- function(input, weights) {
z1 <- sigmoid(input %*% weights$w1)
z2 <- sigmoid(z1 %*% weights$w2)
output <- sigmoid(z2 %*% weights$w3)
list(z1 = z1, z2 = z2, output = output)
}
# Backward propagation for weight adjustment
backward_propagation <- function(input, output, actual, z1, z2, weights, learning_rate) {
error_output <- actual - output
delta_output <- error_output * sigmoid_derivative(output)
error_hidden2 <- delta_output %*% t(weights$w3)
delta_hidden2 <- error_hidden2 * sigmoid_derivative(z2)
error_hidden1 <- delta_hidden2 %*% t(weights$w2)
delta_hidden1 <- error_hidden1 * sigmoid_derivative(z1)
weights$w3 <- weights$w3 + learning_rate * t(z2) %*% delta_output
weights$w2 <- weights$w2 + learning_rate * t(z1) %*% delta_hidden2
weights$w1 <- weights$w1 + learning_rate * t(input) %*% delta_hidden1
return(weights)
}
Training Function
# Train function with specified epochs and learning rate
train_perceptron <- function(input, actual, weights, epochs, learning_rate) {
for (i in 1:epochs) {
forward <- forward_propagation(input, weights)
weights <- backward_propagation(input, forward$output, actual, forward$z1, forward$z2, weights, learning_rate)
# Display loss every 100 epochs
if (i %% 100 == 0) {
cat("Epoch:", i, "Loss:", sum((actual - forward$output)^2) / length(actual), "\n")
}
}
return(weights)
}
Data Preprocessing on the Iris Dataset
# Load and preprocess the Iris dataset
data <- iris
data <- data[data$Species != "virginica", ] # Binary classification (versicolor or setosa)
data$Species <- as.numeric(data$Species == "versicolor") # Convert species to binary (0 and 1)
input <- as.matrix(data[, 1:4]) # Use sepal and petal measurements as input
actual <- as.matrix(data$Species) # Target labels
# Scale input data
input <- scale(input)
Initialize Weights and Train the Model
# Initialize weights
weights <- initialize_weights(n_input = 4, n_hidden1 = 5, n_hidden2 = 3, n_output = 1)
# Train the perceptron
trained_weights <- train_perceptron(input, actual, weights, epochs = 1000, learning_rate = 0.01)
## Epoch: 100 Loss: 0.05507123
## Epoch: 200 Loss: 0.01358418
## Epoch: 300 Loss: 0.006778422
## Epoch: 400 Loss: 0.004359182
## Epoch: 500 Loss: 0.003165932
## Epoch: 600 Loss: 0.002466684
## Epoch: 700 Loss: 0.002011264
## Epoch: 800 Loss: 0.001692755
## Epoch: 900 Loss: 0.001458304
## Epoch: 1000 Loss: 0.001278952
Visualize Perceptron Structure
# Visualize the perceptron structure
visualize_perceptron <- function() {
grViz("
digraph neural_network {
node [shape = circle, style = filled, color = lightblue, label = 'Input\nX1'] x1;
node [shape = circle, style = filled, color = lightblue, label = 'Input\nX2'] x2;
# Hidden layers
node [shape = circle, style = filled, color = green, label = 'Hidden\nLayer 1'] h1;
node [shape = circle, style = filled, color = green, label = 'Hidden\nLayer 2'] h2;
# Output layer
node [shape = circle, style = filled, color = orange, label = 'Output\nY'] y;
# Connections
x1 -> h1; x2 -> h1;
h1 -> h2;
h2 -> y;
}
")
}
visualize_perceptron()
Testing the Model
# Test with sample input
test_input <- matrix(input[1, ], nrow = 1) # Use the first row as test input
output <- forward_propagation(test_input, trained_weights)$output
print(output)
## [,1]
## [1,] 0.03326782