
Hyperparameter tuning is one of the lifecycle of designing and building machine learning algorithm. Hyperparameter tuning is a process to find the best parameter for algorithm based in our case. Although may not significantly improve the performance of the model, hyperparameter tuning can increase the performance of the model. This process may time exhausting because we need to try the best parameter from a lot of parameter that can be tuned. One of the tools that we can use is Wandb sweep.
Wandb sweep enable us to monitor the performance of the model based on hyperparameter tune that we have been use. This make easier for us to build a lot of model based on the parameter. There are several method that we can implement such as GridSearchCV, Random Search, and others. We will try to tune our hyperparameter based one previous VGG model on Intel Scene Image Classification.
import tensorflow as tf
import matplotlib.pyplot as plt
import os
import datetime
from wandb.integration.keras import WandbMetricsLogger
import wandb
We need to import several libraries like tensorflow, matplotlib, and wandb
wandb.login(key="key")
Login to your wandb account with specific key.
class_names = os.listdir("/kaggle/input/intel-image-classification/seg_train/seg_train")
print(len(class_names))
Based on the folder name we will convert it to class name. This enable us to give consistent class name order for future data processing pipeline.
config = {
"BATCH_SIZE" :64,
"IMG_SIZE":150,
"VAL_SPLIT":0.1,
"EPOCHS":100,
"PATIENCE":5
}
For easier configuration, we will make variable name that consist of variable that need to be define in our pipeline.
train_dataset = tf.keras.preprocessing.image_dataset_from_directory(
"/kaggle/input/intel-image-classification/seg_train/seg_train",
labels="inferred",
label_mode="categorical",
class_names=class_names,
color_mode="rgb",
batch_size=config["BATCH_SIZE"],
image_size=(config["IMG_SIZE"],config["IMG_SIZE"]),
shuffle=True,
seed=32,
validation_split=config["VAL_SPLIT"],
subset="training",
interpolation="bilinear",
verbose=True
)
valid_dataset = tf.keras.preprocessing.image_dataset_from_directory(
"/kaggle/input/intel-image-classification/seg_train/seg_train",
labels="inferred",
label_mode="categorical",
class_names=class_names,
color_mode="rgb",
batch_size=config["BATCH_SIZE"],
image_size=(config["IMG_SIZE"],config["IMG_SIZE"]),
shuffle=True,
seed=32,
validation_split=config["VAL_SPLIT"],
subset="validation",
interpolation="bilinear",
verbose=True
)
test_dataset = tf.keras.preprocessing.image_dataset_from_directory(
"/kaggle/input/intel-image-classification/seg_test/seg_test",
labels='inferred',
label_mode='categorical',
class_names=class_names,
color_mode='rgb',
batch_size=config["BATCH_SIZE"],
image_size=(config["IMG_SIZE"],config["IMG_SIZE"]),
interpolation='bilinear',
verbose=True
)
On the tensorflow we can use image_dataset_from_directory to convert our dataset to tf.data to improve our processing pipeline. TF.data have more efficient way to utilize our hardware accelerator while training.
plt.figure(figsize=(10,10))
for img,label in train_dataset.take(1):
for i in range(16):
ax = plt.subplot(4,4,i+1)
plt.imshow(img[i].numpy().astype("uint8"))
plt.title(f"Label :{class_names[tf.argmax(label[i])]}")
plt.axis(False)
plt.tight_layout()
plt.show()
In order to gain more information about the dataset, we will visualize first 16 image on the first batch.

