|
|
|
""" |
|
Created on Thu Feb 8 15:27:13 2024 |
|
|
|
@author: Dhrumit Patel |
|
""" |
|
|
|
""" |
|
Get helper functions |
|
""" |
|
|
|
from helper_functions import create_tensorboard_callback, plot_loss_curves, compare_historys |
|
|
|
""" |
|
Use TensorFlow Datasets(TFDS) to download data |
|
""" |
|
|
|
import tensorflow_datasets as tfds |
|
|
|
|
|
datasets_list = tfds.list_builders() |
|
print("food101" in datasets_list) |
|
|
|
|
|
(train_data, test_data), ds_info = tfds.load(name="food101", |
|
split=["train", "validation"], |
|
shuffle_files=True, |
|
with_info=True) |
|
|
|
ds_info.features |
|
|
|
|
|
class_names = ds_info.features["label"].names |
|
class_names[:10] |
|
|
|
|
|
train_one_sample = train_data.take(1) |
|
|
|
train_one_sample |
|
|
|
|
|
for sample in train_one_sample: |
|
image, label = sample["image"], sample["label"] |
|
print(f""" |
|
Image shape: {image.shape} |
|
Image datatype: {image.dtype} |
|
Target class from Food101 (tensor form): {label} |
|
Class name (str form): {class_names[label.numpy()]} |
|
""") |
|
|
|
|
|
import tensorflow as tf |
|
image |
|
tf.reduce_min(image), tf.reduce_max(image) |
|
|
|
""" |
|
Plot an image from TensorFlow Datasets |
|
""" |
|
|
|
import matplotlib.pyplot as plt |
|
plt.imshow(image) |
|
plt.title(class_names[label.numpy()]) |
|
plt.axis(False) |
|
|
|
(image, label) |
|
|
|
|
|
def preprocess_img(image, label, img_shape=224): |
|
""" |
|
Converts image datatype from uint8 -> float32 and reshapes |
|
image to [img_shape, img_shape, color_channels] |
|
""" |
|
image = tf.image.resize(image, [img_shape, img_shape]) |
|
|
|
return tf.cast(image, dtype=tf.float32), label |
|
|
|
|
|
preprocessed_img = preprocess_img(image, label)[0] |
|
print(f"Image before preprocessing:\n {image[:2]}..., \n Shape: {image.shape},\nDatatype: {image.dtype}\n") |
|
print(f"Image after preprocessing:]n {preprocessed_img[:2]}..., \n Shape: {preprocessed_img.shape}, \nDatatype: {preprocessed_img.dtype}") |
|
|
|
""" |
|
Batch and preprare datasets |
|
|
|
We are now going to make our data input pipeline run really fast. |
|
""" |
|
|
|
train_data = train_data.map(map_func=lambda sample: preprocess_img(sample['image'], sample['label']), num_parallel_calls=tf.data.AUTOTUNE) |
|
|
|
train_data = train_data.shuffle(buffer_size=1000).batch(batch_size=32).prefetch(buffer_size=tf.data.AUTOTUNE) |
|
|
|
|
|
test_data = test_data.map(map_func=lambda sample: preprocess_img(sample['image'], sample['label']), num_parallel_calls=tf.data.AUTOTUNE) |
|
|
|
test_data = test_data.batch(batch_size=32).prefetch(tf.data.AUTOTUNE) |
|
|
|
train_data, test_data |
|
|
|
""" |
|
Create modelling callbacks |
|
|
|
We are going to create a couple of callbacks to help us while our model trains: |
|
1. TensorBoard callback to log training results (so we can visualize them later if need be) |
|
2. ModelCheckpoint callback to save our model's progress after feature extraction. |
|
""" |
|
|
|
from helper_functions import create_tensorboard_callback |
|
|
|
|
|
checkpoint_path = "model_checkpoints/cp.ckpt" |
|
model_checkpoint = tf.keras.callbacks.ModelCheckpoint(checkpoint_path, |
|
monitor="val_acc", |
|
save_best_only=True, |
|
save_weights_only=True, |
|
verbose=1) |
|
|
|
|
|
from tensorflow.keras import mixed_precision |
|
mixed_precision.set_global_policy("mixed_float16") |
|
mixed_precision.global_policy() |
|
|
|
""" |
|
Build feature extraction model |
|
""" |
|
from tensorflow.keras import layers |
|
from tensorflow.keras.layers.experimental import preprocessing |
|
|
|
|
|
input_shape = (224, 224, 3) |
|
base_model = tf.keras.applications.efficientnet_v2.EfficientNetV2B0(include_top=False) |
|
base_model.trainable = False |
|
|
|
|
|
inputs = layers.Input(shape=input_shape, name="input_layer") |
|
|
|
|
|
x = base_model(inputs, training=False) |
|
x = layers.GlobalAveragePooling2D(name="global_pooling_layer")(x) |
|
outputs = layers.Dense(len(class_names), activation="softmax", dtype=tf.float32, name="softmax_float32")(x) |
|
|
|
model = tf.keras.Model(inputs, outputs) |
|
|
|
|
|
model.compile(loss="sparse_categorical_crossentropy", |
|
optimizer=tf.keras.optimizers.Adam(), |
|
metrics=["accuracy"]) |
|
|
|
model.summary() |
|
|
|
|
|
for layer in model.layers: |
|
print(layer.name, layer.trainable, layer.dtype, layer.dtype_policy) |
|
|
|
|
|
|
|
for layer in model.layers[1].layers: |
|
print(layer.name, layer.trainable, layer.dtype, layer.dtype_policy) |
|
|
|
|
|
|
|
for layer in base_model.layers: |
|
print(layer.name, layer.trainable, layer.dtype, layer.dtype_policy) |
|
|
|
|
|
history_101_food_classes_feature_extract = model.fit(train_data, |
|
epochs=10, |
|
steps_per_epoch=len(train_data), |
|
validation_data=test_data, |
|
validation_steps=int(0.15 * len(test_data)), |
|
callbacks=[create_tensorboard_callback(dir_name="training_logs", experiment_name="efficientnetb0_101_classes_all_data_feature_extract"), model_checkpoint]) |
|
|
|
|
|
|
|
results_feature_extract_model = model.evaluate(test_data) |
|
results_feature_extract_model |
|
|
|
|
|
|
|
def create_model(): |
|
|
|
input_shape = (224, 224, 3) |
|
base_model = tf.keras.applications.efficientnet.EfficientNetB0(include_top=False) |
|
base_model.trainable = False |
|
|
|
|
|
inputs = layers.Input(shape=input_shape, name="input_layer") |
|
|
|
|
|
x = base_model(inputs, training=False) |
|
x = layers.GlobalAveragePooling2D(name="pooling_layer")(x) |
|
x = layers.Dense(len(class_names))(x) |
|
|
|
outputs = layers.Activation("softmax", dtype=tf.float32, name="softmax_float32")(x) |
|
model = tf.keras.Model(inputs, outputs) |
|
|
|
return model |
|
|
|
|
|
created_model = create_model() |
|
created_model.compile(loss="sparse_categorical_crossentropy", |
|
optimizer=tf.keras.optimizers.Adam(), |
|
metrics=["accuracy"]) |
|
|
|
|
|
created_model.load_weights(checkpoint_path) |
|
|
|
|
|
results_created_model_with_loaded_weights = created_model.evaluate(test_data) |
|
|
|
|
|
import numpy as np |
|
assert np.isclose(results_feature_extract_model, results_created_model_with_loaded_weights).all(), "Loaded weights results are not close to original model." |
|
|
|
|
|
for layer in created_model.layers[1].layers[:20]: |
|
print(layer.name, layer.trainable, layer.dtype, layer.dtype_policy) |
|
|
|
|
|
save_dir = "07_efficientnetb0_feature_extract_model_mixed_precision" |
|
model.save(save_dir) |
|
|
|
|
|
loaded_saved_model = tf.keras.models.load_model(save_dir) |
|
|
|
|
|
loaded_saved_model = tf.keras.models.load_model(save_dir) |
|
|
|
|
|
|
|
for layer in loaded_saved_model.layers[1].layers[:20]: |
|
print(layer.name, layer.trainable, layer.dtype, layer.dtype_policy) |
|
|
|
results_loaded_saved_model = loaded_saved_model.evaluate(test_data) |
|
results_loaded_saved_model |
|
|
|
|
|
import numpy as np |
|
assert np.isclose(results_feature_extract_model, results_loaded_saved_model).all() |
|
|
|
|
|
""" |
|
Optional |
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
loaded_gs_model = tf.keras.models.load_model("downloaded_gs_model/07_efficientnetb0_feature_extract_model_mixed_precision") |
|
|
|
|
|
loaded_gs_model.summary() |
|
|
|
|
|
results_loaded_gs_model = loaded_gs_model.evaluate(test_data) |
|
results_loaded_gs_model |
|
|
|
|
|
for layer in loaded_gs_model.layers: |
|
layer.trainable = True |
|
print(layer.name, layer.trainable, layer.dtype, layer.dtype_policy) |
|
|
|
|
|
|
|
for layer in loaded_gs_model.layers[1].layers[:20]: |
|
print(layer.name, layer.trainable, layer.dtype, layer.dtype_policy) |
|
|
|
|
|
early_stopping = tf.keras.callbacks.EarlyStopping(monitor="val_loss", |
|
patience=3) |
|
|
|
|
|
checkpoint_path = "fine_tune_checkpoints/" |
|
model_checkpoint = tf.keras.callbacks.ModelCheckpoint(checkpoint_path, |
|
save_best_only=True, |
|
monitor="val_loss") |
|
|
|
reduce_lr = tf.keras.callbacks.ReduceLROnPlateau(monitor="val_loss", |
|
factor=0.2, |
|
patience=2, |
|
verbose=1, |
|
min_lr=1e-7) |
|
|
|
|
|
loaded_gs_model.compile(loss="sparse_categorical_crossentropy", |
|
optimizer=tf.keras.optimizers.Adam(0.0001), |
|
metrics=["accuracy"]) |
|
|
|
|
|
|
|
history_101_food_classes_all_data_fine_tune = loaded_gs_model.fit(train_data, |
|
epochs=100, |
|
steps_per_epoch=len(train_data), |
|
validation_data=test_data, |
|
validation_steps=int(0.15 * len(test_data)), |
|
callbacks=[create_tensorboard_callback("training_logs", "efficientb0_101_classes_all_data_fine_tuning"), |
|
model_checkpoint, |
|
early_stopping, |
|
reduce_lr]) |
|
|
|
|
|
loaded_gs_model.save("07_efficientnetb0_fine_tuned_101_classes_mixed_precision") |
|
|
|
|
|
""" |
|
Optional |
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
loaded_fine_tuned_gs_model = tf.keras.models.load_model("downloaded_fine_tuned_gs_model/07_efficientnetb0_fine_tuned_101_classes_mixed_precision") |
|
|
|
|
|
loaded_fine_tuned_gs_model.summary() |
|
|
|
|
|
results_downloaded_fine_tuned_gs_model = loaded_fine_tuned_gs_model.evaluate(test_data) |
|
results_downloaded_fine_tuned_gs_model |
|
|
|
""" |
|
# Upload experiment results to TensorBoard (uncomment to run) |
|
# !tensorboard dev upload --logdir ./training_logs \ |
|
# --name "Fine-tuning EfficientNetB0 on all Food101 Data" \ |
|
# --description "Training results for fine-tuning EfficientNetB0 on Food101 Data with learning rate 0.0001" \ |
|
# --one_shot |
|
|
|
# View past TensorBoard experiments |
|
# !tensorboard dev list |
|
|
|
|
|
# Delete past TensorBoard experiments |
|
# !tensorboard dev delete --experiment_id YOUR_EXPERIMENT_ID |
|
|
|
# Example |
|
# !tensorboard dev delete --experiment_id OAE6KXizQZKQxDiqI3cnUQ |
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|