Neural networks are the backbone of deep learning and have revolutionized fields such as computer vision, natural language processing, and more. While powerful libraries like TensorFlow and PyTorch make it easy to build complex models, understanding how to implement a basic neural network from scratch can provide valuable insights into how these models work under the hood.
In this tutorial, we will walk through the steps to create a simple feedforward neural network using Python, without relying on any deep learning libraries. We'll implement the forward pass, backpropagation, and training loop manually.
Overview of the Neural Network
A basic neural network consists of layers of neurons that are connected by weights. The network we will build will have:
Input Layer: Takes the input features.
Hidden Layer: A single hidden layer with a configurable number of neurons.
Output Layer: Provides the final output predictions.
We will use the sigmoid activation function for the hidden layer and a binary cross-entropy loss function for training on a binary classification problem.
Step 1: Import Libraries
We'll start by importing the necessary libraries. For this implementation, we only need NumPy.
import numpy as np
Step 2: Initialize the Neural Network
Let's define a simple neural network class with an initializer to set up weights and biases.
class SimpleNeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
self.weights_input_hidden = np.random.randn(input_size, hidden_size)
self.weights_hidden_output = np.random.randn(hidden_size, output_size)
self.bias_hidden = np.zeros((1, hidden_size))
self.bias_output = np.zeros((1, output_size))
Here, input_size is the number of input features, hidden_size is the number of neurons in the hidden layer, and output_size is the number of output classes (1 for binary classification).
Step 3: Define Activation and Loss Functions
We'll use the sigmoid function as our activation function and binary cross-entropy for the loss.
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x):
return x * (1 - x)
def binary_cross_entropy(y_true, y_pred):
return -np.mean(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))
Step 4: Implement the Forward Pass
The forward pass computes the output of the neural network for a given input.
class SimpleNeuralNetwork:
def forward(self, X):
self.hidden_input = np.dot(X, self.weights_input_hidden) + self.bias_hidden
self.hidden_output = sigmoid(self.hidden_input)
self.output_input = np.dot(self.hidden_output, self.weights_hidden_output) + self.bias_output
self.output = sigmoid(self.output_input)
return self.output
Step 5: Implement Backpropagation
Backpropagation calculates the gradients of the loss with respect to each weight, which will be used to update the weights.
class SimpleNeuralNetwork:
def backward(self, X, y, learning_rate):
output_error = self.output - y
output_delta = output_error * sigmoid_derivative(self.output)
hidden_error = output_delta.dot(self.weights_hidden_output.T)
hidden_delta = hidden_error * sigmoid_derivative(self.hidden_output)
self.weights_hidden_output -= self.hidden_output.T.dot(output_delta) * learning_rate
self.bias_output -= np.sum(output_delta, axis=0, keepdims=True) * learning_rate
self.weights_input_hidden -= X.T.dot(hidden_delta) * learning_rate
self.bias_hidden -= np.sum(hidden_delta, axis=0, keepdims=True) * learning_rate
Step 6: Train the Neural Network
Now we need a method to train the network using forward and backward passes.
class SimpleNeuralNetwork:
def train(self, X, y, epochs, learning_rate):
for epoch in range(epochs):
self.forward(X)
self.backward(X, y, learning_rate)
loss = binary_cross_entropy(y, self.output)
if epoch % 100 == 0:
print(f"Epoch {epoch}, Loss: {loss}")
Step 7: Test the Neural Network
To test the neural network, we'll create some dummy data. Let's create a simple dataset for binary classification.
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])
nn = SimpleNeuralNetwork(input_size=2, hidden_size=2, output_size=1)
nn.train(X, y, epochs=10000, learning_rate=0.1)
output = nn.forward(X)
print("Predictions:")
print(output)
Conclusion
You have now implemented a simple neural network from scratch in Python. This network can solve basic binary classification problems like the XOR problem. By understanding how each component of the network works, you gain deeper insights into how neural networks learn and generalize from data. While this is a very basic implementation, it lays the foundation for understanding more complex networks and can be extended to multi-class problems, deeper architectures, and more sophisticated activation functions and optimizers.