{"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":"Import needed modules","metadata":{"id":"CKeVGxZ5GG6o"}},{"cell_type":"code","source":"import os\nimport cv2\nimport time\nimport shutil\nimport itertools\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport tensorflow as tf\nsns.set_style('darkgrid')\nfrom tensorflow import keras\nimport matplotlib.pyplot as plt\nfrom tensorflow.keras import regularizers\nfrom tensorflow.keras.optimizers import Adam, Adamax\nfrom sklearn.model_selection import train_test_split\nfrom tensorflow.keras.metrics import categorical_crossentropy\nfrom tensorflow.keras.models import Model, load_model, Sequential\nfrom sklearn.metrics import confusion_matrix, classification_report\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Activation, Dropout, BatchNormalization\nprint ('modules loaded')","metadata":{"id":"CeMcAy_5GG6s","execution":{"iopub.status.busy":"2023-01-02T06:15:31.496851Z","iopub.execute_input":"2023-01-02T06:15:31.497232Z","iopub.status.idle":"2023-01-02T06:15:38.375255Z","shell.execute_reply.started":"2023-01-02T06:15:31.497121Z","shell.execute_reply":"2023-01-02T06:15:38.374207Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create needed functions","metadata":{"id":"SA_gwvwnGG6v"}},{"cell_type":"markdown","source":"## Function to create dataframe\nWe will use the _create_df()_ function to create train and validation dataframe depending on _define_trpaths()_ and _define_trdf()_ functions which are responsible for getting file paths.","metadata":{"id":"JQdhl_CRGG6v"}},{"cell_type":"code","source":"def define_trpaths(train_data, train_csv):\n    filepaths = []\n    labels = []\n    df = pd.read_csv(train_csv)\n    files = os.listdir(train_data)\n    for file, i in zip(sorted(files), df['diagnosis']):\n        fpath = os.path.join(train_data, file)\n        filepaths.append(fpath)\n        if i == 0:\n            labels.append('No DR')\n        elif i == 1:\n            labels.append('Mild')\n        elif i == 2:\n            labels.append('Moderate')\n        elif i == 3:\n            labels.append('Severe')\n        elif i == 2:\n            labels.append('Proliferative DR')\n        else:\n            labels.append('Not Classified')\n        \n    return filepaths, labels\n\ndef define_trdf(files, classes):\n    Fseries = pd.Series(files, name= 'filepaths')\n    Lseries = pd.Series(classes, name='labels')\n    return pd.concat([Fseries, Lseries], axis= 1)\n\ndef create_df(train_data, train_csv):\n    # train dataframe\n    files, classes = define_trpaths(train_data, train_csv)\n    df = define_trdf(files, classes)\n    strat = df['labels']\n    train_df, valid_df = train_test_split(df, train_size= 0.8, shuffle= True, random_state= 123, stratify= strat)\n    \n    return train_df, valid_df","metadata":{"id":"La4bEbHlGG6w","execution":{"iopub.status.busy":"2023-01-02T06:15:38.377161Z","iopub.execute_input":"2023-01-02T06:15:38.380145Z","iopub.status.idle":"2023-01-02T06:15:38.392989Z","shell.execute_reply.started":"2023-01-02T06:15:38.380106Z","shell.execute_reply":"2023-01-02T06:15:38.391199Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Function to generate images from dataframe\n_create_gens()_ function is responsible for generating batches of tensor image data with real-time data augmentation.","metadata":{"id":"JZaHdeFxGG6x"}},{"cell_type":"code","source":"def create_gens(train_df, valid_df, train_dir):\n    img_size = (224, 224)\n    channels = 3\n    batch_size = 40\n    img_shape = (img_size[0], img_size[1], channels)\n    \n    def scalar(img):\n        return img\n    tr_gen = ImageDataGenerator(preprocessing_function= scalar, horizontal_flip= True)\n    val_gen = ImageDataGenerator(preprocessing_function= scalar)\n    train_gen = tr_gen.flow_from_dataframe( train_df, x_col= 'filepaths', y_col= 'labels', directory = train_dir, target_size= img_size, class_mode= 'categorical',\n                                        color_mode= 'rgb', shuffle= True, batch_size= batch_size)\n    valid_gen = val_gen.flow_from_dataframe( valid_df, x_col= 'filepaths', y_col= 'labels', directory = train_dir, target_size= img_size, class_mode= 'categorical',\n                                        color_mode= 'rgb', shuffle= True, batch_size= batch_size)\n\n    return train_gen, valid_gen","metadata":{"id":"iLL8hHQcGG6x","execution":{"iopub.status.busy":"2023-01-02T06:15:38.394701Z","iopub.execute_input":"2023-01-02T06:15:38.395118Z","iopub.status.idle":"2023-01-02T06:15:38.413163Z","shell.execute_reply.started":"2023-01-02T06:15:38.395074Z","shell.execute_reply":"2023-01-02T06:15:38.412194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Function to show images\n*show_images()* function is responsible for showing images sample from a specific directory after image generator.","metadata":{"id":"8ifXox4SGG6y"}},{"cell_type":"code","source":"def show_images(gen):\n    g_dict = gen.class_indices\n    classes = list(g_dict.keys())\n    images, labels = next(gen)\n    plt.figure(figsize= (20, 20))\n    length = len(labels)\n    sample = min(length, 25)\n    for i in range(sample):\n        plt.subplot(5, 5, i + 1)\n        image = images[i] / 255\n        plt.imshow(image)\n        index = np.argmax(labels[i])\n        class_name = classes[index]\n        plt.title(class_name, color= 'blue', fontsize= 12)\n        plt.axis('off')\n    plt.show()","metadata":{"id":"IAGbj3ZyGG6y","execution":{"iopub.status.busy":"2023-01-02T06:15:38.415902Z","iopub.execute_input":"2023-01-02T06:15:38.416320Z","iopub.status.idle":"2023-01-02T06:15:38.425988Z","shell.execute_reply.started":"2023-01-02T06:15:38.416275Z","shell.execute_reply":"2023-01-02T06:15:38.425121Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Callback Class\n* We will use a custom callback class MyCallback which is responsible for modifying hyperparameters in run-time.\n\n* It will inherit its parameters and hyperparameters from keras.callbacks.Callback.","metadata":{"id":"_K-ryg0DGG6z"}},{"cell_type":"code","source":"### Define a class for custom callback\nclass MyCallback(keras.callbacks.Callback):\n    def __init__(self, model, base_model, patience, stop_patience, threshold, factor, batches, initial_epoch, epochs, ask_epoch):\n        super(MyCallback, self).__init__()\n        self.model = model\n        self.base_model = base_model\n        self.patience = patience # specifies how many epochs without improvement before learning rate is adjusted\n        self.stop_patience = stop_patience # specifies how many times to adjust lr without improvement to stop training\n        self.threshold = threshold # specifies training accuracy threshold when lr will be adjusted based on validation loss\n        self.factor = factor # factor by which to reduce the learning rate\n        self.batches = batches # number of training batch to runn per epoch\n        self.initial_epoch = initial_epoch\n        self.epochs = epochs\n        self.ask_epoch = ask_epoch\n        self.ask_epoch_initial = ask_epoch # save this value to restore if restarting training\n        # callback variables\n        self.count = 0 # how many times lr has been reduced without improvement\n        self.stop_count = 0\n        self.best_epoch = 1   # epoch with the lowest loss\n        self.initial_lr = float(tf.keras.backend.get_value(model.optimizer.lr)) # get the initial learning rate and save it\n        self.highest_tracc = 0.0 # set highest training accuracy to 0 initially\n        self.lowest_vloss = np.inf # set lowest validation loss to infinity initially\n        self.best_weights = self.model.get_weights() # set best weights to model's initial weights\n        self.initial_weights = self.model.get_weights()   # save initial weights if they have to get restored\n\n    # Define a function that will run when train begins\n    def on_train_begin(self, logs= None):\n        msg = '{0:^8s}{1:^10s}{2:^9s}{3:^9s}{4:^9s}{5:^9s}{6:^9s}{7:^10s}{8:10s}{9:^8s}'.format('Epoch', 'Loss', 'Accuracy', 'V_loss', 'V_acc', 'LR', 'Next LR', 'Monitor','% Improv', 'Duration')\n        print(msg)\n        self.start_time = time.time()\n\n    def on_train_end(self, logs= None):\n        stop_time = time.time()\n        tr_duration = stop_time - self.start_time\n        hours = tr_duration // 3600\n        minutes = (tr_duration - (hours * 3600)) // 60\n        seconds = tr_duration - ((hours * 3600) + (minutes * 60))\n        msg = f'training elapsed time was {str(hours)} hours, {minutes:4.1f} minutes, {seconds:4.2f} seconds)'\n        print(msg)\n        self.model.set_weights(self.best_weights) # set the weights of the model to the best weights\n\n    def on_train_batch_end(self, batch, logs= None):\n        acc = logs.get('accuracy') * 100 # get batch accuracy\n        loss = logs.get('loss')\n        msg = '{0:20s}processing batch {1:} of {2:5s}-   accuracy=  {3:5.3f}   -   loss: {4:8.5f}'.format(' ', str(batch), str(self.batches), acc, loss)\n        print(msg, '\\r', end= '') # prints over on the same line to show running batch count\n\n    def on_epoch_begin(self, epoch, logs= None):\n        self.ep_start = time.time()\n\n    # Define method runs on the end of each epoch\n    def on_epoch_end(self, epoch, logs= None):\n        ep_end = time.time()\n        duration = ep_end - self.ep_start\n\n        lr = float(tf.keras.backend.get_value(self.model.optimizer.lr)) # get the current learning rate\n        current_lr = lr\n        acc = logs.get('accuracy')  # get training accuracy\n        v_acc = logs.get('val_accuracy')  # get validation accuracy\n        loss = logs.get('loss')  # get training loss for this epoch\n        v_loss = logs.get('val_loss')  # get the validation loss for this epoch\n\n        if acc < self.threshold: # if training accuracy is below threshold adjust lr based on training accuracy\n            monitor = 'accuracy'\n            if epoch == 0:\n                pimprov = 0.0\n            else:\n                pimprov = (acc - self.highest_tracc ) * 100 / self.highest_tracc # define improvement of model progres\n\n            if acc > self.highest_tracc: # training accuracy improved in the epoch\n                self.highest_tracc = acc # set new highest training accuracy\n                self.best_weights = self.model.get_weights() # training accuracy improved so save the weights\n                self.count = 0 # set count to 0 since training accuracy improved\n                self.stop_count = 0 # set stop counter to 0\n                if v_loss < self.lowest_vloss:\n                    self.lowest_vloss = v_loss\n                self.best_epoch = epoch + 1  # set the value of best epoch for this epoch\n\n            else:\n                # training accuracy did not improve check if this has happened for patience number of epochs\n                # if so adjust learning rate\n                if self.count >= self.patience - 1: # lr should be adjusted\n                    lr = lr * self.factor # adjust the learning by factor\n                    tf.keras.backend.set_value(self.model.optimizer.lr, lr) # set the learning rate in the optimizer\n                    self.count = 0 # reset the count to 0\n                    self.stop_count = self.stop_count + 1 # count the number of consecutive lr adjustments\n                    self.count = 0 # reset counter\n                    if v_loss < self.lowest_vloss:\n                        self.lowest_vloss = v_loss\n                else:\n                    self.count = self.count + 1 # increment patience counter\n\n        else: # training accuracy is above threshold so adjust learning rate based on validation loss\n            monitor = 'val_loss'\n            if epoch == 0:\n                pimprov = 0.0\n            else:\n                pimprov = (self.lowest_vloss - v_loss ) * 100 / self.lowest_vloss\n            if v_loss < self.lowest_vloss: # check if the validation loss improved\n                self.lowest_vloss = v_loss # replace lowest validation loss with new validation loss\n                self.best_weights = self.model.get_weights() # validation loss improved so save the weights\n                self.count = 0 # reset count since validation loss improved\n                self.stop_count = 0\n                self.best_epoch = epoch + 1 # set the value of the best epoch to this epoch\n            else: # validation loss did not improve\n                if self.count >= self.patience - 1: # need to adjust lr\n                    lr = lr * self.factor # adjust the learning rate\n                    self.stop_count = self.stop_count + 1 # increment stop counter because lr was adjusted\n                    self.count = 0 # reset counter\n                    tf.keras.backend.set_value(self.model.optimizer.lr, lr) # set the learning rate in the optimizer\n                else:\n                    self.count = self.count + 1 # increment the patience counter\n                if acc > self.highest_tracc:\n                    self.highest_tracc = acc\n\n        msg = f'{str(epoch + 1):^3s}/{str(self.epochs):4s} {loss:^9.3f}{acc * 100:^9.3f}{v_loss:^9.5f}{v_acc * 100:^9.3f}{current_lr:^9.5f}{lr:^9.5f}{monitor:^11s}{pimprov:^10.2f}{duration:^8.2f}'\n        print(msg)\n\n        if self.stop_count > self.stop_patience - 1: # check if learning rate has been adjusted stop_count times with no improvement\n            msg = f' training has been halted at epoch {epoch + 1} after {self.stop_patience} adjustments of learning rate with no improvement'\n            print(msg)\n            self.model.stop_training = True # stop training\n\n        else:\n            if self.ask_epoch != None:\n                if epoch + 1 >= self.ask_epoch:\n                    msg = 'enter H to halt training or an integer for number of epochs to run then ask again'\n                    print(msg)\n                    ans = input('')\n                    if ans == 'H' or ans == 'h':\n                        msg = f'training has been halted at epoch {epoch + 1} due to user input'\n                        print(msg)\n                        self.model.stop_training = True # stop training\n                    else:\n                        try:\n                            ans = int(ans)\n                            self.ask_epoch += ans\n                            msg = f' training will continue until epoch ' + str(self.ask_epoch)\n                            print(msg)\n                            msg = '{0:^8s}{1:^10s}{2:^9s}{3:^9s}{4:^9s}{5:^9s}{6:^9s}{7:^10s}{8:10s}{9:^8s}'.format('Epoch', 'Loss', 'Accuracy', 'V_loss', 'V_acc', 'LR', 'Next LR', 'Monitor', '% Improv', 'Duration')\n                            print(msg)\n                        except:\n                            print('Invalid')","metadata":{"id":"d5HiN8XDGG60","execution":{"iopub.status.busy":"2023-01-02T06:15:38.429873Z","iopub.execute_input":"2023-01-02T06:15:38.430196Z","iopub.status.idle":"2023-01-02T06:15:38.458614Z","shell.execute_reply.started":"2023-01-02T06:15:38.430148Z","shell.execute_reply":"2023-01-02T06:15:38.457552Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Function to plot history of training\nWe will use plot_training() function for plotting trainning history items [accuracy and loss] in train data and validation data.","metadata":{"id":"2zwhoj3zGG61"}},{"cell_type":"code","source":"def plot_training(hist):\n    tr_acc = hist.history['accuracy']\n    tr_loss = hist.history['loss']\n    val_acc = hist.history['val_accuracy']\n    val_loss = hist.history['val_loss']\n    index_loss = np.argmin(val_loss)\n    val_lowest = val_loss[index_loss]\n    index_acc = np.argmax(val_acc)\n    acc_highest = val_acc[index_acc]\n\n    plt.figure(figsize= (20, 8))\n    plt.style.use('fivethirtyeight')\n    Epochs = [i+1 for i in range(len(tr_acc))]\n    loss_label = f'best epoch= {str(index_loss + 1)}'\n    acc_label = f'best epoch= {str(index_acc + 1)}'\n    plt.subplot(1, 2, 1)\n    plt.plot(Epochs, tr_loss, 'r', label= 'Training loss')\n    plt.plot(Epochs, val_loss, 'g', label= 'Validation loss')\n    plt.scatter(index_loss + 1, val_lowest, s= 150, c= 'blue', label= loss_label)\n    plt.title('Training and Validation Loss')\n    plt.xlabel('Epochs')\n    plt.ylabel('Loss')\n    plt.legend()\n    plt.subplot(1, 2, 2)\n    plt.plot(Epochs, tr_acc, 'r', label= 'Training Accuracy')\n    plt.plot(Epochs, val_acc, 'g', label= 'Validation Accuracy')\n    plt.scatter(index_acc + 1 , acc_highest, s= 150, c= 'blue', label= acc_label)\n    plt.title('Training and Validation Accuracy')\n    plt.xlabel('Epochs')\n    plt.ylabel('Accuracy')\n    plt.legend()\n    plt.tight_layout\n    plt.show()\n","metadata":{"id":"pU3eAW5jGG62","execution":{"iopub.status.busy":"2023-01-02T06:15:38.459935Z","iopub.execute_input":"2023-01-02T06:15:38.460784Z","iopub.status.idle":"2023-01-02T06:15:38.472982Z","shell.execute_reply.started":"2023-01-02T06:15:38.460744Z","shell.execute_reply":"2023-01-02T06:15:38.472016Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model Structure","metadata":{"id":"57eDFl3oGG65"}},{"cell_type":"markdown","source":"### Show images sample","metadata":{"id":"2GHNMVrhGG65"}},{"cell_type":"code","source":"# Get Dataframes\ntrain_data = '/kaggle/input/aptos2019-blindness-detection/train_images'\ntrain_csv = '/kaggle/input/aptos2019-blindness-detection/train.csv'\n\ntrain_df, valid_df = create_df(train_data, train_csv)\n\n# Get Generators\ntrain_gen, valid_gen = create_gens(train_df, valid_df, train_data)\n\nshow_images(train_gen)","metadata":{"id":"1xfcIPMeGG65","execution":{"iopub.status.busy":"2023-01-02T06:15:38.474288Z","iopub.execute_input":"2023-01-02T06:15:38.474672Z","iopub.status.idle":"2023-01-02T06:15:50.166026Z","shell.execute_reply.started":"2023-01-02T06:15:38.474636Z","shell.execute_reply":"2023-01-02T06:15:50.165081Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Create Pre-trained model\nWe will use _EfficientNetB5","metadata":{"id":"3wvOKjeRGG65"}},{"cell_type":"code","source":"# Create Model Structure\nimg_size = (224, 224)\nchannels = 3\nimg_shape = (img_size[0], img_size[1], channels)\nclass_count = len(list(train_gen.class_indices.keys())) # to define number of classes in dense layer\n\n# create pre-trained model\nbase_model = tf.keras.applications.efficientnet.EfficientNetB5(include_top= False, weights= \"imagenet\", input_shape= img_shape, pooling= 'max')\n\nmodel = Sequential([\n    base_model,\n    BatchNormalization(axis= -1, momentum= 0.99, epsilon= 0.001),\n    Dense(256, kernel_regularizer= regularizers.l2(l= 0.016), activity_regularizer= regularizers.l1(0.006),\n                bias_regularizer= regularizers.l1(0.006), activation= 'relu'),\n    Dropout(rate= 0.45, seed= 123),\n    Dense(class_count, activation= 'softmax')\n])\n\nmodel.compile(Adamax(learning_rate= 0.001), loss= 'categorical_crossentropy', metrics= ['accuracy'])\n\nmodel.summary()","metadata":{"id":"e0JI_Zd_GG66","execution":{"iopub.status.busy":"2023-01-02T06:15:50.167124Z","iopub.execute_input":"2023-01-02T06:15:50.167654Z","iopub.status.idle":"2023-01-02T06:16:02.225087Z","shell.execute_reply.started":"2023-01-02T06:15:50.167617Z","shell.execute_reply":"2023-01-02T06:16:02.224065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Get custom callbacks parameters","metadata":{"id":"TciwhdM1GG66"}},{"cell_type":"code","source":"batch_size = 40\nepochs = 40\npatience = 1 \t\t# number of epochs to wait to adjust lr if monitored value does not improve\nstop_patience = 3 \t# number of epochs to wait before stopping training if monitored value does not improve\nthreshold = 0.9 \t# if train accuracy is < threshhold adjust monitor accuracy, else monitor validation loss\nfactor = 0.5 \t\t# factor to reduce lr by\nfreeze = False \t\t# if true free weights of  the base model\nask_epoch = 5\t\t# number of epochs to run before asking if you want to halt training\nbatches = int(np.ceil(len(train_gen.labels) / batch_size))\n\ncallbacks = [MyCallback(model= model, base_model= base_model, patience= patience,\n            stop_patience= stop_patience, threshold= threshold, factor= factor,\n            batches= batches, initial_epoch= 0, epochs= epochs, ask_epoch= ask_epoch )]","metadata":{"id":"7abvdv7mGG66","execution":{"iopub.status.busy":"2023-01-02T06:16:02.226471Z","iopub.execute_input":"2023-01-02T06:16:02.227140Z","iopub.status.idle":"2023-01-02T06:16:02.704770Z","shell.execute_reply.started":"2023-01-02T06:16:02.227085Z","shell.execute_reply":"2023-01-02T06:16:02.703746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Train model","metadata":{"id":"ap89fjdxGG67"}},{"cell_type":"code","source":"history = model.fit(x= train_gen, epochs= epochs, verbose= 0, callbacks= callbacks,\n                    validation_data= valid_gen, validation_steps= None, shuffle= False,\n                    initial_epoch= 0)","metadata":{"id":"0Uk3BTERGG67","execution":{"iopub.status.busy":"2023-01-02T06:16:02.708410Z","iopub.execute_input":"2023-01-02T06:16:02.708838Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Plot training history","metadata":{"id":"dNKq6ebOGG67"}},{"cell_type":"code","source":"plot_training(history)","metadata":{"id":"L0Bj0Sp_GG68","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Evaluate model","metadata":{"id":"MySXhfAJGG68"}},{"cell_type":"code","source":"train_score = model.evaluate(train_gen, verbose= 1)\nvalid_score = model.evaluate(valid_gen, verbose= 1)\n\nprint(\"Train Loss: \", train_score[0])\nprint(\"Train Accuracy: \", train_score[1])\nprint('-' * 20)\nprint(\"Validation Loss: \", valid_score[0])\nprint(\"Validation Accuracy: \", valid_score[1])","metadata":{"id":"wSKDkyXXGG68","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"markdown","source":"### Create test generator","metadata":{}},{"cell_type":"code","source":"test_dir = '/kaggle/input/aptos2019-blindness-detection/test_images'\ntest_csv = '/kaggle/input/aptos2019-blindness-detection/test.csv'\ntest_df = pd.read_csv(test_csv)\ntest_df['id_code'] = test_df['id_code'] + \".png\"\ntest_df['diagnosis'] = np.zeros(test_df.shape[0])\nimg_size = (224, 224)\nts_length = len(test_df)\ntest_batch_size = max(sorted([ts_length // n for n in range(1, ts_length + 1) if ts_length%n == 0 and ts_length/n <= 80]))\n\ndef scalar(img):\n    return img\n    \ntst_gen = ImageDataGenerator(preprocessing_function= scalar)\ntest_gen = tst_gen.flow_from_dataframe( test_df, x_col= 'id_code', y_col= 'diagnosis', directory= test_dir, target_size= img_size,\n                                        color_mode= 'rgb', class_mode='raw', shuffle= False, batch_size= test_batch_size)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Get Prediction","metadata":{}},{"cell_type":"code","source":"preds = model.predict_generator(test_gen)\ny_pred = np.argmax(preds, axis=1)\ny_pred","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df['diagnosis'] = y_pred","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Save the model","metadata":{}},{"cell_type":"code","source":"model_name = 'EffecientNetB5'\nsubject = 'Blindness-Detection'\nacc = valid_score[1] * 100\nsave_path = ''\n\nsave_id = str(f'{model_name}-{subject}-{\"%.2f\" %round(acc, 2)}.h5')\nmodel_save_loc = os.path.join(save_path, save_id)\nmodel.save(model_save_loc)\nprint(f'model was saved as {model_save_loc}')","metadata":{"id":"oy5ShUciGG6-","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Save Submission","metadata":{}},{"cell_type":"code","source":"test_df.to_csv('Submission.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}