Week 11 · Neural networks in sklearn
Read the words of the video
- Imagine a special room filled with tiny voters, like little decision-makers. They each take some information, "squish" it, and then vote on an outcome. This "room of tiny voters" is what a neural network is! It helps computers learn to classify things, like telling cats from dogs.
- Scikit-learn helps build this room of voters for you. You decide its shape: how many rows of voters and how many in each row. You also pick the "squish" they use, and how long to patiently train them. Then, the computer adjusts all connections to make it smart.
- Let's count network parts! If you have 20 features for input, and two hidden layers with 30 and 10 voters, leading to 4 output classes, you'll have specific connections. For example, between the first two layers, there are 20 times 30 weights plus 30 biases. This gives a total of 984 adjustable parameters.
- Remember, "squish" functions create non-linearity, which is super important! If your network is too good on training data but bad on new data, you're overfitting. To fix this, increase "alpha" or use early stopping. Always set a "random state" for consistent results. Keep practicing, you've got this!
The one-minute story
In MLT week 12 you met the room of tiny voters. scikit-learn's MLPClassifier and MLPRegressor build that room for you with a single line of code. ("MLP" here means multi-layer perceptron, which is another name for a plain neural network, and has nothing to do with this course being called MLP!)
You decide the shape of the room (how many rows of voters, how many in each row), the squish each voter uses, and how patiently the training should run. scikit-learn then adjusts every weight by backpropagation, shows you the loss falling epoch by epoch, and stops when it stops improving.
The skills this week: reading the shape of the network from the code, counting its parameters, picking sensible dials, and noticing the same old villains: overfitting (cure: alpha, early stopping) and unscaled data.
By the end of this week you can:
- train
MLPClassifier/MLPRegressorand readcoefs_,intercepts_,n_layers_,n_iter_,loss_curve_; - set
hidden_layer_sizes,activation,solver,alpha,max_iter,early_stopping; - count parameters and know the output activation for each task;
- explain what happens with no non-linearity and with too few hidden units.
Words you need
- Hidden layer - a layer between input and output.
hidden_layer_sizes=(100,)means one hidden layer of 100 neurons. - Activation - the non-linear squish:
'relu'(default),'tanh','logistic'(sigmoid),'identity'(no squish). - Solver - the optimiser:
'adam'(default),'sgd','lbfgs'. - Epoch - one pass over the training data.
max_itercounts epochs foradamandsgd. alpha- the L2 regularisation strength (like ridge). Largeralpha= more regularisation.- Loss curve - the training loss after every epoch.
Idea 1: The API
from sklearn.neural_network import MLPClassifier, MLPRegressor
mlp = MLPClassifier(hidden_layer_sizes=(100,), activation="relu", solver="adam",
alpha=0.0001, batch_size="auto", learning_rate_init=0.001,
max_iter=200, early_stopping=False, random_state=42)
Those are (almost) the defaults. The ones to remember:
| Parameter | Default | Notes |
|---|---|---|
hidden_layer_sizes | (100,) | a tuple: one number per hidden layer. (50, 50) = two hidden layers of 50 |
activation | 'relu' | applies to hidden layers only |
solver | 'adam' | good default; 'lbfgs' is quick for small data; 'sgd' adds momentum options |
alpha | 0.0001 | L2 penalty |
batch_size | 'auto' | |
learning_rate_init | 0.001 | for adam and sgd |
max_iter | 200 | maximum epochs (a ConvergenceWarning means it was not enough) |
tol, n_iter_no_change | 1e-4, 10 | stop if the loss stops improving by tol for 10 epochs |
early_stopping | False | hold out validation_fraction=0.1 and stop when the validation score stops improving |
random_state | None | set it: the start is random, so results vary between runs |
You do not specify the input or output layer sizes: they are read from the data (number of features, number of classes). The output activation is chosen for you and stored in out_activation_:
| Task | Output activation |
|---|---|
| multiclass classification | softmax |
| binary or multilabel classification | logistic (sigmoid) |
regression (MLPRegressor) | identity |
Idea 2: A real run on digits
The 1797 digit images (64 pixels each), standardised, 75/25 split, with the default network (one hidden layer of 100 ReLU neurons):
mlp = make_pipeline(StandardScaler(), MLPClassifier(random_state=42, max_iter=300))
mlp.fit(X_train, y_train)
test accuracy 0.980 train accuracy 1.000
n_iter_ = 147 n_layers_ = 3 n_outputs_ = 10 out_activation_ = 'softmax'
(n_layers_ counts input + hidden + output layers: .) Inspect the learned numbers:
[c.shape for c in mlp[-1].coefs_] # [(64, 100), (100, 10)] one weight matrix per layer
[b.shape for b in mlp[-1].intercepts_] # [(100,), (10,)] one bias vector per layer
Counting parameters (it is the sum over layers of ):
For hidden_layer_sizes=(50, 50) the shapes become [(64,50), (50,50), (50,10)] and the count is , with n_layers_=4.
loss_curve_ has one entry per epoch (147 here) and falls from about 2.52 to 0.0055: plot it to watch training. predict_proba(X) returns an array whose rows sum to 1 (softmax).
Idea 3: The dials, with evidence
| Change (digits, scaled) | Test accuracy | What it shows |
|---|---|---|
default, (100,) | 0.980 | train accuracy 1.0: it fits the training data perfectly |
(2,) only 2 hidden units | 0.587 | underfits: too small a bottleneck to represent 10 digits |
alpha=1.0 (strong L2) | 0.982 | train 1.0, test slightly up: regularisation helps a little |
activation="identity" (no non-linearity) | 0.964 | collapses to a linear model; worse, even if the problem is almost linear |
early_stopping=True | 0.960 | stopped after 39 epochs; validation_scores_ and best_validation_score_ (0.985) are recorded |
Lessons:
- Capacity: too few hidden units underfit; many units can overfit. Tune the architecture with cross-validation.
alphais the regulariser: larger = simpler weights = less overfitting. (Andearly_stopping=Trueis another regulariser.)- With
activation="identity"the whole network is a single linear map, no matter how many layers: this is what "introducing non-linearity" fixes. To make a network non-linear, use a non-linear activation ('relu','tanh','logistic'). - Scale your inputs. Networks train much better when inputs are standardised or in . (The digit pixels are all between 0 and 16 so the unscaled run still reached 0.978; with features on very different scales the gap is large.)
- Results change between runs because the start is random (
random_state). For reproducible results set it.
Idea 4: Other points
- Binary classification gives
n_outputs_=1,out_activation_='logistic', and the last weight matrix has shape(n_hidden, 1). MLPRegressorhas an identity output; scale the target too when it is large.partial_fitis available (onadamandsgd): for classification passclasses=the first time. Training in chunks like this is not the same as a full-epochfit; our 3-pass demo only reached 0.53.- Hyperparameters to tune:
hidden_layer_sizes,alpha,learning_rate_init,activation. UseGridSearchCVwith the pipeline name:{"mlpclassifier__hidden_layer_sizes": [(50,), (100,), (50, 50)], "mlpclassifier__alpha": [1e-4, 1e-2]}. - scikit-learn's MLP is fine for small and medium data. For big images or text use a deep-learning library (PyTorch, TensorFlow/Keras) with GPUs.
- Neural nets are non-convex: different starts can land in different minima.
Solved examples
Question. MLPClassifier(hidden_layer_sizes=(30, 10)) is trained on 20 features and 4 classes. Give the shapes of coefs_ and the total number of parameters.
Solution. Layers: . coefs_ shapes: . Parameters: . n_layers_ .
Question. An MLPClassifier has activation="identity". Does adding more hidden layers help?
Solution. No. With identity activations, any number of layers collapses to one linear map, so it can only draw straight boundaries, no more powerful than logistic regression. Use relu/tanh/logistic for non-linearity.
Question. loss_curve_ is [2.3, 1.1, 0.6, 0.4, 0.40001, 0.40000, ...] and training stops with n_iter_=15 although max_iter=200. Why?
Solution. The loss improved by less than tol for n_iter_no_change (10) epochs in a row, so training was declared converged. If n_iter_ had equalled max_iter you would instead see a ConvergenceWarning, and you should raise max_iter or scale the data.
Your turn
Inputs: 10 features. hidden_layer_sizes=(8,). 3 classes. How many parameters?
Need a hint?
.
Show the full solution
.
coefs_ shapes are [(5, 12), (12, 12), (12, 2)]. How many hidden layers, features, hidden units per layer, and outputs?
Need a hint?
Each tuple is (input size, output size).
Show the full solution
5 features; 2 hidden layers of 12 units each; 2 outputs (so a 2-class multiclass-style output, or 2 labels). n_layers_ .
Your MLP has train accuracy 100% and test 90%. Name two dials to change.
Need a hint?
Overfitting.
Show the full solution
Increase alpha (more L2), use early_stopping=True, or reduce hidden_layer_sizes. (Also: more data.)
For (a) a 5-class problem, (b) predicting house price, (c) a yes/no problem, which output activation does MLP* use?
Need a hint?
Use the table.
Show the full solution
(a) softmax, (b) identity, (c) logistic.
(a) hidden_layer_sizes=(100,) means 100 hidden layers. (b) The default solver is adam. (c) activation is applied to the output layer. (d) Results are identical between runs without random_state.
Need a hint?
Read the table again.
Show the full solution
(a) False: one hidden layer of 100 neurons. (b) True. (c) False: hidden layers only (the output activation is automatic). (d) False: random initialisation.
Exam radar
MLP End Term: "You're designing an MLPClassifier for an image recognition task ... which element introduces non-linearity?" (the activation function), "which of these settings gives the lowest overfitting?" (more alpha, early stopping), "what is hidden_layer_sizes=(50, 50)?" and parameter counts / coefs_ shapes.
From MLT: neural networks in 16 End Term papers, activation functions in 19, ReLU in 11, architecture in 18.
hidden_layer_sizesis a tuple of hidden sizes only; the input and output sizes are automatic.(100)without the comma is just the number 100: write(100,).n_layers_counts input + hidden + output.- Identity activation = no non-linearity.
- Count the biases too.
max_itercounts epochs, not weight updates.- Set
random_statefor repeatable results.
Quick quiz
MLPClassifier(hidden_layer_sizes=(64, 32)) creates how many hidden layers?
- 1
- 2
- 3
- 96
Which element of a neural network introduces non-linearity?
- the learning rate
- the bias
- the activation function
- the batch size
Which setting is a way to reduce overfitting in MLPClassifier?
- early_stopping=True or a larger alpha
- a smaller alpha and more hidden units
- activation set to identity
- removing the scaler
Select all TRUE statements. (select all that apply)
- The default activation for hidden layers is relu.
- Multiclass output uses softmax.
- n_layers_ counts only the hidden layers.
- max_iter counts mini-batches.
Recap
MLPClassifier/Regressor:hidden_layer_sizes=(100,),activation='relu',solver='adam',alpha=1e-4,max_iter=200(epochs),early_stopping=False. Setrandom_state; scale inputs.- Output activation is automatic: softmax (multiclass), logistic (binary), identity (regression).
coefs_/intercepts_; parameters ; digits default: 7510.- Overfit raise
alpha, early stop, shrink the network. Too few units underfit. Identity activation linear model.
- Parameters: over layers;
n_layers_= input + hidden + output - Defaults:
hidden_layer_sizes=(100,),activation="relu",solver="adam",alpha=1e-4,learning_rate_init=1e-3,max_iter=200,tol=1e-4,n_iter_no_change=10
- MLT week 12 - Neural networks: Neural networks: the theory, then the code.
Practise with real exam questions
These come straight from past papers (with the real figures and the official answer key). Open 14 real questions on this week All End Term papers