{"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":"# <div style=\"color:white;display:fill;border-radius:5px;background-color:#75B7BF;letter-spacing:0.1px;overflow:hidden\"><p style=\"padding:20px;color:white;overflow:hidden;margin:0;font-size:100%;text-align:center\">1. Import</p></div>\n****\nI used a resized image dataset that be created by [here](https://www.kaggle.com/phanttan/basiceda-ultramnist)","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport datetime\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score\nimport tensorflow as tf\nprint(\"TensorFlow version:\", tf.__version__)\nfrom tensorflow.keras import models, layers\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau\nfrom tensorflow.keras.applications import ResNet50\nfrom tensorflow.keras.optimizers import Adam\n\n# ignoring warnings\nimport warnings\nwarnings.simplefilter(\"ignore\")\n\nimport os, cv2, json\nfrom PIL import Image\n\nimport random\nimport gc # for garbage cleaning","metadata":{"execution":{"iopub.status.busy":"2022-03-25T00:13:18.850315Z","iopub.execute_input":"2022-03-25T00:13:18.850909Z","iopub.status.idle":"2022-03-25T00:13:27.787228Z","shell.execute_reply.started":"2022-03-25T00:13:18.850812Z","shell.execute_reply":"2022-03-25T00:13:27.786683Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div style=\"color:white;display:fill;border-radius:5px;background-color:#75B7BF;letter-spacing:0.1px;overflow:hidden\"><p style=\"padding:20px;color:white;overflow:hidden;margin:0;font-size:100%;text-align:center\">2. Configuration</p></div>","metadata":{}},{"cell_type":"code","source":"class CFG:    \n    # config\n    WORK_DIR = '../input/ultra-mnist/'\n    IMG_FOLDER = '../input/ultramnist-resized-512/'\n    BATCH_SIZE = 16\n    EPOCHS = 30\n    IMG_SIZE = 512\n    TARGET_SIZE = 28\n    # ResNet\n    RESNET_POOLING_AVERAGE = 'avg'\n    DENSE_LAYER_ACTIVATION = 'softmax'\n    OBJECTIVE_FUNCTION = 'categorical_crossentropy'\n    # Path\n    TRAIN_DIRECTORY = os.path.join(IMG_FOLDER,'train_img')\n    ","metadata":{"execution":{"iopub.status.busy":"2022-03-24T09:50:53.591577Z","iopub.execute_input":"2022-03-24T09:50:53.592098Z","iopub.status.idle":"2022-03-24T09:50:53.597346Z","shell.execute_reply.started":"2022-03-24T09:50:53.592063Z","shell.execute_reply":"2022-03-24T09:50:53.596722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def seed_everything(seed: int = 42) -> None:\n    random.seed(seed)\n    np.random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    tf.random.set_seed(seed)\n       \nseed_everything(42)","metadata":{"execution":{"iopub.status.busy":"2022-03-24T09:28:34.581148Z","iopub.execute_input":"2022-03-24T09:28:34.58187Z","iopub.status.idle":"2022-03-24T09:28:34.588709Z","shell.execute_reply.started":"2022-03-24T09:28:34.581819Z","shell.execute_reply":"2022-03-24T09:28:34.58726Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div style=\"color:white;display:fill;border-radius:5px;background-color:#75B7BF;letter-spacing:0.1px;overflow:hidden\"><p style=\"padding:20px;color:white;overflow:hidden;margin:0;font-size:100%;text-align:center\">3.Helping Functions</p></div>","metadata":{}},{"cell_type":"code","source":"def threshold_image(img):\n    return cv2.threshold(img,200,255, cv2.THRESH_BINARY)[1]","metadata":{"execution":{"iopub.status.busy":"2022-03-24T09:28:34.687283Z","iopub.execute_input":"2022-03-24T09:28:34.687632Z","iopub.status.idle":"2022-03-24T09:28:34.69338Z","shell.execute_reply.started":"2022-03-24T09:28:34.687594Z","shell.execute_reply":"2022-03-24T09:28:34.692014Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def background_converter(img):\n    # at first convert our array to int32 from uint8 (numeric format OpenCV)\n    img = np.array(img, dtype='int32')\n    \n    # then we go through 16 squares 1000x1000\n    for i in range(4):\n        for j in range(4):\n            \n            # top and left are indicators that help us understand whether we need to change color of square or not\n            top, left = False, False\n            \n            # slice of square\n            img_slice = img[i * 1000:(i + 1) * 1000, j * 1000:(j + 1) * 1000]\n            \n            # slices of our square's edges\n            top_slice = img[i * 1000, j * 1000:(j + 1) * 1000]\n            left_slice = img[i * 1000:(i + 1) * 1000, j * 1000]\n            \n            # slices of neigbour squares' edges\n            if i > 0:\n                top_slice_oppos = img[i * 1000 - 1, j * 1000:(j + 1) * 1000]\n            if j > 0:\n                left_slice_oppos = img[i * 1000:(i + 1) * 1000, j * 1000 - 1]\n            \n            # check top edge\n            if (i == 0 and top_slice.mean() > 250\n                or i > 0 and (top_slice != top_slice_oppos).sum() > 900):\n                top = True\n                \n            # check left edge\n            if (j == 0 and left_slice.mean() > 250\n                or j > 0 and (left_slice != left_slice_oppos).sum() > 900):\n                left = True\n                \n            # make final decision    \n            if top or left:\n                img[i * 1000:(i + 1) * 1000, j * 1000:(j + 1) * 1000] = np.abs(img_slice - 255) \n                \n    # convert array to uint8 back and return from function\n    return img.astype('uint8')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div style=\"color:white;display:fill;border-radius:5px;background-color:#75B7BF;letter-spacing:0.1px;overflow:hidden\"><p style=\"padding:20px;color:white;overflow:hidden;margin:0;font-size:100%;text-align:center\">4. EDA</p></div>\n****\nhttps://www.kaggle.com/code/phanttan/basiceda-ultramnist","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv('../input/ultra-mnist/train.csv')\nrandom_sample = train_df.sample()\nname_image = random_sample.to_numpy()[0][0]\nprint(name_image)","metadata":{"execution":{"iopub.status.busy":"2022-03-24T09:28:34.74331Z","iopub.execute_input":"2022-03-24T09:28:34.744356Z","iopub.status.idle":"2022-03-24T09:28:34.811392Z","shell.execute_reply.started":"2022-03-24T09:28:34.744279Z","shell.execute_reply":"2022-03-24T09:28:34.810338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"random_image = cv2.imread(f'../input/ultra-mnist/train/{name_image}.jpeg', 0)\nplt.imshow(random_image, cmap='Greys_r')","metadata":{"execution":{"iopub.status.busy":"2022-03-24T09:28:34.813468Z","iopub.execute_input":"2022-03-24T09:28:34.814261Z","iopub.status.idle":"2022-03-24T09:28:36.760959Z","shell.execute_reply.started":"2022-03-24T09:28:34.814207Z","shell.execute_reply":"2022-03-24T09:28:36.759791Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div style=\"color:white;display:fill;border-radius:5px;background-color:#75B7BF;letter-spacing:0.1px;overflow:hidden\"><p style=\"padding:20px;color:white;overflow:hidden;margin:0;font-size:100%;text-align:center\">5. Preprocessing</p></div>","metadata":{}},{"cell_type":"markdown","source":"   # <div style=\"color:white;display:fill;border-radius:5px;background-color:#75B7BF;letter-spacing:0.1px;overflow:hidden\"><p style=\"padding:20px;color:white;overflow:hidden;margin:0;font-size:70%;text-align:left\">5.1 Background Preprocessing</p></div>","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots(1, 2, figsize=(18, 10))\nax[0].imshow(random_image, cmap='Greys_r')\nrandom_image_processed = background_converter(random_image)\nax[1].imshow(random_image_processed, cmap='Greys_r');","metadata":{"execution":{"iopub.status.busy":"2022-03-24T09:28:36.762742Z","iopub.execute_input":"2022-03-24T09:28:36.76298Z","iopub.status.idle":"2022-03-24T09:28:42.123845Z","shell.execute_reply.started":"2022-03-24T09:28:36.762952Z","shell.execute_reply":"2022-03-24T09:28:42.122844Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"   # <div style=\"color:white;display:fill;border-radius:5px;background-color:#75B7BF;letter-spacing:0.1px;overflow:hidden\"><p style=\"padding:20px;color:white;overflow:hidden;margin:0;font-size:70%;text-align:left\">5.2 Preparing Dataset</p></div>","metadata":{}},{"cell_type":"code","source":"STEPS_PER_EPOCH = len(train_df)*0.8 / CFG.BATCH_SIZE\nVALIDATION_STEPS = len(train_df)*0.2 / CFG.BATCH_SIZE","metadata":{"execution":{"iopub.status.busy":"2022-03-24T09:28:42.12526Z","iopub.execute_input":"2022-03-24T09:28:42.125772Z","iopub.status.idle":"2022-03-24T09:28:42.131295Z","shell.execute_reply.started":"2022-03-24T09:28:42.125725Z","shell.execute_reply":"2022-03-24T09:28:42.130385Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.digit_sum = train_df.digit_sum.astype('str')\ntrain_df.id = train_df.id+'.jpeg'\ntrain_datagen = ImageDataGenerator(validation_split=0.2, \n                                   rescale=1.0/255.0)\ntrain_generator = train_datagen.flow_from_dataframe(train_df, \n                                                    directory=CFG.TRAIN_DIRECTORY, \n                                                    subset='training', \n                                                    x_col='id', \n                                                    y_col='digit_sum', \n                                                    target_size=(CFG.IMG_SIZE, CFG.IMG_SIZE), \n                                                    batch_size = CFG.BATCH_SIZE, \n                                                    class_mode = \"sparse\")\nval_generator = train_datagen.flow_from_dataframe(train_df, \n                                                    directory=CFG.TRAIN_DIRECTORY, \n                                                    subset='validation', \n                                                    x_col='id', \n                                                    y_col='digit_sum', \n                                                    target_size=(CFG.IMG_SIZE, CFG.IMG_SIZE), \n                                                    batch_size = CFG.BATCH_SIZE, \n                                                    class_mode = \"sparse\")","metadata":{"execution":{"iopub.status.busy":"2022-03-24T10:10:25.583161Z","iopub.execute_input":"2022-03-24T10:10:25.58349Z","iopub.status.idle":"2022-03-24T10:11:51.705571Z","shell.execute_reply.started":"2022-03-24T10:10:25.583455Z","shell.execute_reply":"2022-03-24T10:11:51.704638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"del train_df\ngc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div style=\"color:white;display:fill;border-radius:5px;background-color:#75B7BF;letter-spacing:0.1px;overflow:hidden\"><p style=\"padding:20px;color:white;overflow:hidden;margin:0;font-size:100%;text-align:center\">6. Modelling</p></div>","metadata":{}},{"cell_type":"code","source":"def get_model():\n    conv_base = ResNet50(include_top=False,\n                     weights=\"imagenet\", pooling=CFG.RESNET_POOLING_AVERAGE)\n    model = conv_base.output\n    \n    model = layers.Dropout(.8)(model)\n    \n    model = layers.Dense(28, activation = \"softmax\")(model)\n    model = models.Model(conv_base.input, model)\n\n    model.compile(optimizer = Adam(lr = 0.001),\n                  loss = \"sparse_categorical_crossentropy\",\n                  metrics = [\"acc\"])\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2022-03-24T10:20:41.960229Z","iopub.execute_input":"2022-03-24T10:20:41.961632Z","iopub.status.idle":"2022-03-24T10:20:41.968982Z","shell.execute_reply.started":"2022-03-24T10:20:41.961554Z","shell.execute_reply":"2022-03-24T10:20:41.968023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = get_model()\n\nmodel_save = ModelCheckpoint('./model_weights.h5', \n                             save_best_only = True, \n                             save_weights_only = True,\n                             monitor = 'val_acc', \n                             mode = 'max', verbose = 1)\n\nearly_stop = EarlyStopping(monitor = 'val_acc', min_delta = 0.001, \n                           patience = 5, mode = 'max', verbose = 1,\n                           restore_best_weights = True)\n\nreduce_lr = ReduceLROnPlateau(monitor = 'val_acc', factor = 0.3, \n                              patience = 2, min_delta = 0.001, \n                              mode = 'max', verbose = 1)\n\nhistory = model.fit(train_generator,\n                    steps_per_epoch = STEPS_PER_EPOCH,\n                    epochs = CFG.EPOCHS,\n                    validation_data = val_generator,\n                    validation_steps = VALIDATION_STEPS,\n                    callbacks = [model_save, early_stop, reduce_lr]\n                    )","metadata":{"execution":{"iopub.status.busy":"2022-03-24T10:21:06.139064Z","iopub.execute_input":"2022-03-24T10:21:06.139971Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"acc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs = range(1, len(acc) + 1)\n\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))\nsns.set_style(\"white\")\nplt.suptitle('Train history', size = 15)\n\nax1.plot(epochs, acc, \"bo\", label = \"Training acc\")\nax1.plot(epochs, val_acc, \"b\", label = \"Validation acc\")\nax1.set_title(\"Training and validation acc\")\nax1.legend()\n\nax2.plot(epochs, loss, \"bo\", label = \"Training loss\", color = 'red')\nax2.plot(epochs, val_loss, \"b\", label = \"Validation loss\", color = 'red')\nax2.set_title(\"Training and validation loss\")\nax2.legend()\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-03-24T09:28:42.512475Z","iopub.status.idle":"2022-03-24T09:28:42.512974Z","shell.execute_reply.started":"2022-03-24T09:28:42.512719Z","shell.execute_reply":"2022-03-24T09:28:42.512746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div style=\"color:white;display:fill;border-radius:5px;background-color:#75B7BF;letter-spacing:0.1px;overflow:hidden\"><p style=\"padding:20px;color:white;overflow:hidden;margin:0;font-size:100%;text-align:center\">10. References</p></div>\n\n****\nhttps://www.kaggle.com/code/phanttan/cnn-keras-99-accuracy","metadata":{}}]}