{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Library\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#glob\nfrom glob import glob\n\n#logging\nfrom logging import DEBUG\nfrom logging import Formatter\nfrom logging import getLogger\nfrom logging import StreamHandler\n\n#matplotlib\nfrom matplotlib import pyplot\n\n#numpy\nfrom numpy import arange\nfrom numpy import argmax\nfrom numpy import asarray\n\n#os\nfrom os import path\n\n#pandas\nfrom pandas import DataFrame\nfrom pandas import read_csv\n\n#tensorflow\nfrom tensorflow import random\n\n#tensorflow.keras\nfrom tensorflow.keras import callbacks\nfrom tensorflow.keras import initializers\nfrom tensorflow.keras import layers\nfrom tensorflow.keras import models\nfrom tensorflow.keras import optimizers\nfrom tensorflow.keras import utils\n\n#tensorflow.keras.preprocessing.image\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.preprocessing.image import img_to_array\nfrom tensorflow.keras.preprocessing.image import load_img\nfrom tensorflow.keras.preprocessing.image import smart_resize\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Constant\n"},{"metadata":{},"cell_type":"markdown","source":"## IO path\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Folder path\nFOLDER_PATH_ROOT = '../input/cassava-leaf-disease-classification/'\nFOLDER_PATH_TRAIN = FOLDER_PATH_ROOT + 'train_images/'\nFOLDER_PATH_TEST = FOLDER_PATH_ROOT + 'test_images/'\n\n#File name\nFILE_NAME_TRAIN = 'train.csv'\nFILE_NAME_SUBMISSION = 'submission.csv'\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Param\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Image size\nIMAGE_SIZE = 256\n\n#Batch size\nBATCH_SIZE = 100\n\n#Epochs\nEPOCHS = 12\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Log\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get logger\ndef get_logger():\n    #Get handler\n    fmt = '%(asctime)s'\n    fmt += ' - %(levelname)s'\n    fmt += ' - %(name)s'\n    fmt += ' - %(lineno)d'\n    fmt += ' - %(funcName)s'\n    fmt += ' - %(message)s'\n    handler = StreamHandler()\n    handler.setLevel(DEBUG)\n    handler.setFormatter(Formatter(fmt))\n    \n    #Get logger\n    logger = getLogger(__name__)\n    logger.setLevel(DEBUG)\n    logger.addHandler(handler)\n    logger.propagate = False\n    \n    #Return logger\n    return logger\n\n#Kill logger\ndef kill_logger(logger):\n    for h in logger.handlers:\n        logger.removeHandler(h)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Initialize\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Initialize\ndef initialize():\n    #Fix random seed\n    random.set_seed(0)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Terminate\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Terminate\ndef terminate():\n    pass\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get model\ndef get_model():\n    #Get layers\n    layer_in, layer_out = get_layers()\n    \n    #Compile model\n    model = models.Model(\n        name='Model',\n        inputs=layer_in,\n        outputs=layer_out\n    )\n    model.compile(\n        loss='categorical_crossentropy',\n        optimizer=optimizers.Nadam(learning_rate=0.01),\n        metrics=['accuracy']\n    )\n    \n    #Show model summary\n    model.summary()\n    \n    #Return model\n    return model\n\n#Get layers\ndef get_layers():\n    #Get input layer\n    layer_in = get_input_layer('I01', IMAGE_SIZE, IMAGE_SIZE, 3)\n    layer_out = layer_in\n    \n    #Get hidden layer group1\n    layer_temp = layer_out\n    layer_out = get_conv_layer(layer_out, 'H11', 3, 3, 16)\n    layer_out = get_conv_layer(layer_out, 'H12', 3, 3, 16)\n    layer_out = get_concatenate_layer([layer_out, layer_temp], 'H13')\n    layer_out = get_pooling_layer(layer_out, 'H14', 4, 4)\n    layer_out = get_dropout_layer(layer_out, 'H15', 0.1)\n    layer_out = get_batchnormalization_layer(layer_out, 'H16')\n    \n    #Get hidden layer group2\n    layer_temp = layer_out\n    layer_out = get_conv_layer(layer_out, 'H21', 3, 3, 32)\n    layer_out = get_conv_layer(layer_out, 'H22', 3, 3, 32)\n    layer_out = get_concatenate_layer([layer_out, layer_temp], 'H23')\n    layer_out = get_pooling_layer(layer_out, 'H24', 4, 4)\n    layer_out = get_dropout_layer(layer_out, 'H25', 0.1)\n    layer_out = get_batchnormalization_layer(layer_out, 'H26')\n    \n    #Get hidden layer group3\n    layer_temp = layer_out\n    layer_out = get_conv_layer(layer_out, 'H31', 3, 3, 64)\n    layer_out = get_conv_layer(layer_out, 'H32', 3, 3, 64)\n    layer_out = get_concatenate_layer([layer_out, layer_temp], 'H33')\n    layer_out = get_pooling_layer(layer_out, 'H34', 4, 4)\n    layer_out = get_dropout_layer(layer_out, 'H35', 0.1)\n    layer_out = get_batchnormalization_layer(layer_out, 'H36')\n    \n    #Get hidden layer group4\n    layer_out = get_global_pooling_layer(layer_out, 'H41')\n    \n    #Get output layer\n    layer_out = get_output_layer(layer_out, 'O01', 5)\n    \n    #Return layers\n    return layer_in, layer_out\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Input layer\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get input layer\ndef get_input_layer(name, width, height, channel):\n    return layers.Input(\n        name=name,\n        shape=(height, width, channel)\n    )\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Convolutional layer\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get convolutional layer\ndef get_conv_layer(layer, name, width, height, filters):\n    #Get initializer\n    stddev = (1 / height / width / layer.shape[-1]) ** 0.5\n    initializer = initializers.TruncatedNormal(stddev=stddev)\n    \n    #Return convolutional layer\n    return layers.Conv2D(\n        name=name,\n        filters=filters,\n        kernel_size=(height, width),\n        padding='same',\n        kernel_initializer=initializer,\n        activation='relu'\n    )(layer)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Pooling layer\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get pooling layer\ndef get_pooling_layer(layer, name, width, height):\n    return layers.MaxPooling2D(\n        name=name,\n        pool_size=(height, width)\n    )(layer)\n\n#Get global pooling layer\ndef get_global_pooling_layer(layer, name):\n    return layers.GlobalAveragePooling2D(\n        name=name\n    )(layer)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Dropout layer\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get dropout layer\ndef get_dropout_layer(layer, name, rate):\n    return layers.Dropout(\n        name=name,\n        rate=rate\n    )(layer)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Batchnormalization layer\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get batchnormalization layer\ndef get_batchnormalization_layer(layer, name):\n    return layers.BatchNormalization(\n        name=name\n    )(layer)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Concatenate layer\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get concatenate layer\ndef get_concatenate_layer(layer, name):\n    return layers.Concatenate(\n        name=name\n    )(layer)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Flatten layer\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get flatten layer\ndef get_flatten_layer(layer, name):\n    return layers.Flatten(\n        name=name\n    )(layer)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Full connection layer\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get full connection layer\ndef get_full_connect_layer(layer, name, units):\n    #Get initializer\n    stddev = (1 / layer.shape[-1]) ** 0.5\n    initializer = initializers.TruncatedNormal(stddev=stddev)\n    \n    #Return full connection layer\n    return layers.Dense(\n        name=name,\n        units=units,\n        kernel_initializer=initializer,\n        activation='relu'\n    )(layer)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Output layer\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get output layer\ndef get_output_layer(layer, name, units):\n    #Get initializer\n    stddev = (1 / layer.shape[-1]) ** 0.5\n    initializer = initializers.TruncatedNormal(stddev=stddev)\n    \n    #Return output layer\n    return layers.Dense(\n        name=name,\n        units=units,\n        kernel_initializer=initializer,\n        activation='softmax'\n    )(layer)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Extract\n"},{"metadata":{},"cell_type":"markdown","source":"## CSV file\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Read csv file(y)\ndef read_csv_y():\n    return read_csv(\n        FOLDER_PATH_ROOT + FILE_NAME_TRAIN,\n        usecols=[\n            'image_id',\n            'label',\n        ],\n        dtype={\n            'image_id': object,\n            'label': object,\n        }\n    )\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Image file\n"},{"metadata":{},"cell_type":"markdown","source":"### Image data generator\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get image data generator(train)\ndef get_img_gen_train():\n    return ImageDataGenerator(\n        rescale=1 / 255,\n        validation_split=0.1,\n        rotation_range=360,\n        width_shift_range=0.1,\n        height_shift_range=0.1,\n        brightness_range=[0.1, 0.9],\n        shear_range=25,\n        zoom_range=0.1,\n        channel_shift_range=0.1,\n        horizontal_flip=True,\n        vertical_flip=True\n    )\n\n#Get image data generator(validate)\ndef get_img_gen_vali():\n    return ImageDataGenerator(\n        rescale=1 / 255,\n        validation_split=0.1\n    )\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Image data flow\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get image data flow(train)\ndef get_img_flow_train():\n    #Get image data generator\n    gen = get_img_gen_train()\n    \n    #Return image data flow\n    return gen.flow_from_dataframe(\n        directory=FOLDER_PATH_TRAIN,\n        target_size=(IMAGE_SIZE, IMAGE_SIZE),\n        dataframe=read_csv_y(),\n        x_col='image_id',\n        y_col='label',\n        class_mode='categorical',\n        batch_size=BATCH_SIZE,\n        shuffle=True,\n        subset='training'\n    )\n\n#Get image data flow(validate)\ndef get_img_flow_vali():\n    #Get image data generator\n    gen = get_img_gen_vali()\n    \n    #Return image data flow\n    return gen.flow_from_dataframe(\n        directory=FOLDER_PATH_TRAIN,\n        target_size=(IMAGE_SIZE, IMAGE_SIZE),\n        dataframe=read_csv_y(),\n        x_col='image_id',\n        y_col='label',\n        class_mode='categorical',\n        batch_size=BATCH_SIZE,\n        shuffle=False,\n        subset='validation'\n    )\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Train\ndef train(model):\n    #Get image data flow\n    flow_train = get_img_flow_train()\n    flow_vali = get_img_flow_vali()\n    \n    #Get early stop\n    early_stop = callbacks.EarlyStopping(\n        monitor='val_loss',\n        min_delta=0.001,\n        patience=3,\n        mode='min',\n        verbose=1,\n        restore_best_weights=True\n    )\n    \n    #Train\n    hist = model.fit(\n        flow_train,\n        steps_per_epoch=flow_train.samples // flow_train.batch_size,\n        validation_data=flow_vali,\n        validation_steps=flow_vali.samples // flow_vali.batch_size,\n        batch_size=BATCH_SIZE,\n        epochs=EPOCHS,\n        callbacks=[early_stop]\n    )\n    \n    #Show plots\n    show_plots(hist)\n\n#Show plots\ndef show_plots(hist):\n    #Create plots\n    fig, ax = pyplot.subplots(nrows=2, ncols=2, figsize=(16, 8))\n    fig.subplots_adjust(hspace=0.25)\n    set_plot(ax[0][0], hist, 'loss')\n    set_plot(ax[0][1], hist, 'accuracy')\n    set_plot(ax[1][0], hist, 'val_loss')\n    set_plot(ax[1][1], hist, 'val_accuracy')\n    \n    #Show plots\n    pyplot.show()\n\n#Set plot\ndef set_plot(ax, hist, name):\n    #Set data\n    ax.plot(arange(len(hist.epoch)) + 1, hist.history[name])\n    \n    #Set title, label\n    ax.set_title(name)\n    ax.set_xlabel('epoch')\n    ax.set_ylabel(name)\n    \n    #Set ticks, limit\n    ax.set_xticks(arange(len(hist.epoch)) + 1)\n    if name in ['loss', 'val_loss']:\n        ax.set_ylim(0)\n    else:\n        ax.set_yticks(arange(0.4, 1.01, 0.06))\n    \n    #Set grid\n    ax.grid(True)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Predict\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Predict\ndef predicts(model):\n    #Get file paths\n    file_paths = glob(FOLDER_PATH_TEST + '*.jpg')\n    \n    #Return result\n    return [predict(model, f) for f in file_paths]\n\n#Predict\ndef predict(model, file_path):\n    #Read image file\n    x_read = smart_resize(\n        img_to_array(load_img(file_path)),\n        (IMAGE_SIZE, IMAGE_SIZE)\n    )\n    \n    #Transform image\n    x = x_read.reshape(-1, IMAGE_SIZE, IMAGE_SIZE, 3) / 255.0\n    \n    #Return result\n    return argmax(model.predict(x))\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Output\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Write csv file\ndef write_csv(result):\n    #Get file paths\n    file_paths = glob(FOLDER_PATH_TEST + '*.jpg')\n    \n    #Create dataframe\n    df = DataFrame()\n    df['image_id'] = [path.basename(f) for f in file_paths]\n    df['label'] = result\n    \n    #Write csv file\n    df.to_csv(FILE_NAME_SUBMISSION, index=False)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Main\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get logger\nlogger = get_logger()\nlogger.debug('Start')\n\n#Initialize\ninitialize()\n\n#Get model\nmodel = get_model()\n\n#Train\ntrain(model)\n\n#Predict\nresult = predicts(model)\n\n#Write csv file\nwrite_csv(result)\n\n#Terminate\nterminate()\n\n#Kill logger\nlogger.debug('End')\nkill_logger(logger)\n","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}