| import matplotlib.pyplot as plt
|
| import numpy as np
|
| import torch
|
|
|
| from pathlib import Path
|
|
|
| from src.predict import CLASS_NAMES
|
| from src.logger import get_logger
|
|
|
| logger = get_logger(__name__)
|
|
|
| Path(
|
| "outputs/plots"
|
| ).mkdir(
|
| parents=True,
|
| exist_ok=True
|
| )
|
|
|
|
|
| def tensor_to_image(image):
|
| """
|
| Convert PyTorch image (C,H,W)
|
| to matplotlib format (H,W,C).
|
| """
|
|
|
| if torch.is_tensor(image):
|
|
|
| image = (
|
| image
|
| .detach()
|
| .cpu()
|
| .numpy()
|
| )
|
|
|
| if len(image.shape) == 3:
|
|
|
|
|
|
|
| image = np.transpose(
|
| image,
|
| (1, 2, 0)
|
| )
|
|
|
| image = np.clip(
|
| image,
|
| 0,
|
| 1
|
| )
|
|
|
| return image
|
|
|
|
|
| def show_dataset_samples(
|
| X,
|
| y,
|
| rows=3,
|
| cols=3
|
| ):
|
|
|
| logger.info(
|
| "Displaying sample images"
|
| )
|
|
|
| fig = plt.figure(
|
| "Sample Dataset Images",
|
| figsize=(10, 10)
|
| )
|
|
|
| for i in range(rows * cols):
|
|
|
| plt.subplot(
|
| rows,
|
| cols,
|
| i + 1
|
| )
|
|
|
| plt.imshow(
|
| tensor_to_image(
|
| X[i]
|
| )
|
| )
|
|
|
| plt.title(
|
| CLASS_NAMES[
|
| int(y[i])
|
| ]
|
| )
|
|
|
| plt.axis(
|
| "off"
|
| )
|
|
|
| fig.tight_layout()
|
|
|
| fig.savefig(
|
| "outputs/plots/dataset_samples.png",
|
| dpi=300,
|
| bbox_inches="tight"
|
| )
|
|
|
| plt.show()
|
| plt.close(fig)
|
|
|
|
|
| def show_correct_predictions(
|
| X_test,
|
| y_test,
|
| y_pred,
|
| n=9
|
| ):
|
|
|
| logger.info(
|
| "Displaying correct predictions"
|
| )
|
|
|
| if torch.is_tensor(y_test):
|
|
|
| y_test = (
|
| y_test
|
| .cpu()
|
| .numpy()
|
| )
|
|
|
| correct = np.where(
|
| y_pred == y_test
|
| )[0]
|
|
|
| fig = plt.figure(
|
| "Correct Predictions",
|
| figsize=(10, 10)
|
| )
|
|
|
| for i, idx in enumerate(
|
| correct[:n]
|
| ):
|
|
|
| plt.subplot(
|
| 3,
|
| 3,
|
| i + 1
|
| )
|
|
|
| plt.imshow(
|
| tensor_to_image(
|
| X_test[idx]
|
| )
|
| )
|
|
|
| plt.title(
|
| CLASS_NAMES[
|
| int(y_pred[idx])
|
| ]
|
| )
|
|
|
| plt.axis(
|
| "off"
|
| )
|
|
|
| fig.tight_layout()
|
|
|
| fig.savefig(
|
| "outputs/plots/correct_predictions.png",
|
| dpi=300,
|
| bbox_inches="tight"
|
| )
|
|
|
| plt.show()
|
| plt.close(fig)
|
|
|
|
|
| def show_misclassifications(
|
| X_test,
|
| y_test,
|
| y_pred,
|
| n=9
|
| ):
|
|
|
| logger.info(
|
| "Displaying errors"
|
| )
|
|
|
| if torch.is_tensor(y_test):
|
|
|
| y_test = (
|
| y_test
|
| .cpu()
|
| .numpy()
|
| )
|
|
|
| errors = np.where(
|
| y_pred != y_test
|
| )[0]
|
|
|
| fig = plt.figure(
|
| "Misclassifications",
|
| figsize=(12, 10)
|
| )
|
|
|
| for i, idx in enumerate(
|
| errors[:n]
|
| ):
|
|
|
| plt.subplot(
|
| 3,
|
| 3,
|
| i + 1
|
| )
|
|
|
| plt.imshow(
|
| tensor_to_image(
|
| X_test[idx]
|
| )
|
| )
|
|
|
| actual = CLASS_NAMES[
|
| int(y_test[idx])
|
| ]
|
|
|
| predicted = CLASS_NAMES[
|
| int(y_pred[idx])
|
| ]
|
|
|
| plt.title(
|
| f"A:{actual}\nP:{predicted}"
|
| )
|
|
|
| plt.axis(
|
| "off"
|
| )
|
|
|
| fig.tight_layout()
|
|
|
| fig.savefig(
|
| "outputs/plots/misclassifications.png",
|
| dpi=300,
|
| bbox_inches="tight"
|
| )
|
|
|
| plt.show()
|
| plt.close(fig)
|
|
|
|
|
| def plot_training_history(
|
| history
|
| ):
|
|
|
| logger.info(
|
| "Plotting training history"
|
| )
|
|
|
| fig = plt.figure(
|
| "Training History",
|
| figsize=(12, 5)
|
| )
|
|
|
| plt.plot(
|
| history["accuracy"],
|
| label="Train Accuracy"
|
| )
|
|
|
| plt.plot(
|
| history["val_accuracy"],
|
| label="Validation Accuracy"
|
| )
|
|
|
| plt.xlabel(
|
| "Epoch"
|
| )
|
|
|
| plt.ylabel(
|
| "Accuracy"
|
| )
|
|
|
| plt.title(
|
| "Training vs Validation Accuracy"
|
| )
|
|
|
| plt.legend()
|
|
|
| fig.savefig(
|
| "outputs/plots/training_history.png",
|
| dpi=300,
|
| bbox_inches="tight"
|
| )
|
|
|
| plt.show()
|
| plt.close(fig)
|
|
|
|
|
| def plot_accuracy_loss(
|
| history
|
| ):
|
|
|
| logger.info(
|
| "Plotting accuracy and loss"
|
| )
|
|
|
| fig, axes = plt.subplots(
|
| 1,
|
| 2,
|
| figsize=(14, 5)
|
| )
|
|
|
| axes[0].plot(
|
| history["accuracy"]
|
| )
|
|
|
| axes[0].plot(
|
| history["val_accuracy"]
|
| )
|
|
|
| axes[0].set_title(
|
| "Accuracy"
|
| )
|
|
|
| axes[0].legend(
|
| [
|
| "Train",
|
| "Validation"
|
| ]
|
| )
|
|
|
| axes[1].plot(
|
| history["loss"]
|
| )
|
|
|
| axes[1].plot(
|
| history["val_loss"]
|
| )
|
|
|
| axes[1].set_title(
|
| "Loss"
|
| )
|
|
|
| axes[1].legend(
|
| [
|
| "Train",
|
| "Validation"
|
| ]
|
| )
|
|
|
| fig.tight_layout()
|
|
|
| fig.savefig(
|
| "outputs/plots/accuracy_loss.png",
|
| dpi=300,
|
| bbox_inches="tight"
|
| )
|
|
|
| plt.show()
|
| plt.close(fig) |