""" Simple Neural Network from Scratch =================================== This example builds a basic neural network without using any ML frameworks. It helps you understand what's happening "under the hood" in neural networks. What you'll learn: - How neurons work - Forward propagation (making predictions) - Backward propagation (learning from mistakes) - The sigmoid activation function Use case: Learn to classify points as "above" or "below" a line. """ import random import math def sigmoid(x): """ Sigmoid activation function: converts any value to a number between 0 and 1. This is like asking "how confident are we?" - Values close to 1 mean "very confident YES" - Values close to 0 mean "very confident NO" - Values around 0.5 mean "not sure" Args: x: Input value Returns: Value between 0 and 1 """ # Prevent overflow for very large/small numbers if x > 100: return 1.0 if x < -100: return 0.0 return 1 / (1 + math.exp(-x)) def sigmoid_derivative(x): """ Derivative of sigmoid function - needed for learning. This tells us how much to adjust our weights. Args: x: Sigmoid output value Returns: Derivative value """ return x * (1 - x) class SimpleNeuron: """ A single artificial neuron - the building block of neural networks. Think of it as a tiny decision maker that: 1. Takes inputs (like features of data) 2. Multiplies them by learned weights 3. Adds them up with a bias 4. Applies an activation function 5. Outputs a prediction """ def __init__(self, num_inputs): """ Initialize the neuron with random weights. Args: num_inputs: Number of input values this neuron will receive """ # Each input gets a weight (how important is this input?) self.weights = [random.uniform(-1, 1) for _ in range(num_inputs)] # Bias helps adjust the output self.bias = random.uniform(-1, 1) # Store the last output for learning self.output = 0 def feedforward(self, inputs): """ Calculate the neuron's output (prediction). This is called "forward propagation". Args: inputs: List of input values Returns: Neuron's output (between 0 and 1) """ # Step 1: Multiply each input by its weight and sum them total = sum(w * x for w, x in zip(self.weights, inputs)) # Step 2: Add bias total += self.bias # Step 3: Apply activation function (sigmoid) self.output = sigmoid(total) return self.output def train(self, inputs, target, learning_rate=0.1): """ Teach the neuron to improve its predictions. This is called "backpropagation". Args: inputs: The input values target: What the output should have been learning_rate: How much to adjust weights """ # Calculate error error = target - self.output # Calculate adjustment amount using derivative delta = error * sigmoid_derivative(self.output) # Update weights for i in range(len(self.weights)): self.weights[i] += learning_rate * delta * inputs[i] # Update bias self.bias += learning_rate * delta return abs(error) def generate_training_data(num_samples=100): """ Generate sample data for training. Task: Classify points as above (1) or below (0) the line y = x. Args: num_samples: How many training examples to create Returns: List of (inputs, target) tuples """ data = [] for _ in range(num_samples): # Random point in 2D space (x, y coordinates) x = random.uniform(0, 10) y = random.uniform(0, 10) # Label: 1 if point is above the line y=x, 0 if below label = 1 if y > x else 0 data.append(([x, y], label)) return data def visualize_decision(neuron, test_points): """ Show how the neuron classifies different points. Args: neuron: Trained neuron test_points: List of points to test """ print("\nšŸŽÆ Testing the trained neuron:") print("-" * 70) print(f"{'Point':<15} | {'Prediction':<15} | {'Actual':<15} | {'Correct?'}") print("-" * 70) correct = 0 for point, actual in test_points: prediction = neuron.feedforward(point) predicted_class = 1 if prediction > 0.5 else 0 actual_class = actual is_correct = "āœ“" if predicted_class == actual_class else "āœ—" if predicted_class == actual_class: correct += 1 print(f"({point[0]:5.2f}, {point[1]:5.2f}) | {prediction:14.4f} | {actual_class:^15} | {is_correct}") print("-" * 70) accuracy = (correct / len(test_points)) * 100 print(f"Accuracy: {accuracy:.1f}% ({correct}/{len(test_points)} correct)") def main(): """ Main function - Build and train a neural network! """ print("=" * 70) print("Simple Neural Network from Scratch") print("=" * 70) print("\nšŸ“š Task: Learn to classify points as above or below the line y = x") print() # Step 1: Generate training data print("šŸ“Š Generating training data...") training_data = generate_training_data(num_samples=100) print(f"Created {len(training_data)} training examples") # Show a few examples print("\nExample training data:") for i in range(3): point, label = training_data[i] position = "above" if label == 1 else "below" print(f" Point ({point[0]:.2f}, {point[1]:.2f}) is {position} the line y=x") # Step 2: Create neuron print("\n🧠 Creating a neuron with 2 inputs (x and y coordinates)...") neuron = SimpleNeuron(num_inputs=2) print(f"Initial weights: [{neuron.weights[0]:.3f}, {neuron.weights[1]:.3f}]") print(f"Initial bias: {neuron.bias:.3f}") # Step 3: Train the neuron print("\nšŸŽ“ Training the neuron...") epochs = 50 for epoch in range(epochs): total_error = 0 # Train on each example for inputs, target in training_data: neuron.feedforward(inputs) error = neuron.train(inputs, target, learning_rate=0.1) total_error += error # Show progress if (epoch + 1) % 10 == 0: avg_error = total_error / len(training_data) print(f"Epoch {epoch + 1}/{epochs} - Average error: {avg_error:.4f}") print("\nāœ… Training complete!") print(f"Final weights: [{neuron.weights[0]:.3f}, {neuron.weights[1]:.3f}]") print(f"Final bias: {neuron.bias:.3f}") # Step 4: Test the neuron test_data = generate_training_data(num_samples=10) visualize_decision(neuron, test_data) # Explanation print("\nšŸ’” What just happened?") print("1. The neuron started with random weights") print("2. It looked at 100 example points and their correct labels") print("3. Each time it was wrong, it adjusted its weights slightly") print("4. After 50 rounds, it learned to classify points correctly!") print() print("šŸŽ‰ You just built a neural network from scratch!") print() print("šŸš€ Try this:") print(" - Change num_samples to train on more/fewer examples") print(" - Modify epochs to train for longer/shorter") print(" - Change learning_rate (line 185) and see what happens") print(" - Try different decision boundaries (modify generate_training_data)") print() if __name__ == "__main__": main()