{"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":"code","source":"import pandas as pd\nimport numpy as np\nimport json\nimport os\nimport random\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport cv2\n#from tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import train_test_split\nimport tensorflow as tf\nfrom tensorflow.keras import backend as K\nimport tensorflow_addons as tfa","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:52:03.055507Z","iopub.execute_input":"2022-06-28T18:52:03.056326Z","iopub.status.idle":"2022-06-28T18:52:17.11742Z","shell.execute_reply.started":"2022-06-28T18:52:03.056189Z","shell.execute_reply":"2022-06-28T18:52:17.116178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"EDA: https://www.kaggle.com/code/hanselliott/herbarium22-eda/edit","metadata":{}},{"cell_type":"code","source":"TRAIN_DIR = \"../input/herbarium-2022-fgvc9/train_images/\"\nTEST_DIR = \"../input/herbarium-2022-fgvc9/test_images/\"\n\nwith open(\"../input/herbarium-2022-fgvc9/train_metadata.json\") as json_file:\n    train_meta = json.load(json_file)\nwith open(\"../input/herbarium-2022-fgvc9/test_metadata.json\") as json_file:\n    test_meta = json.load(json_file)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:52:45.49925Z","iopub.execute_input":"2022-06-28T18:52:45.499956Z","iopub.status.idle":"2022-06-28T18:53:09.095499Z","shell.execute_reply.started":"2022-06-28T18:52:45.499914Z","shell.execute_reply":"2022-06-28T18:53:09.092426Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Import Setup","metadata":{}},{"cell_type":"code","source":"#Create a meta-data df that can be used to call in images\nids = []\ncategories = []\npaths = []\n\nfor annotation, image in zip(train_meta['annotations'], train_meta['images']):\n    ids.append(image[\"image_id\"])\n    categories.append(annotation['category_id'])\n    paths.append(image[\"file_name\"])\n\ndf_meta = pd.DataFrame({\"id\":ids, \"category\":categories, \"path\":paths})\ndf_meta.head()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:54:01.301919Z","iopub.execute_input":"2022-06-28T18:54:01.303585Z","iopub.status.idle":"2022-06-28T18:54:02.284012Z","shell.execute_reply.started":"2022-06-28T18:54:01.303509Z","shell.execute_reply":"2022-06-28T18:54:02.282789Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"##extract metadata features by category to merge with df_meta\nsci_name = {cat[\"category_id\"]:cat[\"scientificName\"] for cat in train_meta['categories']}\nfamily = {cat[\"category_id\"]:cat[\"family\"] for cat in train_meta['categories']}\ngenus = {cat[\"category_id\"]:cat[\"genus\"] for cat in train_meta['categories']}\nspecies = {cat[\"category_id\"]:cat[\"species\"] for cat in train_meta['categories']}\n\ndf_meta[\"scientific_name\"] = df_meta[\"category\"].map(sci_name)\ndf_meta[\"family\"] = df_meta[\"category\"].map(family)\ndf_meta[\"genus\"] = df_meta[\"category\"].map(genus)\ndf_meta[\"species\"] = df_meta[\"category\"].map(species)\ndf_meta.head()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:54:07.257067Z","iopub.execute_input":"2022-06-28T18:54:07.257829Z","iopub.status.idle":"2022-06-28T18:54:07.404889Z","shell.execute_reply.started":"2022-06-28T18:54:07.257792Z","shell.execute_reply":"2022-06-28T18:54:07.403795Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"##split the path based on '/' into parent and child folder. \n##lambda fn is applied to each row in the column to split each path\ndf_meta['path'].apply(lambda x : x.split('/'))\n\n#add categories/num_categories equivalents to df_meta\ndf_meta['parent_folder'] = df_meta['path'].apply(lambda x : x.split('/')[0])\ndf_meta['child_folder'] = df_meta['path'].apply(lambda x : x.split('/')[1])\n\ndf_meta.head()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:54:10.066756Z","iopub.execute_input":"2022-06-28T18:54:10.067579Z","iopub.status.idle":"2022-06-28T18:54:14.236089Z","shell.execute_reply.started":"2022-06-28T18:54:10.06754Z","shell.execute_reply":"2022-06-28T18:54:14.234616Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preprocessing Helper Functions","metadata":{}},{"cell_type":"code","source":"def preprocess_cnn(categories, sub_categories, width, height):\n    ## Add train, test\n    ## if x == train, DIR = TRAIN_DIR else DIR == TEST_DIR...\n    \"\"\"\n    Ex: categories = 000, sub_categories = 00 (correspond to parent_folder, child_folder of an image path)\n    Function imports images from the selected categories and applies some preprocessing.\n    Produces X, y data (image, label)\n    \"\"\"\n    list_img = [] ## a list of the images\n    labels = []   ## a list of the correspondign categories\n    for cat, sub_cat in zip(categories, sub_categories):\n        ## Now extract each image from the current categories/sub_categories path\n        for ig in os.listdir(os.path.join(\"../input/herbarium-2022-fgvc9/train_images\", cat, sub_cat)):\n            ##read in image\n            img = cv2.imread(os.path.join(\"../input/herbarium-2022-fgvc9/train_images\", cat, sub_cat, ig))\n            ##resize\n            img = cv2.resize(img, (width, height), interpolation=cv2.INTER_LINEAR)\n            ##equalize\n            img_yuv = cv2.cvtColor(img,cv2.COLOR_RGB2YUV) ##convert to YUB\n            img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0]) ##equalize histogram\n            img_equ = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2RGB) ##convert to RGB\n             #img_equ = img ##cancelling out equalization for now\n            list_img.append(img_equ)\n            labels.append(ig.split(\"__\")[0]) ##label is the part before \"__\" (eg, 2774 for 02774__001.jpg where cat=27, sub_cat=74)\n            \n    return list_img, labels #X, y","metadata":{"execution":{"iopub.status.busy":"2022-06-28T19:10:30.513478Z","iopub.execute_input":"2022-06-28T19:10:30.513919Z","iopub.status.idle":"2022-06-28T19:10:30.524948Z","shell.execute_reply.started":"2022-06-28T19:10:30.513882Z","shell.execute_reply":"2022-06-28T19:10:30.523476Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"02774__001\".split()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:55:07.832802Z","iopub.execute_input":"2022-06-28T18:55:07.833227Z","iopub.status.idle":"2022-06-28T18:55:07.841965Z","shell.execute_reply.started":"2022-06-28T18:55:07.833191Z","shell.execute_reply":"2022-06-28T18:55:07.840218Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Top 20 Test\nWe will test preprocessing/modeling on a smaller subset of the data. We will just use the top 20 categories (out of ~1500 possible).","metadata":{}},{"cell_type":"code","source":"print(\"Unique categories: \", len(df_meta['category'].unique()))\nprint(\"\")\n\n##get the indices of the top 20 most common categories\nindex_top20 = df_meta['category'].value_counts().head(20).index\n#These are the top 20:\nprint(\"Top 20 Most Common Categories (scientific name):\")\ndf_meta['scientific_name'].value_counts().head(20)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:56:01.74428Z","iopub.execute_input":"2022-06-28T18:56:01.744945Z","iopub.status.idle":"2022-06-28T18:56:01.833865Z","shell.execute_reply.started":"2022-06-28T18:56:01.744888Z","shell.execute_reply":"2022-06-28T18:56:01.832986Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"##Create new df with only the top 20 categoires.\ndf_meta_top20 = df_meta[df_meta['category'].isin(index_top20)] ##subset based on top 20 indices found above\nprint(\"Top 20 Most Common Categories (id):\")\ndf_meta_top20['category'].unique()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:56:12.339263Z","iopub.execute_input":"2022-06-28T18:56:12.339664Z","iopub.status.idle":"2022-06-28T18:56:12.357067Z","shell.execute_reply.started":"2022-06-28T18:56:12.339629Z","shell.execute_reply":"2022-06-28T18:56:12.356167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"The subset of the data we will try:\")\nprint(\"Unique parent folders: \", df_meta_top20['parent_folder'].unique()) ##working with only a subset of the data now\nprint(\"Unique subfolders length: \", df_meta_top20['child_folder'].unique().shape, \" corresponds to the 20 categories\") ##only 20 subfolders = to 20 unique categories\ndf_meta_top20['child_folder'].unique()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:56:27.551527Z","iopub.execute_input":"2022-06-28T18:56:27.551935Z","iopub.status.idle":"2022-06-28T18:56:27.563794Z","shell.execute_reply.started":"2022-06-28T18:56:27.5519Z","shell.execute_reply":"2022-06-28T18:56:27.562309Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_meta_top20.head()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:56:43.277473Z","iopub.execute_input":"2022-06-28T18:56:43.277853Z","iopub.status.idle":"2022-06-28T18:56:43.292728Z","shell.execute_reply.started":"2022-06-28T18:56:43.277822Z","shell.execute_reply":"2022-06-28T18:56:43.291794Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Parent_folders\", df_meta_top20['parent_folder'].unique())\nprint(\"Child folders\", df_meta_top20['child_folder'].unique())\nparent_cats = df_meta_top20['category'].unique()\nprint(\"Categories\", parent_cats)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:56:47.822443Z","iopub.execute_input":"2022-06-28T18:56:47.822859Z","iopub.status.idle":"2022-06-28T18:56:47.830576Z","shell.execute_reply.started":"2022-06-28T18:56:47.822824Z","shell.execute_reply":"2022-06-28T18:56:47.829591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cat_parent = ['002', '009', '011', '011', '027', '028', '028', '040', '046', '046', '087', '088','088', '100', '108', \n              '109', '125', '125', '125', '125']\ncat_child = df_meta_top20['child_folder'].unique()\nlen(cat_child)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T18:57:02.083921Z","iopub.execute_input":"2022-06-28T18:57:02.085314Z","iopub.status.idle":"2022-06-28T18:57:02.095187Z","shell.execute_reply.started":"2022-06-28T18:57:02.08525Z","shell.execute_reply":"2022-06-28T18:57:02.093694Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preprocessing","metadata":{}},{"cell_type":"code","source":"# Import the training images from the top 20 categories\nX_raw, y_raw = preprocess_cnn(categories=cat_parent,\n                              sub_categories=cat_child,\n                              width=299, height=299)   ##the dimensions of each images","metadata":{"execution":{"iopub.status.busy":"2022-06-28T19:10:43.233318Z","iopub.execute_input":"2022-06-28T19:10:43.233753Z","iopub.status.idle":"2022-06-28T19:11:03.420694Z","shell.execute_reply.started":"2022-06-28T19:10:43.233714Z","shell.execute_reply":"2022-06-28T19:11:03.419365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"##convert X and y to np arrays\nX = np.array(X_raw)\ny = np.array(y_raw)\nnum_classes = len(np.unique(y))\n\nprint(\"X.shape: \", X.shape, \"~ 1600 imgs, each 299x299 array, with 3 dims (RGB)\") \nprint(\"y.shape: \", y.shape)\nprint(\"unique y: \", np.unique(y))","metadata":{"execution":{"iopub.status.busy":"2022-06-28T19:11:17.321769Z","iopub.execute_input":"2022-06-28T19:11:17.322207Z","iopub.status.idle":"2022-06-28T19:11:17.807293Z","shell.execute_reply.started":"2022-06-28T19:11:17.322171Z","shell.execute_reply":"2022-06-28T19:11:17.805826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"##shuffle images?\ny_indices = np.arange(len(y))\n\n##randomly shuffle the images up\nnp.random.seed(42)\nnp.random.shuffle(y_indices)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T19:11:19.297826Z","iopub.execute_input":"2022-06-28T19:11:19.299348Z","iopub.status.idle":"2022-06-28T19:11:19.304563Z","shell.execute_reply.started":"2022-06-28T19:11:19.299294Z","shell.execute_reply":"2022-06-28T19:11:19.30328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"##Encode target labels with value between 0 and n_classes-1 (since the categories are currently an assortment of random # strings)\nle = LabelEncoder() ##sklearn.preprocessing\ny = le.fit_transform(y)\nprint(\"unique y: \", np.unique(y))\n##One-hot encode\ny = tf.keras.utils.to_categorical(y)\ny","metadata":{"execution":{"iopub.status.busy":"2022-06-28T19:11:21.48058Z","iopub.execute_input":"2022-06-28T19:11:21.481511Z","iopub.status.idle":"2022-06-28T19:11:21.491775Z","shell.execute_reply.started":"2022-06-28T19:11:21.481472Z","shell.execute_reply":"2022-06-28T19:11:21.490336Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Submissions are evaluated using the macro F1 score.","metadata":{}},{"cell_type":"code","source":"f1_macro = tfa.metrics.F1Score(num_classes=num_classes, average='macro') ##from TensorFlow Addons","metadata":{"execution":{"iopub.status.busy":"2022-06-28T19:11:24.617794Z","iopub.execute_input":"2022-06-28T19:11:24.618878Z","iopub.status.idle":"2022-06-28T19:11:24.630748Z","shell.execute_reply.started":"2022-06-28T19:11:24.618835Z","shell.execute_reply":"2022-06-28T19:11:24.62934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# split training and testing subsets\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, stratify= y, random_state = 42)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T19:11:26.39845Z","iopub.execute_input":"2022-06-28T19:11:26.398838Z","iopub.status.idle":"2022-06-28T19:11:27.425513Z","shell.execute_reply.started":"2022-06-28T19:11:26.398807Z","shell.execute_reply":"2022-06-28T19:11:27.424121Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"X_train.shape: \", X_train.shape)\nprint(\"y_train.shape: \", y_train.shape)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T19:11:29.085709Z","iopub.execute_input":"2022-06-28T19:11:29.086197Z","iopub.status.idle":"2022-06-28T19:11:29.094549Z","shell.execute_reply.started":"2022-06-28T19:11:29.086157Z","shell.execute_reply":"2022-06-28T19:11:29.092671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"2592**0.","metadata":{"execution":{"iopub.status.busy":"2022-06-28T20:35:43.692288Z","iopub.execute_input":"2022-06-28T20:35:43.692756Z","iopub.status.idle":"2022-06-28T20:35:43.700642Z","shell.execute_reply.started":"2022-06-28T20:35:43.692714Z","shell.execute_reply":"2022-06-28T20:35:43.699246Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 2d ConvNet\ntop20mod = tf.keras.models.Sequential([\n    tf.keras.layers.Input(shape=(299, 299, 3)), ##299 x 299 images, RGB\n    tf.keras.layers.Conv2D(filters=32, kernel_size=(3,3), padding='same', activation='relu'),\n    tf.keras.layers.Conv2D(filters=32, kernel_size=(3,3), padding='same', activation='relu'),\n    tf.keras.layers.MaxPool2D(pool_size=(2,2)),\n    tf.keras.layers.Dropout(0.2),\n    tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding='same', activation='relu'),\n    tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding='same', activation='relu'),\n    tf.keras.layers.MaxPool2D(pool_size=(4,4)),\n    tf.keras.layers.Dropout(0.2),\n    #tf.keras.layers.Conv2D(filters=32, kernel_size=(3,3), padding='same', activation='relu'),\n    #tf.keras.layers.MaxPool2D(pool_size=(6,6)),\n    #tf.keras.layers.Dropout(0.25),\n    tf.keras.layers.Flatten(),\n    tf.keras.layers.Dense(360, activation='relu'),\n    tf.keras.layers.Dense(num_classes, activation='softmax')\n])\ntop20mod.summary()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T20:52:15.366503Z","iopub.execute_input":"2022-06-28T20:52:15.366943Z","iopub.status.idle":"2022-06-28T20:52:15.589757Z","shell.execute_reply.started":"2022-06-28T20:52:15.366905Z","shell.execute_reply":"2022-06-28T20:52:15.587552Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"t20weights = top20mod.get_weights()\n#fn to reset model weights to randomly initialized if want to restart training\nreset_model = lambda model, weights: model.set_weights(weights) \n\nloss_fn = tf.keras.losses.CategoricalCrossentropy(from_logits=False)\noptim = tf.keras.optimizers.Adam(learning_rate=0.0001,\n                                 beta_1=0.9,\n                                 beta_2=0.999)\n\ntop20mod.compile(optimizer=optim,\n                 loss=loss_fn,\n                 metrics=['accuracy', f1_macro])\n","metadata":{"execution":{"iopub.status.busy":"2022-06-28T20:52:19.539189Z","iopub.execute_input":"2022-06-28T20:52:19.539614Z","iopub.status.idle":"2022-06-28T20:52:19.746914Z","shell.execute_reply.started":"2022-06-28T20:52:19.53958Z","shell.execute_reply":"2022-06-28T20:52:19.745591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Data Generator (for augmentation/preprocessing in the flow of training)\n##train\ntrain_datagen = tf.keras.preprocessing.image.ImageDataGenerator(\n                rescale=1.0/255,\n                rotation_range=30,\n                width_shift_range=0.1,\n                height_shift_range=0.1,\n                shear_range=0.1,\n                zoom_range=0.2,\n                horizontal_flip=True,\n                fill_mode='nearest',\n                validation_split=0.2\n)\n\n\n##test\ntest_datagen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)\n#\nprint(\"Post-datagen train N:\", \ntrain_datagen.flow(X_train, y_train, batch_size=16, subset='training').n,\n      \"\\n Post-datagen validation N:\",\ntrain_datagen.flow(X_train, y_train, batch_size=16, subset='validation').n,\n)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T20:52:22.303262Z","iopub.execute_input":"2022-06-28T20:52:22.304023Z","iopub.status.idle":"2022-06-28T20:52:23.887709Z","shell.execute_reply.started":"2022-06-28T20:52:22.303973Z","shell.execute_reply":"2022-06-28T20:52:23.886341Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"top20mod = tf.keras.models.Sequential([\n    tf.keras.layers.Input(shape=(299, 299, 3)), ##299 x 299 images, RGB\n    tf.keras.layers.Conv2D(filters=32, kernel_size=(3,3), padding='same', activation='relu'),\n    tf.keras.layers.Conv2D(filters=32, kernel_size=(3,3), padding='same', activation='relu'),\n    tf.keras.layers.MaxPool2D(pool_size=(2,2)),\n    tf.keras.layers.Dropout(0.2),\n    tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding='same', activation='relu'),\n    tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding='same', activation='relu'),\n    tf.keras.layers.MaxPool2D(pool_size=(4,4)),\n    tf.keras.layers.Dropout(0.2),\n    #tf.keras.layers.Conv2D(filters=32, kernel_size=(3,3), padding='same', activation='relu'),\n    #tf.keras.layers.MaxPool2D(pool_size=(6,6)),\n    #tf.keras.layers.Dropout(0.25),\n    tf.keras.layers.Flatten(),\n    tf.keras.layers.Dense(360, activation='relu'),\n    tf.keras.layers.Dense(num_classes, activation='softmax')\n])","metadata":{}},{"cell_type":"code","source":"# TRAINING\nreset_model(top20mod, t20weights)\nhistory_cnn = top20mod.fit(\n    train_datagen.flow(X_train, y_train, batch_size=16, subset='training'),\n    validation_data = train_datagen.flow(X_train, y_train,batch_size=8,subset='validation'),\n    batch_size=32, \n    epochs=5)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T20:52:26.092395Z","iopub.execute_input":"2022-06-28T20:52:26.093487Z","iopub.status.idle":"2022-06-28T21:09:02.158636Z","shell.execute_reply.started":"2022-06-28T20:52:26.093426Z","shell.execute_reply":"2022-06-28T21:09:02.157289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Plotting the fit history\nfig, ax = plt.subplots(nrows=1, ncols=3, figsize=(20,10))\n\nax[0].plot(history_cnn.history['loss'], label='loss')\nax[0].plot(history_cnn.history['val_loss'], label='val loss')\nax[0].legend()\n\nax[1].plot(history_cnn.history['accuracy'], label='acc')\nax[1].plot(history_cnn.history['val_accuracy'], label='val acc')\nax[1].legend()\n\nax[2].plot(history_cnn.history['f1_score'], label='f1')\nax[2].plot(history_cnn.history['val_f1_score'], label='val f1')\nax[2].legend()\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T21:11:29.594063Z","iopub.execute_input":"2022-06-28T21:11:29.594592Z","iopub.status.idle":"2022-06-28T21:11:30.128955Z","shell.execute_reply.started":"2022-06-28T21:11:29.594554Z","shell.execute_reply":"2022-06-28T21:11:30.12751Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Predict model onto test data\ny_pred = top20mod.predict(test_datagen.flow(X_test))","metadata":{"execution":{"iopub.status.busy":"2022-06-28T21:11:41.67136Z","iopub.execute_input":"2022-06-28T21:11:41.672679Z","iopub.status.idle":"2022-06-28T21:11:52.441454Z","shell.execute_reply.started":"2022-06-28T21:11:41.672629Z","shell.execute_reply":"2022-06-28T21:11:52.439984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Determine class with highest predicted prob\ny_pred_class = np.argmax(y_pred, axis=1)\n# Convert y_test from one-hot encoded to sparse\ny_true = np.argmax(y_test, axis=1)\n\nprint(\n\"y_pred.shape \", y_pred_class.shape,\n\", y_true.shape \", y_true.shape\n)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T21:13:46.618415Z","iopub.execute_input":"2022-06-28T21:13:46.619477Z","iopub.status.idle":"2022-06-28T21:13:46.627014Z","shell.execute_reply.started":"2022-06-28T21:13:46.619427Z","shell.execute_reply":"2022-06-28T21:13:46.625909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# compute confusion matrix\nconf_mat = tf.math.confusion_matrix(y_true, y_pred_class)\n# plot with seaborn\nplt.figure(figsize= (10,10))\nsns.heatmap(conf_mat, annot=True).set(xlabel=\"Pred\", ylabel=\"True\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T21:13:47.930982Z","iopub.execute_input":"2022-06-28T21:13:47.931393Z","iopub.status.idle":"2022-06-28T21:13:49.393545Z","shell.execute_reply.started":"2022-06-28T21:13:47.931359Z","shell.execute_reply":"2022-06-28T21:13:49.392399Z"},"trusted":true},"execution_count":null,"outputs":[]}]}