microsoft/AI-For-Beginners

Public

mirrored fromhttps://github.com/microsoft/AI-For-BeginnersAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
b9a5cd50a610d241d1b2b59755ef93eaea20d353

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

examples/02-simple-neural-network.py

259lines ยท modepreview

"""
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()