EX3 = r"""print("3) Image Classification on 'Imagenette' Dataset with and without Data Augmentation, and Simplified R-CNN.")

import tensorflow as tf
import tensorflow_datasets as tfds
import matplotlib.pyplot as plt
import numpy as np

(train_ds, val_ds), info = tfds.load(
    "imagenette",
    split=["train", "validation"],
    with_info=True,
    as_supervised=True
)

num_classes = info.features["label"].num_classes
IMG_SIZE = 224
BATCH = 32

print("Classes:", num_classes)
train_count = info.splits["train"].num_examples
val_count   = info.splits["validation"].num_examples

print("Training Images:", train_count)
print("Validation Images:", val_count)

plt.figure(figsize=(10,4))
for i, example in enumerate(tfds.as_numpy(train_ds.take(5))):
    image, label = example
    plt.subplot(1,5,i+1)
    plt.imshow(image)
    plt.title(f"Label: {label}")
    plt.axis("off")
plt.show()

def normalize(img, label):
    img = tf.image.resize(img, (IMG_SIZE, IMG_SIZE))
    return tf.cast(img, tf.float32) / 255.0, label

def augment(img, label):
    img = tf.image.resize(img, (IMG_SIZE, IMG_SIZE))
    img = tf.image.random_flip_left_right(img)
    img = tf.image.random_flip_up_down(img)
    img = tf.image.random_brightness(img, 0.3)
    img = tf.image.random_contrast(img, 0.7, 1.3)
    img = tf.image.rot90(img, k=np.random.randint(4))
    return tf.cast(img, tf.float32) / 255.0, label

train_no_aug = train_ds.map(normalize).shuffle(1000).batch(BATCH)
train_aug    = train_ds.map(augment).shuffle(1000).batch(BATCH)
val_ds       = val_ds.map(normalize).batch(BATCH)

print("\nTraining samples (with & without aug):", train_count)

def build_cnn():
    model = tf.keras.Sequential([
        tf.keras.layers.Conv2D(32, 3, activation="relu", input_shape=(IMG_SIZE,IMG_SIZE,3)),
        tf.keras.layers.MaxPooling2D(),
        tf.keras.layers.Conv2D(64, 3, activation="relu"),
        tf.keras.layers.MaxPooling2D(),
        tf.keras.layers.Conv2D(128, 3, activation="relu"),
        tf.keras.layers.GlobalAveragePooling2D(),
        tf.keras.layers.Dense(256, activation="relu"),
        tf.keras.layers.Dense(num_classes, activation="softmax")
    ])
    model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
    return model
print("\nTraining CNN WITHOUT augmentation...")
cnn_no_aug = build_cnn()
hist_no_aug = cnn_no_aug.fit(train_no_aug, epochs=10, validation_data=val_ds)

_, acc_no_aug = cnn_no_aug.evaluate(val_ds)
print(f"\nCNN Accuracy WITHOUT augmentation: {acc_no_aug*100:.2f}%")
print("\nTraining CNN WITH augmentation...")
cnn_aug = build_cnn()
hist_aug = cnn_aug.fit(train_aug, epochs=10, validation_data=val_ds)

_, acc_aug = cnn_aug.evaluate(val_ds)
print(f"\nCNN Accuracy WITH augmentation: {acc_aug*100:.2f}%")

def build_r_cnn():
    inputs = tf.keras.Input(shape=(IMG_SIZE, IMG_SIZE, 3))
    x = tf.keras.layers.Conv2D(32, 3, activation="relu")(inputs)
    x = tf.keras.layers.MaxPooling2D()(x)
    x = tf.keras.layers.Conv2D(64, 3, activation="relu")(x)
    x = tf.keras.layers.MaxPooling2D()(x)
    x = tf.keras.layers.Flatten()(x)
    x = tf.keras.layers.Dense(256, activation="relu")(x)
    outputs = tf.keras.layers.Dense(num_classes, activation="softmax")(x)
    model = tf.keras.Model(inputs, outputs)
    model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
    return model

print("\nTraining simplified R-CNN...")
r_cnn = build_r_cnn()
hist_r = r_cnn.fit(train_no_aug, epochs=10, validation_data=val_ds)

_, acc_r = r_cnn.evaluate(val_ds)
print(f"\nR-CNN Accuracy: {acc_r*100:.2f}%")

print("\n==================== ACCURACY COMPARISON =====================")
print(f"CNN WITHOUT Augmentation  : {acc_no_aug*100:.2f}%")
print(f"CNN WITH Augmentation     : {acc_aug*100:.2f}%")
print(f"Simplified R-CNN Accuracy : {acc_r*100:.2f}%")
print("==============================================================")
"""
def get3():
    print(EX3)