i have this code
# **Installing Libraries**
"""
!pip install tensorflow opencv-python matplotlib scikit-learn
"""

# **Importing Libraries**
import numpy as np
import os
import tensorflow as tf
from tensorflow.keras import layers, models
from sklearn.utils.class_weight import compute_class_weight
from sklearn.metrics import classification_report, confusion_matrix, f1_score
from tensorflow.keras.callbacks import ReduceLROnPlateau, EarlyStopping
import matplotlib.pyplot as plt
import seaborn as sns  # For confusion matrix visualization

# **Downloading Dataset**
# Assuming the dataset is manually downloaded and decompressed for use
data_dir = 'OASIS_Alzheimers_Dataset'
# Ensure your dataset has subdirectories for each class.

# **Creating Data Pipeline with Augmentation for Minority Class**
# Define data generators
# Augmenting only the minority class
minority_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
    rescale=1./255,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode='nearest'
)

# Normal data generator for majority class, no augmentation
normal_datagen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)

# Load the full dataset to split later
data = tf.keras.utils.image_dataset_from_directory(
    data_dir,
    image_size=(256, 256),
    batch_size=32,
    label_mode='sparse'  # Could use 'categorical' if you want one-hot encoding
)

# **Split Data into Train, Validate, and Test**
train_size = int(len(data) * 0.7)  # 70% for training
val_size = int(len(data) * 0.2)    # 20% for validation
test_size = len(data) - train_size - val_size  # Remaining for testing

train = data.take(train_size)  # Take the first 70% for training
val = data.skip(train_size).take(val_size)  # Skip first 70%, take the next 20%
test = data.skip(train_size + val_size)  # Skip first 90%, take the last 10% for testing

# Get class distribution to determine minority class
class_labels = np.concatenate([y.numpy() for x, y in train])  # Get class labels from the train dataset
class_counts = np.bincount(class_labels.astype(int))  # Count occurrences of each class
minority_class_index = np.argmin(class_counts)  # Find the index of the minority class

# **Data Augmentation for Minority Class**
# Create a generator for the minority class
min_gen = minority_datagen.flow_from_directory(
    data_dir,
    target_size=(256, 256),
    class_mode='sparse',
    batch_size=32,
    classes=[os.listdir(data_dir)[minority_class_index]],  # augment only minority class
    shuffle=True
)

# Adjust normal to combine with the augmented minority class
train_data = tf.data.Dataset.zip((train, min_gen))
val_data = val
test_data = test

# **Calculate Class Weights**
class_weights = compute_class_weight('balanced', classes=np.unique(class_labels), y=class_labels)
class_weight_dict = dict(enumerate(class_weights))

# **Building The Model using Transfer Learning**
base_model = tf.keras.applications.VGG16(include_top=False, input_shape=(256, 256, 3))

for layer in base_model.layers:
    layer.trainable = False

model = models.Sequential([
    base_model,
    layers.Flatten(),
    layers.Dense(256, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(4, activation='softmax')  # Adjust for number of classes
])

model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001),
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.summary()

# **Callbacks**
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, min_lr=1e-7, verbose=1)
early_stopping = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True)

# **Train The Model**
history = model.fit(train_data,
                    epochs=50,
                    class_weight=class_weight_dict,
                    validation_data=val_data,
                    callbacks=[reduce_lr, early_stopping])

# **Monitor Training Performance**
fig, ax = plt.subplots(1, 2, figsize=(15, 5))

# Plot training & validation loss values
ax[0].plot(history.history['loss'], color='teal', label='Training Loss')
ax[0].plot(history.history['val_loss'], color='orange', label='Validation Loss')
ax[0].set_title('Model Loss')
ax[0].set_ylabel('Loss')
ax[0].set_xlabel('Epoch')
ax[0].legend(loc="upper right")

# Plot training & validation accuracy values
ax[1].plot(history.history['accuracy'], color='teal', label='Training Accuracy')
ax[1].plot(history.history['val_accuracy'], color='orange', label='Validation Accuracy')
ax[1].set_title('Model Accuracy')
ax[1].set_ylabel('Accuracy')
ax[1].set_xlabel('Epoch')
ax[1].legend(loc="upper left")

plt.show()

# **Evaluate the Model**
y_true = []
y_pred = []

for batch in test_data:  # Iterate over test data
    x, y = batch
    yhat = model.predict(x)
    yhat_classes = np.argmax(yhat, axis=1)

    y_true.extend(y.numpy())
    y_pred.extend(yhat_classes)

# Calculate metrics
precision = tf.keras.metrics.Precision()
recall = tf.keras.metrics.Recall()
accuracy = tf.keras.metrics.Accuracy()

# Update states
precision.update_state(y_true, y_pred)
recall.update_state(y_true, y_pred)
accuracy.update_state(y_true, y_pred)

# Print metrics
print("Precision:", precision.result().numpy())
print("Recall:", recall.result().numpy())
print("Accuracy:", accuracy.result().numpy())
print("F1 Score:", f1_score(y_true, y_pred, average='weighted'))

# **Confusion Matrix**
conf_matrix = confusion_matrix(y_true, y_pred)

# Plot confusion matrix
plt.figure(figsize=(10, 8))
sns.heatmap(conf_matrix, annot=True, fmt='d', cmap='Blues', xticklabels=list(class_names.values()), yticklabels=list(class_names.values()))
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
plt.title('Confusion Matrix')
plt.show()

# **Save the Trained Model**
model.save('AD_Model_VGG16.h5')
print("Model saved as AD_Model_VGG16.h5")

# **Function to Predict New Images**
def test_image(image_path):
    img = cv2.imread(image_path)  # Load the image
    img = cv2.resize(img, (256, 256))  # Resize to the model's input shape
    img = img / 255.0  # Normalize the image
    img = np.expand_dims(img, axis=0)  # Add batch dimension

    predictions = model.predict(img)  # Make predictions
    predicted_class = np.argmax(predictions)

    return predicted_class

# **Class Labels and Test Prediction**
class_names = {
    0: "Mild Dementia",
    1: "Moderate Dementia",
    2: "Non Demented",
    3: "Very Mild Dementia"
}

# Test the prediction function
image_path = '/content/OAS1_0028_MR1_mpr-1_100.jpg'  # Change to your test image path
predicted_class = test_image(image_path)
predicted_class_name = class_names[predicted_class]
print(f'The input image belongs to class: {predicted_class} - {predicted_class_name}\n')

# Display original image
original_img = cv2.imread(image_path)
original_img = cv2.cvtColor(original_img, cv2.COLOR_BGR2RGB)

plt.imshow(original_img)
plt.title(f'Predicted Class: {predicted_class_name}')
plt.axis('off')
plt.show()