{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":93122,"databundleVersionId":11101269,"sourceType":"competition"}],"dockerImageVersionId":30887,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# 1. นำเข้าไลบรารีที่จำเป็น\nimport os\nfrom PIL import Image\n\n# 2. กำหนดแหล่งที่อยู่ของไฟล์ภาพ (Input) และโฟลเดอร์สำหรับส่งออก (Output)\ninput_folder = \"/kaggle/input/durian-hackathon-durian-disease-classification/Images\"\n# กำหนด output_folder ให้เป็นโฟลเดอร์ใน Kaggle working directory (คุณสามารถเปลี่ยนแปลงได้ตามต้องการ)\noutput_folder = \"/kaggle/working/output_images\"\nos.makedirs(output_folder, exist_ok=True)  # สร้างโฟลเดอร์ส่งออกถ้ายังไม่มี\n\n# 3. กำหนดขนาดที่ต้องการให้กับภาพทั้งหมด (เช่น 256x256 พิกเซล)\ntarget_size = (512, 512)\n\n# 4. นำไฟล์ภาพทุกไฟล์ในโฟลเดอร์ Input ที่มีนามสกุลที่ต้องการและปรับขนาดให้เท่ากัน\nfor filename in os.listdir(input_folder):\n    # ตรวจสอบไฟล์ที่มีนามสกุลเป็นภาพ\n    if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')):\n        img_path = os.path.join(input_folder, filename)\n        try:\n            with Image.open(img_path) as img:\n                # ปรับขนาดภาพให้เท่ากับ target_size\n                img_resized = img.resize(target_size)\n                \n                # 5. ส่งออกภาพที่ได้ไปยังโฟลเดอร์ Output\n                output_path = os.path.join(output_folder, filename)\n                img_resized.save(output_path)\n                print(f\"Processed and saved: {output_path}\")\n        except Exception as e:\n            print(f\"Error processing {filename}: {e}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T05:54:33.283502Z","iopub.execute_input":"2025-02-16T05:54:33.283949Z","iopub.status.idle":"2025-02-16T05:55:01.058892Z","shell.execute_reply.started":"2025-02-16T05:54:33.283908Z","shell.execute_reply":"2025-02-16T05:55:01.058192Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#;;;;;;;;;;;;;;;;;;;;;;;;","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T05:55:01.059954Z","iopub.execute_input":"2025-02-16T05:55:01.060254Z","iopub.status.idle":"2025-02-16T05:55:01.063833Z","shell.execute_reply.started":"2025-02-16T05:55:01.060223Z","shell.execute_reply":"2025-02-16T05:55:01.062958Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom skimage.io import imread\n\nfrom keras.models import Sequential, Model, load_model\nfrom keras.layers import Conv2D, MaxPooling2D, Dense, Dropout, Input, Flatten, SeparableConv2D","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:19:51.600375Z","iopub.execute_input":"2025-02-16T07:19:51.600641Z","iopub.status.idle":"2025-02-16T07:20:04.717774Z","shell.execute_reply.started":"2025-02-16T07:19:51.600620Z","shell.execute_reply":"2025-02-16T07:20:04.717140Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.python.client import device_lib\nprint(device_lib.list_local_devices())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:20:08.935302Z","iopub.execute_input":"2025-02-16T07:20:08.935581Z","iopub.status.idle":"2025-02-16T07:20:09.800502Z","shell.execute_reply.started":"2025-02-16T07:20:08.935559Z","shell.execute_reply":"2025-02-16T07:20:09.799170Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/durian-hackathon-durian-disease-classification/train.csv')\n\n# Get the counts for each class\ncases_count = df['label'].value_counts()\nprint(cases_count)\n\n# Plot the results \nplt.figure(figsize=(10,8))\nsns.barplot(x=cases_count.index, y= cases_count.values)\nplt.title('Number of images', fontsize=14)\nplt.xlabel('class', fontsize=12)\nplt.ylabel('Count', fontsize=12)\n# plt.xticks(range(len(cases_count.index)), ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19'])\nplt.show()\ndel cases_count","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:02:23.468704Z","iopub.execute_input":"2025-02-16T07:02:23.468979Z","iopub.status.idle":"2025-02-16T07:02:23.476692Z","shell.execute_reply.started":"2025-02-16T07:02:23.468959Z","shell.execute_reply":"2025-02-16T07:02:23.475889Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\ntrain_df, validate_df = train_test_split(df, test_size=0.50, stratify=df['label'])\ntrain_df = train_df.reset_index(drop=True)\nvalidate_df = validate_df.reset_index(drop=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:02:26.957092Z","iopub.execute_input":"2025-02-16T07:02:26.957390Z","iopub.status.idle":"2025-02-16T07:02:26.964698Z","shell.execute_reply.started":"2025-02-16T07:02:26.957364Z","shell.execute_reply":"2025-02-16T07:02:26.963885Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df['label'] = train_df['label'].astype(str)\nvalidate_df['label'] = validate_df['label'].astype(str)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:02:28.521639Z","iopub.execute_input":"2025-02-16T07:02:28.521970Z","iopub.status.idle":"2025-02-16T07:02:28.526565Z","shell.execute_reply.started":"2025-02-16T07:02:28.521929Z","shell.execute_reply":"2025-02-16T07:02:28.525734Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:02:30.294500Z","iopub.execute_input":"2025-02-16T07:02:30.294804Z","iopub.status.idle":"2025-02-16T07:02:30.302375Z","shell.execute_reply.started":"2025-02-16T07:02:30.294780Z","shell.execute_reply":"2025-02-16T07:02:30.301505Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df['label'].value_counts().sort_index().plot.bar()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:02:32.146321Z","iopub.execute_input":"2025-02-16T07:02:32.146625Z","iopub.status.idle":"2025-02-16T07:02:32.283446Z","shell.execute_reply.started":"2025-02-16T07:02:32.146600Z","shell.execute_reply":"2025-02-16T07:02:32.282534Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"validate_df['label'].value_counts().sort_index().plot.bar()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:02:34.366056Z","iopub.execute_input":"2025-02-16T07:02:34.366375Z","iopub.status.idle":"2025-02-16T07:02:34.512677Z","shell.execute_reply.started":"2025-02-16T07:02:34.366347Z","shell.execute_reply":"2025-02-16T07:02:34.511921Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_size = 512\ntarget_size = (512, 512)\ninput_shape = (512, 512, 3)\n\nbatch_size = 16\nnum_class = 4\nepochs = 30","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:04:57.530718Z","iopub.execute_input":"2025-02-16T07:04:57.531021Z","iopub.status.idle":"2025-02-16T07:04:57.535252Z","shell.execute_reply.started":"2025-02-16T07:04:57.530994Z","shell.execute_reply":"2025-02-16T07:04:57.534334Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\ntrain_datagen = ImageDataGenerator(\n    rescale=1./255,\n    rotation_range=15,\n    shear_range=0.1,\n)\n\ntrain_generator = train_datagen.flow_from_dataframe(\n    train_df, \n    \"/kaggle/working/output_images\", \n    x_col='id',\n    y_col='label',\n    target_size=target_size,\n    class_mode='categorical',\n    batch_size=batch_size\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:04:59.493049Z","iopub.execute_input":"2025-02-16T07:04:59.493328Z","iopub.status.idle":"2025-02-16T07:04:59.504089Z","shell.execute_reply.started":"2025-02-16T07:04:59.493306Z","shell.execute_reply":"2025-02-16T07:04:59.503236Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"batch=next(train_generator)  # returns the next batch of images and labels \nprint(batch[0].shape) # batch[0] is the images, batch[1] are the labels\n\nfor i in range(0,4):\n    img=batch[0][i] \n    plt.imshow(img)\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:05:01.756817Z","iopub.execute_input":"2025-02-16T07:05:01.757097Z","iopub.status.idle":"2025-02-16T07:05:03.026410Z","shell.execute_reply.started":"2025-02-16T07:05:01.757076Z","shell.execute_reply":"2025-02-16T07:05:03.025484Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"validation_datagen = ImageDataGenerator(rescale=1./255)\nvalidation_generator = validation_datagen.flow_from_dataframe(\n    validate_df, \n    \"/kaggle/working/output_images\", \n    x_col='id',\n    y_col='label',\n    target_size=target_size,\n    class_mode='categorical',\n    batch_size=batch_size\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:05:07.637685Z","iopub.execute_input":"2025-02-16T07:05:07.638027Z","iopub.status.idle":"2025-02-16T07:05:07.647048Z","shell.execute_reply.started":"2025-02-16T07:05:07.637988Z","shell.execute_reply":"2025-02-16T07:05:07.646408Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nimport os\n\nbase_model = tf.keras.applications.VGG16(\n    input_shape=input_shape,\n    include_top=False,\n    weights='imagenet'\n)\n\nbase_model.trainable = False\n\nx = base_model.output\nx = tf.keras.layers.GlobalAveragePooling2D()(x)\nx = tf.keras.layers.Dropout(0.2)(x)\noutput = tf.keras.layers.Dense(num_class, activation=\"softmax\")(x)\n\nmodel = keras.Model(inputs = base_model.input,\n                    outputs = output)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:05:09.547674Z","iopub.execute_input":"2025-02-16T07:05:09.547974Z","iopub.status.idle":"2025-02-16T07:05:09.815096Z","shell.execute_reply.started":"2025-02-16T07:05:09.547953Z","shell.execute_reply":"2025-02-16T07:05:09.814412Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:05:12.393227Z","iopub.execute_input":"2025-02-16T07:05:12.393504Z","iopub.status.idle":"2025-02-16T07:05:12.421365Z","shell.execute_reply.started":"2025-02-16T07:05:12.393483Z","shell.execute_reply":"2025-02-16T07:05:12.420744Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.optimizers import Adam\nfrom keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau\n# Define the optimizer\nadam = Adam(learning_rate=0.001)\n\nearlyStopping = EarlyStopping(monitor='val_loss', patience=30, verbose=0, mode='min')\nmcp_save = ModelCheckpoint('best_model.keras', save_best_only=True, monitor='val_loss', mode='min')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:05:15.538791Z","iopub.execute_input":"2025-02-16T07:05:15.539073Z","iopub.status.idle":"2025-02-16T07:05:15.545855Z","shell.execute_reply.started":"2025-02-16T07:05:15.539051Z","shell.execute_reply":"2025-02-16T07:05:15.544902Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Compile the model\nmodel.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer=adam)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:05:18.812771Z","iopub.execute_input":"2025-02-16T07:05:18.813082Z","iopub.status.idle":"2025-02-16T07:05:18.819441Z","shell.execute_reply.started":"2025-02-16T07:05:18.813054Z","shell.execute_reply":"2025-02-16T07:05:18.818516Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Train the model\nhistory = model.fit(train_generator, \n                validation_data = validation_generator,\n                epochs = 30,\n                batch_size = batch_size,\n                callbacks=[earlyStopping, mcp_save])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:05:21.092216Z","iopub.execute_input":"2025-02-16T07:05:21.092509Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12))\nax1.plot(history.history['loss'], color='b', label=\"Training loss\")\nax1.plot(history.history['val_loss'], color='r', label=\"validation loss\")\n\nax2.plot(history.history['accuracy'], color='b', label=\"Training accuracy\")\nax2.plot(history.history['val_accuracy'], color='r',label=\"Validation accuracy\")\n\nlegend = plt.legend(loc='best', shadow=True)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T06:59:47.050850Z","iopub.execute_input":"2025-02-16T06:59:47.051175Z","iopub.status.idle":"2025-02-16T06:59:47.410781Z","shell.execute_reply.started":"2025-02-16T06:59:47.051143Z","shell.execute_reply":"2025-02-16T06:59:47.409851Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#test data\ntest_df = pd.read_csv('/kaggle/input/durian-hackathon-durian-disease-classification/submit.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T06:59:47.411758Z","iopub.execute_input":"2025-02-16T06:59:47.411985Z","iopub.status.idle":"2025-02-16T06:59:47.428300Z","shell.execute_reply.started":"2025-02-16T06:59:47.411966Z","shell.execute_reply":"2025-02-16T06:59:47.427481Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T06:59:47.431359Z","iopub.execute_input":"2025-02-16T06:59:47.431568Z","iopub.status.idle":"2025-02-16T06:59:47.441429Z","shell.execute_reply.started":"2025-02-16T06:59:47.431550Z","shell.execute_reply":"2025-02-16T06:59:47.440669Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df.tail()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T06:59:47.443015Z","iopub.execute_input":"2025-02-16T06:59:47.443283Z","iopub.status.idle":"2025-02-16T06:59:47.452681Z","shell.execute_reply.started":"2025-02-16T06:59:47.443261Z","shell.execute_reply":"2025-02-16T06:59:47.451987Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# create test generator\n\ntest_gen = ImageDataGenerator(rescale=1./255)\ntest_generator = test_gen.flow_from_dataframe(\n    test_df, \n    \"/kaggle/working/output_images\", \n    x_col='id',\n    y_col=None,\n    class_mode=None,\n    target_size=target_size,\n    batch_size=batch_size,\n    shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T06:59:47.453520Z","iopub.execute_input":"2025-02-16T06:59:47.453891Z","iopub.status.idle":"2025-02-16T06:59:47.468428Z","shell.execute_reply.started":"2025-02-16T06:59:47.453857Z","shell.execute_reply":"2025-02-16T06:59:47.467529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load best model from saved file\nmodel = load_model('/kaggle/working/best_model.keras')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T06:59:47.469126Z","iopub.execute_input":"2025-02-16T06:59:47.469308Z","iopub.status.idle":"2025-02-16T06:59:47.722100Z","shell.execute_reply.started":"2025-02-16T06:59:47.469291Z","shell.execute_reply":"2025-02-16T06:59:47.720980Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Predict\npredict = model.predict(test_generator)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T06:59:47.723120Z","iopub.execute_input":"2025-02-16T06:59:47.723372Z","iopub.status.idle":"2025-02-16T07:00:06.773305Z","shell.execute_reply.started":"2025-02-16T06:59:47.723346Z","shell.execute_reply":"2025-02-16T07:00:06.772658Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df['predict'] = np.argmax(predict, axis=-1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:00:06.774337Z","iopub.execute_input":"2025-02-16T07:00:06.774741Z","iopub.status.idle":"2025-02-16T07:00:06.778958Z","shell.execute_reply.started":"2025-02-16T07:00:06.774693Z","shell.execute_reply":"2025-02-16T07:00:06.778119Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"label_map = dict((v,k) for k,v in train_generator.class_indices.items())\ntest_df['predict'] = test_df['predict'].replace(label_map)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:00:06.779873Z","iopub.execute_input":"2025-02-16T07:00:06.780211Z","iopub.status.idle":"2025-02-16T07:00:06.791480Z","shell.execute_reply.started":"2025-02-16T07:00:06.780170Z","shell.execute_reply":"2025-02-16T07:00:06.790744Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df['predict'].value_counts().plot.bar()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:00:06.792223Z","iopub.execute_input":"2025-02-16T07:00:06.792515Z","iopub.status.idle":"2025-02-16T07:00:06.922766Z","shell.execute_reply.started":"2025-02-16T07:00:06.792494Z","shell.execute_reply":"2025-02-16T07:00:06.922089Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(test_df.head()) ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:00:06.923502Z","iopub.execute_input":"2025-02-16T07:00:06.923852Z","iopub.status.idle":"2025-02-16T07:00:06.929362Z","shell.execute_reply.started":"2025-02-16T07:00:06.923815Z","shell.execute_reply":"2025-02-16T07:00:06.928669Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df.to_csv('../working/submit.csv', index=False)\nfrom IPython.display import FileLink\nFileLink(r'submit.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-16T07:00:06.930269Z","iopub.execute_input":"2025-02-16T07:00:06.930563Z","iopub.status.idle":"2025-02-16T07:00:06.947825Z","shell.execute_reply.started":"2025-02-16T07:00:06.930536Z","shell.execute_reply":"2025-02-16T07:00:06.947019Z"}},"outputs":[],"execution_count":null}]}