EduFlow

Section 5 · Beyond the Basics

Neural Networks and Deep Learning

20 min4 min readPython exercise

Lesson at a glance

Explain what layers, activations, epochs and backpropagation are, train a small neural network with MLPClassifier, and judge honestly when deep learning beats simpler models.

  1. 1From one neuron to a network
  2. 2How a network learns
  3. 3A network on handwritten digits
  4. 4Where deep learning wins

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

“Deep learning” gets used as a synonym for AI, and it powers image recognition, speech-to-text and the large language models in the next lesson. Underneath, it’s built from pieces you already know: weighted sums like linear regression, a squashing function like the sigmoid, and gradient descent. This lesson assembles them, trains a small network, and then puts it next to logistic regression to see what it’s really worth.

From one neuron to a network

A neuron does what logistic regression does without the final squash: multiply each input by a weight, add them up, add a bias. Then it applies an activation function. The most common is ReLU, which outputs the sum if it’s positive and 0 otherwise. A layer is a set of neurons that all read the same inputs, each with its own weights. A network stacks layers: the outputs of one become the inputs of the next.

Three input nodes connect to every one of four hidden nodes, which connect to every one of three output nodes. Hidden nodes apply ReLU; outputs apply softmax to give class probabilities. inputs hidden layer (ReLU) outputs (softmax) every line is one weight
A small fully connected network

The activation is the whole trick. Without it, a layer is a linear function, and a linear function of a linear function is still linear: ten layers would be no more powerful than one logistic regression. With ReLU in between, each layer can bend and combine what the previous one produced, so the network can represent curves and interactions you never wrote down. In effect, the hidden layers learn their own features.

For classification, the output layer has one neuron per class and a softmax, which turns the outputs into probabilities that sum to 1, the multi-class cousin of the sigmoid.

How a network learns

Training repeats four steps:

  1. Forward pass: run a batch of examples through the network to get predictions.
  2. Loss: measure how wrong they are, with log loss for classification.
  3. Backpropagation: compute the gradient of the loss with respect to every weight, working backwards from the output layer with the chain rule.
  4. Optimiser step: nudge every weight against its gradient. adam, the default, is gradient descent with a per-weight adaptive learning rate.

One pass through the whole training set is an epoch. Training runs for many epochs, and you watch the loss fall exactly as it did in your hand-written gradient descent in section 2, just across thousands of weights instead of two.

A network on handwritten digits

The digits dataset holds 1,797 images of handwritten digits, each 8×8 pixels flattened into 64 numbers. scikit-learn’s MLPClassifier (multi-layer perceptron) is a small fully connected network.

Python
from sklearn.datasets import load_digits
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

X, y = load_digits(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42, stratify=y)

net = make_pipeline(StandardScaler(),
                    MLPClassifier(hidden_layer_sizes=(64,), max_iter=500, random_state=42))
net.fit(X_train, y_train)
mlp = net[-1]
print("weight matrices:", [w.shape for w in mlp.coefs_])
print("parameters:", sum(w.size for w in mlp.coefs_) + sum(b.size for b in mlp.intercepts_))
print("epochs run:", mlp.n_iter_, "| loss first, 10th, last:",
      [round(float(mlp.loss_curve_[i]), 3) for i in (0, 9, -1)])
print("network test accuracy: ", round(net.score(X_test, y_test), 3))

linear = make_pipeline(StandardScaler(), LogisticRegression(max_iter=2000)).fit(X_train, y_train)
print("logistic test accuracy:", round(linear.score(X_test, y_test), 3))

One hidden layer of 64 neurons means two weight matrices: 64×64 from pixels to hidden units and 64×10 from hidden units to digits, 4,810 parameters with the biases. The loss falls from 2.31 (a uniform guess over ten classes) to under 0.01, and training stops on its own after 164 epochs because the improvement has stalled. Test accuracy: 98%.

And logistic regression? Also about 98%. On 8×8 images with a few hundred examples per class, a straight boundary is already enough. The network’s extra power has almost nothing to work on. Try it on churn and the result is the same, slightly worse: around 0.79 ROC AUC against 0.81 for logistic regression.

Where deep learning wins

The networks behind modern AI differ from MLPClassifier in scale and in architecture. Convolutional networks reuse the same small filters across an image, so they learn edges, then shapes, then objects. Transformers, behind today’s language models, let every word in a text weigh every other word. Both are trained on millions or billions of examples, on GPUs, with libraries such as PyTorch, Keras or JAX, not scikit-learn.

What they share with your 4,810-weight network is everything conceptual: layers, activations, a loss, backpropagation, epochs, overfitting, a validation set. When a deep learning paper says “we trained for 20 epochs with early stopping on validation loss”, you now know what every word means.

Pretrained models are the bridge between the two worlds, and the most visible of them are large language models. Next lesson explains what they do, how embeddings turn text into the kind of vectors you’ve been feeding models all course, and where they fit next to a churn model.

Key takeaways

  • A neuron computes a weighted sum of its inputs plus a bias and passes it through an activation function such as ReLU; a layer is many neurons side by side.
  • Without non-linear activations, any stack of layers collapses into a single linear model.
  • Training repeats forward pass, loss, backpropagation (gradients for every weight) and an optimiser step; one pass over the training data is an epoch.
  • MLPClassifier is a small fully connected network for tabular-sized problems; real deep learning uses PyTorch, Keras or JAX on GPUs.
  • Neural networks shine on large amounts of raw, unstructured data such as images, audio and text; on small tables, linear models and boosted trees usually match or beat them.

Further reading

Check your understanding

3 questions

Question 1 of 3

Why do neural networks need non-linear activation functions between layers?

Question 2 of 3

A network trains on 1,347 images with max_iter=500, and n_iter_ reports 164. What happened?

Question 3 of 3

On the churn table, a small MLP reaches CV ROC AUC 0.79 while logistic regression reaches 0.81. What’s the most sensible reading?

Practice

Python exercise

Train and inspect a small network

  1. net: a pipeline of StandardScaler then MLPClassifier with one hidden layer of 32 neurons (max_iter=500, random_state=42), fitted on the digits training data.
  2. From the fitted network, set n_params (all weights plus all biases), epochs (how many epochs training actually ran) and test_acc (accuracy on the test set).
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

X, y = load_digits(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42, stratify=y)

# 1. Pipeline: StandardScaler, then an MLPClassifier with ONE hidden layer of 32 neurons,
#    max_iter=500, random_state=42. Fit it on the training data.
net = MLPClassifier(hidden_layer_sizes=(32, 32), max_iter=500, random_state=42)

# 2. Facts about the trained network
n_params = None      # total number of weights + biases
epochs = None        # epochs actually run
test_acc = None      # test accuracy
Loading the editor…

Ctrl/⌘ + Enter to run · Runs in a sandbox in your browser. Nothing leaves your device.

(no output)

Checks

  • net scales, then runs an MLPClassifier
  • One hidden layer of 32 neurons
  • n_params counts every weight and bias
  • epochs matches the epochs run, and the loss fell
  • test_acc is above 0.95