{"cells":[{"metadata":{"id":"YNphtJTnMU37"},"cell_type":"markdown","source":"# ***Data2040 Midterm: Cassava Leaf Disease Classification (Kaggle)***\n\n**Authors: Haoda Song, Siyuan Li, Yuyang Li**\n\n**Brown Data Science Initiative**\n\n"},{"metadata":{"id":"G9MPhVDxLd7_","trusted":false},"cell_type":"code","source":"#Load packages\nimport keras\nfrom keras.layers import Dense, Dropout, Input, MaxPooling2D, ZeroPadding2D, Conv2D, Flatten,BatchNormalization\nfrom tensorflow.keras.layers import AveragePooling2D, ZeroPadding2D\nfrom tensorflow.keras.layers import Concatenate\nfrom keras.models import Sequential, Model\nfrom keras.losses import categorical_crossentropy\nfrom keras.optimizers import Adam, SGD\nfrom keras.preprocessing.image import img_to_array, load_img, ImageDataGenerator\nfrom keras.utils import to_categorical\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras import regularizers\n\nfrom tensorflow.keras.layers import MaxPool2D, AveragePooling2D, GlobalAveragePooling2D\nimport numpy as np\nimport pandas as pd\nfrom sklearn.model_selection import train_test_split\n\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.axes_grid1 import ImageGrid\n\nfrom zipfile import ZipFile\nimport time\nfrom datetime import timedelta\nfrom io import BytesIO\n\nimport PIL.Image\n\nimport pickle\nimport os\nimport random\n\nimport json","execution_count":null,"outputs":[]},{"metadata":{"id":"nvg9wZE7NwOj"},"cell_type":"markdown","source":"**Add a \"shortcut\" from the \"Shared Drive\" to \"My Drive\". The data folder is called \"Data_leaf\"**"},{"metadata":{"id":"J-EJ70MQDH_D","outputId":"dc879174-0b39-48b7-c063-212d578571a7","trusted":false},"cell_type":"code","source":"from google.colab import drive\ndrive.mount('/content/drive')\npath = \"/content/drive/MyDrive/Data_leaf/\"","execution_count":null,"outputs":[]},{"metadata":{"id":"CT8dGlfWOPhq","trusted":false},"cell_type":"code","source":"archive_train = ZipFile(path + \"train_images.zip\", 'r')","execution_count":null,"outputs":[]},{"metadata":{"id":"1qu7h44bOej4","trusted":false},"cell_type":"code","source":"train_list = ZipFile.namelist(archive_train)","execution_count":null,"outputs":[]},{"metadata":{"id":"veiceACVkP99","outputId":"b64b8539-bf50-4e44-e4fe-c016fa2e988d","trusted":false},"cell_type":"code","source":"train_img_list = train_list[2:42796:2]\nlen(train_img_list) #21397 Images in the file","execution_count":null,"outputs":[]},{"metadata":{"id":"MxRhP94kiHEL","outputId":"68bc5f08-d346-40a5-e537-9e0cf52129d3","trusted":false},"cell_type":"code","source":"class_data = pd.read_csv(path + \"train.csv\", header=0, sep=',', quotechar='\"')\nprint(class_data.shape)\nprint(class_data.head(5))","execution_count":null,"outputs":[]},{"metadata":{"id":"LEr-_KCJTPqg","outputId":"ad9cc674-0cfb-4511-821c-8c0ea926c63f","trusted":false},"cell_type":"code","source":"#Mapping each disease code and the real disease name for visualization purpose\nclass_data = pd.read_csv(path + \"train.csv\", header=0, sep=',', quotechar='\"')\n\nwith open(path + '/label_num_to_disease_map.json') as f:\n  disease_dict = json.load(f)\ndisease_df = pd.DataFrame(list(disease_dict.items()),columns = ['label','real_label'])\n\nfor i in range(len(disease_df)):\n  disease_df['label'][i] = int(i)\n\nactual_class = pd.merge(class_data,disease_df,on='label') \n#Count the number of images in each disease\nobs_in_actual = actual_class.groupby(['label','real_label']).size()\nprint(obs_in_actual) ","execution_count":null,"outputs":[]},{"metadata":{"id":"t_hCCtSugQec","outputId":"382344d8-1bed-4432-ac18-cf0638cf0533","trusted":false},"cell_type":"code","source":"ax = (actual_class.value_counts(actual_class['real_label'], ascending=True)\n                 .plot(kind='barh', fontsize=\"20\", \n                       title=\"Class Distribution\", figsize=(8,5)))\n\nax.set(xlabel=\"Images per class\", ylabel=\"Classes\")\nax.xaxis.label.set_size(15)\nax.yaxis.label.set_size(15)\nax.title.set_size(15)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"id":"pdY67JjxUAcW"},"cell_type":"markdown","source":"# Image Preprocessing\n\n\n"},{"metadata":{"id":"oGCSovCPZmnM","trusted":false},"cell_type":"code","source":"image_resize = 100\ns = (len(train_img_list[:]), image_resize, image_resize,3)\nallImage = np.zeros(s)\nlabels = np.empty(len(train_img_list[:]), dtype = \"object\")\nfor i in range(0,len(train_img_list[:])):\n    filename = BytesIO(archive_train.read(train_img_list[i]))\n    image = PIL.Image.open(filename)\n    image = image.resize((image_resize, image_resize))\n    image = np.array(image)\n    image = np.clip(image/255.0, 0.0, 1.0)\n\n    allImage[i]=image\n    labels[i]=list(class_data[train_img_list[i][13:] == class_data['image_id']]['label'])[0]","execution_count":null,"outputs":[]},{"metadata":{"id":"MeSWws0RbRG0","outputId":"d94fac1f-ed94-422a-a9a5-e8726dfdb312","trusted":false},"cell_type":"code","source":"#reshape labels\ntrain_img = allImage\nlabels_reshape = labels\nlabels_reshape = labels.reshape(labels.shape[0],1)\nlabels_reshape = pd.get_dummies(labels)\nlabels_reshape.shape","execution_count":null,"outputs":[]},{"metadata":{"id":"Ye64dpOJo_Fy","outputId":"e86a79eb-f102-4646-c4ae-2a4480b39fb2","trusted":false},"cell_type":"code","source":"#Training and Test split\nrandom.seed(2040)\nX = train_img\ny = labels_reshape\nprint(X.shape)\nprint(y.shape)\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)\nprint(X_train.shape)\nprint(y_train.shape)\nprint(X_test.shape)\nprint(y_test.shape)","execution_count":null,"outputs":[]},{"metadata":{"id":"JoAhNpQZpqPX","trusted":false},"cell_type":"code","source":"#Data Augmentation\ntrain_datagen = ImageDataGenerator(\n    rotation_range=45,\n    width_shift_range=0.3,\n    height_shift_range=0.3,\n    shear_range=0.2,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    fill_mode='nearest'\n)\n\ntest_datagen = ImageDataGenerator()","execution_count":null,"outputs":[]},{"metadata":{"id":"_KmE-OwBqFzo","trusted":false},"cell_type":"code","source":"BATCH_SIZE = 64\ntraining_set = train_datagen.flow(X_train, y=y_train, batch_size=BATCH_SIZE)\ntesting_set = test_datagen.flow(X_test, y=y_test, batch_size=BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{"id":"qK61StjEllqx"},"cell_type":"markdown","source":"# Baseline CNN\n\n\n"},{"metadata":{"id":"fGy3F-8MBNzM","outputId":"7a768f65-b256-45a2-c1f3-986c17707b74","trusted":false},"cell_type":"code","source":"input_shape = (image_resize, image_resize, 3)\n\nmodel = Sequential()\nmodel.add(Conv2D(32, kernel_size=(3, 3),activation='relu',kernel_initializer='he_normal',input_shape=input_shape))\nmodel.add(MaxPooling2D((2, 2)))\nmodel.add(Dropout(0.2))\n\nmodel.add(Conv2D(64, (3, 3), activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.2))\n\nmodel.add(Conv2D(128, (3, 3), activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.4))\n\nmodel.add(Flatten())\nmodel.add(Dense(384, activation='relu'))\nmodel.add(Dropout(0.3))\nmodel.add(Dense(5, activation='softmax'))\n\nmodel.compile(loss=keras.losses.categorical_crossentropy,\n              optimizer=keras.optimizers.Adam(lr=0.001),\n              metrics=['accuracy'])\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"id":"BUPc_xdglyyk","outputId":"5a778280-d39a-4a1e-8dbe-6b80e4531dea","trusted":false},"cell_type":"code","source":"early_stopping = EarlyStopping(\n    monitor='val_accuracy', \n    patience=10)\n\nhistory = model.fit(\n  training_set, \n  steps_per_epoch = X_train.shape[0] // BATCH_SIZE,\n  validation_data = testing_set, \n  epochs = 100, \n  callbacks = [early_stopping, tensorboard_callback('project')],\n  verbose = 1\n)","execution_count":null,"outputs":[]},{"metadata":{"id":"TCUChkKGDUa6"},"cell_type":"markdown","source":"#GoogLeNet\n(For later use)\nCitation: https://www.kaggle.com/luckscylla/googlenet-implementation"},{"metadata":{"id":"M4QAiA7gwli3","trusted":false},"cell_type":"code","source":"def inception(x, filters):\n    # 1x1\n    path1 = Conv2D(filters=filters[0], kernel_size=(1,1), strides=1, padding='same', activation='relu')(x)\n\n    # 1x1->3x3\n    path2 = Conv2D(filters=filters[1][0], kernel_size=(1,1), strides=1, padding='same', activation='relu')(x)\n    path2 = Conv2D(filters=filters[1][1], kernel_size=(3,3), strides=1, padding='same', activation='relu')(path2)\n    \n    # 1x1->5x5\n    path3 = Conv2D(filters=filters[2][0], kernel_size=(1,1), strides=1, padding='same', activation='relu')(x)\n    path3 = Conv2D(filters=filters[2][1], kernel_size=(5,5), strides=1, padding='same', activation='relu')(path3)\n\n    # 3x3->1x1\n    path4 = MaxPooling2D(pool_size=(3,3), strides=1, padding='same')(x)\n    path4 = Conv2D(filters=filters[3], kernel_size=(1,1), strides=1, padding='same', activation='relu')(path4)\n\n    return Concatenate(axis=-1)([path1,path2,path3,path4])\n\n\ndef auxiliary(x, name=None):\n    layer = AveragePooling2D(pool_size=(5,5), strides=3, padding='valid')(x)\n    layer = Conv2D(filters=128, kernel_size=(1,1), strides=1, padding='same', activation='relu')(layer)\n    layer = Flatten()(layer)\n    layer = Dense(units=256, activation='relu')(layer)\n    layer = Dropout(0.4)(layer)\n    layer = Dense(units=5, activation='softmax', name=name)(layer)\n    return layer","execution_count":null,"outputs":[]},{"metadata":{"id":"lXTOWTD0vZCl","outputId":"f5520534-5bdb-4ff5-9436-028880d81224","trusted":false},"cell_type":"code","source":"def googlenet():\n    layer_in = Input(shape = (image_resize, image_resize, 3))\n    \n    # stage-1\n    layer = Conv2D(filters=64, kernel_size=(7,7), strides=2, padding='same', activation='relu')(layer_in)\n    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)\n    layer = BatchNormalization()(layer)\n\n    # stage-2\n    layer = Conv2D(filters=64, kernel_size=(1,1), strides=1, padding='same', activation='relu')(layer)\n    layer = Conv2D(filters=192, kernel_size=(3,3), strides=1, padding='same', activation='relu')(layer)\n    layer = BatchNormalization()(layer)\n    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)\n\n    # stage-3\n    layer = inception(layer, [ 64,  (96,128), (16,32), 32]) #3a\n    layer = inception(layer, [128, (128,192), (32,96), 64]) #3b\n    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)\n    \n    # stage-4\n    layer = inception(layer, [192,  (96,208),  (16,48),  64]) #4a\n    aux1  = auxiliary(layer, name='aux1')\n    layer = inception(layer, [160, (112,224),  (24,64),  64]) #4b\n    layer = inception(layer, [128, (128,256),  (24,64),  64]) #4c\n    layer = inception(layer, [112, (144,288),  (32,64),  64]) #4d\n    aux2  = auxiliary(layer, name='aux2')\n    layer = inception(layer, [256, (160,320), (32,128), 128]) #4e\n    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)\n    \n    # stage-5\n    layer = inception(layer, [256, (160,320), (32,128), 128]) #5a\n    layer = inception(layer, [384, (192,384), (48,128), 128]) #5b\n    layer = AveragePooling2D(pool_size=(3,3), strides=1, padding='valid')(layer)\n    \n    # stage-6\n    layer = Flatten()(layer)\n    layer = Dropout(0.4)(layer)\n    layer = Dense(units=256, activation='linear')(layer)\n    main = Dense(units=5, activation='softmax', name='main')(layer)\n    \n    model = Model(inputs=layer_in, outputs=[main, aux1, aux2])\n    \n    return model\n\nmodel_google = googlenet()\n\nopt_google = keras.optimizers.SGD(learning_rate=0.01)\nmodel_google.compile(loss='categorical_crossentropy', \n                  loss_weights={'main': 1.0, 'aux1': 0.3, 'aux2': 0.3},\n                  optimizer=opt_google, metrics=['accuracy'])\nmodel_google.summary()","execution_count":null,"outputs":[]},{"metadata":{"id":"wkKAzOLiwRZ6","outputId":"e2a4e0ab-ede8-4649-e385-acbcacaab200","trusted":false},"cell_type":"code","source":"early_stopping = EarlyStopping(\n    monitor='val_main_accuracy', \n    patience=10)\n\nhistory = model_google.fit(\n  training_set, \n  steps_per_epoch = X_train.shape[0] // BATCH_SIZE,\n  validation_data = testing_set, \n  epochs = 10, \n  callbacks = [early_stopping],\n  verbose = 1\n)","execution_count":null,"outputs":[]},{"metadata":{"id":"iur0-Tr5RG9b"},"cell_type":"markdown","source":"# TensorBoard"},{"metadata":{"id":"cSQE2_G91Ss3","outputId":"7308a75a-657e-4119-9ec2-e7144c6ff914","trusted":false},"cell_type":"code","source":"# imports\nimport tensorflow as tf\nimport numpy as np\nfrom sklearn.datasets import make_circles\nfrom matplotlib import pyplot\nimport tensorflow.keras as keras\nfrom tensorflow.keras.layers import Dense\nfrom tensorflow.keras.models import Sequential\n \n# setup tensorboard, directories\n!rm -rf ./logs\n!mkdir ./logs/\n!mkdir ./logs/project\n \nlog_dir=\"./logs/project/\"\ndef tensorboard_callback(exp_name):\n  return tf.keras.callbacks.TensorBoard(log_dir=log_dir + exp_name, profile_batch=0, histogram_freq=1)\n# launch tensorboard with specific directory\n%reload_ext tensorboard\n%tensorboard --logdir logs/project","execution_count":null,"outputs":[]},{"metadata":{"id":"oi-1Rd8lMLZo"},"cell_type":"markdown","source":"# Additional EDA "},{"metadata":{"id":"CC_KIHbzBJdI","outputId":"21eaeaaa-b23d-4fc5-dfb4-87a6b9c0645e","trusted":false},"cell_type":"code","source":"# Show an sample image for each disease class\nlabel_0=np.where(labels == 0)\ns_0=label_0[0].flatten().tolist()\nlabel_1=np.where(labels == 1)\ns_1=label_1[0].flatten().tolist()\nlabel_2=np.where(labels == 2)\ns_2=label_2[0].flatten().tolist()\nlabel_3=np.where(labels == 3)\ns_3=label_3[0].flatten().tolist()\nlabel_4=np.where(labels == 4)\ns_4=label_4[0].flatten().tolist()","execution_count":null,"outputs":[]},{"metadata":{"id":"oC-SHEGpZiux"},"cell_type":"markdown","source":"### Class 0:"},{"metadata":{"id":"A-UCIFHxSoqd","outputId":"0f8613c3-29d6-4437-c952-40afd06d4d6f","trusted":false},"cell_type":"code","source":"fig, axes = plt.subplots(1, 5, figsize=(15,15))\nprint(\"Class 0: Cassava Bacterial Blight (CBB)\")\nfor i in range(5):\n  random_index = random.choice(s_0) \n  lum_img = train_img[random_index,:,:,:]\n  axes[i].imshow(lum_img)","execution_count":null,"outputs":[]},{"metadata":{"id":"Xr_yGXNYmCv1"},"cell_type":"markdown","source":"### Class 1"},{"metadata":{"id":"BLeQ-ixBXxNJ","outputId":"3e9f5809-ab36-4adf-9f21-428bfe4d3a82","trusted":false},"cell_type":"code","source":"fig, axes = plt.subplots(1, 5, figsize=(15,15))\nprint(\"Class 1: Cassava Brown Streak Disease (CBSD)\")\nfor i in range(5):\n  random_index = random.choice(s_1) \n  lum_img = train_img[random_index,:,:,:]\n  axes[i].imshow(lum_img)","execution_count":null,"outputs":[]},{"metadata":{"id":"GkFJUPpUmKau"},"cell_type":"markdown","source":"### Class 2"},{"metadata":{"id":"QC2Ko0t5mdBD","outputId":"ce95f934-a363-4381-bcb9-0959eedf57ee","trusted":false},"cell_type":"code","source":"fig, axes = plt.subplots(1, 5, figsize=(15,15))\nprint(\"Class 2: Cassava Green Mottle (CGM) \")\nfor i in range(5):\n  random_index = random.choice(s_2) \n  lum_img = train_img[random_index,:,:,:]\n  axes[i].imshow(lum_img)","execution_count":null,"outputs":[]},{"metadata":{"id":"x2iF7EnumOMU"},"cell_type":"markdown","source":"### Class 3"},{"metadata":{"id":"v2YlR4iVmmwW","outputId":"381711b1-f1b6-4756-820f-0bd8eecbf066","trusted":false},"cell_type":"code","source":"fig, axes = plt.subplots(1, 5, figsize=(15,15))\nprint(\"Class 3: Cassava Mosaic Disease (CMD)\")\nfor i in range(5):\n  random_index = random.choice(s_3) \n  lum_img = train_img[random_index,:,:,:]\n  axes[i].imshow(lum_img)","execution_count":null,"outputs":[]},{"metadata":{"id":"ZYrp72eImQGK"},"cell_type":"markdown","source":"### Class 4"},{"metadata":{"id":"kVh_R7jdm3P6","outputId":"e8b44205-d41d-4759-8df2-449f4cb3bd19","trusted":false},"cell_type":"code","source":"fig, axes = plt.subplots(1, 5, figsize=(15,15))\nprint(\"Class 4: Healthy\")\nfor i in range(5):\n  random_index = random.choice(s_4) \n  lum_img = train_img[random_index,:,:,:]\n  axes[i].imshow(lum_img)","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}