{"cells":[{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import os\nimport cv2\n\nimport numpy as np\nimport pandas as pd\n\nfrom matplotlib import pyplot as plt\n\nfrom sklearn import metrics\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import MultiLabelBinarizer\n\nfrom keras.layers import Dense, Activation, Flatten, Dropout, BatchNormalization\nfrom keras_preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import LearningRateScheduler\nfrom keras.layers import Conv2D, MaxPooling2D\nfrom keras import regularizers, optimizers\nfrom keras.models import Sequential","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Constants"},{"metadata":{"trusted":true},"cell_type":"code","source":"INPUT = \"/kaggle/input/imet-2020-fgvc7/\"\nTRAIN_DIR = \"/kaggle/input/imet-2020-fgvc7/train/\"\nTEST_DIR = \"/kaggle/input/imet-2020-fgvc7/test/\"\n\nEPOCHS = 6\nBATCH_SIZE = 512\nIM_SIZE = 128","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Working with our datasets"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv(INPUT + \"train.csv\")\ntest_df = pd.read_csv(INPUT + \"sample_submission.csv\")\nlabels_df = pd.read_csv(INPUT + \"labels.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# adding \"png\" to the image id\ntest_df[\"id\"] = test_df[\"id\"] + \".png\" \ntrain_df['id'] = train_df[\"id\"] + \".png\"\ntrain_df.head(2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# labels = labels_df.attribute_id.to_list()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### The DataFrame has the following format:\n![](https://miro.medium.com/max/276/1*Aofuhp0h0qLZ2hEvYSbNPg.png)\n\nIf the dataset is formatted this way, In order to tell the flow_from_dataframe function that “desert,mountains” is not a single class name but 2 class names separated by a comma, you need to convert each entry in the “labels” column to a list(not necessary to convert single labels to a list of length 1 along with entries that contains more than 1 label,but it’s good to maintain everything as a list anyway)."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df[\"attribute_ids\"] = train_df[\"attribute_ids\"].apply(lambda x:x.split())\nprint(train_df.shape)\ntrain_df.head(3)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### The data is not distributed normally, so in this paper I do not clear the data. I want to look at the previous results."},{"metadata":{},"cell_type":"markdown","source":"## Prepare image to train"},{"metadata":{"trusted":true},"cell_type":"code","source":"datagen = ImageDataGenerator(width_shift_range=0.1,\n                             height_shift_range=0.1,\n                             zoom_range=0.2,\n                             rescale=1/255. )\n\ntest_datagen = ImageDataGenerator(rescale=1./255.)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_generator = datagen.flow_from_dataframe(\n                                            dataframe=train_df,\n                                            directory=TRAIN_DIR,\n                                            x_col=\"id\",\n                                            y_col=\"attribute_ids\",\n                                            batch_size=BATCH_SIZE,\n                                            seed=42,\n                                            shuffle=True,\n                                            class_mode=\"categorical\",\n#                                             classes=labels,\n                                            target_size=(IM_SIZE,IM_SIZE))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# valid_generator = test_datagen.flow_from_dataframe(\n#                                                  dataframe=val_x,\n#                                                  directory=TRAIN_DIR,\n#                                                  x_col=\"id\",\n#                                                  y_col=\"attribute_ids\",\n#                                                  batch_size=BATCH_SIZE,\n#                                                  seed=42,\n#                                                  shuffle=True,\n#                                                  class_mode=\"categorical\",\n# #                                                  classes=labels,\n#                                                  target_size=(IM_SIZE,IM_SIZE))\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_generator = test_datagen.flow_from_dataframe(\n                                                dataframe=test_df,\n                                                directory=TEST_DIR,\n                                                x_col=\"id\",\n                                                batch_size=1,\n                                                seed=42,\n                                                shuffle=False,\n                                                class_mode=None,\n                                                target_size=(IM_SIZE,IM_SIZE))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Build model"},{"metadata":{"trusted":true},"cell_type":"code","source":"model = Sequential()\ninputShape = (IM_SIZE, IM_SIZE, 3)\nchanDim = -1\n\n# first CONV => RELU => CONV => RELU => POOL layer set\nmodel.add(Conv2D(32, (3, 3), padding=\"same\",\n    input_shape=inputShape))\nmodel.add(Activation(\"relu\"))\nmodel.add(BatchNormalization(axis=chanDim))\nmodel.add(Conv2D(32, (3, 3), padding=\"same\"))\nmodel.add(Activation(\"relu\"))\nmodel.add(BatchNormalization(axis=chanDim))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.25))\n\n# second CONV => RELU => CONV => RELU => POOL layer set\nmodel.add(Conv2D(64, (3, 3), padding=\"same\"))\nmodel.add(Activation(\"relu\"))\nmodel.add(BatchNormalization(axis=chanDim))\nmodel.add(Conv2D(64, (3, 3), padding=\"same\"))\nmodel.add(Activation(\"relu\"))\nmodel.add(BatchNormalization(axis=chanDim))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.25))\n\n# third CONV => RELU => CONV => RELU => POOL layer set\nmodel.add(Conv2D(128, (3, 3), padding=\"same\"))\nmodel.add(Activation(\"relu\"))\nmodel.add(BatchNormalization(axis=chanDim))\nmodel.add(Conv2D(128, (3, 3), padding=\"same\"))\nmodel.add(Activation(\"relu\"))\nmodel.add(BatchNormalization(axis=chanDim))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.25))\n\n# first (and only) set of FC => RELU layers\nmodel.add(Flatten())\nmodel.add(Dense(512))\nmodel.add(Activation(\"relu\"))\nmodel.add(BatchNormalization())\nmodel.add(Dropout(0.5))\n\n# softmax classifier\nmodel.add(Dense(3471, activation='sigmoid')) \n\nmodel.compile(optimizers.Adam(),loss=\"binary_crossentropy\",metrics=[\"accuracy\"])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Why “binary_crossentropy” as loss function and “sigmoid” as the final layer activation?\n\nRefer to this [thread](https://github.com/keras-team/keras/issues/741) it includes many articles and discussions related to this"},{"metadata":{},"cell_type":"markdown","source":"### This function changes Learning Rate "},{"metadata":{"trusted":true},"cell_type":"code","source":"def build_lrfn(lr_start=0.00001, lr_max=0.000075, \n               lr_min=0.000001, lr_rampup_epochs=20, \n               lr_sustain_epochs=0, lr_exp_decay=.8):\n    \n    def lrfn(epoch):\n        if epoch < lr_rampup_epochs:\n            lr = (lr_max - lr_start) / lr_rampup_epochs * epoch + lr_start\n        elif epoch < lr_rampup_epochs + lr_sustain_epochs:\n            lr = lr_max\n        else:\n            lr = (lr_max - lr_min) * lr_exp_decay**(epoch - lr_rampup_epochs - lr_sustain_epochs) + lr_min\n        return lr\n    \n    return lrfn\n\nlrfn = build_lrfn()\nlr_schedule = LearningRateScheduler(lrfn, verbose=1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Fitting the Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"STEP_SIZE_TRAIN=train_generator.n//train_generator.batch_size\n# STEP_SIZE_VALID=valid_generator.n//valid_generator.batch_size\nSTEP_SIZE_TEST=test_generator.n//test_generator.batch_size\n\nmodel.fit_generator(generator=train_generator,\n                    steps_per_epoch=STEP_SIZE_TRAIN,\n#                     validation_data=valid_generator,\n#                     validation_steps=STEP_SIZE_VALID,\n                    callbacks=[lr_schedule],\n                    epochs=EPOCHS\n                   )","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Predict the output"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_generator.reset()\npred=model.predict_generator(test_generator,\nsteps=STEP_SIZE_TEST,\nverbose=1)\npred_bool = (pred >0.2)\npredictions=[]\nlabels = train_generator.class_indices\nlabels = dict((v,k) for k,v in labels.items())\nfor row in pred_bool:\n    l=[]\n    \n    for index,cls in enumerate(row):\n        if cls:\n            l.append(labels[index])\n    predictions.append(\" \".join(l))\n    \nfilenames=test_generator.filenames\n\nresults = pd.DataFrame({\"id\":filenames,\"attribute_ids\":predictions})\nresults[\"id\"] = results[\"id\"].apply(lambda x:x.split(\".\")[0])\nresults.to_csv(\"submission.csv\",index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### If you have some ideas please tell me."}],"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}