DS701 Session 20 — Wed Nov 11, 2026
The lecture maps the ideas from Neural Networks I onto MLPClassifier arguments. Name the scikit-learn argument that sets each of the following, and say in one phrase what a larger value does: (a) the number of layers and neurons per layer, (b) the learning rate, (c) the mini-batch size, (d) the maximum number of epochs, (e) the strength of L2 regularization. Which solver does the lecture recommend as the default?
After training the MNIST model, the lecture plots mlp.loss_curve_ and remarks that “the loss decreases smoothly — our model is learning.” What exactly is being plotted (which data, which quantity), and why does a smoothly decreasing curve of that kind not by itself guarantee good performance on the test set? Which two MLPRegressor arguments in the California-housing example address that concern, and how?
A colleague has 8,000 rows of tabular customer data with 25 numeric features and wants to build the classifier in PyTorch “because neural networks.” Using the lecture’s scikit-learn-vs-PyTorch/TensorFlow criteria, what would you recommend and why? Name two things about the problem that would change your recommendation, and one preprocessing step you would insist on either way.
| Concept (NN I) | scikit-learn |
|---|---|
| layers and neurons | hidden_layer_sizes |
| activation \(f\) | activation |
| learning rate \(\eta\) | learning_rate_init |
| mini-batch size | batch_size |
| optimizer | solver — adam / sgd / lbfgs |
| epochs / stopping | max_iter, early_stopping, n_iter_no_change |
| regularization | alpha (L2) |
max_iter is a ceiling, not a target: adam stops when the training loss stalls for n_iter_no_change epochs.adam forgives a mediocre learning rate; sgd does not.Gradient descent takes one step size for every direction. If one feature spans 0–4000 and another 0–0.2, that feature dominates every weighted sum and every gradient, the loss surface is a long narrow valley, and no single learning rate suits both.
StandardScaler → zero mean, unit variance per feature.transform the test split with it. Fitting on everything leaks test statistics into training.Pipeline([('scaler', StandardScaler()), ('mlp', MLPClassifier(...))]) so cross-validation and grid search re-fit it correctly per fold.When it barely matters: features already on one common scale (pixels).
When it rescues you: real measurements with wildly different units — the difference between a model that works and one that flails.
Today’s activity has one dataset of each kind.

One point = training loss after one epoch. Healthy: fast initial drop, smooth flattening. That is what “the model is learning” looks like.

Too low: barely moves. Too high: starts absurdly high, bounces, stalls, and stops “because it stopped improving”. The right-hand model happened to score well — would you ship it?

(512, 512) network has ~300K weights; 50 training digits cannot pin them down. Training loss → 0 — the samples are memorized.loss_curve_ alone would have said “learning nicely”.| repair | scikit-learn | what it changes |
|---|---|---|
| L2 regularization | alpha=0.01 (default 1e-4) |
the objective: penalizes large weights |
| early stopping | early_stopping=True, validation_fraction=0.1, n_iter_no_change=10 |
the training loop: stop on validation evidence, not training loss |
| cross-validation | cross_val_score(mlp, X, y, cv=5) |
the evaluation: an honest estimate, so you notice — a measurement, not a repair |
Not on the lecture’s list, but the lever that usually matters most: more data. Regularizers trade variance for bias; they cannot create information.
Early stopping is not free either — it takes validation_fraction of your training data away. Ask what that costs when the training set is tiny.
In the activity you will overfit on purpose, then pull each lever and measure it — including the one the lecture only gestured at.
GridSearchCV(mlp, param_grid, cv=3) — every configuration × every fold is a full training run: \(3 \text{ architectures} \times 2\ \alpha \times 3 \text{ folds} = 18\) fits before the refit. Budget accordingly (the lecture used 1,500 samples for the demo).cv_results_ — the spread (std_test_score) tells you whether the “best” setting is really better or just lucky.adam 0.90, lbfgs 0.88, sgd 0.83 — the one that lost had simply not converged yet.scikit-learn MLPClassifier / MLPRegressor
Pipeline, cross_val_score, GridSearchCVPyTorch / TensorFlow
Depth on those architectures lives in the optional modules M4 (CNNs) and M3 (RNNs), and in a dedicated course — DS542, Deep Learning for Data Science. In DS701 the point is to train a network correctly and know when you have.
Goal: run the lecture’s recipe on a real dataset — standardize, fit, read the loss curve, evaluate, compare solvers and learning rates on a fixed budget — then overfit a huge network on purpose, watch training and validation loss diverge, repair it three ways (alpha, early_stopping, more data) and measure which lever actually helped, and finally diagnose three mystery loss curves.
numpy, matplotlib, scikit-learn. Every fit takes well under a second.The activity notebook goes live on the day of the lecture. Colab is optional — you can also open it on GitHub and run it locally.
Full lecture notes: Neural Networks II: Making Training Work
Pipeline patternalpha, early stopping, cross-validation