def image_augmentation(img,label):
img = tf.image.flip_left_right(img)
img = tf.image.random_brightness(img, max_delta=0.2)
img =tf.image.random_contrast(img,lower=0.8, upper=1.2)
img = normalize_img(img,label)
return img,label
def normalize_img(img,label):
img = tf.cast(img,tf.float32)/255.0
return img,label
Data augmentation in image classification took crucial aspect because image augmentation enable us to make different image data from the few number of image dataset. This method enable the model to learning vast of variation of dataset without need many images.
train_dataset = (train_dataset.map(lambda img,label : image_augmentation(img,label))
.prefetch(tf.data.AUTOTUNE))
valid_dataset = (valid_dataset.map(lambda img,label:normalize_img(img,label))
.prefetch(tf.data.AUTOTUNE))
test_data = (
test_dataset.map(lambda img,label:normalize_img(img,label))
.prefetch(tf.data.AUTOTUNE)
)
sweep_config = {
"method":"grid",
"metric":{
"name":"val_accuracy",
"goal":"maximize"
},
"parameters":
{
"learning_rate":{
"values":[0.001,0.0005]
},
"batch_size":{
"value":64
},
"units":{
"values":[1024,2048,4096]
},
"epochs":
{
"value":100
},
"num_blocks":{
"values":[3,4,5,6]},
"filter_mults":{
"values":[1,2,3]},
"dropouts":{
"values":[0.3,0.4,0.5]},
"IMG_SIZE" : {
"values":[150,200]
}
}
}
In this practice, we will try to find the best parameters such as learning rate, number of block, filter multiply, dropout, and image size. The method that are use is grid search which will make exhausting search from all the parameters. It will take several hours to complete with GPU support.
def train_models():
wandb.init()
config = wandb.config
strategy = tf.distribute.MirroredStrategy()
print(f"Number of GPUS : {strategy.num_replicas_in_sync}")
with strategy.scope():
VGG_model = VGG((config.IMG_SIZE,config.IMG_SIZE,3),len(class_names),
num_blocks = config.num_blocks,filter_mult=config.filter_mults,
dense_neurons=config.units,dropout=config.dropouts)
VGG_model(tf.keras.layers.Input(shape=(config.IMG_SIZE,config.IMG_SIZE,3)))
early_stopping_cb = tf.keras.callbacks.EarlyStopping(patience=3)
VGG_model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=config.learning_rate),
loss=tf.keras.losses.CategoricalCrossentropy(),
metrics=["accuracy"])
history = VGG_model.fit(
train_dataset,
epochs=config.epochs,
validation_data=valid_dataset,
callbacks=[early_stopping_cb,
WandbMetricsLogger(log_freq=10)]
)
val_loss = history.history["val_loss"][-1]
train_loss = history.history["loss"][-1]
val_accuracy = history.history["val_accuracy"][-1]
accuracy = history.history["accuracy"][-1]
wandb.log({"val_loss": val_loss,
"train_loss": train_loss,
"val_accuracy":val_accuracy,
"accuracy":accuracy})
Define the train function to call all the dependencies we need in training. In this training we will initialize and finish each of the model and push it to the wandb. This code utilize T4 × 2 on kaggle and took severals hours to complete. Make sure to use the GPUs.
sweep_id = wandb.sweep(sweep_config,project="testing_sweep2")
wandb.agent(sweep_id, function=train_models)
We will train the model based on the agent and sweep. This code will call the train function and will do all combination of the parameters to train the models.
After completing the sweep. We can see the performance of the model based on the combination of the parameters. In this model we use performance of val accuracy to measures our models.

From the correlation and importance maps we can also see which parameters that have correlation and importance of the models. This is important to gain the insight to the models that we have been trained.
We can see the combination of parameters respect to the val accuracy. From this we can also mentioned some null values which is incomplete of the training because of the OOM (Out Of Memory) because of the parameters that lead to high complexity such as number of block and number of units (neurons).

Based on the val accuracy, you can find that the best parameters is image size = 150, dropout = 0.3, filter mult = 1, learning rate = 0.001, num blocks = 3 and units = 2048. For more detail you can also read more about on the section wordly-sweep-2 (which may different) on the wandb

In summary, we already done hyperparameter tuning using wandb and monitore the performance of the model. This is important in machine learning pipeline to gain and find the best parameters on the models. Although there are several problem like OOM on the model, we already gain insight about the model behaviors.
Code Link :