{"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":"# 1. Pyvips library installation from local","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font:18px Verdana; text-indent: 5%\">\nHere is a notebook intended to illustrate the implementation of a generator under Keras. This supports reading images via the Pyvips library, capable of managing significant sizes.\n</p>\n\n<p style=\"font:18px Verdana; text-indent: 0%; color:red\">\nPlease consider upvoting if you find any interest in this notebook.\n</p>","metadata":{}},{"cell_type":"code","source":"print(\"\\n... INSTALLING LOCAL VERSION OF PYVIPS! ...\")\n!dpkg -i --force-depends /kaggle/input/pyvips-local/libvips-apt/libvips-apt/*.deb >/dev/null 2>&1\n!pip install /kaggle/input/pyvips-local/cffi-1.14.4-cp37-cp37m-manylinux1_x86_64.whl\n!pip install /kaggle/input/pyvips-local/pycparser-2.20-py2.py3-none-any.whl\n!pip install /kaggle/input/pyvips-local/pyvips-2.1.13-py2.py3-none-any.whl\nprint(\"... INSTALL COMPLETE! ...\\n\")","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:49:16.647989Z","iopub.execute_input":"2023-10-14T19:49:16.648293Z","iopub.status.idle":"2023-10-14T19:51:44.745953Z","shell.execute_reply.started":"2023-10-14T19:49:16.648257Z","shell.execute_reply":"2023-10-14T19:51:44.744865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2. Libraries import","metadata":{}},{"cell_type":"code","source":"#from PIL import Image; Image.MAX_IMAGE_PIXELS = 5_000_000_000;\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport numpy as np\nimport cv2 # for resize\nimport pyvips\nimport os, gc\nimport multiprocessing\nfrom itertools import islice\nfrom sklearn.model_selection import train_test_split\nimport tensorflow as tf\nfrom tensorflow.keras.applications import EfficientNetB0\n\nfrom tensorflow.keras.optimizers import Nadam\nfrom tensorflow.keras import callbacks","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:05.706219Z","iopub.execute_input":"2023-10-14T19:56:05.706592Z","iopub.status.idle":"2023-10-14T19:56:10.981206Z","shell.execute_reply.started":"2023-10-14T19:56:05.706555Z","shell.execute_reply":"2023-10-14T19:56:10.980419Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras import regularizers\nfrom tensorflow.keras.applications.inception_v3 import InceptionV3\nfrom keras.applications import VGG16, ResNet50, Xception, InceptionResNetV2\nfrom tensorflow.keras.models import Sequential, Model\nfrom tensorflow.keras.layers import Dense, Dropout, Activation, Flatten, Conv2D\nfrom tensorflow.keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D, GlobalAveragePooling2D, AveragePooling2D\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.callbacks import ModelCheckpoint, CSVLogger\nfrom tensorflow.keras.optimizers import SGD\nfrom tensorflow.keras.regularizers import l2\nfrom tensorflow import keras\nfrom tensorflow.keras import models\nfrom keras import layers\nfrom keras.models import Model, Sequential\nimport keras.backend as K\nfrom albumentations import Compose, VerticalFlip, HorizontalFlip, Rotate, RandomGamma ","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:13.914262Z","iopub.execute_input":"2023-10-14T19:56:13.914597Z","iopub.status.idle":"2023-10-14T19:56:14.564539Z","shell.execute_reply.started":"2023-10-14T19:56:13.914565Z","shell.execute_reply":"2023-10-14T19:56:14.56375Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. Config variables setting","metadata":{}},{"cell_type":"code","source":"config = {\n    'random_state' : 123,\n    'test_size' : 5,\n    'target_size': (512, 512),\n    'nb_canaux': 3,\n    'batch_size' : 16,\n         }\n\nnum_cores = multiprocessing.cpu_count()\n\nrepBase        = '/kaggle/input/UBC-OCEAN'\nrepTest        = 'test_images/'\nrepTest_thumb  = 'test_thumbnails/'\nrepTrain       = 'train_images/'\nrepTrain_thumb = 'train_thumbnails/'\n\nsubmissionMod = False","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:17.524349Z","iopub.execute_input":"2023-10-14T19:56:17.5247Z","iopub.status.idle":"2023-10-14T19:56:17.530229Z","shell.execute_reply.started":"2023-10-14T19:56:17.52467Z","shell.execute_reply":"2023-10-14T19:56:17.529276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4. Data processing","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font:18px Verdana; text-indent: 0%\">\nWe first import data and set, by the way, target file path for each image (depends on TMA flag).\n</p>","metadata":{}},{"cell_type":"code","source":"train = pd.read_csv('/kaggle/input/UBC-OCEAN/train.csv')\ntrain['path'] = train.apply(lambda row: (os.path.join(repTrain, str(row['image_id'])+'.png')) if row['is_tma'] else (os.path.join(repTrain_thumb, str(row['image_id'])+'_thumbnail.png')), axis=1)\ntrain.head()","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:20.316636Z","iopub.execute_input":"2023-10-14T19:56:20.31725Z","iopub.status.idle":"2023-10-14T19:56:20.370422Z","shell.execute_reply.started":"2023-10-14T19:56:20.317209Z","shell.execute_reply":"2023-10-14T19:56:20.369514Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test = pd.read_csv('/kaggle/input/UBC-OCEAN/test.csv')\ntest['path'] = test.apply(lambda row: (os.path.join(repTest_thumb, str(row['image_id'])+'_thumbnail.png')) if os.path.isfile(os.path.join(repBase, repTest_thumb, str(row['image_id'])+'_thumbnail.png')) else (os.path.join(repTest, str(row['image_id'])+'.png')), axis=1)\ntest.head()","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:22.82319Z","iopub.execute_input":"2023-10-14T19:56:22.82354Z","iopub.status.idle":"2023-10-14T19:56:22.844761Z","shell.execute_reply.started":"2023-10-14T19:56:22.823498Z","shell.execute_reply":"2023-10-14T19:56:22.843773Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font:18px Verdana; text-indent: 0%\">\nLabels are saved in a list\n</p>","metadata":{}},{"cell_type":"code","source":"#First we get classes list from train dataframe ...\nlabels = sorted(train['label'].unique())\nprint('LABELS :\\n------------------------')\nprint(labels)\n\n# ... how many different classes are there ?\n# ... will be usefull to size final layer of neural networks\nnb_classes = len(labels)\n","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:24.981297Z","iopub.execute_input":"2023-10-14T19:56:24.98165Z","iopub.status.idle":"2023-10-14T19:56:24.988235Z","shell.execute_reply.started":"2023-10-14T19:56:24.981601Z","shell.execute_reply":"2023-10-14T19:56:24.987376Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font:18px Verdana; text-indent: 0%\">\nOne hot encoding of target labels\n</p>","metadata":{}},{"cell_type":"code","source":"# ... One hot encoding of labels\ntrain_disjonctiv = (train\n.assign(num=1)\n.pivot(index='image_id', columns='label', values='num')\n.replace({1:1, np.nan:0})\n.rename_axis(columns=None)\n.reset_index()\n) ","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:27.356206Z","iopub.execute_input":"2023-10-14T19:56:27.35653Z","iopub.status.idle":"2023-10-14T19:56:27.372004Z","shell.execute_reply.started":"2023-10-14T19:56:27.356489Z","shell.execute_reply":"2023-10-14T19:56:27.371112Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font:18px Verdana; text-indent: 0%\">\nIndexes building for generator\n</p>","metadata":{}},{"cell_type":"code","source":"# ... Build 2 dictionaries image_id / labels and image_id / image_path\nindex_labels = {image:codage for image, codage in zip(train_disjonctiv['image_id'], train_disjonctiv.iloc[:, 1:].values.astype('float32'))}\nindex_paths  = {image:codage for image, codage in zip(train['image_id'], train['path'])}\nindex_test_paths  = {image:codage for image, codage in zip(test['image_id'], test['path'])}\n\n# ... Display 5 first elements of labels index\nprint('\\nLABELS INDEX :\\n------------------------')\nprint(list(islice(index_labels.items(), 5)))\n\n# ... Display 5 first elements of paths index\nprint('\\nPATHS INDEX :\\n------------------------')\nprint(list(islice(index_paths.items(), 5)))","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:29.617753Z","iopub.execute_input":"2023-10-14T19:56:29.618067Z","iopub.status.idle":"2023-10-14T19:56:29.62904Z","shell.execute_reply.started":"2023-10-14T19:56:29.618037Z","shell.execute_reply":"2023-10-14T19:56:29.627904Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font:18px Verdana; text-indent: 0%\">\nWe reserve few images to make some test\n</p>","metadata":{}},{"cell_type":"code","source":"data_collector, test_collector = train_test_split(train['image_id'], \n                                                  test_size = config['test_size'], \n                                                  random_state = config['random_state'], \n                                                  shuffle = True)","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:32.631212Z","iopub.execute_input":"2023-10-14T19:56:32.631637Z","iopub.status.idle":"2023-10-14T19:56:32.637754Z","shell.execute_reply.started":"2023-10-14T19:56:32.631567Z","shell.execute_reply":"2023-10-14T19:56:32.636789Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4. Data Generator","metadata":{}},{"cell_type":"code","source":"class MultiGenerator(tf.keras.utils.Sequence):\n\n    def __init__(self, \n                 images_set,                           #Images list\n                 index_labels=None,                    #Dictionary image Id / label\n                 index_paths=None,                     #Dictionary image Id / path\n                 base_path=repBase,                    #root folder\n                 batch_size=config['batch_size'],      #Batch size\n                 nb_canaux=config['nb_canaux'],        #Number of channel (1: grayscale, 3:color)\n                 reshape=None,                         #Target size of images\n                 augment=False,                        #Do some augmentations on images\n                 nb_classes=nb_classes,                #Number of targets classes\n                 random_state=config['random_state'],  #Seed\n                 shuffle=True,                         #Shuffle images\n                 tta_mode=False,                       #Test Time augmentation mode (prediction only)\n                 preproc=[]):                          #Make noise on image as pre training\n\n        self.images_set = images_set         \n        self.index_labels = index_labels     \n        self.index_paths = index_paths       \n        self.base_path = base_path                              \n        self.reshape = reshape                     \n        self.batch_size = batch_size         \n        self.nb_canaux = nb_canaux           \n        self.augment = augment               \n        self.nb_classes = nb_classes         \n        self.shuffle = shuffle               \n        self.random_state = random_state    \n\n        self.tta_mode = tta_mode             #Test Time Augment. \n        #Info : Here, TTA will be an horizontal flip on image\n\n        #TTA is available only on prediction mode \n        if self.index_labels is not None:\n            self.tta_mode = False\n\n        #TTA mode and Augmentation are exclusive   \n        if self.tta_mode:\n            self.augment = False\n        \n        self.on_epoch_end()\n        np.random.seed(self.random_state)\n\n    ##  __len__\n    #  -------------------\n    #  Lots by epoch determination\n    def __len__(self):\n        return int(np.floor(len(self.images_set) / self.batch_size))\n\n    # Lot building\n    def __getitem__(self, index):\n\n        # Generate indexes of the batch\n        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]\n\n        # Find list of IDs\n        images_set_batch = [self.images_set[k] for k in indexes]\n        \n        X = self.__generate_X(images_set_batch)\n        \n        #Prediction Mode : labels index has not been specified\n        if self.index_labels == None:                    \n            return X  \n\n        #Training Mode : labels index has been specified\n        else:                                             \n            y = self.__generate_y(images_set_batch)\n            \n            if self.augment:\n                X = self.__augment_batch(X)\n            \n            return X, y\n\n        \n    def on_epoch_end(self):\n        'Lots are indexed'\n        self.indexes = np.arange(len(self.images_set))\n        if self.shuffle == True:\n            np.random.seed(self.random_state)\n            np.random.shuffle(self.indexes)\n    \n    def __generate_X(self, images_set_batch):\n        'Features generation'\n        # Features initialization\n        X = np.empty((self.batch_size, *self.reshape, self.nb_canaux))\n        \n        # Data generation from images\n        for i, image_name in enumerate(images_set_batch):\n            imagePath = self.index_paths[image_name]\n            fullPath = f\"{self.base_path}/{imagePath}\"\n            img = self.__pyvips_open_downsampled_slide(fullPath, \n                                                       downsample_by=-1, \n                                                       as_numpy=True, \n                                                       resize_to=self.reshape)\n            img = img.astype(np.float32) / 255.\n            \n            #TTA enabled : do horizontal flip\n            if self.tta_mode:\n                img = np.flip(img, axis=1)\n\n            X[i,] = img\n\n        return X\n    \n    def __generate_y(self, images_set_batch):\n        y = np.empty((self.batch_size, self.nb_classes), dtype=int)\n        \n        for i, image_name in enumerate(images_set_batch):\n            classes = self.index_labels[image_name]\n            y[i, :] = classes\n\n        return y\n    \n    def __vips2numpy(self, vi):\n\n        # map vips formats to np dtypes\n        format_to_dtype = {\n            'uchar': np.uint8,       'char': np.int8,\n            'ushort': np.uint16,     'short': np.int16,\n            'uint': np.uint32,       'int': np.int32,\n            'float': np.float32,     'double': np.float64,\n            'complex': np.complex64, 'dpcomplex': np.complex128,\n        }\n\n        # Return newly written np.ndarray\n        return np.ndarray(buffer=vi.write_to_memory(),\n                          dtype=format_to_dtype[vi.format],\n                          shape=[vi.height, vi.width, vi.bands])\n\n    def __pyvips_open_downsampled_slide(self, img_path, downsample_by=8, as_numpy=True, resize_to=(512,512)):\n\n        # Open the image with PIL\n        tmp_img = pyvips.Image.new_from_file(img_path)    \n\n        if downsample_by==-1:\n            _epsilon = 1e-3\n            downsample_by=min(tmp_img.width, tmp_img.height)/resize_to[0]-_epsilon\n\n        # Resize the image\n        tmp_img = tmp_img.resize(1/downsample_by)\n        tmp_img = self.__vips2numpy(tmp_img) if as_numpy else tmp_img\n        tmp_img = cv2.resize(tmp_img, resize_to, interpolation = cv2.INTER_LANCZOS4) if resize_to is not None else tmp_img\n        \n        if self.nb_canaux==1:\n            tmp_img = cv2.cvtColor(tmp_img, cv2.COLOR_BGR2GRAY)\n            tmp_img = np.expand_dims(tmp_img, axis=-1)\n        return tmp_img\n\n    ## albumentationApply \n    #  -------------------\n    #  On applique à l'image et au masque passé en paramètre\n    #  une série de transformations. \n\n    def __albumentationApply(self, img):\n        transformations_pipline = Compose([\n            HorizontalFlip(),         #Symétrie horizontale\n            VerticalFlip(),           #Symétrie verticale\n            Rotate(limit=10),         #Rotation dans la limite de 10 degrés\n            RandomGamma()             #Correction gamma\n        ])\n        \n        transformations = transformations_pipline(image=img)\n        augmented_img   = transformations['image']\n        \n        return augmented_img\n    \n    def __augment_batch(self, img_batch):\n        for i in range(img_batch.shape[0]):\n            img_batch[i, ] = self.__albumentationApply(img_batch[i, ])\n        \n        return img_batch","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:35.030907Z","iopub.execute_input":"2023-10-14T19:56:35.031225Z","iopub.status.idle":"2023-10-14T19:56:35.057902Z","shell.execute_reply.started":"2023-10-14T19:56:35.031196Z","shell.execute_reply":"2023-10-14T19:56:35.057017Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5. Model","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font:18px Verdana; text-indent: 0%\">\nWe implement a very simple model, the purpose of this notebook being to illustrate the generator\n</p>","metadata":{}},{"cell_type":"code","source":"def builClassifModel(tx: int = 512, ty: int = 512):\n\n    model = Sequential()\n    conv11 = Conv2D(filters = 30, kernel_size = (5,5), input_shape = (tx, ty, 1),\n                    activation = 'relu', padding = 'valid')\n    pool1 = MaxPooling2D(pool_size = (5,5))\n    conv21 = Conv2D(filters = 8, kernel_size = (5,5), activation = 'relu', padding = 'valid')\n    pool2 = MaxPooling2D(pool_size = (5,5))\n    drop = Dropout(rate = 0.2)\n    flat = Flatten()\n    dense1 = Dense(units = 128, activation = 'relu')\n    drop2 = Dropout(rate = 0.2)\n    dense2 = Dense(units = nb_classes, activation = 'softmax')\n    listeLayers = [conv11, pool1, conv21, pool2, drop, flat, dense1, drop2, dense2]\n    for layer in listeLayers :\n        model.add(layer)\n    return model","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:40.066703Z","iopub.execute_input":"2023-10-14T19:56:40.067018Z","iopub.status.idle":"2023-10-14T19:56:40.074721Z","shell.execute_reply.started":"2023-10-14T19:56:40.066991Z","shell.execute_reply":"2023-10-14T19:56:40.07366Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = builClassifModel(config['target_size'][0], config['target_size'][1])\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:42.636962Z","iopub.execute_input":"2023-10-14T19:56:42.637283Z","iopub.status.idle":"2023-10-14T19:56:45.00523Z","shell.execute_reply.started":"2023-10-14T19:56:42.637254Z","shell.execute_reply":"2023-10-14T19:56:45.004558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 6. Loss function","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font:18px Verdana; text-indent: 5%\">\nDataset being unbalanced, we opt for categorical focal loss function. This could indeed avoid us specifying weights to classes when fitting the model.\n</p>","metadata":{}},{"cell_type":"code","source":"def categorical_focal_loss(gamma=2., alpha=.25):\n    \"\"\"\n    Softmax version of focal loss.\n           m\n      FL = ∑  -alpha * (1 - p_o,c)^gamma * y_o,c * log(p_o,c)\n          c=1\n      where m = number of classes, c = class and o = observation\n    Parameters:\n      alpha -- the same as weighing factor in balanced cross entropy\n      gamma -- focusing parameter for modulating factor (1-p)\n    Default value:\n      gamma -- 2.0 as mentioned in the paper\n      alpha -- 0.25 as mentioned in the paper\n    References:\n        Official paper: https://arxiv.org/pdf/1708.02002.pdf\n        https://www.tensorflow.org/api_docs/python/tf/keras/backend/categorical_crossentropy\n    Usage:\n     model.compile(loss=[categorical_focal_loss(alpha=.25, gamma=2)], metrics=[\"accuracy\"], optimizer=adam)\n    \"\"\"\n    def categorical_focal_loss_fixed(y_true, y_pred):\n        \"\"\"\n        :param y_true: A tensor of the same shape as `y_pred`\n        :param y_pred: A tensor resulting from a softmax\n        :return: Output tensor.\n        \"\"\"\n        y_true = K.cast(y_true, tf.float32)\n        y_pred = K.cast(y_pred, tf.float32)\n        \n        # Scale predictions so that the class probas of each sample sum to 1\n        \n        y_pred /= K.sum(y_pred, axis=-1, keepdims=True)\n\n        # Clip the prediction value to prevent NaN's and Inf's\n        epsilon = K.epsilon()\n        y_pred = K.clip(y_pred, epsilon, 1. - epsilon)\n\n        # Calculate Cross Entropy\n        cross_entropy = -y_true * K.log(y_pred)\n\n        # Calculate Focal Loss\n        loss = alpha * K.pow(1 - y_pred, gamma) * cross_entropy\n\n        # Sum the losses in mini_batch\n        return K.sum(loss, axis=1)\n\n    return categorical_focal_loss_fixed","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:48.570533Z","iopub.execute_input":"2023-10-14T19:56:48.570854Z","iopub.status.idle":"2023-10-14T19:56:48.578821Z","shell.execute_reply.started":"2023-10-14T19:56:48.570826Z","shell.execute_reply":"2023-10-14T19:56:48.577746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 7. Callbacks","metadata":{}},{"cell_type":"code","source":"def cb_earlyStopping(patience=6, monitor='val_loss'):\n    return callbacks.EarlyStopping(monitor=monitor, patience=patience)\n\ndef cb_modelCheckPoint(filename, weights_only = True, monitor='val_loss'):\n    return callbacks.ModelCheckpoint(filepath = filename,\n                                       monitor = monitor,\n                                       save_best_only = True,\n                                       save_weights_only = weights_only,\n                                       mode = 'min',\n                                       save_freq = 'epoch')\n\ndef cb_reduceLr(patience=3, factor=0.08, monitor='val_loss'):\n    return callbacks.ReduceLROnPlateau(monitor = monitor,\n                                         patience=patience,\n                                         factor=factor,\n                                         verbose=2,\n                                         mode='min')","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:51.895005Z","iopub.execute_input":"2023-10-14T19:56:51.895314Z","iopub.status.idle":"2023-10-14T19:56:51.901819Z","shell.execute_reply.started":"2023-10-14T19:56:51.895285Z","shell.execute_reply":"2023-10-14T19:56:51.900571Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#TRAINING MODE\n#======================================\nif not submissionMod:\n    \n    # Hyperparameters\n    #-------------------------------\n    epochs         = 10               \n    learning_rate  = 0.001              \n    checkpointName = 'ubcv1'            \n\n    reducePatience = 3                  \n    reduceFactor   = 0.05               \n    earlyStopPatience = 7               \n                                        \n\n    # Image Generation\n    #-------------------------------\n    train_imgs, val_imgs = train_test_split(data_collector, \n                                            test_size = 0.2, \n                                            random_state = config['random_state'], \n                                            shuffle = True)\n    train_imgs = train_imgs.tolist()\n    val_imgs = val_imgs.tolist()\n\n    train_generator = MultiGenerator(train_imgs,\n                                    index_labels=index_labels,\n                                    index_paths=index_paths,\n                                    batch_size=config['batch_size'],\n                                    reshape=config['target_size'],\n                                    augment=True,\n                                    nb_canaux=config['nb_canaux'])\n\n    val_generator = MultiGenerator(val_imgs,\n                                    index_labels=index_labels,\n                                    index_paths=index_paths,\n                                    batch_size=config['batch_size'], \n                                    reshape=config['target_size'],\n                                    augment=False,\n                                    nb_canaux=config['nb_canaux'])\n\n    # Callbacks setting\n    #-------------------------------\n    lstCallbacks = [cb_earlyStopping(patience = earlyStopPatience),\n                    cb_modelCheckPoint(checkpointName),  \n                    cb_reduceLr(patience =reducePatience, factor = reduceFactor)]\n\n    # Optimizer initialization and model compilation\n    #-------------------------------\n    optimizer = Nadam(lr=learning_rate)\n    model.compile(loss=[categorical_focal_loss(alpha=.25, gamma=2)],optimizer = optimizer, metrics=['accuracy'])\n    \n    # Model traing\n    #-------------------------------    \n    history = model.fit(train_generator, \n                         validation_data = val_generator, \n                         epochs = epochs, \n                         callbacks = lstCallbacks, \n                         class_weight = None)","metadata":{"execution":{"iopub.status.busy":"2023-10-14T19:56:59.749212Z","iopub.execute_input":"2023-10-14T19:56:59.749559Z","iopub.status.idle":"2023-10-14T20:22:19.951626Z","shell.execute_reply.started":"2023-10-14T19:56:59.74952Z","shell.execute_reply":"2023-10-14T20:22:19.950468Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# TRAINING MODE\n# We do predictions on images we first reserved\n#======================================\nif not submissionMod:\n    test_imgs = test_collector.tolist()\n    test_generator = MultiGenerator(test_imgs,\n                                    index_labels=None,\n                                    index_paths=index_paths,\n                                    batch_size=1, \n                                    reshape=config['target_size'],\n                                    augment=False,\n                                    shuffle=False,                               \n                                    nb_canaux=config['nb_canaux'],\n                                    nb_classes=nb_classes)\n\n    predictions = model.predict(test_generator, workers=1, verbose=1)\n","metadata":{"execution":{"iopub.status.busy":"2023-10-14T20:22:24.085103Z","iopub.execute_input":"2023-10-14T20:22:24.085429Z","iopub.status.idle":"2023-10-14T20:22:26.68005Z","shell.execute_reply.started":"2023-10-14T20:22:24.085393Z","shell.execute_reply":"2023-10-14T20:22:26.679232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# SUBMISSION MODE\n#======================================\nif submissionMod:\n    \n    # Weigths loading\n    model.load_weights('/kaggle/input/...Dataset where you saved weights.../ubcv1')\n    \n    # Images to predict are generated\n    sub_imgs = test['image_id'].tolist()\n    sub_generator = MultiGenerator(sub_imgs,\n                                    index_labels=None,\n                                    index_paths=index_test_paths,\n                                    batch_size=1, \n                                    reshape=config['target_size'],\n                                    augment=False,\n                                    shuffle=False,                               \n                                    nb_canaux=config['nb_canaux'],\n                                    nb_classes=nb_classes)\n\n    # Predictios\n    predictions = model.predict(sub_generator, workers=1, verbose=1)\n    \n    # Submission file building\n    subDf = []\n    for i in range(0, len(sub_imgs)):\n        image_id = sub_imgs[i]\n        preds = predictions[i]\n        maxPred = np.argmax(preds)\n        currentPrediction = [image_id, labels[maxPred]]\n        subDf.append(currentPrediction)\n    subDf = pd.DataFrame(subDf, columns = ['image_id', 'label']) \n    subDf.to_csv('submission.csv', index=False)  ","metadata":{"execution":{"iopub.status.busy":"2023-10-14T20:22:30.42475Z","iopub.execute_input":"2023-10-14T20:22:30.425069Z","iopub.status.idle":"2023-10-14T20:22:30.433212Z","shell.execute_reply.started":"2023-10-14T20:22:30.425039Z","shell.execute_reply":"2023-10-14T20:22:30.43219Z"},"trusted":true},"execution_count":null,"outputs":[]}]}