{"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":"gpu","dataSources":[{"sourceId":70497,"databundleVersionId":7713244,"sourceType":"competition"}],"dockerImageVersionId":30648,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.image as mpimg\n\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 ResNet101V2, VGG19, Xception, InceptionV3\nfrom tensorflow.keras.applications.imagenet_utils import preprocess_input\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array\nfrom tensorflow.keras.layers import GlobalAveragePooling2D, Dense\n#from tensorflow.keras.optimizers import Adam","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-03-12T08:21:16.925791Z","iopub.execute_input":"2024-03-12T08:21:16.926556Z","iopub.status.idle":"2024-03-12T08:21:30.086336Z","shell.execute_reply.started":"2024-03-12T08:21:16.926520Z","shell.execute_reply":"2024-03-12T08:21:30.085445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install git+https://github.com/keras-team/keras-tuner.git -q","metadata":{"execution":{"iopub.status.busy":"2024-03-12T08:22:22.084875Z","iopub.execute_input":"2024-03-12T08:22:22.085533Z","iopub.status.idle":"2024-03-12T08:22:50.052617Z","shell.execute_reply.started":"2024-03-12T08:22:22.085497Z","shell.execute_reply":"2024-03-12T08:22:50.051403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom keras.callbacks import EarlyStopping,ModelCheckpoint\nfrom keras.layers import Dense,Flatten,Dropout,BatchNormalization\nfrom keras.layers import Conv2D,MaxPooling2D,GlobalAveragePooling2D\nfrom keras.applications import MobileNetV2,InceptionResNetV2,VGG16\nfrom keras.preprocessing.image import ImageDataGenerator,array_to_img,img_to_array,load_img","metadata":{"execution":{"iopub.status.busy":"2024-03-12T08:22:55.047147Z","iopub.execute_input":"2024-03-12T08:22:55.047802Z","iopub.status.idle":"2024-03-12T08:22:55.053713Z","shell.execute_reply.started":"2024-03-12T08:22:55.047763Z","shell.execute_reply":"2024-03-12T08:22:55.052737Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"# **Data Preprocessing**\n\n- We fix the size of our entire dataset image to be 224 x 224 pixels, and this variable will be called over and over again as basedline image size within this project.\n- With the ImageDatGenerator, we are generating tensor image data for our training and validating.\n    - samplewise_center=True indicating that we will be centerting our pixels to 0 value for each image. This is done in order to normalize our data and remove bias.\n    - rescale: this is different from the normalization we did in samplewise_center, we also rescale our data into range (0,1), thus it's standardization. This is done to avoid the wrong scaling issue, where different value from different parameter can affect the result of the calculation.","metadata":{}},{"cell_type":"code","source":"SEED = 42\nnp.random.seed(SEED)\ntf.random.set_seed(SEED)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Data Augmentation\ntrain_datagen=ImageDataGenerator(rescale=1/255.0,zoom_range=0.2,shear_range=0.3,horizontal_flip=True,brightness_range=[0.5,1.5])\ntest_datagen=ImageDataGenerator(rescale=1/255.0)\nval_datagen=ImageDataGenerator(rescale=1/255.0)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T08:23:00.604163Z","iopub.execute_input":"2024-03-12T08:23:00.604731Z","iopub.status.idle":"2024-03-12T08:23:00.610363Z","shell.execute_reply.started":"2024-03-12T08:23:00.604695Z","shell.execute_reply":"2024-03-12T08:23:00.609308Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Creating Batch size and Image shape\nBATCH_SIZE=32\nIMG_SHAPE=(224,224)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T08:23:02.540956Z","iopub.execute_input":"2024-03-12T08:23:02.541364Z","iopub.status.idle":"2024-03-12T08:23:02.545926Z","shell.execute_reply.started":"2024-03-12T08:23:02.541333Z","shell.execute_reply":"2024-03-12T08:23:02.544712Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# IMG_SIZE = 224\n# datagen = ImageDataGenerator(\n#         samplewise_center=True,\n#         rescale=1/255.)","metadata":{"execution":{"iopub.status.busy":"2024-03-11T16:35:54.370457Z","iopub.execute_input":"2024-03-11T16:35:54.370836Z","iopub.status.idle":"2024-03-11T16:35:54.376523Z","shell.execute_reply.started":"2024-03-11T16:35:54.370805Z","shell.execute_reply":"2024-03-11T16:35:54.375488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training and Validating Data Generated\n\n\nWe generate our train image sets from the input image file path of this compeitition, the size of the image is predefined with the IMG_SIZE variable. \n\nThe color mode parameter is defined to set the color style of the output generated tensor images. The default is set to \"RGB\".\n\nClass_mode indicates the task in which we are doing, classification for many classes.","metadata":{}},{"cell_type":"code","source":"#Defining Train, Test and Validation data\ntrain_data=train_datagen.flow_from_directory(\"../input/csc532-fruits-categorical-classification-2024/csc532_2024_train/train\",\n                                            target_size=IMG_SHAPE,batch_size=BATCH_SIZE,class_mode=\"categorical\")\n\ntest_data=train_datagen.flow_from_directory(\"../input/csc532-fruits-categorical-classification-2024/csc532_2024_test/test\",\n                                            target_size=IMG_SHAPE,batch_size=BATCH_SIZE,class_mode=\"categorical\")\nval_data=train_datagen.flow_from_directory(\"../input/csc532-fruits-categorical-classification-2024/csc532_2024_test/test\",\n                                            target_size=IMG_SHAPE,batch_size=BATCH_SIZE,class_mode=\"categorical\")","metadata":{"execution":{"iopub.status.busy":"2024-03-12T08:23:05.900745Z","iopub.execute_input":"2024-03-12T08:23:05.901120Z","iopub.status.idle":"2024-03-12T08:23:09.986962Z","shell.execute_reply.started":"2024-03-12T08:23:05.901090Z","shell.execute_reply":"2024-03-12T08:23:09.986035Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2024-03-11T17:25:47.163388Z","iopub.execute_input":"2024-03-11T17:25:47.163776Z","iopub.status.idle":"2024-03-11T17:25:47.170166Z","shell.execute_reply.started":"2024-03-11T17:25:47.163745Z","shell.execute_reply":"2024-03-11T17:25:47.169163Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data.class_indices","metadata":{"execution":{"iopub.status.busy":"2024-03-12T08:23:18.031290Z","iopub.execute_input":"2024-03-12T08:23:18.032261Z","iopub.status.idle":"2024-03-12T08:23:18.041119Z","shell.execute_reply.started":"2024-03-12T08:23:18.032217Z","shell.execute_reply":"2024-03-12T08:23:18.040026Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Dictionary with key and correct values as labels\nimage_class_dict={0:'freshapples',\n 1:'freshbanana',\n 2:'freshoranges',\n 3:'rottenapples',\n 4:'rottenbanana',\n 5:'rottenoranges'}","metadata":{"execution":{"iopub.status.busy":"2024-03-12T08:23:20.882412Z","iopub.execute_input":"2024-03-12T08:23:20.882778Z","iopub.status.idle":"2024-03-12T08:23:20.887530Z","shell.execute_reply.started":"2024-03-12T08:23:20.882748Z","shell.execute_reply":"2024-03-12T08:23:20.886527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train_it = datagen.flow_from_directory('../input/csc532-fruits-categorical-classification-2024/csc532_2024_train/train', \n#                                        target_size=(IMG_SIZE, IMG_SIZE), \n#                                        color_mode='rgb', \n#                                        class_mode=\"categorical\")","metadata":{"execution":{"iopub.status.busy":"2024-03-11T16:35:58.284810Z","iopub.execute_input":"2024-03-11T16:35:58.285508Z","iopub.status.idle":"2024-03-11T16:36:04.967372Z","shell.execute_reply.started":"2024-03-11T16:35:58.285474Z","shell.execute_reply":"2024-03-11T16:36:04.966600Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Same process goes with the validation data","metadata":{}},{"cell_type":"code","source":"# valid_it = datagen.flow_from_directory('../input/csc532-fruits-categorical-classification-2024/csc532_2024_test/test', \n#                                        target_size=(IMG_SIZE, IMG_SIZE), \n#                                        color_mode='rgb', \n#                                        class_mode=\"categorical\")","metadata":{"execution":{"iopub.status.busy":"2024-03-11T16:36:08.503924Z","iopub.execute_input":"2024-03-11T16:36:08.504636Z","iopub.status.idle":"2024-03-11T16:36:08.826765Z","shell.execute_reply.started":"2024-03-11T16:36:08.504605Z","shell.execute_reply":"2024-03-11T16:36:08.825835Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Modeling Process\n\nThis project, I decided to use the same model as P'PITTAWAT TAVEEKITWORACHAI's notebook\nhttps://www.kaggle.com/code/stormcloser/fruits-categorical-resnet101v2\n\n\nAnd here is a blog, explaining about the ResNet101V2's potential. \n\n\" ResNet (Residual Network) is a type of CNN that excels at training very deep networks, mitigating the vanishing gradient problem through the use of residual blocks. ResNet101v2 is an evolution that refines the original design, enhancing its efficiency and performance.\"\n\nhttps://mtburakk.medium.com/unveiling-the-power-of-resnet101v2-a-deep-dive-into-image-classification-d1a10ad02f29\n\nSo overhere, we are trying to use the pretrained model and add the extra weight to it via imagenet dataset.\n\ninclude_top = False indicates that only the convolutional base of the model is loaded, which is useful when you want to add your own custom classifier on top.\n\nAnd lastly we defined that our ResNet101V2 model will be our base model and don't want to train all over again, so we set the trainable to False\n","metadata":{}},{"cell_type":"code","source":"# #Creating CNN model\n# cnn_model=tf.keras.models.Sequential([\n#     Conv2D(16,3,activation=\"relu\",input_shape=(224,224,3)),\n#     MaxPooling2D(2,2),\n#     Conv2D(32,3,activation=\"relu\"),\n#     MaxPooling2D(2,2),\n#     Conv2D(64,3,activation=\"relu\"),\n#     MaxPooling2D(2,2),\n#     Flatten(),\n#     Dense(100,activation=\"relu\"),\n#     Dense(6,activation=\"sigmoid\")\n# ])","metadata":{"execution":{"iopub.status.busy":"2024-03-12T09:02:58.686130Z","iopub.execute_input":"2024-03-12T09:02:58.686470Z","iopub.status.idle":"2024-03-12T09:02:58.690683Z","shell.execute_reply.started":"2024-03-12T09:02:58.686445Z","shell.execute_reply":"2024-03-12T09:02:58.689678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# def cnn_model(hp):\n#     model = keras.Sequential()\n\n#     # Add convolutional layers with hyperparameter search\n#     model.add(layers.Conv2D(\n#         filters=hp.Int('conv_filters', min_value=32, max_value=128, step=32),\n#         kernel_size=hp.Choice('conv_kernel', values=[3, 5]),\n#         activation='relu',\n#         input_shape=(IMG_SHAPE[0], IMG_SHAPE[1], 3)  # Assuming RGB images\n#     ))\n#     model.add(layers.MaxPooling2D(pool_size=(2, 2)))\n\n#     # Add more layers as desired\n\n#     # Compile the model\n#     model.compile(\n#         optimizer=keras.optimizers.Adam(\n#             hp.Choice('learning_rate', values=[1e-2, 1e-3, 1e-4])\n#         ),\n#         loss='categorical_crossentropy',  # Adjust as needed\n#         metrics=['accuracy']\n#     )\n\n#     return model","metadata":{"execution":{"iopub.status.busy":"2024-03-11T17:45:31.156732Z","iopub.execute_input":"2024-03-11T17:45:31.157388Z","iopub.status.idle":"2024-03-11T17:45:31.164296Z","shell.execute_reply.started":"2024-03-11T17:45:31.157356Z","shell.execute_reply":"2024-03-11T17:45:31.163330Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import kerastuner as kt\n\n# tuner = kt.tuners.RandomSearch(\n#     cnn_model,\n#     objective='val_acc',\n#     max_trials=100,\n#     overwrite=True)\n\n# callbacks=[keras.callbacks.EarlyStopping(monitor='val_acc', mode='max', patience=6, baseline=0.9)]\n# tuner.search(train_data, callbacks=callbacks, verbose=1, epochs=20)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T09:02:49.628606Z","iopub.execute_input":"2024-03-12T09:02:49.629464Z","iopub.status.idle":"2024-03-12T09:02:49.633485Z","shell.execute_reply.started":"2024-03-12T09:02:49.629427Z","shell.execute_reply":"2024-03-12T09:02:49.632471Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def build_model(hp):\n    model = keras.models.Sequential()\n    model.add(Conv2D(hp.Int('conv1_filters', min_value=16, max_value=64, step=16),\n                     3,\n                     activation='relu',\n                     input_shape=(224, 224, 3)))\n    model.add(MaxPooling2D(2, 2))\n    model.add(Conv2D(hp.Int('conv2_filters', min_value=16, max_value=64, step=16),\n                     3,\n                     activation='relu'))\n    model.add(MaxPooling2D(2, 2))\n    model.add(Conv2D(hp.Int('conv3_filters', min_value=16, max_value=64, step=16),\n                     3,\n                     activation='relu'))\n    model.add(MaxPooling2D(2, 2))\n    model.add(Flatten())\n    model.add(Dense(100, activation='relu'))\n    model.add(Dense(6, activation='softmax'))\n    \n    model.compile(optimizer=keras.optimizers.Adam(),\n                  loss='categorical_crossentropy',\n                  metrics=['accuracy'])\n    return model\n\ntuner = kt.tuners.RandomSearch(\n    build_model,\n    objective='val_accuracy',\n    max_trials=2,\n    overwrite=True,\n    seed= SEED)\n\ncallbacks=[keras.callbacks.EarlyStopping(monitor='val_accuracy', mode='max', patience=6, baseline=0.9)]\ntuner.search(train_data, callbacks=callbacks, verbose=1, epochs=15)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T09:05:12.366525Z","iopub.execute_input":"2024-03-12T09:05:12.367022Z","iopub.status.idle":"2024-03-12T09:19:07.983344Z","shell.execute_reply.started":"2024-03-12T09:05:12.366966Z","shell.execute_reply":"2024-03-12T09:19:07.982405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"best_hp = tuner.get_best_hyperparameters()[0]\nmodel = build_model(best_hp)\n# history = model.fit(train_data, validation_split=0.2, epochs=50)\n\nhistory = model.fit_generator(train_data,validation_data=(val_data),epochs=50,steps_per_epoch=18,validation_steps=9)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T09:26:11.477147Z","iopub.execute_input":"2024-03-12T09:26:11.478050Z","iopub.status.idle":"2024-03-12T09:27:34.296126Z","shell.execute_reply.started":"2024-03-12T09:26:11.478001Z","shell.execute_reply":"2024-03-12T09:27:34.295293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# base_model = ResNet101V2(\n#     weights='imagenet',\n#     input_shape=(IMG_SIZE, IMG_SIZE, 3),\n#     include_top=False)\n\n# base_model.trainable = False","metadata":{"execution":{"iopub.status.busy":"2024-02-19T06:46:46.674074Z","iopub.execute_input":"2024-02-19T06:46:46.674529Z","iopub.status.idle":"2024-02-19T06:46:53.300911Z","shell.execute_reply.started":"2024-02-19T06:46:46.674496Z","shell.execute_reply":"2024-02-19T06:46:53.299641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Basically over here, we are plugging all model and data togethertrough inputs and outputs\n\ni) Our base model is called and plugged with the input template with all img size defined.\n\nii) We then add a Global Average Pooling layer on top of the output of the base model. *Global Average Pooling* computes the average of each feature map in the previous layer, **reducing the spatial dimensions to 1x1 while retaining the depth.** This helps in reducing the total number of parameters in the model and prevents overfitting. - from ChatGPT\n\niii) We also add a Dense layer with softmax activation. The *softmax* activation function is commonly used for multi-class classification problems as it *produces probability distributions over the classes*. And hence it suits mode with classification problem.","metadata":{}},{"cell_type":"code","source":"from keras.preprocessing import image\nimport math\n\n\ntest_image = image.load_img(\"../input/csc532-fruits-categorical-classification-2024/csc532_2024_test/test/freshoranges/Screen Shot 2018-06-12 at 11.50.41 PM.png\", target_size = (224,224))\ntest_image = image.img_to_array(test_image)\ntest_image = np.expand_dims(test_image, axis = 0)\nresult = np.argmax(model.predict(test_image))\nprint(\"The test_image is classified as\",result)\n# print(\"The key and value associated are: 0=Fresh, 1=Rotten\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"model.evaluate(val_data, steps=val_data.samples/val_data.batch_size)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T09:32:22.485725Z","iopub.execute_input":"2024-03-12T09:32:22.486460Z","iopub.status.idle":"2024-03-12T09:33:10.533983Z","shell.execute_reply.started":"2024-03-12T09:32:22.486425Z","shell.execute_reply":"2024-03-12T09:33:10.533116Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# model.save('dlai5_inceptionV3_fine_tuned')","metadata":{"execution":{"iopub.status.busy":"2024-02-17T13:19:14.106522Z","iopub.status.idle":"2024-02-17T13:19:14.107246Z","shell.execute_reply.started":"2024-02-17T13:19:14.106915Z","shell.execute_reply":"2024-02-17T13:19:14.106943Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# zf = ZipFile(\"model_inceptionV3_fine_tuned.zip\", \"w\")\n# for dirname, subdirs, files in walk(\"dlai5_inceptionV3_fine_tuned\"):\n#     zf.write(dirname)\n#     for filename in files:\n#         zf.write(os.path.join(dirname, filename))\n# zf.close()","metadata":{"execution":{"iopub.status.busy":"2024-02-17T13:19:14.109302Z","iopub.status.idle":"2024-02-17T13:19:14.110684Z","shell.execute_reply.started":"2024-02-17T13:19:14.110336Z","shell.execute_reply":"2024-02-17T13:19:14.110366Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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))]","metadata":{"execution":{"iopub.status.busy":"2024-03-12T09:33:48.931247Z","iopub.execute_input":"2024-03-12T09:33:48.931865Z","iopub.status.idle":"2024-03-12T09:33:48.967256Z","shell.execute_reply.started":"2024-03-12T09:33:48.931834Z","shell.execute_reply":"2024-03-12T09:33:48.966353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"result_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":{"execution":{"iopub.status.busy":"2024-03-12T09:34:54.528577Z","iopub.execute_input":"2024-03-12T09:34:54.529225Z","iopub.status.idle":"2024-03-12T09:35:08.352408Z","shell.execute_reply.started":"2024-03-12T09:34:54.529188Z","shell.execute_reply":"2024-03-12T09:35:08.351423Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.DataFrame.from_dict(result_dict)\ndf.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T09:35:11.242140Z","iopub.execute_input":"2024-03-12T09:35:11.242526Z","iopub.status.idle":"2024-03-12T09:35:11.255235Z","shell.execute_reply.started":"2024-03-12T09:35:11.242497Z","shell.execute_reply":"2024-03-12T09:35:11.254244Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}