{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":70497,"databundleVersionId":7713244,"sourceType":"competition"}],"dockerImageVersionId":30646,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Notebook for \"CSC532 Fruit Categorical Classification\" in CSC532 Machine Learning class from SIT, KMUTT\n### by 64130500257 Kanyarat Premprapapong ","metadata":{}},{"cell_type":"markdown","source":"**Competition**\n* https://www.kaggle.com/competitions/csc532-fruits-categorical-classification-2024\n\n**Reference :**\n* https://www.kaggle.com/code/stormcloser/simple-mlp-hyperspectral-image-classification-ii\n* https://www.kaggle.com/code/jonathanchan/mnist-cnn-keras-baseline\n* https://www.kaggle.com/code/elcaiseri/mnist-simple-cnn-keras-accuracy-0-99-top-1\n* https://www.kaggle.com/code/jonathanchan/hyperspectral-image-classification-baseline","metadata":{}},{"cell_type":"markdown","source":"--------------\n# Table of Contents\n\n**1. Setup enviroment**\n- 1.1 Install library\n- 1.2 Import dependencies\n\n**2.  Data preparation**\n- 2.1 Data Augmentation\n- 2.2 Input dataset\n- 2.3 Sample images\n\n**3. Pre-trained Model Setup**\n- 3.1 Load ImageNet Base Model\n- 3.2 Extract features using the base model\n- 3.3 Flatten the features\n\n**4. Model Construction**\n- 4.1 Add Layers to model\n- 4.2 Compile Model\n\n**5. Model Training**\n- 5.1 Train the model\n\n**6. Model Fine Tuning**\n- 6.1 Fine tune the model\n\n**7. Model Saving**\n- 7.1 Save the model\n\n**8. Prediction and Submission**\n- 8.1 Generate predictions\n- 8.2 Prepare submission file","metadata":{}},{"cell_type":"markdown","source":"-------------------","metadata":{}},{"cell_type":"markdown","source":"## 1. Setup enviroment","metadata":{}},{"cell_type":"markdown","source":"**1.1 Install library**","metadata":{}},{"cell_type":"code","source":"pip install scikit-learn-extra","metadata":{"execution":{"iopub.status.busy":"2024-05-26T11:53:07.409084Z","iopub.execute_input":"2024-05-26T11:53:07.409393Z","iopub.status.idle":"2024-05-26T11:53:22.200224Z","shell.execute_reply.started":"2024-05-26T11:53:07.409367Z","shell.execute_reply":"2024-05-26T11:53:22.199234Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**1.2 Import dependencies**","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport matplotlib.image as mpimg\nfrom tensorflow import keras\nfrom zipfile import ZipFile\nfrom os import listdir, walk\nfrom os.path import isfile, join\nfrom tensorflow.keras import Input, Model\nfrom tensorflow.keras.applications import InceptionV3\nfrom tensorflow.keras.applications.inception_v3 import preprocess_input\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array\nfrom tensorflow.keras.layers import Input, GlobalAveragePooling2D, Dense, Dropout, BatchNormalization, Activation\nfrom tensorflow.keras.optimizers import Adam\nfrom sklearn.cluster import KMeans\nfrom sklearn_extra.cluster import KMedoids\nfrom sklearn.metrics import silhouette_score\nimport matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2024-05-26T11:53:22.202049Z","iopub.execute_input":"2024-05-26T11:53:22.202341Z","iopub.status.idle":"2024-05-26T11:53:36.786398Z","shell.execute_reply.started":"2024-05-26T11:53:22.202313Z","shell.execute_reply":"2024-05-26T11:53:36.785533Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2. Data Preparation","metadata":{}},{"cell_type":"markdown","source":"**2.1 Data Augementation**","metadata":{}},{"cell_type":"code","source":"IMG_SIZE = 224\n\ndatagen = ImageDataGenerator(\n    samplewise_center=True,\n    rescale=1/255.,\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    fill_mode='nearest'\n)","metadata":{"execution":{"iopub.status.busy":"2024-05-26T11:53:36.787614Z","iopub.execute_input":"2024-05-26T11:53:36.788218Z","iopub.status.idle":"2024-05-26T11:53:36.793646Z","shell.execute_reply.started":"2024-05-26T11:53:36.788188Z","shell.execute_reply":"2024-05-26T11:53:36.792628Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**2.2 Input the dataset**","metadata":{}},{"cell_type":"code","source":"train_it = datagen.flow_from_directory('../input/csc532-fruits-categorical-classification-2024/csc532_2024_train/train', \n                                       target_size=(224, 224), \n                                       color_mode='rgb', \n                                       class_mode=\"categorical\")\n\nvalid_it = datagen.flow_from_directory('../input/csc532-fruits-categorical-classification-2024/csc532_2024_test/test', \n                                       target_size=(224, 224), \n                                       color_mode='rgb', \n                                       class_mode=\"categorical\")","metadata":{"execution":{"iopub.status.busy":"2024-05-26T11:53:36.796146Z","iopub.execute_input":"2024-05-26T11:53:36.796482Z","iopub.status.idle":"2024-05-26T11:53:42.835920Z","shell.execute_reply.started":"2024-05-26T11:53:36.796453Z","shell.execute_reply":"2024-05-26T11:53:42.835020Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**2.3 Sample images**","metadata":{}},{"cell_type":"code","source":"images, labels = next(train_it)\n\n# Display the first 5 images in the batch\nnum_images = 5\nfig, axes = plt.subplots(1, num_images, figsize=(20, 20))\n\nfor i in range(num_images):\n    ax = axes[i]\n    ax.imshow(images[i])\n    ax.axis('off')  # Hide the axis\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-05-26T11:53:42.836907Z","iopub.execute_input":"2024-05-26T11:53:42.837205Z","iopub.status.idle":"2024-05-26T11:53:43.802730Z","shell.execute_reply.started":"2024-05-26T11:53:42.837179Z","shell.execute_reply":"2024-05-26T11:53:43.801802Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3. Pre-trained Model Setup","metadata":{}},{"cell_type":"markdown","source":"**3.1 Load ImageNet Base Model**","metadata":{}},{"cell_type":"code","source":"base_model = keras.applications.InceptionV3(\n    weights='imagenet',\n    input_shape=(224, 224, 3),\n    include_top=False)\n\n# Freeze base model\nbase_model.trainable = False","metadata":{"execution":{"iopub.status.busy":"2024-05-26T11:53:43.804061Z","iopub.execute_input":"2024-05-26T11:53:43.804441Z","iopub.status.idle":"2024-05-26T11:53:48.084951Z","shell.execute_reply.started":"2024-05-26T11:53:43.804406Z","shell.execute_reply":"2024-05-26T11:53:48.084162Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**3.2 Extract features using the base model**","metadata":{}},{"cell_type":"code","source":"train_features = base_model.predict(train_it)\nvalid_features = base_model.predict(valid_it)","metadata":{"execution":{"iopub.status.busy":"2024-05-26T11:53:48.085953Z","iopub.execute_input":"2024-05-26T11:53:48.086255Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**3.3 Flatten the features**","metadata":{}},{"cell_type":"code","source":"train_features_flat = train_features.reshape(train_features.shape[0], -1)\nvalid_features_flat = valid_features.reshape(valid_features.shape[0], -1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 4. Model Construction","metadata":{}},{"cell_type":"markdown","source":"**4.1 Add Layers to Model**","metadata":{}},{"cell_type":"code","source":"inputs = Input(shape=(224, 224, 3))\n\nx = base_model(inputs, training=False)\nx = GlobalAveragePooling2D()(x)\nx = Dense(1024)(x)\nx = BatchNormalization()(x)\nx = Activation('relu')(x)\nx = Dropout(0.5)(x)\nx = Dense(512)(x)\nx = BatchNormalization()(x)\nx = Activation('relu')(x)\n\n# Add another dropout layer for regularization\nx = Dropout(0.5)(x)\n\noutputs = Dense(len(train_it.class_indices), activation = 'softmax')(x)\n\nmodel = Model(inputs, outputs)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**4.2 Compile Model**","metadata":{}},{"cell_type":"code","source":"model.compile(optimizer='adam', loss = 'categorical_crossentropy' , metrics = ['accuracy'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 5. Model Training","metadata":{}},{"cell_type":"markdown","source":"**5.1 Train the model**","metadata":{}},{"cell_type":"code","source":"history = model.fit(train_it,\n          validation_data=valid_it,\n          steps_per_epoch=train_it.samples/train_it.batch_size,\n          validation_steps=valid_it.samples/valid_it.batch_size,\n          epochs=30)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 6. Model Fine Tuning","metadata":{}},{"cell_type":"markdown","source":"**6.1 Fine tune the model**","metadata":{}},{"cell_type":"code","source":"base_model.trainable = True\n\nfine_tune_at = 100\n\nfor layer in base_model.layers[:fine_tune_at]:\n  layer.trainable =  False","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(loss = 'categorical_crossentropy' , optimizer=Adam(learning_rate=0.001/10), metrics = [\"accuracy\"])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(train_it,\n          validation_data=valid_it,\n          steps_per_epoch=train_it.samples/train_it.batch_size,\n          validation_steps=valid_it.samples/valid_it.batch_size,\n          epochs=10)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 7. Model saving","metadata":{}},{"cell_type":"markdown","source":"**7.1 Save the Model**","metadata":{}},{"cell_type":"code","source":"model.save('resnet_fine_tuned.h5')\nmodel.save('dlai5_resnet_fine_tuned')\n\nzf = ZipFile(\"model_resnet_fine_tuned.zip\", \"w\")\nfor dirname, subdirs, files in walk(\"dlai5_resnet_fine_tuned\"):\n    zf.write(dirname)\n    for filename in files:\n        zf.write(os.path.join(dirname, filename))\nzf.close()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 8. Prediction and Submission","metadata":{}},{"cell_type":"markdown","source":"**8.1 Generate predictions**","metadata":{}},{"cell_type":"code","source":"files = [f for f in listdir('../input/csc532-fruits-categorical-classification-2024/csc532_2024_validation/validation') if isfile(join('../input/csc532-fruits-categorical-classification-2024/csc532_2024_validation/validation', f))]\n\nresult_dict = {\n    'ID': [],\n    'Code': [],\n}\n\nfor file in files:\n  image = load_img(f'../input/csc532-fruits-categorical-classification-2024/csc532_2024_validation/validation/{file}', target_size=(224, 224))\n  image = img_to_array(image)\n  image = image.reshape(1, 224, 224, 3)\n  image = image / 255\n\n  pred = np.argmax(model.predict(image)) + 1\n  result_dict['ID'].append(file)\n  result_dict['Code'].append(pred)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**8.2 Prepare submission file**","metadata":{}},{"cell_type":"code","source":"df = pd.DataFrame.from_dict(result_dict)\ndf.to_csv('result_Inception_fine_tuned.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}