Comparative Analysis of Adam and SGD Optimizers in Image Classification

Environment and Hardware Configuration

To ensure efficient computation, the environment is configured to utilize available GPU resources dynamically. Non-critical warnings are suppressed to maintain a clean log output.

import os
import pathlib
import warnings
import tensorflow as tf
import matplotlib.pyplot as plt

# Configure GPU memory growth to prevent allocation errors
gpus = tf.config.list_physical_devices('GPU')
if gpus:
    try:
        tf.config.experimental.set_memory_growth(gpus[0], True)
        tf.config.set_visible_devices(gpus[0], 'GPU')
    except RuntimeError as e:
        print(e)

# Ignore unnecessary warnings
warnings.filterwarnings('ignore')

Data Pipeline Construction

The dataset is loaded from a specified directory and split into training and validation subsets. Image dimensions are standardized to 336x336 pixels with a batch size of 8.

DATA_ROOT = pathlib.Path("D:/BaiduNetdiskDownload/T6")
TARGET_SIZE = (336, 336)
BATCH_SIZE = 8

# Create training dataset
train_ds = tf.keras.utils.image_dataset_from_directory(
    DATA_ROOT,
    validation_split=0.2,
    subset="training",
    seed=42,
    image_size=TARGET_SIZE,
    batch_size=BATCH_SIZE
)

# Create validation dataset
val_ds = tf.keras.utils.image_dataset_from_directory(
    DATA_ROOT,
    validation_split=0.2,
    subset="validation",
    seed=42,
    image_size=TARGET_SIZE,
    batch_size=BATCH_SIZE
)

class_names = train_ds.class_names

Data Optimization and Normalization

Performance is enhanced by caching, shuffling, and prefetching the datasets. A normalization function is applied to scale pixel values to the range [0, 1].

AUTOTUNE = tf.data.AUTOTUNE

def normalize_img(image, label):
    return image / 255.0, label

def optimize_pipeline(dataset):
    return (dataset
            .cache()
            .shuffle(1000)
            .map(normalize_img, num_parallel_calls=AUTOTUNE)
            .prefetch(buffer_size=AUTOTUNE))

train_ds = optimize_pipeline(train_ds)
val_ds = optimize_pipeline(val_ds)

Sample Data Visualization

A grid of sample images is generated to verify data integrity and label correspondence before training begins.

plt.figure(figsize=(12, 10))
images, labels = next(iter(train_ds))

for i in range(16):
    ax = plt.subplot(4, 4, i + 1)
    plt.imshow(images[i])
    plt.title(class_names[labels[i]])
    plt.axis("off")

plt.show()

Model Architecture Definition

A transfer learning approach is employed using VGG16 as the feature extractor. The top layers are replaced with a custom classifier containing a Dense layer, Batch Normalization, and Dropout. A function dynamically creates two instances of this model: one utilizing the Adam optimizer and the other using SGD.

from tensorflow.keras.layers import Dense, Dropout, BatchNormalization
from tensorflow.keras.models import Model

def build_classifier(optimizer):
    # Load pre-trained VGG16 base
    base_model = tf.keras.applications.VGG16(
        weights='imagenet',
        include_top=False,
        input_shape=(*TARGET_SIZE, 3),
        pooling='avg'
    )
    
    # Freeze base model layers
    base_model.trainable = False
    
    # Construct custom head
    x = base_model.output
    x = Dense(170, activation='relu')(x)
    x = BatchNormalization()(x)
    x = Dropout(0.5)(x)
    outputs = Dense(len(class_names), activation='softmax')(x)
    
    # Assemble full model
    model = Model(inputs=base_model.input, outputs=outputs)
    
    model.compile(
        optimizer=optimizer,
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy']
    )
    return model

# Initialize models with different optimizers
adam_model = build_classifier(tf.keras.optimizers.Adam())
sgd_model = build_classifier(tf.keras.optimizers.SGD())

sgd_model.summary()

Training Execution

Both models are trained for 50 epochs to compare convergence rates and final performance metrics on the validation set.

EPOCH_COUNT = 50

print("Starting training with Adam optimizer...")
history_adam = adam_model.fit(
    train_ds, 
    epochs=EPOCH_COUNT, 
    validation_data=val_ds, 
    verbose=1
)

print("Starting training with SGD optimizer...")
history_sgd = sgd_model.fit(
    train_ds, 
    epochs=EPOCH_COUNT, 
    validation_data=val_ds, 
    verbose=1
)

Performance Benchmarking

The training histories of both models are visualized to compare loss and accuracy trajectories. This analysis highlights the impact of the optimization algorithm choice on model stability and convergence speed.

def plot_comparison(hist1, hist2, name1, name2):
    acc1 = hist1.history['accuracy']
    val_acc1 = hist1.history['val_accuracy']
    loss1 = hist1.history['loss']
    val_loss1 = hist1.history['val_loss']

    acc2 = hist2.history['accuracy']
    val_acc2 = hist2.history['val_accuracy']
    loss2 = hist2.history['loss']
    val_loss2 = hist2.history['val_loss']

    epochs = range(len(acc1))

    plt.figure(figsize=(16, 6))

    # Plot Accuracy
    plt.subplot(1, 2, 1)
    plt.plot(epochs, acc1, label=f'Train Acc ({name1})')
    plt.plot(epochs, val_acc1, label=f'Val Acc ({name1})')
    plt.plot(epochs, acc2, label=f'Train Acc ({name2})')
    plt.plot(epochs, val_acc2, label=f'Val Acc ({name2})')
    plt.title('Accuracy Metrics')
    plt.legend(loc='lower right')

    # Plot Loss
    plt.subplot(1, 2, 2)
    plt.plot(epochs, loss1, label=f'Train Loss ({name1})')
    plt.plot(epochs, val_loss1, label=f'Val Loss ({name1})')
    plt.plot(epochs, loss2, label=f'Train Loss ({name2})')
    plt.plot(epochs, val_loss2, label=f'Val Loss ({name2})')
    plt.title('Loss Metrics')
    plt.legend(loc='upper right')

    plt.show()

plot_comparison(history_adam, history_sgd, 'Adam', 'SGD')

# Final Evaluation
def evaluate_model(model, model_name):
    loss, acc = model.evaluate(val_ds, verbose=0)
    print(f"{model_name} - Loss: {loss:.4f}, Accuracy: {acc:.4f}")

evaluate_model(adam_model, "Adam Optimizer")
evaluate_model(sgd_model, "SGD Optimizer")

Tags: TensorFlow Deep Learning Computer Vision Optimization VGG16

Posted on Tue, 12 May 2026 21:41:58 +0000 by Tagette