{"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":"!readlink -f ../input/sorghum-id-fgvc-9\n!ls ../input/sorghum-id-fgvc-9","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-03-24T11:58:50.818246Z","iopub.execute_input":"2022-03-24T11:58:50.818913Z","iopub.status.idle":"2022-03-24T11:58:52.122502Z","shell.execute_reply.started":"2022-03-24T11:58:50.818874Z","shell.execute_reply":"2022-03-24T11:58:52.121622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!nvidia-smi","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:58:52.126185Z","iopub.execute_input":"2022-03-24T11:58:52.126418Z","iopub.status.idle":"2022-03-24T11:58:52.808969Z","shell.execute_reply.started":"2022-03-24T11:58:52.12638Z","shell.execute_reply":"2022-03-24T11:58:52.808121Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Dataloader class for augmentation by albumentation.\n#ref https://www.kaggle.com/meaninglesslives/unet-with-efficientnet-encoder-in-keras\nimport tensorflow as tf\nimport tensorflow.keras as keras\nimport numpy as np\nfrom PIL import Image\nimport cv2\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import train_test_split\nimport pandas as pd\nimport os","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:58:52.811638Z","iopub.execute_input":"2022-03-24T11:58:52.811926Z","iopub.status.idle":"2022-03-24T11:58:58.925711Z","shell.execute_reply.started":"2022-03-24T11:58:52.81189Z","shell.execute_reply":"2022-03-24T11:58:58.924889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.__version__","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:58:58.93152Z","iopub.execute_input":"2022-03-24T11:58:58.93358Z","iopub.status.idle":"2022-03-24T11:58:58.94783Z","shell.execute_reply.started":"2022-03-24T11:58:58.933535Z","shell.execute_reply":"2022-03-24T11:58:58.946234Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.random.seed(42)\ntf.random.set_seed(42)\n\nproj_dir = \"/kaggle/input/sorghum-id-fgvc-9/\"\ndf = pd.read_csv(proj_dir + \"train_cultivar_mapping.csv\")\n# df.groupby(\"cultivar\").describe().to_csv(proj_dir + \"cultivars.csv\")\nbase_path = proj_dir + \"train_images/\"\n\ndf[\"fullpath\"] = base_path + df[\"image\"]","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:58:58.951794Z","iopub.execute_input":"2022-03-24T11:58:58.95405Z","iopub.status.idle":"2022-03-24T11:58:59.014789Z","shell.execute_reply.started":"2022-03-24T11:58:58.954013Z","shell.execute_reply":"2022-03-24T11:58:59.013982Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Remove non-existent images\nexists = []\n\nfor i in df[\"fullpath\"]:\n    if not os.path.exists(i):\n        exists.append(False)\n    else:\n        exists.append(True)\n\ndf[\"exist\"] = pd.Series(exists)\ndf = df[df.exist]","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:58:59.019031Z","iopub.execute_input":"2022-03-24T11:58:59.020966Z","iopub.status.idle":"2022-03-24T11:59:15.365452Z","shell.execute_reply.started":"2022-03-24T11:58:59.020924Z","shell.execute_reply":"2022-03-24T11:59:15.364701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# constants\nBATCH_SIZE = 16\nAUTOTUNE = tf.data.experimental.AUTOTUNE\nTRAIN_SIZE = 0.9\n# SHUFFLE_SIZE = 5000\ntest_data_paths = proj_dir + 'test/*.png'\nWIDTH = 512\nHEIGHT = 512\nEPOCHS = 20\nPREPROCESS_INPUT = tf.keras.applications.resnet_v2.preprocess_input\nIS_SCALED_NEG1_TO_POS1 = True","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:59:15.366822Z","iopub.execute_input":"2022-03-24T11:59:15.367399Z","iopub.status.idle":"2022-03-24T11:59:15.373143Z","shell.execute_reply.started":"2022-03-24T11:59:15.367342Z","shell.execute_reply":"2022-03-24T11:59:15.372543Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"paths = df[\"fullpath\"]\nlabels_str = df[\"cultivar\"]\n\nlabel_to_index = dict((name, index) for index,name in enumerate(labels_str.unique()))\nlabels_idx = labels_str.map(lambda x: label_to_index[x])\n\ntrain_paths, val_paths, train_labels, val_labels = train_test_split(paths, labels_idx, train_size=TRAIN_SIZE, shuffle=True, random_state=42, stratify=labels_idx)","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:59:15.37449Z","iopub.execute_input":"2022-03-24T11:59:15.374973Z","iopub.status.idle":"2022-03-24T11:59:15.415575Z","shell.execute_reply.started":"2022-03-24T11:59:15.374936Z","shell.execute_reply":"2022-03-24T11:59:15.414941Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from albumentations import (\n    Compose, HorizontalFlip, VerticalFlip, CLAHE, HueSaturationValue,\n    RandomBrightness, RandomContrast, RandomGamma, OneOf, ToFloat, ShiftScaleRotate, GridDistortion, ElasticTransform, JpegCompression, HueSaturationValue,\n    RGBShift, RandomBrightnessContrast, Blur, MotionBlur, MedianBlur, GaussNoise, CenterCrop, IAAAdditiveGaussianNoise, OpticalDistortion, RandomSizedCrop)\n\nAUGMENTATIONS_TRAIN = Compose([\n    HorizontalFlip(p=0.5),\n    VerticalFlip(p=0.5),\n    OneOf([\n        RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2, brightness_by_max=False),\n#         RandomGamma(gamma_limit=(90, 110)),\n        ], p=0.5),\n    OneOf([\n        ElasticTransform(alpha=120, sigma=120*0.05, alpha_affine=120*0.03),\n        GridDistortion(),\n        OpticalDistortion(distort_limit=2, shift_limit=0.5),\n        ], p=0),\n    # RandowSizedCrap(in_max_height=(128, 256), height=h, width=w, p=0.5),\n],p=1)","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:59:15.417275Z","iopub.execute_input":"2022-03-24T11:59:15.417542Z","iopub.status.idle":"2022-03-24T11:59:16.248185Z","shell.execute_reply.started":"2022-03-24T11:59:15.417509Z","shell.execute_reply":"2022-03-24T11:59:16.247467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_and_crop(path, img_size):\n    image = np.array(Image.open(path))\n    image = cv2.resize(image, img_size)\n\n    return np.uint8(image)","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:59:16.250634Z","iopub.execute_input":"2022-03-24T11:59:16.250907Z","iopub.status.idle":"2022-03-24T11:59:16.256124Z","shell.execute_reply.started":"2022-03-24T11:59:16.250871Z","shell.execute_reply":"2022-03-24T11:59:16.254728Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DataGenerator(keras.utils.Sequence):\n    def __init__(self, im_paths, labels, batch_size, augmentations=None, img_size=[256, 256], n_channels=3, shuffle=True):\n        \"\"\"\n        `im_paths` and `labels` must be pd.Series\n        \"\"\"\n    \n        self.batch_size = batch_size\n        self.im_paths = im_paths\n        self.labels = labels\n        self.img_size = img_size\n        self.n_channels = n_channels\n        self.shuffle = shuffle\n        self.augment = augmentations\n\n        self.on_epoch_end()\n\n    def __len__(self):\n        return int(np.ceil(len(self.im_paths)/self.batch_size))\n\n    def __getitem__(self, index):\n        indexes = self.indexes[index*self.batch_size:min((index+1)*self.batch_size, len(self.im_paths))]\n\n        X, y = self.data_generation(indexes)\n\n        if self.augment is None:\n            return PREPROCESS_INPUT(X), y\n\n        else:\n            im = []\n            for x in X:\n                augmented = self.augment(image=x)\n                im.append(PREPROCESS_INPUT(augmented['image']))\n            return np.array(im), y\n\n    def on_epoch_end(self):\n        self.indexes = np.arange(len(self.im_paths))\n\n        if self.shuffle == True:\n            np.random.shuffle(self.indexes)\n\n    def data_generation(self, indexes): \n        X = np.empty((len(indexes), self.img_size[0], self.img_size[1], self.n_channels))\n        y = np.empty((len(indexes), 1))\n\n        for i, index in enumerate(indexes):\n            im_path = self.im_paths.iloc[index]\n            \n            im = load_and_crop(im_path, self.img_size)\n            label = self.labels.iloc[index]\n\n            X[i,] = im\n            y[i,] = label\n\n        return np.uint8(X), np.uint8(y)","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:59:16.25755Z","iopub.execute_input":"2022-03-24T11:59:16.258077Z","iopub.status.idle":"2022-03-24T11:59:16.272048Z","shell.execute_reply.started":"2022-03-24T11:59:16.258041Z","shell.execute_reply":"2022-03-24T11:59:16.271288Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_generator = DataGenerator(im_paths=train_paths, labels=train_labels, img_size=[WIDTH, HEIGHT], batch_size=BATCH_SIZE, augmentations=AUGMENTATIONS_TRAIN)\nval_generator = DataGenerator(im_paths=val_paths, labels=val_labels, img_size=[WIDTH, HEIGHT], batch_size=BATCH_SIZE, augmentations=None)","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:59:16.27351Z","iopub.execute_input":"2022-03-24T11:59:16.273768Z","iopub.status.idle":"2022-03-24T11:59:16.28299Z","shell.execute_reply.started":"2022-03-24T11:59:16.273733Z","shell.execute_reply":"2022-03-24T11:59:16.282393Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images, labels = train_generator.__getitem__(0)\n# images, labels = val_generator.__getitem__(0)\nmax_images = 8\ngrid_width = 4\nscale_factor = 4\ngrid_height = int(max_images / grid_width)\nfig, axs = plt.subplots(grid_height, grid_width, figsize=(grid_width*scale_factor, grid_height*scale_factor))\n\nfor i, (im, label) in enumerate(zip(images, labels)):\n    if i < max_images:\n        ax = axs[int(i / grid_width), i % grid_width]\n        ax.set_title(label)\n        if IS_SCALED_NEG1_TO_POS1:\n            ax.imshow(im+1)\n        else:\n            ax.imshow(im)\n        ax.axis('off')","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:59:16.284552Z","iopub.execute_input":"2022-03-24T11:59:16.284779Z","iopub.status.idle":"2022-03-24T11:59:18.719131Z","shell.execute_reply.started":"2022-03-24T11:59:16.284747Z","shell.execute_reply":"2022-03-24T11:59:18.718483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"basemodel = tf.keras.applications.resnet_v2.ResNet50V2(include_top=False,weights=\"imagenet\",input_shape=(WIDTH,HEIGHT,3))\nimage_input = tf.keras.layers.Input(shape=(WIDTH,HEIGHT,3))\nout = basemodel(image_input)\nout = tf.keras.layers.GlobalAveragePooling2D()(out)\n# out = tf.keras.layers.Dropout(0.2)(out)\nout = tf.keras.layers.Dense(len(label_to_index), activation=\"softmax\")(out)\n\nmodel = tf.keras.Model(image_input, out)\n\nmodel.compile(optimizer=tf.keras.optimizers.Adam(), \n              loss='sparse_categorical_crossentropy',\n              metrics=[\"accuracy\"])","metadata":{"execution":{"iopub.status.busy":"2022-03-24T12:00:12.395871Z","iopub.execute_input":"2022-03-24T12:00:12.396146Z","iopub.status.idle":"2022-03-24T12:00:17.082876Z","shell.execute_reply.started":"2022-03-24T12:00:12.396116Z","shell.execute_reply":"2022-03-24T12:00:17.082174Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"steps_per_epoch=tf.math.ceil(len(train_paths)/BATCH_SIZE).numpy()\ncallback = tf.keras.callbacks.EarlyStopping(monitor='accuracy',mode='max', patience=20)\n\nhistory = model.fit(train_generator, epochs=EPOCHS, validation_data=val_generator, steps_per_epoch=steps_per_epoch, callbacks=callback)","metadata":{"execution":{"iopub.status.busy":"2022-03-24T12:04:06.749179Z","iopub.execute_input":"2022-03-24T12:04:06.749508Z","iopub.status.idle":"2022-03-24T12:09:33.331773Z","shell.execute_reply.started":"2022-03-24T12:04:06.749474Z","shell.execute_reply":"2022-03-24T12:09:33.330294Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import glob\ntest_image_paths = list(glob.glob(test_data_paths))\ntest_image_paths = [str(path) for path in test_image_paths]\nlen(test_image_paths)\npath_label_test = tf.data.Dataset.from_tensor_slices(test_image_paths)\ntest_ds = path_label_test.map(load_and_preprocess_image, tf.data.experimental.AUTOTUNE)\ntest_ds = test_ds.batch(BATCH_SIZE)\ntest_ds = test_ds.prefetch(buffer_size=AUTOTUNE)\npredictions = model.predict(test_ds, batch_size=BATCH_SIZE)","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:59:19.041729Z","iopub.status.idle":"2022-03-24T11:59:19.042147Z","shell.execute_reply.started":"2022-03-24T11:59:19.041923Z","shell.execute_reply":"2022-03-24T11:59:19.041946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"prediction_output = [(\"filename\", \"cultivar\")]\n\nfor i in range(len(predictions.argmax(axis=1))):\n    pred_idx = predictions.argmax(axis=1)[i]\n    prediction_output.append((os.path.basename(test_image_paths[i]), [k for k, v in label_to_index.items() if v == pred_idx][0]))\n#%%\npd.DataFrame(prediction_output).to_csv(\"submission.csv\", index=None, header=None)","metadata":{"execution":{"iopub.status.busy":"2022-03-24T11:59:19.043664Z","iopub.status.idle":"2022-03-24T11:59:19.044078Z","shell.execute_reply.started":"2022-03-24T11:59:19.043856Z","shell.execute_reply":"2022-03-24T11:59:19.043879Z"},"trusted":true},"execution_count":null,"outputs":[]}]}