sklearn
MLP Classifier
hyperparameter optimization
RandomizedSearchCV
machine learning

Sklearn MLP Classifier Hyperparameter Optimization RandomizedSearchCV

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

RandomizedSearchCV is often a better starting point than grid search for MLPClassifier because neural-network hyperparameter spaces get large quickly. You usually care about hidden-layer shape, regularization, learning rate, solver behavior, and early stopping, not every possible combination. A randomized search lets you explore that space efficiently while still using cross-validation.

Start With a Proper Pipeline

MLPClassifier is sensitive to feature scale, so you should usually search it inside a pipeline with a scaler.

python
1from sklearn.datasets import load_wine
2from sklearn.model_selection import RandomizedSearchCV
3from sklearn.neural_network import MLPClassifier
4from sklearn.pipeline import Pipeline
5from sklearn.preprocessing import StandardScaler
6
7X, y = load_wine(return_X_y=True)
8
9pipeline = Pipeline([
10    ("scaler", StandardScaler()),
11    ("mlp", MLPClassifier(max_iter=500, random_state=42))
12])

Without scaling, search results are much harder to interpret because bad feature magnitudes can dominate the model behavior.

Choose a Search Space That Makes Sense

The goal is not to search everything. The goal is to search plausible values.

A practical parameter distribution might look like this:

python
1from scipy.stats import loguniform
2
3param_distributions = {
4    "mlp__hidden_layer_sizes": [(50,), (100,), (100, 50), (150, 75)],
5    "mlp__activation": ["relu", "tanh"],
6    "mlp__solver": ["adam", "lbfgs"],
7    "mlp__alpha": loguniform(1e-5, 1e-1),
8    "mlp__learning_rate_init": loguniform(1e-4, 1e-1),
9    "mlp__early_stopping": [True, False],
10}

This is better than a giant exhaustive grid because:

  • 'alpha and learning_rate_init usually span orders of magnitude'
  • not every hidden-layer architecture is worth trying
  • some solvers are more appropriate than others depending on dataset size
python
1search = RandomizedSearchCV(
2    estimator=pipeline,
3    param_distributions=param_distributions,
4    n_iter=20,
5    cv=5,
6    scoring="accuracy",
7    n_jobs=-1,
8    random_state=42,
9    verbose=1,
10)
11
12search.fit(X, y)
13
14print(search.best_score_)
15print(search.best_params_)

n_iter=20 does not mean "the best possible model." It means you sampled twenty candidate configurations. If the search space is broad, you can increase n_iter as your compute budget allows.

Solver Choice Matters

For MLPClassifier, the solver changes training behavior significantly.

  • 'adam is often a good default for larger datasets'
  • 'lbfgs can work well on smaller datasets'
  • 'sgd can be useful, but it often needs more careful tuning'

If you include sgd, you may also need to search momentum and learning-rate schedule parameters. That makes the space larger, so many practical searches start with adam and lbfgs only.

Watch the Training Budget

MLPClassifier can emit convergence warnings when max_iter is too small for a sampled configuration. That does not always invalidate the search, but it can indicate the search budget is too tight.

A practical adjustment is to:

  • increase max_iter
  • enable early_stopping where appropriate
  • inspect the best estimator after the search
python
best_model = search.best_estimator_
print(best_model)

Do not assume every warning means failure. But if most configurations fail to converge, your parameter space or iteration budget probably needs work.

Evaluate on a Holdout Set

Cross-validation selects the best hyperparameters, but you still want a final holdout test set for honest evaluation.

python
1from sklearn.model_selection import train_test_split
2from sklearn.metrics import classification_report
3
4X_train, X_test, y_train, y_test = train_test_split(
5    X, y, test_size=0.2, random_state=42, stratify=y
6)
7
8search.fit(X_train, y_train)
9pred = search.predict(X_test)
10print(classification_report(y_test, pred))

This separates model selection from final performance reporting.

Common Pitfalls

The most common mistake is tuning MLPClassifier without feature scaling. That usually makes the search noisy and unreliable.

Another mistake is using a giant exhaustive grid over parameters that naturally vary across orders of magnitude. Random search is usually a better fit there.

Developers also often search too many solver-specific parameters at once. Start with a manageable space and widen it only if needed.

Finally, do not judge the model only by the best cross-validation score. Check convergence behavior, fit time, and holdout performance too.

Summary

  • Use RandomizedSearchCV to explore MLPClassifier hyperparameters efficiently.
  • Put the classifier inside a pipeline with StandardScaler.
  • Search plausible ranges for alpha, learning_rate_init, architecture, and solver.
  • Use enough n_iter to explore meaningfully, then validate on a holdout set.
  • Treat convergence warnings as feedback about the search space, not just noise.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.