{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Contents\n1. Import Libraries\n2. Load data\n3. Data Pre-processing\n4. Structure Model\n5. Setup Fitting conditions\n6. Evaluate Model (See from Here, if you don't have time to train model)"},{"metadata":{},"cell_type":"markdown","source":"> # 1. Import Libraries\n    * systemical       : os,glob,shutil,json\n    * data handling    : itertools,collections,numpy,pandas,seaborn,PIL,matplot,sklearn\n    * Machine Learning : tensorflow, keras"},{"metadata":{"trusted":true},"cell_type":"code","source":"# import system libraries\nimport os, glob,shutil,json\n\n# import data handling libraries\nimport itertools\nfrom collections import Counter\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import train_test_split\n%matplotlib inline\n\n# import Machine Learning libraries\nimport keras\nfrom keras.preprocessing.image import ImageDataGenerator\nimport tensorflow as tf","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> ## 2. Data load\n    * [images] are in 'train_images' folder without dividing train/test set\n    * [labels] are in 'train.csv'\n    ** key value is name of image"},{"metadata":{"trusted":true},"cell_type":"code","source":"# directories of files\nbase_dir = '../input/cassava-leaf-disease-classification'\nimgs_dir = 'train_images'\nlabels_file = 'train.csv'\ntest_img_dir = 'test_images'\njson_file = 'label_num_to_disease_map.json'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# function for check null value in dataframe\ndef check_null_values(df):\n    # check null values by col\n    A = df.isnull().any(axis=0)\n    A = pd.DataFrame(A,columns=['exist_null'])\n    # check number of null values by col\n    B = df.isnull().sum(axis=0)\n    B = pd.DataFrame(B,columns=['num_of_null'])\n    # merge data\n    merge = pd.concat([A,B],axis=1)\n    print(merge)\n    return","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# load json file & check classification target\n\nprint('[Classification Target]')\nwith open(os.path.join(base_dir,json_file)) as j:\n    classes = json.load(j)\n    classes_set = {int(k):v for k,v in classes.items()}\n    for k,v in classes.items():\n        print(k, \":\", v)\n    j.close()\n\n# check useless value\n\nprint('\\n[check null values]')\ndata = pd.read_csv(os.path.join(base_dir,labels_file))\ndata_cnt = Counter(data['label'])\nprint('Number of labels : ', data.shape[0])\ncheck_null_values(data)\n\n# check the data balance with graph\n\nfor key,value in data_cnt.items():\n    plt.barh(classes[str(key)], value)\n    plt.title('Distribution of Labels')\n    plt.xlabel('Number of Labels')\n\n# add more column with class names\n\ndata['class_name'] = data.label.map(classes_set)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> # 3. Data Pre-processing\n* Split data on purpose by train/val\n* Set parameters : image size, number of classes, batch size\n* data generating rule"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Split train images with purpose\n\ntrain,val = train_test_split(data,test_size=0.1, random_state=42, stratify = data['class_name'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Set parameters\n\nIMG_SIZE = 240\nsize = (IMG_SIZE,IMG_SIZE)\nN_CLASS = len(classes)\nBATCH_SIZE = 15","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Setup Data augmetations and Generate Dataset\n\n# Setup data augmentations\n\ndatagen_train = ImageDataGenerator(\n                    preprocessing_function=tf.keras.applications.efficientnet.preprocess_input,\n                    rotation_range=40,\n                    width_shift_range=0.2,\n                    height_shift_range=0.2,\n                    shear_range=0.2,\n                    zoom_range=0.2,\n                    horizontal_flip=True,\n                    vertical_flip=True,\n                    fill_mode='nearest')\n\ndatagen_val = ImageDataGenerator(\n                preprocessing_function=tf.keras.applications.efficientnet.preprocess_input,)\n\n# Generate data with above conditions\n\nimg_path = os.path.join(base_dir,imgs_dir)\n\ntrain_set = datagen_train.flow_from_dataframe(train,\n                    directory = img_path,\n                    seed=42,\n                    x_col='image_id',\n                    y_col='class_name',\n                    target_size=size,\n                    class_mode='categorical',\n                    interpolation='nearest',\n                    shuffle=True,\n                    batch_size=BATCH_SIZE)\n                    \nval_set = datagen_val.flow_from_dataframe(val,\n                    directory = img_path,\n                    seed = 42,\n                    x_col='image_id',\n                    y_col='class_name',\n                    target_size=size,\n                    class_mode='categorical',\n                    interpolation='nearest',\n                    shuffle=True,\n                    batch_size=BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> # 4. Structure Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Stacking Model Layer Architecture\n\nfrom keras.models import Sequential\nfrom keras.layers import GlobalAveragePooling2D, Flatten, Dense, Dropout, BatchNormalization\nfrom keras.optimizers import RMSprop, Adam\nfrom keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau\nfrom tensorflow.keras.applications import EfficientNetB3\n\ndef create_model():\n    \n    model = Sequential()\n    # initialize the model with input shape\n    model.add(EfficientNetB3(input_shape = (IMG_SIZE, IMG_SIZE, 3), include_top = False,\n                             weights = 'imagenet',\n                             drop_connect_rate=0.6))\n    model.add(GlobalAveragePooling2D())\n    model.add(Flatten())\n    model.add(Dense(256, activation = 'relu', bias_regularizer=tf.keras.regularizers.L1L2(l1=0.01, l2=0.001)))\n    model.add(Dropout(0.5))\n    model.add(Dense(N_CLASS, activation = 'softmax'))\n    \n    return model\n\nleaf_model = create_model()\nleaf_model.summary()\n\n# Model layer diagram \n# keras.utils.plot_model(leaf_model)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> # 5. Setup Fitting conditions & Train Model\n* loss fuction : categorical_crossentropy\n* learning rate : 1e-3\n* compile with /"},{"metadata":{"trusted":true},"cell_type":"code","source":"EPOCHS = 5\nSTEP_SIZE_TRAIN = train_set.n//train_set.batch_size\nSTEP_SIZE_VALID = val_set.n//val_set.batch_size\n\n# Setup fitting parameters\n\ndef Model_fit():\n    leaf_model = create_model()\n    \n    # Select loss function\n    \n    loss = tf.keras.losses.CategoricalCrossentropy(from_logits = False,\n                                                   label_smoothing=0.0001,\n                                                   name='categorical_crossentropy' )\n    \n    # Compile the model\n    \n    leaf_model.compile(optimizer = Adam(learning_rate = 1e-3),\n                        loss = loss, #'categorical_crossentropy'\n                        metrics = ['categorical_accuracy']) # 'accuracy'\n    \n    # Early Stopping train when loss value has stopped decreasing for 3 epochs\n    \n    es = EarlyStopping(monitor='val_loss', mode='min', patience=3,\n                       restore_best_weights=True, verbose=1)\n    \n    # Save the model with the minimum validation loss\n\n    checkpoint_cb = ModelCheckpoint(\"Cassava_best_model.h5\",\n                                    save_best_only=True,\n                                    monitor = 'val_loss',\n                                    mode='min')\n    \n    # reduce learning rate\n\n    reduce_lr = ReduceLROnPlateau(monitor = 'val_loss',\n                                  factor = 0.2,\n                                  patience = 2,\n                                  min_lr = 1e-6,\n                                  mode = 'min',\n                                  verbose = 1)\n\n    # log model fit histories \n\n    history = leaf_model.fit(train_set,\n                             validation_data = val_set,\n                             epochs= EPOCHS,\n                             batch_size = BATCH_SIZE,\n                             #class_weight = d_class_weights,\n                             steps_per_epoch = STEP_SIZE_TRAIN,\n                             validation_steps = STEP_SIZE_VALID,\n                             callbacks=[es, checkpoint_cb, reduce_lr])\n    \n    # Save trained model\n    \n    leaf_model.save('Cassava_model'+'.h5')  \n    \n    return history","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# results = Model_fit()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('Train_Cat-Acc: ', max(results.history['categorical_accuracy']))\nprint('Val_Cat-Acc: ', max(results.history['val_categorical_accuracy']))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Plotting Results (Train vs Validation FOLDER 1)\n\ndef Train_Val_Plot(acc,val_acc,loss,val_loss):\n    \n    fig, (ax1, ax2) = plt.subplots(1,2, figsize= (15,10))\n    fig.suptitle(\" Model Metrics Visualization \", fontsize=20)\n    \n    # Accuracy value Graph\n    ax1.plot(range(1, len(acc) + 1), acc)\n    ax1.plot(range(1, len(val_acc) + 1), val_acc)\n    ax1.set_title('History of Accuracy', fontsize=15)\n    ax1.set_xlabel('Epochs', fontsize=15)\n    ax1.set_ylabel('Accuracy', fontsize=15)\n    ax1.legend(['training', 'validation'])\n\n    # Loss value Graph\n    ax2.plot(range(1, len(loss) + 1), loss)\n    ax2.plot(range(1, len(val_loss) + 1), val_loss)\n    ax2.set_title('History of Loss', fontsize=15)\n    ax2.set_xlabel('Epochs', fontsize=15)\n    ax2.set_ylabel('Loss', fontsize=15)\n    ax2.legend(['training', 'validation'])\n    plt.show()\n    \n\nTrain_Val_Plot(results.history['categorical_accuracy'],results.history['val_categorical_accuracy'],\n               results.history['loss'],results.history['val_loss'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> # 6. Evaluate Model (See from Here, if you don't have time to train model)\n* load model file\n* do inference(prediction)\n* save submission.csv file"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Evaluate the model\nimport keras \n\nfinal_model = keras.models.load_model('Cassava_best_model.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# load test_image & pred the classification\n\nTEST_DIR = '../input/cassava-leaf-disease-classification/test_images/'\ntest_images = os.listdir(TEST_DIR)\ndatagen = ImageDataGenerator(horizontal_flip=True)\n\n\ndef pred(images):\n    for image in test_images:\n        img = Image.open(TEST_DIR + image)\n        img = img.resize(size)\n        samples = np.expand_dims(img, axis=0)\n        it = datagen.flow(samples, batch_size=10)\n        yhats = final_model.predict_generator(it, steps=10, verbose=0)\n        summed = np.sum(yhats, axis=0)\n    return np.argmax(summed)\n\npredictions = pred(test_images)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Save submission.csv file\n\nsub = pd.DataFrame({'image_id': test_images, 'label': predictions})\ndisplay(sub)\nsub.to_csv('submission.csv', index = False)","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}