{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# ***Note***: \nExtracting the images from the 7z files is time consuming, especially for the images in the test set. \nHence, in a separate notebook ([ADL - A5 - CIFAR10 images as NumPy Arrays](https://www.kaggle.com/code/ahel51798/adl-a5-cifar10-images-as-numpy-arrays)) , we extracted the images into compressed .npz formats and used it in this notebook format instead.\n-------------","metadata":{}},{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session\n\n# Importing required libraries and modules\nimport matplotlib.pyplot as plt  # For creating plots and visualizations\nimport tensorflow as tf  # Machine Learning Framework\nfrom tensorflow import keras  # High-level Neural Networks API\nimport glob  # For Unix style pathname pattern expansion\nimport cv2  # OpenCV for Image Processing\nimport re  # For Regular Expressions\nfrom pathlib import Path\nfrom typing import Dict,Optional, List, Tuple\nfrom tensorflow.keras.models import Sequential, Model, load_model\nfrom tensorflow.keras.layers import Dense, Dropout, Activation, Flatten, BatchNormalization, Input, Conv2D, MaxPooling2D, GlobalAveragePooling2D, Resizing\nfrom tensorflow.keras.applications import ResNet50V2  # Importing the ResNet50V2 model from Keras Applications\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator  # For data augmentation and preprocessing\nfrom sklearn.model_selection import train_test_split  # For splitting dataset into training and test set\nfrom sklearn.metrics import accuracy_score  # For calculating the accuracy score\nfrom sklearn.preprocessing import LabelEncoder  # For encoding categorical features as numerical labels\nfrom tqdm import tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-10-08T17:32:42.621838Z","iopub.execute_input":"2023-10-08T17:32:42.622148Z","iopub.status.idle":"2023-10-08T17:32:50.955203Z","shell.execute_reply.started":"2023-10-08T17:32:42.622123Z","shell.execute_reply":"2023-10-08T17:32:50.954262Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\n# Defining constants\nimages_folder = Path('/kaggle/input/adl-a5-cifar10-images-as-numpy-arrays/')\ninput_folder = Path('/kaggle/input/cifar-10')\nIMG_HEIGHT = 32\nIMG_WIDTH = 32\nN_CLASSES = 10\nBATCH_SIZE = 64\nEPOCHS = 4\n# Loading and Encoding Labels\nlabels_dat = pd.read_csv(input_folder/'trainLabels.csv', index_col=['id']).iloc[:, 0]\nlabel_encoder = LabelEncoder().fit(labels_dat)\nclasses = label_encoder.classes_\nprint('Classes in CIFAR10', classes)\n\ndef load_data_from_npz(filepath:Path) -> Tuple[np.ndarray]:\n    npz_out = np.load(filepath)\n    return npz_out['images'],npz_out['ids']\n\n# Loading images and their corresponding labels\nimages, ids = load_data_from_npz(images_folder/'train.npz')\nlabels = label_encoder.transform(labels_dat.loc[ids])\n\ndef preprocess_images(images:np.ndarray) -> np.ndarray:\n    images = images.astype(np.float32)\n    return tf.keras.applications.resnet50.preprocess_input(images)\n\n# Preprocessing images\nX = preprocess_images(images.astype(np.float32))\n","metadata":{"execution":{"iopub.status.busy":"2023-10-08T17:32:50.957034Z","iopub.execute_input":"2023-10-08T17:32:50.957633Z","iopub.status.idle":"2023-10-08T17:32:53.837140Z","shell.execute_reply.started":"2023-10-08T17:32:50.957600Z","shell.execute_reply":"2023-10-08T17:32:53.836255Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\ndef classifier_module(inputs): # Function to define the final dense layers followed by the softmax layer for classification\n\n    # Applying Global Average Pooling 2D to the input\n    x = tf.keras.layers.GlobalAveragePooling2D()(inputs)\n\n    # Defining and adding Dense layers with 'relu' activation\n    x = tf.keras.layers.Dense(1024, activation=\"relu\")(x)\n    x = tf.keras.layers.Dense(512, activation=\"relu\")(x)\n\n    # Final Dense layer with softmax activation for classification\n    x = tf.keras.layers.Dense(N_CLASSES, activation=\"softmax\", name=\"classification\")(x)\n\n    return x\n\ndef construct_model() -> tf.keras.Model: # Function to construct a ResNet50 based classification model with specified hyperparameters\n\n    # Defining the input layer with image dimensions\n    inputs = tf.keras.Input(shape=(IMG_WIDTH, IMG_HEIGHT, 3))\n\n    # Upsampling the input images to match the required input dimensions of ResNet50\n    resize = tf.keras.layers.UpSampling2D(size=(7,7))(inputs)\n\n    # Loading ResNet50 model with imagenet weights and without the top classification layer\n    resnet_features = tf.keras.applications.resnet.ResNet50(input_shape=(224, 224, 3), include_top=False, weights='imagenet')(resize)\n\n    # Getting the classifier output by calling the previously defined classifier_module function\n    classification_output = classifier_module(resnet_features)\n\n    # Learning rate scheduling\n    lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(initial_learning_rate=1e-2, decay_steps=10000, decay_rate=0.9)\n    optimizer = tf.keras.optimizers.SGD(learning_rate=lr_schedule)\n\n    # Creating and compiling the model\n    model = tf.keras.Model(inputs=inputs, outputs=classification_output)\n    model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])\n\n\n    return model\n\n# Clearing the TensorFlow session to avoid clutter from old models/layers.\ntf.keras.backend.clear_session()\n\n# Building and summarizing the model\nmodel = construct_model()\nprint(model.summary())\n\n# Dividing the dataset into training and validation sets\nX_train, X_val, y_train, y_val = train_test_split(X, labels, test_size=0.1, random_state=1, stratify=labels)\n\n# Training the model with the training set and validating it with the validation set\nhistory = model.fit(X_train, y_train, batch_size=BATCH_SIZE, epochs=EPOCHS, validation_data=(X_val, y_val), verbose=True)\n\n# Evaluating the model on the validation set\nvalidation_loss, validation_accuracy = model.evaluate(X_train[int(0.8*len(X_train)):], y_train[int(0.8*len(y_train)):])\nprint(f\"Validation Accuracy: {validation_accuracy * 100:.2f}%\")\n\n# Extracting and printing the first two digits of the validation accuracy\nAccuracy = str(validation_accuracy*100)[:2]\nprint(\"Accuracy\", Accuracy)\n\n# Optionally saving the model\nmodel.save(f\"cifar10_model_0.{Accuracy}.h5\")\n","metadata":{"execution":{"iopub.status.busy":"2023-10-08T17:32:53.838698Z","iopub.execute_input":"2023-10-08T17:32:53.839348Z","iopub.status.idle":"2023-10-08T17:49:53.498161Z","shell.execute_reply.started":"2023-10-08T17:32:53.839317Z","shell.execute_reply":"2023-10-08T17:49:53.497241Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\n# Load the model\n# Uncomment and adjust the line below if you want to specify a particular accuracy value:\n# Accuracy = 92\nloaded_model = load_model(f\"cifar10_model_0.{Accuracy}.h5\")\n\n# load the test set images\ntest_images, test_ids = load_data_from_npz(images_folder/'test.npz')\n\n# get prediction probabilities\n# using for loop to prevent out-of-memory issues when using predict\nTEST_BATCH_SIZE=1000\nbatch_vectors= []\n\nfor i in tqdm(range(0,test_images.shape[0],TEST_BATCH_SIZE)):\n    #print(f\" Processing Batch {i//TEST_BATCH_SIZE + 1}\")\n    batch_X = preprocess_images(test_images[i:i+TEST_BATCH_SIZE,...])\n    batch_vectors.append(\n        model.predict(batch_X, verbose=False,batch_size=TEST_BATCH_SIZE)\n    )\n    \ntest_pred_probs = np.concatenate(batch_vectors)\n\n# get prediction labels \ntest_preds = test_pred_probs.argmax(axis=1)\n\n# creating submission file\nsubmission = pd.DataFrame({\n    'id': test_ids,\n    'label':label_encoder.inverse_transform(test_preds)\n})\nsubmission.to_csv('submission.csv',index=False)","metadata":{"execution":{"iopub.status.busy":"2023-10-08T17:49:53.500245Z","iopub.execute_input":"2023-10-08T17:49:53.500556Z","iopub.status.idle":"2023-10-08T17:57:40.641055Z","shell.execute_reply.started":"2023-10-08T17:49:53.500526Z","shell.execute_reply":"2023-10-08T17:57:40.640069Z"},"trusted":true},"execution_count":null,"outputs":[]}]}