{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os, sys, math\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport cv2\nfrom imgaug import augmenters as iaa\nfrom tqdm import tqdm\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fd738656b83fbd6d92f3c0e9fd83bafca8856d49"},"cell_type":"code","source":"INPUT_SHAPE = (299,299,3)\nBATCH_SIZE = 10","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"72c425f3aaa2645215a3adc808fc188c5b59106d"},"cell_type":"markdown","source":"### Load dataset info"},{"metadata":{"trusted":true,"_uuid":"42315d01b95b8a901088befa4100b014a1416c7a"},"cell_type":"code","source":"path_to_train = '/kaggle/input/train/'\ndata = pd.read_csv('/kaggle/input/train.csv')\n\ntrain_dataset_info = []\nfor name, labels in zip(data['Id'], data['Target'].str.split(' ')):\n    train_dataset_info.append({\n        'path':os.path.join(path_to_train, name),\n        'labels':np.array([int(label) for label in labels])})\ntrain_dataset_info = np.array(train_dataset_info)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"79baa15c0f198d5fa32242ad2fe33d26a29c2970"},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\ntrain_ids, test_ids, train_targets, test_target = train_test_split(\n    data['Id'], data['Target'], test_size=0.2, random_state=42)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ae3dcb3e4a000051fc8947502a28d399d200a924"},"cell_type":"markdown","source":"### Create datagenerator"},{"metadata":{"trusted":true,"_uuid":"c21509d05e2882e6315fc7390d27658c0654fc15"},"cell_type":"code","source":"class data_generator:\n    \n    def create_train(dataset_info, batch_size, shape, augument=True):\n        assert shape[2] == 3\n        while True:\n            random_indexes = np.random.choice(len(dataset_info), batch_size)\n            batch_images = np.empty((batch_size, shape[0], shape[1], shape[2]))\n            batch_labels = np.zeros((batch_size, 28))\n            for i, idx in enumerate(random_indexes):\n                image = data_generator.load_image(\n                    dataset_info[idx]['path'], shape)   \n                if augument:\n                    image = data_generator.augment(image)\n                batch_images[i] = image\n                batch_labels[i][dataset_info[idx]['labels']] = 1\n            yield batch_images, batch_labels\n            \n    \n    def load_image(path, shape):\n        R = np.array(Image.open(path+'_red.png'))\n        G = np.array(Image.open(path+'_green.png'))\n        B = np.array(Image.open(path+'_blue.png'))\n        Y = np.array(Image.open(path+'_yellow.png'))\n\n        image = np.stack((\n            R/2 + Y/2, \n            G/2 + Y/2, \n            B),-1)\n        \n        image = cv2.resize(image, (shape[0], shape[1]))\n        image = np.divide(image, 255)\n        return image  \n                \n            \n    def augment(image):\n        augment_img = iaa.Sequential([\n            iaa.OneOf([\n                iaa.Affine(rotate=0),\n                iaa.Affine(rotate=90),\n                iaa.Affine(rotate=180),\n                iaa.Affine(rotate=270),\n                iaa.Fliplr(0.5),\n                iaa.Flipud(0.5),\n            ])], random_order=True)\n        \n        image_aug = augment_img.augment_image(image)\n        return image_aug","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"74687ae11e12c8d0559e5421a356a67e8ab01537"},"cell_type":"markdown","source":"\n### Show data"},{"metadata":{"trusted":true,"_uuid":"3f2ae48955c4b75b13dd9e9ad0d9e1c84214b019"},"cell_type":"code","source":"# create train datagen\ntrain_datagen = data_generator.create_train(\n    train_dataset_info, 5, (299,299,3), augument=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5f261d54682cbd326a01e09a0f92598228145d2d"},"cell_type":"code","source":"images, labels = next(train_datagen)\n\nfig, ax = plt.subplots(1,5,figsize=(25,5))\nfor i in range(5):\n    ax[i].imshow(images[i])\nprint('min: {0}, max: {1}'.format(images.min(), images.max()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ddbc11bf72ecab4028380d64a08660a70a2da028"},"cell_type":"markdown","source":"### Create model"},{"metadata":{"trusted":true,"_uuid":"64bba0326be38da7add3594002563bea1c9703db"},"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator\nfrom keras.models import Sequential, load_model\nfrom keras.layers import Activation\nfrom keras.layers import Dropout\nfrom keras.layers import Flatten\nfrom keras.layers import Dense\nfrom keras.layers import Input\nfrom keras.layers import BatchNormalization\nfrom keras.layers import Conv2D\nfrom keras.models import Model\nfrom keras.applications import InceptionResNetV2\nfrom keras.callbacks import ModelCheckpoint\nfrom keras.callbacks import LambdaCallback\nfrom keras.callbacks import Callback\nfrom keras import metrics\nfrom keras.optimizers import Adam,SGD\nfrom keras import backend as K\nimport tensorflow as tf\nimport keras\n\ndef create_model(input_shape, n_out):\n    \n    pretrain_model = InceptionResNetV2(\n        include_top=False, \n        weights='imagenet', \n        input_shape=input_shape)    \n    \n    input_tensor = Input(shape=input_shape)\n    bn = BatchNormalization()(input_tensor)\n    x = pretrain_model(bn)\n    x = Conv2D(128, kernel_size=(1,1), activation='relu')(x)\n    x = Flatten()(x)\n    x = Dropout(0.5)(x)\n    x = Dense(512, activation='relu')(x)\n    x = Dropout(0.5)(x)\n    output = Dense(n_out, activation='sigmoid')(x)\n    model = Model(input_tensor, output)\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f1d143e285b01408b2263a946712131ea87c3b74"},"cell_type":"code","source":"def f1(y_true, y_pred):\n    tp = K.sum(K.cast(y_true*y_pred, 'float'), axis=0)\n    fp = K.sum(K.cast((1-y_true)*y_pred, 'float'), axis=0)\n    fn = K.sum(K.cast(y_true*(1-y_pred), 'float'), axis=0)\n\n    p = tp / (tp + fp + K.epsilon())\n    r = tp / (tp + fn + K.epsilon())\n\n    f1 = 2*p*r / (p+r+K.epsilon())\n    f1 = tf.where(tf.is_nan(f1), tf.zeros_like(f1), f1)\n    return K.mean(f1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f450d5ecc60bd6833f2673127103a7cc49f6ead9"},"cell_type":"code","source":"def show_history(history):\n    fig, ax = plt.subplots(1, 3, figsize=(15,5))\n    ax[0].set_title('loss')\n    ax[0].plot(history.epoch, history.history[\"loss\"], label=\"Train loss\")\n    ax[0].plot(history.epoch, history.history[\"val_loss\"], label=\"Validation loss\")\n    ax[1].set_title('f1')\n    ax[1].plot(history.epoch, history.history[\"f1\"], label=\"Train f1\")\n    ax[1].plot(history.epoch, history.history[\"val_f1\"], label=\"Validation f1\")\n    ax[2].set_title('acc')\n    ax[2].plot(history.epoch, history.history[\"acc\"], label=\"Train acc\")\n    ax[2].plot(history.epoch, history.history[\"val_acc\"], label=\"Validation acc\")\n    ax[0].legend()\n    ax[1].legend()\n    ax[2].legend()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"33936d2e6a7d0d69dda9b96a8dba829f52c2c800"},"cell_type":"code","source":"keras.backend.clear_session()\n\nmodel = create_model(\n    input_shape=(299,299,3), \n    n_out=28)\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2fbffd71262d7d7e591ad5955feb6b0c5ee61737"},"cell_type":"markdown","source":"### Train model"},{"metadata":{"trusted":true,"_uuid":"78beaf3beb4cd4f47b44d82b11e9dacd581075e5"},"cell_type":"code","source":"from keras.callbacks import EarlyStopping, LearningRateScheduler,ReduceLROnPlateau\n\nearly_stop = EarlyStopping(monitor='val_loss', min_delta=0.0001, patience=2, verbose=1)\nlr_reducer = ReduceLROnPlateau(factor=np.sqrt(0.1), cooldown=0, patience=2, min_lr=0.5e-6)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0343374956494b98425448b7aa9092a037aee401"},"cell_type":"code","source":"checkpointer = ModelCheckpoint(\n    '/kaggle/working/InceptionResNetV2.model',\n    verbose=2, save_best_only=True)\n\ntrain_generator = data_generator.create_train(\n    train_dataset_info[train_ids.index], BATCH_SIZE, INPUT_SHAPE, augument=False)\nvalidation_generator = data_generator.create_train(\n    train_dataset_info[test_ids.index], 256, INPUT_SHAPE, augument=False)\n\nmodel.layers[2].trainable = False\n\nmodel.compile(\n    loss='binary_crossentropy',  \n    optimizer=Adam(1e-3),\n    metrics=['acc', f1])\n\nhistory = model.fit_generator(\n    train_generator,\n    steps_per_epoch=100,\n    validation_data=next(validation_generator),\n    epochs=15, \n    verbose=1,\n    callbacks=[checkpointer,lr_reducer, early_stop])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"87c8e7f4219275aa7e2bcb99b195bcb4b5b276c2"},"cell_type":"code","source":"show_history(history)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3f86c2fe274ed65f5d6ddd38eb7fde67aef8f439"},"cell_type":"code","source":"from keras.optimizers import Adam,SGD\n\ntrain_generator = data_generator.create_train(\n    train_dataset_info[train_ids.index], BATCH_SIZE, INPUT_SHAPE, augument=True)\nvalidation_generator = data_generator.create_train(\n    train_dataset_info[test_ids.index], 256, INPUT_SHAPE, augument=False)\n\n#model.layers[2].trainable = True\nfor i in range(len(model.layers)):\n    model.layers[i].trainable = False # On vérouille toutes les couches\nfor i in range(len(model.layers)-10,len(model.layers)):\n    model.layers[i].trainable = True #et on dévérouille les 10 dernières\n \nmodel.compile(\n    loss='binary_crossentropy',  \n    optimizer = SGD(lr=0.0001, decay=1e-6, momentum=0.9, nesterov=True),\n    metrics=['acc', f1])\n# according to https://papers.nips.cc/paper/7003-the-marginal-value-of-adaptive-gradient-methods-in-machine-learning.pdf sgd generalize better than adam, but slower\nhistory = model.fit_generator(\n    train_generator,\n    steps_per_epoch=100,\n    validation_data=next(validation_generator),\n    epochs=180, \n    verbose=1,\n    callbacks=[checkpointer,lr_reducer, early_stop])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3237a2343d4eb4fc5eaee3bc79deb60fe4e03929"},"cell_type":"code","source":"show_history(history)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2a52b306cd27fc030cfd3f7583009945de7828ac"},"cell_type":"markdown","source":"### Create submit"},{"metadata":{"trusted":true,"_uuid":"e3fc9b48ce40e9a392dcae98ce13790d8674d70a"},"cell_type":"code","source":"model = load_model(\n    '/kaggle/working/InceptionResNetV2.model', \n    custom_objects={'f1': f1})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9d9ee4a8c2b1fc75b9f8d58855e33b115e92134d"},"cell_type":"code","source":"submit = pd.read_csv('../input/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"782cdb0d614add0f41c11ea180bd45e5600d60fb"},"cell_type":"code","source":"%%time\npredicted = []\nfor name in tqdm(submit['Id']):\n    path = os.path.join('../input/test/', name)\n    image = data_generator.load_image(path, INPUT_SHAPE)\n    score_predict = model.predict(image[np.newaxis])[0]\n    label_predict = np.arange(28)[score_predict>=0.2]\n    str_predict_label = ' '.join(str(l) for l in label_predict)\n    predicted.append(str_predict_label)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"07043ed35ad009ce6edc017e4aa88ac82571a750"},"cell_type":"code","source":"submit['Predicted'] = predicted\nsubmit.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}