{"cells":[{"metadata":{},"cell_type":"markdown","source":"# I wrote this notebook based on a notebook in this competition (Sorry I can't find it, if you know that, please comment in the comment section)\n# I have modified the simple model with a resnet50 model"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import pandas as pd\nfrom PIL import Image\nimport json\nimport cv2\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nfrom sklearn.utils import shuffle\nfrom sklearn.utils import class_weight\n\nimport tensorflow as tf\nfrom tensorflow.keras.layers import Conv2D, BatchNormalization, Conv3D, ZeroPadding3D, Softmax, Lambda, Add, Layer, MaxPool2D\nfrom tensorflow.keras import initializers\nfrom tensorflow import einsum, nn, meshgrid\n\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras import layers\nfrom tensorflow.keras import Input\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Dense, Flatten, Dropout, Activation\nfrom tensorflow.keras.layers import BatchNormalization, GlobalAveragePooling2D\nfrom tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.layers import Dense, Dropout, Activation, Input, BatchNormalization, GlobalAveragePooling2D\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.applications import EfficientNetB3, EfficientNetB1\n\nfrom tensorflow.keras.layers import Input, Add, Dense, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D, AveragePooling2D, MaxPooling2D\nfrom keras.initializers import glorot_uniform","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Check data"},{"metadata":{"trusted":true},"cell_type":"code","source":"samples_df = pd.read_csv(\"../input/cassava-leaf-disease-classification/train.csv\")\nsamples_df = shuffle(samples_df, random_state=42)\nsamples_df[\"label\"] = samples_df[\"label\"].astype(\"str\")\nsamples_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"training_percentage = 0.9\ntraining_item_count = int(len(samples_df)*training_percentage)\nvalidation_item_count = len(samples_df)-int(len(samples_df)*training_percentage)\ntraining_df = samples_df[:training_item_count]\nvalidation_df = samples_df[training_item_count:]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"training_batch_size = 16\nvalidation_batch_size = 16\nimage_size = 300\ntarget_size = (image_size, image_size)\n\ntrain_datagen = ImageDataGenerator(\n    rescale=1. / 255,\n    horizontal_flip=True,\n    vertical_flip=True,\n    zoom_range=0.2, \n    width_shift_range=0.1,\n    height_shift_range=0.1\n)\n\ntrain_generator = train_datagen.flow_from_dataframe(\n    dataframe = training_df,\n    x_col='image_id',\n    y_col='label',\n    directory='../input/cassava-leaf-disease-classification/train_images/',\n    target_size=target_size,\n    batch_size=training_batch_size,\n    shuffle=True,\n    class_mode='categorical')\n\n\nvalidation_datagen = ImageDataGenerator(rescale=1. / 255)\nvalidation_generator = validation_datagen.flow_from_dataframe(\n    dataframe = validation_df,\n    x_col='image_id',\n    y_col='label',\n    directory='../input/cassava-leaf-disease-classification/train_images/',\n    target_size=target_size,\n    shuffle=False,\n    batch_size=validation_batch_size,\n    class_mode='categorical')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with open(\"../input/cassava-leaf-disease-classification/label_num_to_disease_map.json\") as f:\n    map_dis = json.loads(f.read())\n\nprint(json.dumps(map_dis, indent=4))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# RESNET 50"},{"metadata":{"trusted":true},"cell_type":"code","source":"def identity_block(X, f, filters, stage, block):\n    # defining name basis\n    conv_name_base = 'res' + str(stage) + block + '_branch'\n    bn_name_base = 'bn' + str(stage) + block + '_branch'\n\n    # Retrieve Filters\n    F1, F2, F3 = filters\n\n    # Save the input value. We'll need this later to add back to the main path. \n    X_shortcut = X\n\n    # First component of main path\n    X = Conv2D(filters = F1, kernel_size = (1, 1), strides = (1,1), padding = 'valid', name = conv_name_base + '2a', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = bn_name_base + '2a')(X)\n    X = Activation('relu')(X)\n\n    # Second component of main path\n    X = Conv2D(filters = F2, kernel_size = (f, f), strides = (1,1), padding = 'same', name = conv_name_base + '2b', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = bn_name_base + '2b')(X)\n    X = Activation('relu')(X)\n\n    # Third component of main path\n    X = Conv2D(filters = F3, kernel_size = (1, 1), strides = (1,1), padding = 'valid', name = conv_name_base + '2c', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = bn_name_base + '2c')(X)\n\n    # Final step: Add shortcut value to main path, and pass it through a RELU activation\n    X = Add()([X, X_shortcut])\n    X = Activation('relu')(X)\n\n    return X","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def convolutional_block(X, f, filters, stage, block, s = 2):\n    # defining name basis\n    conv_name_base = 'res' + str(stage) + block + '_branch'\n    bn_name_base = 'bn' + str(stage) + block + '_branch'\n    \n    # Retrieve Filters\n    F1, F2, F3 = filters\n    \n    # Save the input value\n    X_shortcut = X\n\n\n    ##### MAIN PATH #####\n    # First component of main path \n    X = Conv2D(F1, (1, 1), strides = (s,s), name = conv_name_base + '2a', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = bn_name_base + '2a')(X)\n    X = Activation('relu')(X)\n\n    # Second component of main path\n    X = Conv2D(filters=F2, kernel_size=(f, f), strides=(1, 1), padding='same', name=conv_name_base + '2b', kernel_initializer=glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis=3, name=bn_name_base + '2b')(X)\n    X = Activation('relu')(X)\n\n    # Third component of main path\n    X = Conv2D(filters=F3, kernel_size=(1, 1), strides=(1, 1), padding='valid', name=conv_name_base + '2c', kernel_initializer=glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis=3, name=bn_name_base + '2c')(X)\n\n    \n    ##### SHORTCUT PATH ####\n    X_shortcut = Conv2D(F3, (1, 1), strides = (s,s), name = conv_name_base + '1', kernel_initializer = glorot_uniform(seed=0))(X_shortcut)\n    X_shortcut = BatchNormalization(axis = 3, name = bn_name_base + '1')(X_shortcut)\n\n    # Final step: Add shortcut value to main path, and pass it through a RELU activation\n    X = Add()([X, X_shortcut])\n    X = Activation('relu')(X)\n    \n    return X","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def ResNet50(input_shape = (64, 64, 3), classes = 2):   \n    # Define the input as a tensor with shape input_shape\n    X_input = Input(input_shape)\n\n    # Zero-Padding\n    X = ZeroPadding2D((3, 3))(X_input)\n    \n    # Stage 1\n    X = Conv2D(64, (7, 7), strides = (2, 2), name = 'conv1', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = 'bn_conv1')(X)\n    X = Activation('relu')(X)\n    X = MaxPooling2D((3, 3), strides=(2, 2))(X)\n\n    # Stage 2\n    X = convolutional_block(X, f = 3, filters = [64, 64, 256], stage = 2, block='a', s = 1)\n    X = identity_block(X, 3, [64, 64, 256], stage=2, block='b')\n    X = identity_block(X, 3, [64, 64, 256], stage=2, block='c')\n\n    # Stage 3\n    X = convolutional_block(X, f = 3, filters = [128, 128, 512], stage = 3, block='a', s = 2)\n    X = identity_block(X, 3, [128, 128, 512], stage=3, block='b')\n    X = identity_block(X, 3, [128, 128, 512], stage=3, block='c')\n    X = identity_block(X, 3, [128, 128, 512], stage=3, block='d')\n\n    # Stage 4\n    X = convolutional_block(X, f = 3, filters = [256, 256, 1024], stage = 4, block='a', s = 2)\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='b')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='c')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='d')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='e')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='f')\n\n    # Stage 5\n    X = convolutional_block(X, f = 3, filters = [512, 512, 2048], stage = 5, block='a', s = 2)\n    X = identity_block(X, 3, [512, 512, 2048], stage=5, block='b')\n    X = identity_block(X, 3, [512, 512, 2048], stage=5, block='c')\n\n    # AVGPOOL.\n    X = AveragePooling2D((2, 2), name='avg_pool')(X)\n\n    # output layer\n    X = Flatten()(X)\n    X = Dense(classes, activation='softmax', name='fc' + str(classes), kernel_initializer = glorot_uniform(seed=0))(X)\n    \n    # Create model\n    model = Model(inputs = X_input, outputs = X, name='ResNet50')\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"classes_to_predict = sorted(training_df.label.unique())\n\ninput_shape = (image_size, image_size, 3)\n\nmodel = ResNet50(input_shape, len(classes_to_predict))\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"callbacks = [ReduceLROnPlateau(monitor='val_loss', patience=1, verbose=1, factor=0.5),\n             EarlyStopping(monitor='val_loss', patience=3),\n             ModelCheckpoint(filepath='best_model.h5', monitor='val_loss', save_best_only=True)]\n\nmodel.compile(loss=\"categorical_crossentropy\", optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class_weights = class_weight.compute_class_weight(\"balanced\", classes_to_predict, training_df.label.values)\nclass_weights_dict = {i : class_weights[i] for i,label in enumerate(classes_to_predict)}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit(train_generator,\n          epochs = 100, \n          validation_data=validation_generator,\n          class_weight=class_weights_dict,\n          callbacks=callbacks)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.title('Loss over epochs')\nplt.ylabel('Loss')\nplt.xlabel('Epoch')\nplt.legend(['Train', 'Validation'], loc='best')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.load_weights(\"best_model.h5\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = model.predict_generator(validation_generator)\nvalidation_df = pd.DataFrame(columns=[\"prediction\", \"groundtruth\", \"correct_prediction\"])\n\nfor pred, groundtruth in zip(preds[:16], validation_generator.__getitem__(0)[1]):\n    validation_df = validation_df.append({\"prediction\":classes_to_predict[np.argmax(pred)], \n                                       \"groundtruth\":classes_to_predict[np.argmax(groundtruth)], \n                                       \"correct_prediction\":np.argmax(pred)==np.argmax(groundtruth)}, ignore_index=True)\n    \nprint(validation_df)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n\nsubmission_df = pd.DataFrame(columns={\"image_id\",\"label\"})\ntest_folder = '../input/cassava-leaf-disease-classification/test_images/'\ntest_images = os.listdir(test_folder)\n\nfor image_filename in test_images:\n    #will need to replace this by a generator later\n    test_image = Image.open(test_folder+image_filename).resize((300,300))\n    pred = model.predict(np.array(test_image))\n    submission_df = submission_df.append({\"image_id\": image_filename, \n                                          \"label\":classes_to_predict[np.argmax(pred)]},\n                                           ignore_index=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df.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}