{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Credit to Robin Smits and lafoss"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# ! cp -r  '../input/kerasefficientnetb3' '../input/bengaliai-cv19'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import cv2\nimport os\nimport time, gc\nimport numpy as np\nimport pandas as pd\n\nimport tensorflow as tf\nimport keras\nfrom keras import backend as K\nfrom keras.models import Model, Input\nfrom keras.layers import Dense, Lambda\nfrom math import ceil\nimport matplotlib.pyplot as plt\n\n# Install EfficientNet\n!pip install '../input/kerasefficientnetb3/efficientnet-1.0.0-py3-none-any.whl'\nimport efficientnet.keras as efn","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Constants\nHEIGHT = 137\nWIDTH = 236\nFACTOR = 0.70\nHEIGHT_NEW = int(HEIGHT * FACTOR)\nWIDTH_NEW = int(WIDTH * FACTOR)\nCHANNELS = 3\nBATCH_SIZE = 16\n\nDIR = '../input/bengaliai-cv19'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"SIZE = 128\n\nTRAIN = ['/kaggle/input/bengaliai-cv19/train_image_data_0.parquet',\n         '/kaggle/input/bengaliai-cv19/train_image_data_1.parquet',\n         '/kaggle/input/bengaliai-cv19/train_image_data_2.parquet',\n         '/kaggle/input/bengaliai-cv19/train_image_data_3.parquet']\n\nOUT_TRAIN = 'train.zip'\ndef bbox(img):\n    rows = np.any(img, axis=1)\n    cols = np.any(img, axis=0)\n    rmin, rmax = np.where(rows)[0][[0, -1]]\n    cmin, cmax = np.where(cols)[0][[0, -1]]\n    return rmin, rmax, cmin, cmax\n\ndef crop_resize(img0, size=SIZE, pad=16):\n    #crop a box around pixels large than the threshold \n    #some images contain line at the sides\n    ymin,ymax,xmin,xmax = bbox(img0[5:-5,5:-5] > 80)\n    #cropping may cut too much, so we need to add it back\n    xmin = xmin - 13 if (xmin > 13) else 0\n    ymin = ymin - 10 if (ymin > 10) else 0\n    xmax = xmax + 13 if (xmax < WIDTH - 13) else WIDTH\n    ymax = ymax + 10 if (ymax < HEIGHT - 10) else HEIGHT\n    img = img0[ymin:ymax,xmin:xmax]\n    #remove lo intensity pixels as noise\n    img[img < 28] = 0\n    lx, ly = xmax-xmin,ymax-ymin\n    l = max(lx,ly) + pad\n    #make sure that the aspect ratio is kept in rescaling\n    img = np.pad(img, [((l-ly)//2,), ((l-lx)//2,)], mode='constant')\n    return cv2.resize(img,(size,size))\ndf = pd.read_parquet(TRAIN[0])\nn_imgs = 8\nfig, axs = plt.subplots(n_imgs, 2, figsize=(10, 5*n_imgs))\n\nfor idx in range(n_imgs):\n    #somehow the original input is inverted\n    img0 = 255 - df.iloc[idx, 1:].values.reshape(HEIGHT, WIDTH).astype(np.uint8)\n    #normalize each image by its max val\n    img = (img0*(255.0/img0.max())).astype(np.uint8)\n    img = crop_resize(img)\n\n    axs[idx,0].imshow(img0)\n    axs[idx,0].set_title('Original image')\n    axs[idx,0].axis('off')\n    axs[idx,1].imshow(img)\n    axs[idx,1].set_title('Crop & resize')\n    axs[idx,1].axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Image Preprocessing"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Image Size Summary\nprint(HEIGHT_NEW)\nprint(WIDTH_NEW)\n\n# Image Prep\ndef resize_image(img, WIDTH_NEW, HEIGHT_NEW):\n    # Invert\n    img = 255 - img\n\n    # Normalize\n    img = (img * (255.0 / img.max())).astype(np.uint8)\n\n    # Reshape\n    img = img.reshape(HEIGHT, WIDTH)\n    image_resized = cv2.resize(img, (WIDTH_NEW, HEIGHT_NEW), interpolation = cv2.INTER_AREA)\n\n    return image_resized.reshape(-1)   ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Create Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Generalized mean pool - GeM\ngm_exp = tf.Variable(3.0, dtype = tf.float32)\ndef generalized_mean_pool_2d(X):\n    pool = (tf.reduce_mean(tf.abs(X**(gm_exp)), \n                        axis = [1, 2], \n                        keepdims = False) + 1.e-7)**(1./gm_exp)\n    return pool","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create Model\ndef create_model(input_shape):\n    # Input Layer\n    input = Input(shape = input_shape)\n    \n    # Create and Compile Model and show Summary\n    x_model = efn.EfficientNetB3(weights = None, include_top = False, input_tensor = input, pooling = None, classes = None)\n    \n    # UnFreeze all layers\n    for layer in x_model.layers:\n        layer.trainable = True\n    \n    # GeM\n    lambda_layer = Lambda(generalized_mean_pool_2d)\n    lambda_layer.trainable_weights.extend([gm_exp])\n    x = lambda_layer(x_model.output)\n    \n    # multi output\n    grapheme_root = Dense(168, activation = 'softmax', name = 'root')(x)\n    vowel_diacritic = Dense(11, activation = 'softmax', name = 'vowel')(x)\n    consonant_diacritic = Dense(7, activation = 'softmax', name = 'consonant')(x)\n\n    # model\n    model = Model(inputs = x_model.input, outputs = [grapheme_root, vowel_diacritic, consonant_diacritic])\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create Model\nmodel1 = create_model(input_shape = (HEIGHT_NEW, WIDTH_NEW, CHANNELS))\nmodel2 = create_model(input_shape = (HEIGHT_NEW, WIDTH_NEW, CHANNELS))\nmodel3 = create_model(input_shape = (HEIGHT_NEW, WIDTH_NEW, CHANNELS))\nmodel4 = create_model(input_shape = (HEIGHT_NEW, WIDTH_NEW, CHANNELS))\nmodel5 = create_model(input_shape = (HEIGHT_NEW, WIDTH_NEW, CHANNELS))\nmodel6 = create_model(input_shape = (HEIGHT_NEW, WIDTH_NEW, CHANNELS))\nmodel7 = create_model(input_shape = (HEIGHT_NEW, WIDTH_NEW, CHANNELS))\nmodel8 = create_model(input_shape = (HEIGHT_NEW, WIDTH_NEW, CHANNELS))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Load Model Weights\nmodel1.load_weights('../input/kerasefficientnetb3/Train1_model_59.h5') # LB 0.9681\nmodel2.load_weights('../input/kerasefficientnetb3/Train1_model_66.h5') # LB 0.9685\nmodel3.load_weights('../input/kerasefficientnetb3/Train1_model_68.h5') # LB 0.9691\nmodel4.load_weights('../input/mode4weight/model4.h5') # LB ??\nmodel5.load_weights('../input/models-weights/model5.h5') # LB ??\nmodel6.load_weights('../input/kerasefficientnetb3/Train1_model_64.h5')\nmodel7.load_weights('../input/kerasefficientnetb3/Train1_model_70.h5')\nmodel8.load_weights('../input/kerasefficientnetb3/Train1_model_57.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data Generator"},{"metadata":{"trusted":true},"cell_type":"code","source":"class TestDataGenerator(keras.utils.Sequence):\n    def __init__(self, X, batch_size = 16, img_size = (512, 512, 3), *args, **kwargs):\n        self.X = X\n        self.indices = np.arange(len(self.X))\n        self.batch_size = batch_size\n        self.img_size = img_size\n                    \n    def __len__(self):\n        return int(ceil(len(self.X) / self.batch_size))\n\n    def __getitem__(self, index):\n        indices = self.indices[index*self.batch_size:(index+1)*self.batch_size]\n        X = self.__data_generation(indices)\n        return X\n    \n    def __data_generation(self, indices):\n        X = np.empty((self.batch_size, *self.img_size))\n        \n        for i, index in enumerate(indices):\n            image = self.X[index]\n            image = np.stack((image,)*CHANNELS, axis=-1)\n            image = image.reshape(-1, HEIGHT_NEW, WIDTH_NEW, CHANNELS)\n            \n            X[i,] = image\n        \n        return X","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Predict and Submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create Submission File\ntgt_cols = ['grapheme_root','vowel_diacritic','consonant_diacritic']\n\n# Create Predictions\nrow_ids, targets = [], []\n\n# Loop through Test Parquet files (X)\nfor i in range(0, 4):\n    # Test Files Placeholder\n    test_files = []\n\n    # Read Parquet file\n    df = pd.read_parquet(os.path.join(DIR, 'test_image_data_'+str(i)+'.parquet'))\n    # Get Image Id values\n    image_ids = df['image_id'].values \n    # Drop Image_id column\n    df = df.drop(['image_id'], axis = 1)\n\n    # Loop over rows in Dataframe and generate images \n    X = []\n    for image_id, index in zip(image_ids, range(df.shape[0])):\n        test_files.append(image_id)\n        X.append(resize_image(df.loc[df.index[index]].values, WIDTH_NEW, HEIGHT_NEW))\n\n    # Data_Generator\n    data_generator_test = TestDataGenerator(X, batch_size = BATCH_SIZE, img_size = (HEIGHT_NEW, WIDTH_NEW, CHANNELS))\n        \n    # Predict with all 3 models\n    preds1 = model1.predict_generator(data_generator_test, verbose = 1)\n    preds2 = model2.predict_generator(data_generator_test, verbose = 1)\n    preds3 = model3.predict_generator(data_generator_test, verbose = 1)\n    preds4 = model4.predict_generator(data_generator_test, verbose = 1)\n    preds5 = model5.predict_generator(data_generator_test, verbose = 1)\n    preds6 = model6.predict_generator(data_generator_test, verbose = 1)\n    preds7 = model7.predict_generator(data_generator_test, verbose = 1)\n    preds8 = model8.predict_generator(data_generator_test, verbose = 1)\n    \n    # Loop over Preds    \n    for i, image_id in zip(range(len(test_files)), test_files):\n        \n        for subi, col in zip(range(len(preds1)), tgt_cols):\n            sub_preds1 = preds1[subi]\n            sub_preds2 = preds2[subi]\n            sub_preds3 = preds3[subi]\n            sub_preds4 = preds4[subi]\n            sub_preds5 = preds5[subi]\n            sub_preds6 = preds6[subi]\n            sub_preds7 = preds7[subi]\n            sub_preds8 = preds8[subi]\n\n            # Set Prediction with average of 5 predictions\n            row_ids.append(str(image_id)+'_'+col)\n            sub_pred_value = np.argmax((sub_preds1[i] + sub_preds2[i] + sub_preds3[i] + sub_preds4[i] + sub_preds5[i]+sub_preds6[i]+sub_preds7[i]+sub_preds8[i]) / 8)\n            targets.append(sub_pred_value)\n    \n    # Cleanup\n    del df\n    gc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create and Save Submission File\nsubmit_df = pd.DataFrame({'row_id':row_ids,'target':targets}, columns = ['row_id','target'])\nsubmit_df.to_csv('submission.csv', index = False)\nprint(submit_df.head(40))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model1.save(\"model1.h5\")\nmodel2.save(\"model2.h5\")\nmodel3.save(\"model3.h5\")\nmodel4.save(\"model4.h5\")\nmodel5.save(\"model5.h5\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}