Path: blob/master/guides/keras_tuner/getting_started.py
3293 views
"""1Title: Getting started with KerasTuner2Authors: Luca Invernizzi, James Long, Francois Chollet, Tom O'Malley, Haifeng Jin3Date created: 2019/05/314Last modified: 2021/10/275Description: The basics of using KerasTuner to tune model hyperparameters.6Accelerator: GPU7"""89"""shell10pip install keras-tuner -q11"""121314"""15## Introduction1617KerasTuner is a general-purpose hyperparameter tuning library. It has strong18integration with Keras workflows, but it isn't limited to them: you could use19it to tune scikit-learn models, or anything else. In this tutorial, you will20see how to tune model architecture, training process, and data preprocessing21steps with KerasTuner. Let's start from a simple example.2223## Tune the model architecture2425The first thing we need to do is writing a function, which returns a compiled26Keras model. It takes an argument `hp` for defining the hyperparameters while27building the model.2829### Define the search space3031In the following code example, we define a Keras model with two `Dense` layers.32We want to tune the number of units in the first `Dense` layer. We just define33an integer hyperparameter with `hp.Int('units', min_value=32, max_value=512, step=32)`,34whose range is from 32 to 512 inclusive. When sampling from it, the minimum35step for walking through the interval is 32.36"""3738import keras39from keras import layers404142def build_model(hp):43model = keras.Sequential()44model.add(layers.Flatten())45model.add(46layers.Dense(47# Define the hyperparameter.48units=hp.Int("units", min_value=32, max_value=512, step=32),49activation="relu",50)51)52model.add(layers.Dense(10, activation="softmax"))53model.compile(54optimizer="adam",55loss="categorical_crossentropy",56metrics=["accuracy"],57)58return model596061"""62You can quickly test if the model builds successfully.63"""6465import keras_tuner6667build_model(keras_tuner.HyperParameters())6869"""70There are many other types of hyperparameters as well. We can define multiple71hyperparameters in the function. In the following code, we tune whether to72use a `Dropout` layer with `hp.Boolean()`, tune which activation function to73use with `hp.Choice()`, tune the learning rate of the optimizer with74`hp.Float()`.75"""767778def build_model(hp):79model = keras.Sequential()80model.add(layers.Flatten())81model.add(82layers.Dense(83# Tune number of units.84units=hp.Int("units", min_value=32, max_value=512, step=32),85# Tune the activation function to use.86activation=hp.Choice("activation", ["relu", "tanh"]),87)88)89# Tune whether to use dropout.90if hp.Boolean("dropout"):91model.add(layers.Dropout(rate=0.25))92model.add(layers.Dense(10, activation="softmax"))93# Define the optimizer learning rate as a hyperparameter.94learning_rate = hp.Float("lr", min_value=1e-4, max_value=1e-2, sampling="log")95model.compile(96optimizer=keras.optimizers.Adam(learning_rate=learning_rate),97loss="categorical_crossentropy",98metrics=["accuracy"],99)100return model101102103build_model(keras_tuner.HyperParameters())104105"""106As shown below, the hyperparameters are actual values. In fact, they are just107functions returning actual values. For example, `hp.Int()` returns an `int`108value. Therefore, you can put them into variables, for loops, or if109conditions.110"""111112hp = keras_tuner.HyperParameters()113print(hp.Int("units", min_value=32, max_value=512, step=32))114115"""116You can also define the hyperparameters in advance and keep your Keras code in117a separate function.118"""119120121def call_existing_code(units, activation, dropout, lr):122model = keras.Sequential()123model.add(layers.Flatten())124model.add(layers.Dense(units=units, activation=activation))125if dropout:126model.add(layers.Dropout(rate=0.25))127model.add(layers.Dense(10, activation="softmax"))128model.compile(129optimizer=keras.optimizers.Adam(learning_rate=lr),130loss="categorical_crossentropy",131metrics=["accuracy"],132)133return model134135136def build_model(hp):137units = hp.Int("units", min_value=32, max_value=512, step=32)138activation = hp.Choice("activation", ["relu", "tanh"])139dropout = hp.Boolean("dropout")140lr = hp.Float("lr", min_value=1e-4, max_value=1e-2, sampling="log")141# call existing model-building code with the hyperparameter values.142model = call_existing_code(143units=units, activation=activation, dropout=dropout, lr=lr144)145return model146147148build_model(keras_tuner.HyperParameters())149150"""151Each of the hyperparameters is uniquely identified by its name (the first152argument). To tune the number of units in different `Dense` layers separately153as different hyperparameters, we give them different names as `f"units_{i}"`.154155Notably, this is also an example of creating conditional hyperparameters.156There are many hyperparameters specifying the number of units in the `Dense`157layers. The number of such hyperparameters is decided by the number of layers,158which is also a hyperparameter. Therefore, the total number of hyperparameters159used may be different from trial to trial. Some hyperparameter is only used160when a certain condition is satisfied. For example, `units_3` is only used161when `num_layers` is larger than 3. With KerasTuner, you can easily define162such hyperparameters dynamically while creating the model.163164"""165166167def build_model(hp):168model = keras.Sequential()169model.add(layers.Flatten())170# Tune the number of layers.171for i in range(hp.Int("num_layers", 1, 3)):172model.add(173layers.Dense(174# Tune number of units separately.175units=hp.Int(f"units_{i}", min_value=32, max_value=512, step=32),176activation=hp.Choice("activation", ["relu", "tanh"]),177)178)179if hp.Boolean("dropout"):180model.add(layers.Dropout(rate=0.25))181model.add(layers.Dense(10, activation="softmax"))182learning_rate = hp.Float("lr", min_value=1e-4, max_value=1e-2, sampling="log")183model.compile(184optimizer=keras.optimizers.Adam(learning_rate=learning_rate),185loss="categorical_crossentropy",186metrics=["accuracy"],187)188return model189190191build_model(keras_tuner.HyperParameters())192193"""194### Start the search195196After defining the search space, we need to select a tuner class to run the197search. You may choose from `RandomSearch`, `BayesianOptimization` and198`Hyperband`, which correspond to different tuning algorithms. Here we use199`RandomSearch` as an example.200201To initialize the tuner, we need to specify several arguments in the initializer.202203* `hypermodel`. The model-building function, which is `build_model` in our case.204* `objective`. The name of the objective to optimize (whether to minimize or205maximize is automatically inferred for built-in metrics). We will introduce how206to use custom metrics later in this tutorial.207* `max_trials`. The total number of trials to run during the search.208* `executions_per_trial`. The number of models that should be built and fit for209each trial. Different trials have different hyperparameter values. The210executions within the same trial have the same hyperparameter values. The211purpose of having multiple executions per trial is to reduce results variance212and therefore be able to more accurately assess the performance of a model. If213you want to get results faster, you could set `executions_per_trial=1` (single214round of training for each model configuration).215* `overwrite`. Control whether to overwrite the previous results in the same216directory or resume the previous search instead. Here we set `overwrite=True`217to start a new search and ignore any previous results.218* `directory`. A path to a directory for storing the search results.219* `project_name`. The name of the sub-directory in the `directory`.220221"""222223tuner = keras_tuner.RandomSearch(224hypermodel=build_model,225objective="val_accuracy",226max_trials=3,227executions_per_trial=2,228overwrite=True,229directory="my_dir",230project_name="helloworld",231)232233"""234You can print a summary of the search space:235"""236237tuner.search_space_summary()238239"""240Before starting the search, let's prepare the MNIST dataset.241"""242243import keras244import numpy as np245246(x, y), (x_test, y_test) = keras.datasets.mnist.load_data()247248x_train = x[:-10000]249x_val = x[-10000:]250y_train = y[:-10000]251y_val = y[-10000:]252253x_train = np.expand_dims(x_train, -1).astype("float32") / 255.0254x_val = np.expand_dims(x_val, -1).astype("float32") / 255.0255x_test = np.expand_dims(x_test, -1).astype("float32") / 255.0256257num_classes = 10258y_train = keras.utils.to_categorical(y_train, num_classes)259y_val = keras.utils.to_categorical(y_val, num_classes)260y_test = keras.utils.to_categorical(y_test, num_classes)261262"""263Then, start the search for the best hyperparameter configuration.264All the arguments passed to `search` is passed to `model.fit()` in each265execution. Remember to pass `validation_data` to evaluate the model.266"""267268tuner.search(x_train, y_train, epochs=2, validation_data=(x_val, y_val))269270"""271During the `search`, the model-building function is called with different272hyperparameter values in different trial. In each trial, the tuner would273generate a new set of hyperparameter values to build the model. The model is274then fit and evaluated. The metrics are recorded. The tuner progressively275explores the space and finally finds a good set of hyperparameter values.276277### Query the results278279When search is over, you can retrieve the best model(s). The model is saved at280its best performing epoch evaluated on the `validation_data`.281"""282283# Get the top 2 models.284models = tuner.get_best_models(num_models=2)285best_model = models[0]286best_model.summary()287288"""289You can also print a summary of the search results.290"""291292tuner.results_summary()293294"""295You will find detailed logs, checkpoints, etc, in the folder296`my_dir/helloworld`, i.e. `directory/project_name`.297298You can also visualize the tuning results using TensorBoard and HParams plugin.299For more information, please following300[this link](https://keras.io/guides/keras_tuner/visualize_tuning/).301302### Retrain the model303304If you want to train the model with the entire dataset, you may retrieve the305best hyperparameters and retrain the model by yourself.306"""307308# Get the top 2 hyperparameters.309best_hps = tuner.get_best_hyperparameters(5)310# Build the model with the best hp.311model = build_model(best_hps[0])312# Fit with the entire dataset.313x_all = np.concatenate((x_train, x_val))314y_all = np.concatenate((y_train, y_val))315model.fit(x=x_all, y=y_all, epochs=1)316317"""318## Tune model training319320To tune the model building process, we need to subclass the `HyperModel` class,321which also makes it easy to share and reuse hypermodels.322323We need to override `HyperModel.build()` and `HyperModel.fit()` to tune the324model building and training process respectively. A `HyperModel.build()`325method is the same as the model-building function, which creates a Keras model326using the hyperparameters and returns it.327328In `HyperModel.fit()`, you can access the model returned by329`HyperModel.build()`,`hp` and all the arguments passed to `search()`. You need330to train the model and return the training history.331332In the following code, we will tune the `shuffle` argument in `model.fit()`.333334It is generally not needed to tune the number of epochs because a built-in335callback is passed to `model.fit()` to save the model at its best epoch336evaluated by the `validation_data`.337338> **Note**: The `**kwargs` should always be passed to `model.fit()` because it339contains the callbacks for model saving and tensorboard plugins.340"""341342343class MyHyperModel(keras_tuner.HyperModel):344def build(self, hp):345model = keras.Sequential()346model.add(layers.Flatten())347model.add(348layers.Dense(349units=hp.Int("units", min_value=32, max_value=512, step=32),350activation="relu",351)352)353model.add(layers.Dense(10, activation="softmax"))354model.compile(355optimizer="adam",356loss="categorical_crossentropy",357metrics=["accuracy"],358)359return model360361def fit(self, hp, model, *args, **kwargs):362return model.fit(363*args,364# Tune whether to shuffle the data in each epoch.365shuffle=hp.Boolean("shuffle"),366**kwargs,367)368369370"""371Again, we can do a quick check to see if the code works correctly.372"""373374hp = keras_tuner.HyperParameters()375hypermodel = MyHyperModel()376model = hypermodel.build(hp)377hypermodel.fit(hp, model, np.random.rand(100, 28, 28), np.random.rand(100, 10))378379"""380## Tune data preprocessing381382To tune data preprocessing, we just add an additional step in383`HyperModel.fit()`, where we can access the dataset from the arguments. In the384following code, we tune whether to normalize the data before training the385model. This time we explicitly put `x` and `y` in the function signature386because we need to use them.387388"""389390391class MyHyperModel(keras_tuner.HyperModel):392def build(self, hp):393model = keras.Sequential()394model.add(layers.Flatten())395model.add(396layers.Dense(397units=hp.Int("units", min_value=32, max_value=512, step=32),398activation="relu",399)400)401model.add(layers.Dense(10, activation="softmax"))402model.compile(403optimizer="adam",404loss="categorical_crossentropy",405metrics=["accuracy"],406)407return model408409def fit(self, hp, model, x, y, **kwargs):410if hp.Boolean("normalize"):411x = layers.Normalization()(x)412return model.fit(413x,414y,415# Tune whether to shuffle the data in each epoch.416shuffle=hp.Boolean("shuffle"),417**kwargs,418)419420421hp = keras_tuner.HyperParameters()422hypermodel = MyHyperModel()423model = hypermodel.build(hp)424hypermodel.fit(hp, model, np.random.rand(100, 28, 28), np.random.rand(100, 10))425426"""427If a hyperparameter is used both in `build()` and `fit()`, you can define it in428`build()` and use `hp.get(hp_name)` to retrieve it in `fit()`. We use the429image size as an example. It is both used as the input shape in `build()`, and430used by data prerprocessing step to crop the images in `fit()`.431"""432433434class MyHyperModel(keras_tuner.HyperModel):435def build(self, hp):436image_size = hp.Int("image_size", 10, 28)437inputs = keras.Input(shape=(image_size, image_size))438outputs = layers.Flatten()(inputs)439outputs = layers.Dense(440units=hp.Int("units", min_value=32, max_value=512, step=32),441activation="relu",442)(outputs)443outputs = layers.Dense(10, activation="softmax")(outputs)444model = keras.Model(inputs, outputs)445model.compile(446optimizer="adam",447loss="categorical_crossentropy",448metrics=["accuracy"],449)450return model451452def fit(self, hp, model, x, y, validation_data=None, **kwargs):453if hp.Boolean("normalize"):454x = layers.Normalization()(x)455image_size = hp.get("image_size")456cropped_x = x[:, :image_size, :image_size, :]457if validation_data:458x_val, y_val = validation_data459cropped_x_val = x_val[:, :image_size, :image_size, :]460validation_data = (cropped_x_val, y_val)461return model.fit(462cropped_x,463y,464# Tune whether to shuffle the data in each epoch.465shuffle=hp.Boolean("shuffle"),466validation_data=validation_data,467**kwargs,468)469470471tuner = keras_tuner.RandomSearch(472MyHyperModel(),473objective="val_accuracy",474max_trials=3,475overwrite=True,476directory="my_dir",477project_name="tune_hypermodel",478)479480tuner.search(x_train, y_train, epochs=2, validation_data=(x_val, y_val))481482"""483### Retrain the model484485Using `HyperModel` also allows you to retrain the best model by yourself.486"""487488hypermodel = MyHyperModel()489best_hp = tuner.get_best_hyperparameters()[0]490model = hypermodel.build(best_hp)491hypermodel.fit(best_hp, model, x_all, y_all, epochs=1)492493"""494## Specify the tuning objective495496In all previous examples, we all just used validation accuracy497(`"val_accuracy"`) as the tuning objective to select the best model. Actually,498you can use any metric as the objective. The most commonly used metric is499`"val_loss"`, which is the validation loss.500501### Built-in metric as the objective502503There are many other built-in metrics in Keras you can use as the objective.504Here is [a list of the built-in metrics](https://keras.io/api/metrics/).505506To use a built-in metric as the objective, you need to follow these steps:507508* Compile the model with the the built-in metric. For example, you want to use509`MeanAbsoluteError()`. You need to compile the model with510`metrics=[MeanAbsoluteError()]`. You may also use its name string instead:511`metrics=["mean_absolute_error"]`. The name string of the metric is always512the snake case of the class name.513514* Identify the objective name string. The name string of the objective is515always in the format of `f"val_{metric_name_string}"`. For example, the516objective name string of mean squared error evaluated on the validation data517should be `"val_mean_absolute_error"`.518519* Wrap it into `keras_tuner.Objective`. We usually need to wrap the objective520into a `keras_tuner.Objective` object to specify the direction to optimize the521objective. For example, we want to minimize the mean squared error, we can use522`keras_tuner.Objective("val_mean_absolute_error", "min")`. The direction should523be either `"min"` or `"max"`.524525* Pass the wrapped objective to the tuner.526527You can see the following barebone code example.528"""529530531def build_regressor(hp):532model = keras.Sequential(533[534layers.Dense(units=hp.Int("units", 32, 128, 32), activation="relu"),535layers.Dense(units=1),536]537)538model.compile(539optimizer="adam",540loss="mean_squared_error",541# Objective is one of the metrics.542metrics=[keras.metrics.MeanAbsoluteError()],543)544return model545546547tuner = keras_tuner.RandomSearch(548hypermodel=build_regressor,549# The objective name and direction.550# Name is the f"val_{snake_case_metric_class_name}".551objective=keras_tuner.Objective("val_mean_absolute_error", direction="min"),552max_trials=3,553overwrite=True,554directory="my_dir",555project_name="built_in_metrics",556)557558tuner.search(559x=np.random.rand(100, 10),560y=np.random.rand(100, 1),561validation_data=(np.random.rand(20, 10), np.random.rand(20, 1)),562)563564tuner.results_summary()565566"""567### Custom metric as the objective568569You may implement your own metric and use it as the hyperparameter search570objective. Here, we use mean squared error (MSE) as an example. First, we571implement the MSE metric by subclassing `keras.metrics.Metric`. Remember to572give a name to your metric using the `name` argument of `super().__init__()`,573which will be used later. Note: MSE is actually a build-in metric, which can be574imported with `keras.metrics.MeanSquaredError`. This is just an example to show575how to use a custom metric as the hyperparameter search objective.576577For more information about implementing custom metrics, please see [this578tutorial](https://keras.io/api/metrics/#creating-custom-metrics). If you would579like a metric with a different function signature than `update_state(y_true,580y_pred, sample_weight)`, you can override the `train_step()` method of your581model following [this582tutorial](https://keras.io/guides/customizing_what_happens_in_fit/#going-lowerlevel).583584"""585586from keras import ops587588589class CustomMetric(keras.metrics.Metric):590def __init__(self, **kwargs):591# Specify the name of the metric as "custom_metric".592super().__init__(name="custom_metric", **kwargs)593self.sum = self.add_weight(name="sum", initializer="zeros")594self.count = self.add_weight(name="count", dtype="int32", initializer="zeros")595596def update_state(self, y_true, y_pred, sample_weight=None):597values = ops.square(y_true - y_pred)598count = ops.shape(y_true)[0]599if sample_weight is not None:600sample_weight = ops.cast(sample_weight, self.dtype)601values *= sample_weight602count *= sample_weight603self.sum.assign_add(ops.sum(values))604self.count.assign_add(count)605606def result(self):607return self.sum / ops.cast(self.count, "float32")608609def reset_state(self):610self.sum.assign(0)611self.count.assign(0)612613614"""615Run the search with the custom objective.616"""617618619def build_regressor(hp):620model = keras.Sequential(621[622layers.Dense(units=hp.Int("units", 32, 128, 32), activation="relu"),623layers.Dense(units=1),624]625)626model.compile(627optimizer="adam",628loss="mean_squared_error",629# Put custom metric into the metrics.630metrics=[CustomMetric()],631)632return model633634635tuner = keras_tuner.RandomSearch(636hypermodel=build_regressor,637# Specify the name and direction of the objective.638objective=keras_tuner.Objective("val_custom_metric", direction="min"),639max_trials=3,640overwrite=True,641directory="my_dir",642project_name="custom_metrics",643)644645tuner.search(646x=np.random.rand(100, 10),647y=np.random.rand(100, 1),648validation_data=(np.random.rand(20, 10), np.random.rand(20, 1)),649)650651tuner.results_summary()652653"""654If your custom objective is hard to put into a custom metric, you can also655evaluate the model by yourself in `HyperModel.fit()` and return the objective656value. The objective value would be minimized by default. In this case, you657don't need to specify the `objective` when initializing the tuner. However, in658this case, the metric value will not be tracked in the Keras logs by only659KerasTuner logs. Therefore, these values would not be displayed by any660TensorBoard view using the Keras metrics.661"""662663664class HyperRegressor(keras_tuner.HyperModel):665def build(self, hp):666model = keras.Sequential(667[668layers.Dense(units=hp.Int("units", 32, 128, 32), activation="relu"),669layers.Dense(units=1),670]671)672model.compile(673optimizer="adam",674loss="mean_squared_error",675)676return model677678def fit(self, hp, model, x, y, validation_data, **kwargs):679model.fit(x, y, **kwargs)680x_val, y_val = validation_data681y_pred = model.predict(x_val)682# Return a single float to minimize.683return np.mean(np.abs(y_pred - y_val))684685686tuner = keras_tuner.RandomSearch(687hypermodel=HyperRegressor(),688# No objective to specify.689# Objective is the return value of `HyperModel.fit()`.690max_trials=3,691overwrite=True,692directory="my_dir",693project_name="custom_eval",694)695tuner.search(696x=np.random.rand(100, 10),697y=np.random.rand(100, 1),698validation_data=(np.random.rand(20, 10), np.random.rand(20, 1)),699)700701tuner.results_summary()702703"""704If you have multiple metrics to track in KerasTuner, but only use one of them705as the objective, you can return a dictionary, whose keys are the metric names706and the values are the metrics values, for example, return `{"metric_a": 1.0,707"metric_b", 2.0}`. Use one of the keys as the objective name, for example,708`keras_tuner.Objective("metric_a", "min")`.709"""710711712class HyperRegressor(keras_tuner.HyperModel):713def build(self, hp):714model = keras.Sequential(715[716layers.Dense(units=hp.Int("units", 32, 128, 32), activation="relu"),717layers.Dense(units=1),718]719)720model.compile(721optimizer="adam",722loss="mean_squared_error",723)724return model725726def fit(self, hp, model, x, y, validation_data, **kwargs):727model.fit(x, y, **kwargs)728x_val, y_val = validation_data729y_pred = model.predict(x_val)730# Return a dictionary of metrics for KerasTuner to track.731return {732"metric_a": -np.mean(np.abs(y_pred - y_val)),733"metric_b": np.mean(np.square(y_pred - y_val)),734}735736737tuner = keras_tuner.RandomSearch(738hypermodel=HyperRegressor(),739# Objective is one of the keys.740# Maximize the negative MAE, equivalent to minimize MAE.741objective=keras_tuner.Objective("metric_a", "max"),742max_trials=3,743overwrite=True,744directory="my_dir",745project_name="custom_eval_dict",746)747tuner.search(748x=np.random.rand(100, 10),749y=np.random.rand(100, 1),750validation_data=(np.random.rand(20, 10), np.random.rand(20, 1)),751)752753tuner.results_summary()754755"""756## Tune end-to-end workflows757758In some cases, it is hard to align your code into build and fit functions. You759can also keep your end-to-end workflow in one place by overriding760`Tuner.run_trial()`, which gives you full control of a trial. You can see it761as a black-box optimizer for anything.762763### Tune any function764765For example, you can find a value of `x`, which minimizes `f(x)=x*x+1`. In the766following code, we just define `x` as a hyperparameter, and return `f(x)` as767the objective value. The `hypermodel` and `objective` argument for initializing768the tuner can be omitted.769"""770771772class MyTuner(keras_tuner.RandomSearch):773def run_trial(self, trial, *args, **kwargs):774# Get the hp from trial.775hp = trial.hyperparameters776# Define "x" as a hyperparameter.777x = hp.Float("x", min_value=-1.0, max_value=1.0)778# Return the objective value to minimize.779return x * x + 1780781782tuner = MyTuner(783# No hypermodel or objective specified.784max_trials=20,785overwrite=True,786directory="my_dir",787project_name="tune_anything",788)789790# No need to pass anything to search()791# unless you use them in run_trial().792tuner.search()793print(tuner.get_best_hyperparameters()[0].get("x"))794795"""796### Keep Keras code separate797798You can keep all your Keras code unchanged and use KerasTuner to tune it. It799is useful if you cannot modify the Keras code for some reason.800801It also gives you more flexibility. You don't have to separate the model802building and training code apart. However, this workflow would not help you803save the model or connect with the TensorBoard plugins.804805To save the model, you can use `trial.trial_id`, which is a string to uniquely806identify a trial, to construct different paths to save the models from807different trials.808"""809810import os811812813def keras_code(units, optimizer, saving_path):814# Build model815model = keras.Sequential(816[817layers.Dense(units=units, activation="relu"),818layers.Dense(units=1),819]820)821model.compile(822optimizer=optimizer,823loss="mean_squared_error",824)825826# Prepare data827x_train = np.random.rand(100, 10)828y_train = np.random.rand(100, 1)829x_val = np.random.rand(20, 10)830y_val = np.random.rand(20, 1)831832# Train & eval model833model.fit(x_train, y_train)834835# Save model836model.save(saving_path)837838# Return a single float as the objective value.839# You may also return a dictionary840# of {metric_name: metric_value}.841y_pred = model.predict(x_val)842return np.mean(np.abs(y_pred - y_val))843844845class MyTuner(keras_tuner.RandomSearch):846def run_trial(self, trial, **kwargs):847hp = trial.hyperparameters848return keras_code(849units=hp.Int("units", 32, 128, 32),850optimizer=hp.Choice("optimizer", ["adam", "adadelta"]),851saving_path=os.path.join("/tmp", f"{trial.trial_id}.keras"),852)853854855tuner = MyTuner(856max_trials=3,857overwrite=True,858directory="my_dir",859project_name="keep_code_separate",860)861tuner.search()862# Retraining the model863best_hp = tuner.get_best_hyperparameters()[0]864keras_code(**best_hp.values, saving_path="/tmp/best_model.keras")865866"""867## KerasTuner includes pre-made tunable applications: HyperResNet and HyperXception868869These are ready-to-use hypermodels for computer vision.870871They come pre-compiled with `loss="categorical_crossentropy"` and872`metrics=["accuracy"]`.873874"""875876from keras_tuner.applications import HyperResNet877878hypermodel = HyperResNet(input_shape=(28, 28, 1), classes=10)879880tuner = keras_tuner.RandomSearch(881hypermodel,882objective="val_accuracy",883max_trials=2,884overwrite=True,885directory="my_dir",886project_name="built_in_hypermodel",887)888889890