{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":3649,"databundleVersionId":46718,"sourceType":"competition"},{"sourceId":142040146,"sourceType":"kernelVersion"}],"dockerImageVersionId":30554,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport re\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nimport matplotlib.pyplot as plt\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score\nfrom sklearn.preprocessing import LabelEncoder\n\nfrom pathlib import Path\nfrom typing import Dict,Optional, List, Tuple\n\nplt.style.use('ggplot')","metadata":{"execution":{"iopub.status.busy":"2024-11-16T16:29:53.30205Z","iopub.execute_input":"2024-11-16T16:29:53.30234Z","iopub.status.idle":"2024-11-16T16:30:03.218232Z","shell.execute_reply.started":"2024-11-16T16:29:53.302313Z","shell.execute_reply":"2024-11-16T16:30:03.217113Z"},"trusted":true},"outputs":[{"name":"stderr","text":"/opt/conda/lib/python3.10/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.23.5\n  warnings.warn(f\"A NumPy version >={np_minversion} and <{np_maxversion}\"\n","output_type":"stream"}],"execution_count":1},{"cell_type":"code","source":"images_folder = Path('/kaggle/input/cifar10-extract-images-as-numpy-arrays/')\ninput_folder = Path('/kaggle/input/cifar-10')\n\nIMG_HEIGHT = 32\nIMG_WIDTH = 32\nN_CLASSES = 10\nBATCH_SIZE = 64\nEPOCHS = 4","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:09:54.592013Z","iopub.execute_input":"2023-09-05T23:09:54.592636Z","iopub.status.idle":"2023-09-05T23:09:54.600067Z","shell.execute_reply.started":"2023-09-05T23:09:54.5926Z","shell.execute_reply":"2023-09-05T23:09:54.59898Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Load training data and create label encoder","metadata":{}},{"cell_type":"code","source":"# load labels\nlabels_dat = pd.read_csv(input_folder/'trainLabels.csv',index_col=['id']).iloc[:,0]\n\n# build encoder from labels\nlabel_encoder = LabelEncoder().fit(labels_dat)\nclasses = label_encoder.classes_\nprint('Classes in CIFAR10')\nprint(classes)","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:09:54.601895Z","iopub.execute_input":"2023-09-05T23:09:54.602508Z","iopub.status.idle":"2023-09-05T23:09:54.666462Z","shell.execute_reply.started":"2023-09-05T23:09:54.602453Z","shell.execute_reply":"2023-09-05T23:09:54.665538Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_data_from_npz(filepath:Path) -> Tuple[np.ndarray]:\n    npz_out = np.load(filepath)\n    return npz_out['images'],npz_out['ids']","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:09:54.669739Z","iopub.execute_input":"2023-09-05T23:09:54.670046Z","iopub.status.idle":"2023-09-05T23:09:54.675149Z","shell.execute_reply.started":"2023-09-05T23:09:54.670016Z","shell.execute_reply":"2023-09-05T23:09:54.674181Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# load images \nimages, ids = load_data_from_npz(images_folder/'train.npz')\n\n# get corresponding labels\nlabels = label_encoder.transform(labels_dat.loc[ids])","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:09:54.676739Z","iopub.execute_input":"2023-09-05T23:09:54.677413Z","iopub.status.idle":"2023-09-05T23:09:56.702975Z","shell.execute_reply.started":"2023-09-05T23:09:54.677359Z","shell.execute_reply":"2023-09-05T23:09:56.701882Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Visualization utitities","metadata":{}},{"cell_type":"code","source":"def display_images(images:np.ndarray, labels:np.ndarray, title:str,seed:Optional[int]=None):\n\n    n = 10\n    \n    if seed is not None:\n        np.random.seed(seed)\n    idxs_to_show = np.random.choice(len(labels), size=n)\n    \n    imgs_show = images[idxs_to_show,...]\n    labels_show = labels[idxs_to_show]\n\n    fig = plt.figure(figsize=(20, 4))\n    plt.title(title)\n    plt.yticks([])\n    plt.xticks([])\n    \n    for i in range(10):\n        ax = fig.add_subplot(1, 10, i+1)\n        plt.xlabel(classes[labels_show[i]])\n        plt.xticks([])\n        plt.yticks([])\n        plt.imshow(imgs_show[i])\n        \n    return fig","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:09:56.704746Z","iopub.execute_input":"2023-09-05T23:09:56.705151Z","iopub.status.idle":"2023-09-05T23:09:56.715698Z","shell.execute_reply.started":"2023-09-05T23:09:56.705113Z","shell.execute_reply":"2023-09-05T23:09:56.714514Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"_ = display_images(images,labels,'Training data',seed=1)","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:09:56.717737Z","iopub.execute_input":"2023-09-05T23:09:56.718212Z","iopub.status.idle":"2023-09-05T23:09:57.368448Z","shell.execute_reply.started":"2023-09-05T23:09:56.718177Z","shell.execute_reply":"2023-09-05T23:09:57.367429Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Preprocess images","metadata":{}},{"cell_type":"code","source":"def preprocess_images(images:np.ndarray) -> np.ndarray:\n    images = images.astype(np.float32)\n    return tf.keras.applications.resnet50.preprocess_input(images)\n\nX = preprocess_images(images)","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:09:57.369619Z","iopub.execute_input":"2023-09-05T23:09:57.369933Z","iopub.status.idle":"2023-09-05T23:09:57.745287Z","shell.execute_reply.started":"2023-09-05T23:09:57.369905Z","shell.execute_reply":"2023-09-05T23:09:57.744181Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"##  Architecture\n\nI will be performing transfer learning on the ResNet50 model available in Keras. \n- I will load the pretrained imagenet weights to the model\n- I will discard the final classification layer and train one from scratch.\n- The resnet model was trained on images of size 224x224 while the CIFAR images are 32x32. I will be using an Upsampling layer to handle this discrepancy.  \n\nI will be using the functional API in Keras to build the model.","metadata":{}},{"cell_type":"code","source":"def classifier_module(inputs):\n    '''\n    Defines the final dense layers followed by the softmax layer for classification\n    '''\n    x = tf.keras.layers.GlobalAveragePooling2D()(inputs)\n    x = tf.keras.layers.Dense(1024, activation=\"relu\")(x)\n    x = tf.keras.layers.Dense(512, activation=\"relu\")(x)\n    x = tf.keras.layers.Dense(N_CLASSES, activation=\"softmax\", name=\"classification\")(x)\n    return x\n\ndef construct_model() -> tf.keras.Model:\n    '''\n    Builds a resnet50 based classification model with the specified hyperparameters\n        \n    Returns\n    -----------\n    model: tf.keras.Model\n        A compliled keras model\n    '''\n    \n    inputs = tf.keras.Input(shape=(IMG_WIDTH,IMG_HEIGHT,3))\n    resize = tf.keras.layers.UpSampling2D(size=(7,7))(inputs)\n    \n    resnet_features = tf.keras.applications.resnet.ResNet50(\n        input_shape=(224,224,3),\n        include_top=False,\n        weights='imagenet'\n    )(resize)\n    \n    classification_output = classifier_module(resnet_features)\n    \n    model = tf.keras.Model(inputs=inputs,outputs=classification_output)\n    \n    # compile\n    model.compile(\n        optimizer=tf.keras.optimizers.SGD(),\n        loss = 'sparse_categorical_crossentropy',\n        metrics=['accuracy']\n    )\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:09:57.746807Z","iopub.execute_input":"2023-09-05T23:09:57.747526Z","iopub.status.idle":"2023-09-05T23:09:57.758709Z","shell.execute_reply.started":"2023-09-05T23:09:57.747467Z","shell.execute_reply":"2023-09-05T23:09:57.757639Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# build model\ntf.keras.backend.clear_session()        \nmodel = construct_model()\nprint(model.summary())","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:09:57.762266Z","iopub.execute_input":"2023-09-05T23:09:57.763059Z","iopub.status.idle":"2023-09-05T23:10:04.211728Z","shell.execute_reply.started":"2023-09-05T23:09:57.763021Z","shell.execute_reply":"2023-09-05T23:10:04.210667Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Train model","metadata":{}},{"cell_type":"code","source":"#further divide into train and validation splits for early stopping\n# stratified on the labels\nX_train,X_val,y_train,y_val = train_test_split(\n    X,labels,test_size=0.1,random_state=1,\n    stratify = labels\n)\n\n# train model\nhistory = model.fit(\n    X_train,\n    y_train,\n    batch_size=BATCH_SIZE,\n    epochs=EPOCHS,\n    validation_data=(X_val, y_val),\n    verbose=True\n)","metadata":{"execution":{"iopub.status.busy":"2023-09-05T21:00:27.383357Z","iopub.execute_input":"2023-09-05T21:00:27.384257Z","iopub.status.idle":"2023-09-05T21:17:00.725173Z","shell.execute_reply.started":"2023-09-05T21:00:27.384221Z","shell.execute_reply":"2023-09-05T21:17:00.724197Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# save model\nmodel.save_weights(f'cifar10_resnet_{EPOCHS}-epochs.h5')","metadata":{"execution":{"iopub.status.busy":"2023-09-05T21:17:00.726701Z","iopub.execute_input":"2023-09-05T21:17:00.727277Z","iopub.status.idle":"2023-09-05T21:17:01.138578Z","shell.execute_reply.started":"2023-09-05T21:17:00.727242Z","shell.execute_reply":"2023-09-05T21:17:01.137176Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Test predictions","metadata":{}},{"cell_type":"code","source":"# load the test set images\ntest_images, test_ids = load_data_from_npz(images_folder/'test.npz')","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:10:10.228823Z","iopub.execute_input":"2023-09-05T23:10:10.233322Z","iopub.status.idle":"2023-09-05T23:10:24.03805Z","shell.execute_reply.started":"2023-09-05T23:10:10.233265Z","shell.execute_reply":"2023-09-05T23:10:24.036931Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%time \nfrom tqdm import tqdm\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)","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:13:42.25643Z","iopub.execute_input":"2023-09-05T23:13:42.257441Z","iopub.status.idle":"2023-09-05T23:13:58.64916Z","shell.execute_reply.started":"2023-09-05T23:13:42.25739Z","shell.execute_reply":"2023-09-05T23:13:58.648073Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# get prediction labels \ntest_preds = test_pred_probs.argmax(axis=1)","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:04:07.372286Z","iopub.execute_input":"2023-09-05T23:04:07.372699Z","iopub.status.idle":"2023-09-05T23:04:07.378176Z","shell.execute_reply.started":"2023-09-05T23:04:07.37266Z","shell.execute_reply":"2023-09-05T23:04:07.376919Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# visualizaing some of the test set predictions\n_ = display_images(test_images,test_preds,'Test data predictions',seed=0)","metadata":{"execution":{"iopub.status.busy":"2023-09-05T23:04:07.379745Z","iopub.execute_input":"2023-09-05T23:04:07.380183Z","iopub.status.idle":"2023-09-05T23:04:07.983694Z","shell.execute_reply.started":"2023-09-05T23:04:07.380146Z","shell.execute_reply":"2023-09-05T23:04:07.982552Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 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-09-05T23:04:07.986039Z","iopub.execute_input":"2023-09-05T23:04:07.98644Z"},"trusted":true},"outputs":[],"execution_count":null}]}