microsoft/AI-For-Beginners
Publicmirrored fromhttps://github.com/microsoft/AI-For-BeginnersAvailable
examples/02-simple-neural-network.py
259lines ยท modecode
| 1 | """ |
| 2 | Simple Neural Network from Scratch |
| 3 | =================================== |
| 4 | |
| 5 | This example builds a basic neural network without using any ML frameworks. |
| 6 | It helps you understand what's happening "under the hood" in neural networks. |
| 7 | |
| 8 | What you'll learn: |
| 9 | - How neurons work |
| 10 | - Forward propagation (making predictions) |
| 11 | - Backward propagation (learning from mistakes) |
| 12 | - The sigmoid activation function |
| 13 | |
| 14 | Use case: Learn to classify points as "above" or "below" a line. |
| 15 | """ |
| 16 | |
| 17 | import random |
| 18 | import math |
| 19 | |
| 20 | def sigmoid(x): |
| 21 | """ |
| 22 | Sigmoid activation function: converts any value to a number between 0 and 1. |
| 23 | |
| 24 | This is like asking "how confident are we?" |
| 25 | - Values close to 1 mean "very confident YES" |
| 26 | - Values close to 0 mean "very confident NO" |
| 27 | - Values around 0.5 mean "not sure" |
| 28 | |
| 29 | Args: |
| 30 | x: Input value |
| 31 | |
| 32 | Returns: |
| 33 | Value between 0 and 1 |
| 34 | """ |
| 35 | # Prevent overflow for very large/small numbers |
| 36 | if x > 100: |
| 37 | return 1.0 |
| 38 | if x < -100: |
| 39 | return 0.0 |
| 40 | return 1 / (1 + math.exp(-x)) |
| 41 | |
| 42 | |
| 43 | def sigmoid_derivative(x): |
| 44 | """ |
| 45 | Derivative of sigmoid function - needed for learning. |
| 46 | This tells us how much to adjust our weights. |
| 47 | |
| 48 | Args: |
| 49 | x: Sigmoid output value |
| 50 | |
| 51 | Returns: |
| 52 | Derivative value |
| 53 | """ |
| 54 | return x * (1 - x) |
| 55 | |
| 56 | |
| 57 | class SimpleNeuron: |
| 58 | """ |
| 59 | A single artificial neuron - the building block of neural networks. |
| 60 | |
| 61 | Think of it as a tiny decision maker that: |
| 62 | 1. Takes inputs (like features of data) |
| 63 | 2. Multiplies them by learned weights |
| 64 | 3. Adds them up with a bias |
| 65 | 4. Applies an activation function |
| 66 | 5. Outputs a prediction |
| 67 | """ |
| 68 | |
| 69 | def __init__(self, num_inputs): |
| 70 | """ |
| 71 | Initialize the neuron with random weights. |
| 72 | |
| 73 | Args: |
| 74 | num_inputs: Number of input values this neuron will receive |
| 75 | """ |
| 76 | # Each input gets a weight (how important is this input?) |
| 77 | self.weights = [random.uniform(-1, 1) for _ in range(num_inputs)] |
| 78 | # Bias helps adjust the output |
| 79 | self.bias = random.uniform(-1, 1) |
| 80 | # Store the last output for learning |
| 81 | self.output = 0 |
| 82 | |
| 83 | def feedforward(self, inputs): |
| 84 | """ |
| 85 | Calculate the neuron's output (prediction). |
| 86 | This is called "forward propagation". |
| 87 | |
| 88 | Args: |
| 89 | inputs: List of input values |
| 90 | |
| 91 | Returns: |
| 92 | Neuron's output (between 0 and 1) |
| 93 | """ |
| 94 | # Step 1: Multiply each input by its weight and sum them |
| 95 | total = sum(w * x for w, x in zip(self.weights, inputs)) |
| 96 | |
| 97 | # Step 2: Add bias |
| 98 | total += self.bias |
| 99 | |
| 100 | # Step 3: Apply activation function (sigmoid) |
| 101 | self.output = sigmoid(total) |
| 102 | |
| 103 | return self.output |
| 104 | |
| 105 | def train(self, inputs, target, learning_rate=0.1): |
| 106 | """ |
| 107 | Teach the neuron to improve its predictions. |
| 108 | This is called "backpropagation". |
| 109 | |
| 110 | Args: |
| 111 | inputs: The input values |
| 112 | target: What the output should have been |
| 113 | learning_rate: How much to adjust weights |
| 114 | """ |
| 115 | # Calculate error |
| 116 | error = target - self.output |
| 117 | |
| 118 | # Calculate adjustment amount using derivative |
| 119 | delta = error * sigmoid_derivative(self.output) |
| 120 | |
| 121 | # Update weights |
| 122 | for i in range(len(self.weights)): |
| 123 | self.weights[i] += learning_rate * delta * inputs[i] |
| 124 | |
| 125 | # Update bias |
| 126 | self.bias += learning_rate * delta |
| 127 | |
| 128 | return abs(error) |
| 129 | |
| 130 | |
| 131 | def generate_training_data(num_samples=100): |
| 132 | """ |
| 133 | Generate sample data for training. |
| 134 | |
| 135 | Task: Classify points as above (1) or below (0) the line y = x. |
| 136 | |
| 137 | Args: |
| 138 | num_samples: How many training examples to create |
| 139 | |
| 140 | Returns: |
| 141 | List of (inputs, target) tuples |
| 142 | """ |
| 143 | data = [] |
| 144 | for _ in range(num_samples): |
| 145 | # Random point in 2D space (x, y coordinates) |
| 146 | x = random.uniform(0, 10) |
| 147 | y = random.uniform(0, 10) |
| 148 | |
| 149 | # Label: 1 if point is above the line y=x, 0 if below |
| 150 | label = 1 if y > x else 0 |
| 151 | |
| 152 | data.append(([x, y], label)) |
| 153 | |
| 154 | return data |
| 155 | |
| 156 | |
| 157 | def visualize_decision(neuron, test_points): |
| 158 | """ |
| 159 | Show how the neuron classifies different points. |
| 160 | |
| 161 | Args: |
| 162 | neuron: Trained neuron |
| 163 | test_points: List of points to test |
| 164 | """ |
| 165 | print("\n๐ฏ Testing the trained neuron:") |
| 166 | print("-" * 70) |
| 167 | print(f"{'Point':<15} | {'Prediction':<15} | {'Actual':<15} | {'Correct?'}") |
| 168 | print("-" * 70) |
| 169 | |
| 170 | correct = 0 |
| 171 | for point, actual in test_points: |
| 172 | prediction = neuron.feedforward(point) |
| 173 | predicted_class = 1 if prediction > 0.5 else 0 |
| 174 | actual_class = actual |
| 175 | is_correct = "โ" if predicted_class == actual_class else "โ" |
| 176 | |
| 177 | if predicted_class == actual_class: |
| 178 | correct += 1 |
| 179 | |
| 180 | print(f"({point[0]:5.2f}, {point[1]:5.2f}) | {prediction:14.4f} | {actual_class:^15} | {is_correct}") |
| 181 | |
| 182 | print("-" * 70) |
| 183 | accuracy = (correct / len(test_points)) * 100 |
| 184 | print(f"Accuracy: {accuracy:.1f}% ({correct}/{len(test_points)} correct)") |
| 185 | |
| 186 | |
| 187 | def main(): |
| 188 | """ |
| 189 | Main function - Build and train a neural network! |
| 190 | """ |
| 191 | print("=" * 70) |
| 192 | print("Simple Neural Network from Scratch") |
| 193 | print("=" * 70) |
| 194 | print("\n๐ Task: Learn to classify points as above or below the line y = x") |
| 195 | print() |
| 196 | |
| 197 | # Step 1: Generate training data |
| 198 | print("๐ Generating training data...") |
| 199 | training_data = generate_training_data(num_samples=100) |
| 200 | print(f"Created {len(training_data)} training examples") |
| 201 | |
| 202 | # Show a few examples |
| 203 | print("\nExample training data:") |
| 204 | for i in range(3): |
| 205 | point, label = training_data[i] |
| 206 | position = "above" if label == 1 else "below" |
| 207 | print(f" Point ({point[0]:.2f}, {point[1]:.2f}) is {position} the line y=x") |
| 208 | |
| 209 | # Step 2: Create neuron |
| 210 | print("\n๐ง Creating a neuron with 2 inputs (x and y coordinates)...") |
| 211 | neuron = SimpleNeuron(num_inputs=2) |
| 212 | print(f"Initial weights: [{neuron.weights[0]:.3f}, {neuron.weights[1]:.3f}]") |
| 213 | print(f"Initial bias: {neuron.bias:.3f}") |
| 214 | |
| 215 | # Step 3: Train the neuron |
| 216 | print("\n๐ Training the neuron...") |
| 217 | epochs = 50 |
| 218 | |
| 219 | for epoch in range(epochs): |
| 220 | total_error = 0 |
| 221 | |
| 222 | # Train on each example |
| 223 | for inputs, target in training_data: |
| 224 | neuron.feedforward(inputs) |
| 225 | error = neuron.train(inputs, target, learning_rate=0.1) |
| 226 | total_error += error |
| 227 | |
| 228 | # Show progress |
| 229 | if (epoch + 1) % 10 == 0: |
| 230 | avg_error = total_error / len(training_data) |
| 231 | print(f"Epoch {epoch + 1}/{epochs} - Average error: {avg_error:.4f}") |
| 232 | |
| 233 | print("\nโ
Training complete!") |
| 234 | print(f"Final weights: [{neuron.weights[0]:.3f}, {neuron.weights[1]:.3f}]") |
| 235 | print(f"Final bias: {neuron.bias:.3f}") |
| 236 | |
| 237 | # Step 4: Test the neuron |
| 238 | test_data = generate_training_data(num_samples=10) |
| 239 | visualize_decision(neuron, test_data) |
| 240 | |
| 241 | # Explanation |
| 242 | print("\n๐ก What just happened?") |
| 243 | print("1. The neuron started with random weights") |
| 244 | print("2. It looked at 100 example points and their correct labels") |
| 245 | print("3. Each time it was wrong, it adjusted its weights slightly") |
| 246 | print("4. After 50 rounds, it learned to classify points correctly!") |
| 247 | print() |
| 248 | print("๐ You just built a neural network from scratch!") |
| 249 | print() |
| 250 | print("๐ Try this:") |
| 251 | print(" - Change num_samples to train on more/fewer examples") |
| 252 | print(" - Modify epochs to train for longer/shorter") |
| 253 | print(" - Change learning_rate (line 185) and see what happens") |
| 254 | print(" - Try different decision boundaries (modify generate_training_data)") |
| 255 | print() |
| 256 | |
| 257 | |
| 258 | if __name__ == "__main__": |
| 259 | main() |
| 260 | |