Contents
You’ve built your neural network. It trains. It runs. But the accuracy is… mediocre. So you start tweaking — more layers? Fewer neurons? Different learning rate? Three hours later, you’re drowning in experiments and can’t remember which combination actually worked.
Been there. Done that. Got the T-shirt and the eye strain.
Here’s the thing: manually tuning hyperparameters is a terrible way to spend your time. Keras Tuner automates this entire process, testing combinations systematically while you go do literally anything else. I’ve used it on everything from image classifiers to time series models, and honestly, I should have learned it years earlier.
Let me show you how to actually use this tool without the academic jargon that makes most tutorials unreadable.

What Is Keras Tuner and Why Should You Care?
Keras Tuner is a hyperparameter optimization library built specifically for Keras and TensorFlow. It finds the best hyperparameters for your neural network by intelligently searching through the possible combinations.
The hyperparameters it can tune:
- Number of layers and neurons
- Activation functions
- Learning rates
- Dropout rates
- Batch sizes
- Optimizers
- Pretty much anything you can configure
Why does this matter? Because the difference between a mediocre model and a great one often comes down to hyperparameters. Getting them right manually takes forever. Keras Tuner does it faster and usually better.
Installation and Setup (The Part Everyone Skips)
Let’s get this working first. Open your terminal and run:
python
pip install keras-tunerIf you’re using TensorFlow 2.x (which you should be), this usually installs without drama. Windows, Mac, Linux — all good.
You’ll also need TensorFlow installed:
python
pip install tensorflowThat’s it. No compilation nightmares. No mysterious dependency conflicts. It just works, which is refreshing. :)
Your First Keras Tuner Example (Keep It Simple)
Let’s start with something straightforward — a classification problem. I’m using the MNIST dataset because it’s simple and you can actually see results quickly.
Define a Model-Building Function
Here’s where Keras Tuner differs from regular Keras. Instead of defining a model directly, you create a function that builds models with tunable hyperparameters:
python
from tensorflow import keras
from tensorflow.keras import layers
import keras_tuner as ktdef build_model(hp):
model = keras.Sequential()
# Tune the number of units in the first Dense layer
hp_units = hp.Int('units', min_value=32, max_value=512, step=32)
model.add(layers.Dense(units=hp_units, activation='relu', input_shape=(784,)))
# Tune the dropout rate
hp_dropout = hp.Float('dropout', min_value=0.1, max_value=0.5, step=0.1)
model.add(layers.Dropout(hp_dropout))
model.add(layers.Dense(10, activation='softmax'))
# Tune the learning rate
hp_learning_rate = hp.Choice('learning_rate', values=[1e-2, 1e-3, 1e-4])
model.compile(
optimizer=keras.optimizers.Adam(learning_rate=hp_learning_rate),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
return model
See what’s happening? The hp parameter lets you define search spaces. You're telling Keras Tuner: "Try values in this range and find what works."
👉 how to train an image classification model using Keras : Click Here to Know More
Set Up the Tuner
Now you pick a search strategy. Keras Tuner offers several:
python
tuner = kt.RandomSearch(
build_model,
objective='val_accuracy',
max_trials=10,
executions_per_trial=2,
directory='my_dir',
project_name='intro_to_kt'
)What’s happening here:
- RandomSearch: Tries random combinations of hyperparameters
- objective: What we’re optimizing for (validation accuracy)
- max_trials: How many different combinations to try
- executions_per_trial: Runs each combo twice to reduce noise
Run the Search
Load your data and start tuning:
python
# Load and prep your data
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape(-1, 784).astype("float32") / 255.0
x_test = x_test.reshape(-1, 784).astype("float32") / 255.0# Search for best hyperparameters
tuner.search(x_train, y_train, epochs=5, validation_split=0.2)
# Get the best model
best_model = tuner.get_best_models(num_models=1)[0]
That’s it. You just automated hyperparameter tuning. Keras Tuner will test different combinations, track the results, and give you the best model.
When I first ran this, I expected it to be more complicated. It’s almost suspiciously simple.
Understanding Search Strategies (They’re Not All Equal)
Keras Tuner offers multiple search strategies. Picking the right one matters more than you’d think.
RandomSearch
Tries random combinations within your search space. Fast and surprisingly effective.
Use when:
- You’re starting out
- You have limited time
- Your search space is large
- You want quick initial results
I use RandomSearch for about 70% of my projects. It’s the practical choice.
Hyperband
More sophisticated. Allocates more resources to promising trials and kills off bad ones early.
python
tuner = kt.Hyperband(
build_model,
objective='val_accuracy',
max_epochs=50,
factor=3,
directory='my_dir',
project_name='hyperband_tuning'
)Use when:
- You have computational resources
- Training is expensive
- You want better results than random search
Hyperband typically finds better hyperparameters but takes longer to run.
BayesianOptimization
Uses Bayesian optimization to intelligently search the space. Learns from previous trials to make smarter choices.
python
tuner = kt.BayesianOptimization(
build_model,
objective='val_accuracy',
max_trials=20,
directory='my_dir',
project_name='bayesian_opt'
)Use when:
- Each trial is expensive
- You want the most efficient search
- You’re willing to run fewer trials
IMO, BayesianOptimization is underrated. It’s methodical and usually finds good hyperparameters with fewer trials than RandomSearch.
Advanced Hyperparameter Spaces (Getting Fancy)
Let’s go beyond basic Int and Float ranges. Keras Tuner can handle complex search spaces.
Tuning Network Architecture
Want to tune the number of layers themselves? You can do that:
python
def build_flexible_model(hp):
model = keras.Sequential()
model.add(layers.Dense(784, input_shape=(784,)))
# Tune the number of layers
for i in range(hp.Int('num_layers', 1, 5)):
model.add(layers.Dense(
units=hp.Int(f'units_{i}', min_value=32, max_value=512, step=32),
activation=hp.Choice('activation', ['relu', 'tanh', 'sigmoid'])
))
# Conditionally add dropout
if hp.Boolean('dropout'):
model.add(layers.Dropout(rate=0.25))
model.add(layers.Dense(10, activation='softmax'))
model.compile(
optimizer=keras.optimizers.Adam(
learning_rate=hp.Float('lr', min_value=1e-4, max_value=1e-2, sampling='log')
),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
return modelNow you’re tuning the entire architecture. This is powerful but can take a while to run. Ever wonder how people build those perfectly optimized networks? This is one way.
Conditional Hyperparameters
Sometimes you only want certain hyperparameters active under specific conditions:
python
def build_conditional_model(hp):
model = keras.Sequential()
model.add(layers.Dense(784, input_shape=(784,)))
# Choose optimizer type
optimizer_choice = hp.Choice('optimizer', ['adam', 'sgd', 'rmsprop'])
if optimizer_choice == 'adam':
learning_rate = hp.Float('adam_lr', 1e-4, 1e-2, sampling='log')
optimizer = keras.optimizers.Adam(learning_rate=learning_rate)
elif optimizer_choice == 'sgd':
learning_rate = hp.Float('sgd_lr', 1e-3, 1e-1, sampling='log')
momentum = hp.Float('sgd_momentum', 0.0, 0.9, step=0.1)
optimizer = keras.optimizers.SGD(learning_rate=learning_rate, momentum=momentum)
else:
learning_rate = hp.Float('rmsprop_lr', 1e-4, 1e-2, sampling='log')
optimizer = keras.optimizers.RMSprop(learning_rate=learning_rate)
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
return modelThis lets different optimizers have their own hyperparameter ranges. Pretty slick.
Callbacks and Early Stopping (Don’t Waste Time)
You don’t want to train bad models for 50 epochs. Use early stopping:
python
from tensorflow.keras.callbacks import EarlyStopping# Define early stopping
early_stop = EarlyStopping(
monitor='val_loss',
patience=3,
restore_best_weights=True
)
# Search with early stopping
tuner.search(
x_train, y_train,
epochs=50,
validation_split=0.2,
callbacks=[early_stop]
)
Now unpromising models stop training early. Saves time and computational resources. I always use this — there’s no reason not to.
Analyzing Results (Actually Understanding What Happened)
After tuning completes, you want to know what worked and why.
Get the Best Hyperparameters
python
# Get the top 3 models
best_hps = tuner.get_best_hyperparameters(num_trials=3)# Print the best hyperparameters
for hp in best_hps:
print(hp.values)
This shows you exactly which hyperparameters performed best. Sometimes the results surprise you — parameters you thought would work don’t, and combinations you didn’t expect crush it.
View Search Results Summary
python
tuner.results_summary()This prints a nice summary of all trials, sorted by performance. You can see which trials worked, which failed, and how they compare.
Retrieve Specific Models
python
# Get the best model
best_model = tuner.get_best_models(num_models=1)[0]# Evaluate it
test_loss, test_accuracy = best_model.evaluate(x_test, y_test)
print(f'Test accuracy: {test_accuracy}')
Now you have your optimized model, ready to use.
Real-World CNN Example (Because Images Are Cool)
Let’s do something more practical — a convolutional neural network for image classification:
python
def build_cnn_model(hp):
model = keras.Sequential()
# First conv block
model.add(layers.Conv2D(
filters=hp.Int('conv_1_filters', min_value=32, max_value=128, step=16),
kernel_size=hp.Choice('conv_1_kernel', values=[3, 5]),
activation='relu',
input_shape=(28, 28, 1)
))
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
# Optional second conv block
if hp.Boolean('conv_2'):
model.add(layers.Conv2D(
filters=hp.Int('conv_2_filters', min_value=64, max_value=256, step=32),
kernel_size=3,
activation='relu'
))
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
model.add(layers.Flatten())
# Dense layers
model.add(layers.Dense(
units=hp.Int('dense_units', min_value=32, max_value=512, step=32),
activation='relu'
))
model.add(layers.Dropout(hp.Float('dropout', 0.0, 0.5, step=0.1)))
model.add(layers.Dense(10, activation='softmax'))
model.compile(
optimizer=keras.optimizers.Adam(hp.Float('learning_rate', 1e-4, 1e-2, sampling='log')),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
return model# Set up tuner
tuner = kt.Hyperband(
build_cnn_model,
objective='val_accuracy',
max_epochs=20,
factor=3,
directory='cnn_tuning',
project_name='mnist_cnn'
)
# Reshape data for CNN
x_train = x_train.reshape(-1, 28, 28, 1)
x_test = x_test.reshape(-1, 28, 28, 1)
# Run search
tuner.search(x_train, y_train, epochs=20, validation_split=0.2, callbacks=[early_stop])
This tunes a full CNN architecture. Number of filters, kernel sizes, whether to include additional layers, dropout rates, learning rates — everything.
Common Mistakes and How to Avoid Them
I’ve made every mistake possible with Keras Tuner. Learn from my pain:
Mistake 1: Search Space Too Large
Don’t do this:
python
hp_units = hp.Int('units', min_value=8, max_value=2048, step=8)That’s 256 possible values. Combined with other hyperparameters, you’re looking at millions of combinations. Be reasonable.
Better:
python
hp_units = hp.Int('units', min_value=32, max_value=512, step=64)Fewer steps, still covers the useful range.
Mistake 2: Too Few Trials
Running 5 trials on a complex search space is pointless. You’re barely scratching the surface.
Rule of thumb: Start with at least 20–30 trials for meaningful results. More for complex architectures.
Mistake 3: Ignoring Validation Data
Always use validation data. Don’t tune on training accuracy — you’ll just overfit.
python
tuner.search(x_train, y_train, validation_split=0.2) # Good
tuner.search(x_train, y_train) # Bad - no validationMistake 4: Not Saving Progress
Tuning takes time. If your process crashes, you don’t want to start over. Keras Tuner saves progress automatically in the directory you specify, but make sure you’re actually setting that directory parameter.
Performance Tips (Make It Faster)
Hyperparameter tuning is slow. Here’s how to speed things up:
Use Fewer Epochs Per Trial
You don’t need 100 epochs to determine if a hyperparameter combination is promising. Use 10–20 epochs during search, then train the best model longer.
Leverage Early Stopping
Seriously, use it. Bad models stop early, saving massive amounts of time.
Use a GPU
FYI, tuning deep learning models on CPU is painful. If you have GPU access, use it. The speed difference is dramatic.
Start with RandomSearch
Get quick initial results, identify promising regions, then use BayesianOptimization for refinement.
Reduce Training Data During Search
Use a subset of your training data for tuning, then train the final model on the full dataset. This is especially useful for large datasets.
python
# Use only 50% of training data for tuning
sample_size = int(len(x_train) * 0.5)
tuner.search(
x_train[:sample_size],
y_train[:sample_size],
validation_split=0.2
)When NOT to Use Keras Tuner
Keras Tuner isn’t always the answer. Sometimes it’s overkill:
Skip it when:
- You have a tiny dataset (under 1000 samples)
- Your baseline model already performs great
- You’re just learning deep learning basics
- You have strict time constraints for a one-off project
- You’re working with pre-trained models that don’t need tuning
Manual experimentation is fine for small projects. Keras Tuner shines on projects where model performance matters and you have the time to run proper searches.
The Reality Check
Let me be honest: Keras Tuner won’t magically turn a bad model into a great one. If your architecture is fundamentally wrong or your data is garbage, no amount of hyperparameter tuning will save you.
But if you’ve got a decent model and want to optimize it properly, Keras Tuner is incredibly valuable. It finds combinations you wouldn’t have tried manually. It tests systematically instead of based on hunches. And it saves you from spending hours manually tweaking values.
I’ve seen accuracy improvements of 3–7% through proper hyperparameter tuning. On some projects, that difference determines success or failure.
Your Next Steps
Stop manually tweaking hyperparameters. Install Keras Tuner, pick one of your existing projects, and run a search. Start simple — tune learning rate and a few layer sizes. See what happens.
You don’t need to tune everything at once. Start small, build confidence, then tackle more complex search spaces. The library is designed to grow with you.
The time you save not manually experimenting with hyperparameters adds up fast. Use it to build better features, try different architectures, or honestly, just go outside. :) Your models will thank you for the systematic optimization, and your sanity will thank you for not spending another night tweaking learning rates.
Now go automate something and stop suffering through manual hyperparameter searches. You’re better than that.