{"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":"gpu","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"sourceType":"competition"}],"dockerImageVersionId":30627,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:54:03.183167Z","iopub.execute_input":"2026-02-18T06:54:03.183541Z","iopub.status.idle":"2026-02-18T06:54:03.549052Z","shell.execute_reply.started":"2026-02-18T06:54:03.183511Z","shell.execute_reply":"2026-02-18T06:54:03.548116Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nprint(os.listdir(\"../input\"))\n\nimport zipfile\n\nwith zipfile.ZipFile(\"/kaggle/input/dogs-vs-cats/test1.zip\",\"r\") as z:\n    z.extractall(\".\")\n    \nwith zipfile.ZipFile(\"/kaggle/input/dogs-vs-cats/train.zip\",\"r\") as z:\n    z.extractall(\".\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:54:05.018478Z","iopub.execute_input":"2026-02-18T06:54:05.019485Z","iopub.status.idle":"2026-02-18T06:54:17.477329Z","shell.execute_reply.started":"2026-02-18T06:54:05.019448Z","shell.execute_reply":"2026-02-18T06:54:17.476550Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"!ls train","metadata":{"execution":{"iopub.status.busy":"2024-01-08T06:57:18.293035Z","iopub.execute_input":"2024-01-08T06:57:18.293457Z","iopub.status.idle":"2024-01-08T06:57:19.311078Z","shell.execute_reply.started":"2024-01-08T06:57:18.293422Z","shell.execute_reply":"2024-01-08T06:57:19.309969Z"}}},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Plot Dog and Cat Photos - 6810210445","metadata":{}},{"cell_type":"code","source":"# plot dog photos from the dogs vs cats dataset\nfrom matplotlib import pyplot\nfrom matplotlib.image import imread\n# define location of dataset\nfolder = 'train/'\n# plot first few images\nfor i in range(9):\n\t# define subplot\n\tpyplot.subplot(330 + 1 + i)\n\t# define filename\n\tfilename = folder + 'dog.' + str(i) + '.jpg'\n\t# load image pixels\n\timage = imread(filename)\n\t# plot raw pixel data\n\tpyplot.imshow(image)\n# show the figure\npyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:54:23.235002Z","iopub.execute_input":"2026-02-18T06:54:23.235799Z","iopub.status.idle":"2026-02-18T06:54:24.291583Z","shell.execute_reply.started":"2026-02-18T06:54:23.235766Z","shell.execute_reply":"2026-02-18T06:54:24.290654Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# plot cat photos from the dogs vs cats dataset\nfrom matplotlib import pyplot\nfrom matplotlib.image import imread #แปลงเป็นตารางตัวเลข\n# define location of dataset\nfolder = 'train/'\n# plot first few images\nfor i in range(9):\n\t# define subplot\n\tpyplot.subplot(330 + 1 + i) #เลข 330 มาจาก 3 (แถว), 3 (คอลัมน์), 0 (index เริ่มต้น)\n\t# define filename\n\tfilename = folder + 'cat.' + str(i) + '.jpg'\n\t# load image pixels\n\timage = imread(filename)\n\t# plot raw pixel data\n\tpyplot.imshow(image)\n# show the figure\npyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:54:27.234209Z","iopub.execute_input":"2026-02-18T06:54:27.234609Z","iopub.status.idle":"2026-02-18T06:54:28.315235Z","shell.execute_reply.started":"2026-02-18T06:54:27.234580Z","shell.execute_reply":"2026-02-18T06:54:28.314266Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# load dogs vs cats dataset, reshape and save to a new file\nfrom os import listdir\nfrom numpy import asarray\nfrom numpy import save\nfrom keras.preprocessing.image import load_img\nfrom keras.preprocessing.image import img_to_array #แปลงเป็นเมทริกซ์ตัวเลข\n# define location of dataset\nfolder = 'train/'\nphotos, labels = list(), list()\n# enumerate files in the directory\nfor file in listdir(folder):\n\t# determine class\n\toutput = 0.0 # ตั้งสมมติฐานก่อนว่าเป็นแมว (0)\n\tif file.startswith('dog'):\n\t\toutput = 1.0 # ถ้าชื่อไฟล์ขึ้นต้นด้วย 'dog' ให้เปลี่ยนเป็นหมา (1)\n\t# load image\n\tphoto = load_img(folder + file, target_size=(128, 128)) # ตัดรูปให้เหลือ 200x200\n\t# convert to numpy array\n\tphoto = img_to_array(photo) # แปลงรูปเป็นตัวเลข\n\t# store\n\tphotos.append(photo)\n\tlabels.append(output)\n# convert to a numpy arrays\nphotos = asarray(photos)\nlabels = asarray(labels)\nprint(photos.shape, labels.shape)\n# save the reshaped photos\nsave('dogs_vs_cats_photos.npy', photos)\nsave('dogs_vs_cats_labels.npy', labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:54:31.540465Z","iopub.execute_input":"2026-02-18T06:54:31.541301Z","iopub.status.idle":"2026-02-18T06:55:18.656009Z","shell.execute_reply.started":"2026-02-18T06:54:31.541264Z","shell.execute_reply":"2026-02-18T06:55:18.654778Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# load and confirm the shape\nfrom numpy import load\nphotos = load('dogs_vs_cats_photos.npy')\nlabels = load('dogs_vs_cats_labels.npy')\nprint(photos.shape, labels.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:55:23.468945Z","iopub.execute_input":"2026-02-18T06:55:23.469303Z","iopub.status.idle":"2026-02-18T06:55:25.353693Z","shell.execute_reply.started":"2026-02-18T06:55:23.469277Z","shell.execute_reply":"2026-02-18T06:55:25.352667Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Pre-Process Photos into Standard Directories","metadata":{}},{"cell_type":"code","source":"from os import makedirs\n# create directories\ndataset_home = 'dataset_dogs_vs_cats/'\nsubdirs = ['train/', 'test/']\nfor subdir in subdirs:\n    # create label subdirectories\n    labeldirs = ['dogs/', 'cats/']\n    for labldir in labeldirs:\n        newdir = dataset_home + subdir + labldir\n        makedirs(newdir, exist_ok=True)\n        print(f\"สร้างโฟลเดอร์เรียบร้อย: {newdir}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:55:28.161553Z","iopub.execute_input":"2026-02-18T06:55:28.162331Z","iopub.status.idle":"2026-02-18T06:55:28.168981Z","shell.execute_reply.started":"2026-02-18T06:55:28.162293Z","shell.execute_reply":"2026-02-18T06:55:28.168018Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from random import seed\nfrom random import random\nfrom shutil import copyfile\nfrom os import listdir\n# seed random number generator\nseed(1)\n# define ratio of pictures to use for validation\nval_ratio = 0.25 # แบ่ง test ไป 25%\n# copy training dataset images into subdirectories\nsrc_directory = 'train/'\nfor file in listdir(src_directory):\n\tsrc = src_directory + '/' + file\n\tdst_dir = 'train/'\n\tif random() < val_ratio: # ถ้าสุ่มได้ น้อยกว่า 0.25 ย้ายไปโฟลเดอร์ test/ | แต่ถ้า มากกว่า 0.25 อยู่ที่เดิม train/\n\t\tdst_dir = 'test/'\n\tif file.startswith('cat'):\n\t\tdst = dataset_home + dst_dir + 'cats/'  + file\n\t\tcopyfile(src, dst)\n\telif file.startswith('dog'):\n\t\tdst = dataset_home + dst_dir + 'dogs/'  + file\n\t\tcopyfile(src, dst)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:55:51.395834Z","iopub.execute_input":"2026-02-18T06:55:51.396234Z","iopub.status.idle":"2026-02-18T06:55:55.234674Z","shell.execute_reply.started":"2026-02-18T06:55:51.396205Z","shell.execute_reply":"2026-02-18T06:55:55.233656Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Develop a Baseline CNN Model","metadata":{}},{"cell_type":"markdown","source":"## One Block VGG Model","metadata":{}},{"cell_type":"code","source":"import sys\nfrom matplotlib import pyplot\nfrom keras.utils import to_categorical\nfrom keras.models import Sequential\nfrom keras.layers import Conv2D\nfrom keras.layers import MaxPooling2D\nfrom keras.layers import Dense\nfrom keras.layers import Flatten\nfrom keras.optimizers import SGD\nfrom keras.preprocessing.image import ImageDataGenerator","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:55:58.142081Z","iopub.execute_input":"2026-02-18T06:55:58.142438Z","iopub.status.idle":"2026-02-18T06:55:58.147861Z","shell.execute_reply.started":"2026-02-18T06:55:58.142410Z","shell.execute_reply":"2026-02-18T06:55:58.146897Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# สร้าง model\nmodel = Sequential()\n# Block 1\nmodel.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(200, 200, 3)))\nmodel.add(MaxPooling2D((2, 2)))\n\n# Flatten & Dense\nmodel.add(Flatten())\nmodel.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\nmodel.add(Dense(1, activation='sigmoid'))\n\n# Compile Model\nopt = SGD(learning_rate=0.001, momentum=0.9)\nmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:56:00.261216Z","iopub.execute_input":"2026-02-18T06:56:00.261588Z","iopub.status.idle":"2026-02-18T06:56:00.944238Z","shell.execute_reply.started":"2026-02-18T06:56:00.261541Z","shell.execute_reply":"2026-02-18T06:56:00.943179Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# เตรียมข้อมูล\ndatagen = ImageDataGenerator(rescale=1.0/255.0)\n\n# prepare iterators\ntrain_it = datagen.flow_from_directory('dataset_dogs_vs_cats/train/',\n\tclass_mode='binary', batch_size=64, target_size=(200, 200))\ntest_it = datagen.flow_from_directory('dataset_dogs_vs_cats/test/',\n\tclass_mode='binary', batch_size=64, target_size=(200, 200))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:56:03.008387Z","iopub.execute_input":"2026-02-18T06:56:03.008766Z","iopub.status.idle":"2026-02-18T06:56:03.869246Z","shell.execute_reply.started":"2026-02-18T06:56:03.008737Z","shell.execute_reply":"2026-02-18T06:56:03.868477Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# เริ่มเทรน\n# fit model\nhistory = model.fit(train_it, \n                    steps_per_epoch=len(train_it),\n                \tvalidation_data=test_it,\n                    validation_steps=len(test_it), \n                    epochs=20, \n                    verbose=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T06:56:06.051669Z","iopub.execute_input":"2026-02-18T06:56:06.052047Z","iopub.status.idle":"2026-02-18T07:11:09.676546Z","shell.execute_reply.started":"2026-02-18T06:56:06.052020Z","shell.execute_reply":"2026-02-18T07:11:09.675786Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ประเมินผล\n# evaluate model\n_, acc = model.evaluate(test_it, steps=len(test_it), verbose=0)\nprint('> %.3f' % (acc * 100.0))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T07:12:08.261345Z","iopub.execute_input":"2026-02-18T07:12:08.262052Z","iopub.status.idle":"2026-02-18T07:12:18.939914Z","shell.execute_reply.started":"2026-02-18T07:12:08.262021Z","shell.execute_reply":"2026-02-18T07:12:18.938958Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 1. วาดกราฟ Loss\npyplot.subplot(211)\npyplot.title('Cross Entropy Loss')\npyplot.plot(history.history['loss'], color='blue', label='train')\npyplot.plot(history.history['val_loss'], color='orange', label='test')\npyplot.legend()\n\n# 2. วาดกราฟ Accuracy\npyplot.subplot(212)\npyplot.title('Classification Accuracy')\npyplot.plot(history.history['accuracy'], color='blue', label='train')\npyplot.plot(history.history['val_accuracy'], color='orange', label='test')\npyplot.legend()\n\n# 3. show\npyplot.tight_layout()\npyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T07:12:25.917119Z","iopub.execute_input":"2026-02-18T07:12:25.917436Z","iopub.status.idle":"2026-02-18T07:12:26.439642Z","shell.execute_reply.started":"2026-02-18T07:12:25.917413Z","shell.execute_reply":"2026-02-18T07:12:26.438768Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Two Block VGG Model","metadata":{}},{"cell_type":"code","source":"# เตรียมข้อมูล\ndatagen = ImageDataGenerator(rescale=1.0/255.0)\n\n# prepare iterators\ntrain_it = datagen.flow_from_directory('dataset_dogs_vs_cats/train/',\n\tclass_mode='binary', batch_size=64, target_size=(200, 200))\ntest_it = datagen.flow_from_directory('dataset_dogs_vs_cats/test/',\n\tclass_mode='binary', batch_size=64, target_size=(200, 200))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T07:13:00.961291Z","iopub.execute_input":"2026-02-18T07:13:00.961957Z","iopub.status.idle":"2026-02-18T07:13:01.665884Z","shell.execute_reply.started":"2026-02-18T07:13:00.961921Z","shell.execute_reply":"2026-02-18T07:13:01.665138Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# สร้าง model\nmodel = Sequential()\n# Block 1\nmodel.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(200, 200, 3)))\nmodel.add(MaxPooling2D((2, 2)))\n\n# Block 2\nmodel.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\nmodel.add(MaxPooling2D((2, 2)))\n\n# Flatten & Dense\nmodel.add(Flatten())\nmodel.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\nmodel.add(Dense(1, activation='sigmoid'))\n\n# Compile Model\nopt = SGD(learning_rate=0.001, momentum=0.9)\nmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T07:13:02.924134Z","iopub.execute_input":"2026-02-18T07:13:02.924501Z","iopub.status.idle":"2026-02-18T07:13:02.993447Z","shell.execute_reply.started":"2026-02-18T07:13:02.924472Z","shell.execute_reply":"2026-02-18T07:13:02.992444Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# เริ่มเทรน\n# fit model\nhistory = model.fit(train_it, \n                    steps_per_epoch=len(train_it),\n                \tvalidation_data=test_it,\n                    validation_steps=len(test_it), \n                    epochs=20, \n                    verbose=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T07:13:05.911066Z","iopub.execute_input":"2026-02-18T07:13:05.911421Z","iopub.status.idle":"2026-02-18T07:27:29.901847Z","shell.execute_reply.started":"2026-02-18T07:13:05.911393Z","shell.execute_reply":"2026-02-18T07:27:29.901055Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ประเมินผล\n# evaluate model\n_, acc = model.evaluate(test_it, steps=len(test_it), verbose=0)\nprint('> %.3f' % (acc * 100.0))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T07:48:12.792164Z","iopub.execute_input":"2026-02-18T07:48:12.793036Z","iopub.status.idle":"2026-02-18T07:48:24.417352Z","shell.execute_reply.started":"2026-02-18T07:48:12.793005Z","shell.execute_reply":"2026-02-18T07:48:24.416462Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 1. วาดกราฟ Loss\npyplot.subplot(211)\npyplot.title('Cross Entropy Loss')\npyplot.plot(history.history['loss'], color='blue', label='train')\npyplot.plot(history.history['val_loss'], color='orange', label='test')\npyplot.legend()\n\n# 2. วาดกราฟ Accuracy\npyplot.subplot(212)\npyplot.title('Classification Accuracy')\npyplot.plot(history.history['accuracy'], color='blue', label='train')\npyplot.plot(history.history['val_accuracy'], color='orange', label='test')\npyplot.legend()\n\n# 3. show\npyplot.tight_layout()\npyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T07:48:29.911407Z","iopub.execute_input":"2026-02-18T07:48:29.912272Z","iopub.status.idle":"2026-02-18T07:48:30.327366Z","shell.execute_reply.started":"2026-02-18T07:48:29.912242Z","shell.execute_reply":"2026-02-18T07:48:30.326401Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Three Block VGG Model","metadata":{}},{"cell_type":"code","source":"# เตรียมข้อมูล\ndatagen = ImageDataGenerator(rescale=1.0/255.0)\n\n# prepare iterators\ntrain_it = datagen.flow_from_directory('dataset_dogs_vs_cats/train/',\n\tclass_mode='binary', batch_size=64, target_size=(200, 200))\ntest_it = datagen.flow_from_directory('dataset_dogs_vs_cats/test/',\n\tclass_mode='binary', batch_size=64, target_size=(200, 200))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T07:49:04.926849Z","iopub.execute_input":"2026-02-18T07:49:04.927602Z","iopub.status.idle":"2026-02-18T07:49:05.784131Z","shell.execute_reply.started":"2026-02-18T07:49:04.927571Z","shell.execute_reply":"2026-02-18T07:49:05.783190Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# สร้าง model\nmodel = Sequential()\n# Block 1\nmodel.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(200, 200, 3)))\nmodel.add(MaxPooling2D((2, 2)))\n\n# Block 2\nmodel.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\nmodel.add(MaxPooling2D((2, 2)))\n\n# Block 3\nmodel.add(Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\nmodel.add(MaxPooling2D((2, 2)))\n\n\n# Flatten & Dense\nmodel.add(Flatten())\nmodel.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\nmodel.add(Dense(1, activation='sigmoid'))\n\n# Compile Model\nopt = SGD(learning_rate=0.001, momentum=0.9)\nmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T07:49:06.832646Z","iopub.execute_input":"2026-02-18T07:49:06.833385Z","iopub.status.idle":"2026-02-18T07:49:06.920642Z","shell.execute_reply.started":"2026-02-18T07:49:06.833353Z","shell.execute_reply":"2026-02-18T07:49:06.919617Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# เริ่มเทรน\n# fit model\nhistory = model.fit(train_it, \n                    steps_per_epoch=len(train_it),\n                \tvalidation_data=test_it,\n                    validation_steps=len(test_it), \n                    epochs=20, \n                    verbose=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T07:49:09.377076Z","iopub.execute_input":"2026-02-18T07:49:09.377946Z","iopub.status.idle":"2026-02-18T08:04:03.098568Z","shell.execute_reply.started":"2026-02-18T07:49:09.377912Z","shell.execute_reply":"2026-02-18T08:04:03.097862Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ประเมินผล\n# evaluate model\n_, acc = model.evaluate(test_it, steps=len(test_it), verbose=0)\nprint('> %.3f' % (acc * 100.0))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T08:06:21.121528Z","iopub.execute_input":"2026-02-18T08:06:21.122209Z","iopub.status.idle":"2026-02-18T08:06:31.862684Z","shell.execute_reply.started":"2026-02-18T08:06:21.122179Z","shell.execute_reply":"2026-02-18T08:06:31.861870Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 1. วาดกราฟ Loss\npyplot.subplot(211)\npyplot.title('Cross Entropy Loss')\npyplot.plot(history.history['loss'], color='blue', label='train')\npyplot.plot(history.history['val_loss'], color='orange', label='test')\npyplot.legend()\n\n# 2. วาดกราฟ Accuracy\npyplot.subplot(212)\npyplot.title('Classification Accuracy')\npyplot.plot(history.history['accuracy'], color='blue', label='train')\npyplot.plot(history.history['val_accuracy'], color='orange', label='test')\npyplot.legend()\n\n# 3. show\npyplot.tight_layout()\npyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T08:06:34.713509Z","iopub.execute_input":"2026-02-18T08:06:34.713875Z","iopub.status.idle":"2026-02-18T08:06:35.196624Z","shell.execute_reply.started":"2026-02-18T08:06:34.713845Z","shell.execute_reply":"2026-02-18T08:06:35.195967Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Dropout Regularization","metadata":{}},{"cell_type":"code","source":"# เตรียมข้อมูล\ndatagen = ImageDataGenerator(rescale=1.0/255.0)\n\n# prepare iterators\ntrain_it = datagen.flow_from_directory('dataset_dogs_vs_cats/train/',\n\tclass_mode='binary', batch_size=64, target_size=(200, 200))\ntest_it = datagen.flow_from_directory('dataset_dogs_vs_cats/test/',\n\tclass_mode='binary', batch_size=64, target_size=(200, 200))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T08:06:41.168200Z","iopub.execute_input":"2026-02-18T08:06:41.168503Z","iopub.status.idle":"2026-02-18T08:06:42.018416Z","shell.execute_reply.started":"2026-02-18T08:06:41.168480Z","shell.execute_reply":"2026-02-18T08:06:42.017451Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from keras.layers import Dropout\n\n# สร้าง model\nmodel = Sequential()\n# Block 1\nmodel.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(200, 200, 3)))\nmodel.add(MaxPooling2D((2, 2)))\nmodel.add(Dropout(0.2))\n\n# Block 2\nmodel.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\nmodel.add(MaxPooling2D((2, 2)))\nmodel.add(Dropout(0.2))\n\n# Block 3\nmodel.add(Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\nmodel.add(MaxPooling2D((2, 2)))\nmodel.add(Dropout(0.2))\n\n\n# Flatten & Dense\nmodel.add(Flatten())\nmodel.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(1, activation='sigmoid'))\n\n# Compile Model\nopt = SGD(learning_rate=0.001, momentum=0.9)\nmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T08:06:47.951617Z","iopub.execute_input":"2026-02-18T08:06:47.951980Z","iopub.status.idle":"2026-02-18T08:06:48.041612Z","shell.execute_reply.started":"2026-02-18T08:06:47.951951Z","shell.execute_reply":"2026-02-18T08:06:48.040959Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# เริ่มเทรน\n# fit model\nhistory = model.fit(train_it, \n                    steps_per_epoch=len(train_it),\n                \tvalidation_data=test_it,\n                    validation_steps=len(test_it), \n                    epochs=50, \n                    verbose=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T08:06:50.304208Z","iopub.execute_input":"2026-02-18T08:06:50.304562Z","iopub.status.idle":"2026-02-18T08:43:51.214689Z","shell.execute_reply.started":"2026-02-18T08:06:50.304534Z","shell.execute_reply":"2026-02-18T08:43:51.213654Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ประเมินผล\n# evaluate model\n_, acc = model.evaluate(test_it, steps=len(test_it), verbose=0)\nprint('> %.3f' % (acc * 100.0))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T08:48:22.552832Z","iopub.execute_input":"2026-02-18T08:48:22.553258Z","iopub.status.idle":"2026-02-18T08:48:34.116468Z","shell.execute_reply.started":"2026-02-18T08:48:22.553226Z","shell.execute_reply":"2026-02-18T08:48:34.115580Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 1. วาดกราฟ Loss\npyplot.subplot(211)\npyplot.title('Cross Entropy Loss')\npyplot.plot(history.history['loss'], color='blue', label='train')\npyplot.plot(history.history['val_loss'], color='orange', label='test')\npyplot.legend()\n\n# 2. วาดกราฟ Accuracy\npyplot.subplot(212)\npyplot.title('Classification Accuracy')\npyplot.plot(history.history['accuracy'], color='blue', label='train')\npyplot.plot(history.history['val_accuracy'], color='orange', label='test')\npyplot.legend()\n\n# 3. show\npyplot.tight_layout()\npyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T08:48:35.833280Z","iopub.execute_input":"2026-02-18T08:48:35.833619Z","iopub.status.idle":"2026-02-18T08:48:36.265110Z","shell.execute_reply.started":"2026-02-18T08:48:35.833595Z","shell.execute_reply":"2026-02-18T08:48:36.264098Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Image Data Augmentation","metadata":{}},{"cell_type":"code","source":"# create data generators\ntrain_datagen = ImageDataGenerator(rescale=1.0/255.0,\n\twidth_shift_range=0.1, \n    height_shift_range=0.1,\n    horizontal_flip=True\n)\ntest_datagen = ImageDataGenerator(rescale=1.0/255.0)\n\n# prepare iterators\ntrain_it = train_datagen.flow_from_directory('dataset_dogs_vs_cats/train/',\n\tclass_mode='binary', batch_size=64, target_size=(200, 200))\n\ntest_it = test_datagen.flow_from_directory('dataset_dogs_vs_cats/test/',\n\tclass_mode='binary', batch_size=64, target_size=(200, 200))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T08:48:44.141091Z","iopub.execute_input":"2026-02-18T08:48:44.141459Z","iopub.status.idle":"2026-02-18T08:48:44.898338Z","shell.execute_reply.started":"2026-02-18T08:48:44.141427Z","shell.execute_reply":"2026-02-18T08:48:44.897564Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sys\nfrom matplotlib import pyplot\nfrom keras.utils import to_categorical\nfrom keras.models import Sequential\nfrom keras.layers import Conv2D\nfrom keras.layers import MaxPooling2D\nfrom keras.layers import Dense\nfrom keras.layers import Flatten\nfrom keras.optimizers import SGD\nfrom keras.preprocessing.image import ImageDataGenerator\n\n# สร้าง model\nmodel = Sequential()\n# Block 1\nmodel.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(200, 200, 3)))\nmodel.add(MaxPooling2D((2, 2)))\n\n# Block 2\nmodel.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\nmodel.add(MaxPooling2D((2, 2)))\n\n# Block 3\nmodel.add(Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\nmodel.add(MaxPooling2D((2, 2)))\n\n# Flatten & Dense\nmodel.add(Flatten())\nmodel.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\nmodel.add(Dense(1, activation='sigmoid'))\n\n# Compile Model\nopt = SGD(learning_rate=0.001, momentum=0.9)\nmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T08:48:49.611553Z","iopub.execute_input":"2026-02-18T08:48:49.612270Z","iopub.status.idle":"2026-02-18T08:48:49.703092Z","shell.execute_reply.started":"2026-02-18T08:48:49.612236Z","shell.execute_reply":"2026-02-18T08:48:49.701911Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# เริ่มเทรน\n# fit model\nhistory = model.fit(train_it, \n                    steps_per_epoch=len(train_it),\n                    validation_data=test_it, \n                    validation_steps=len(test_it), \n                    epochs=50,\n                    verbose=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T08:49:34.615098Z","iopub.execute_input":"2026-02-18T08:49:34.615508Z","iopub.status.idle":"2026-02-18T11:19:30.869060Z","shell.execute_reply.started":"2026-02-18T08:49:34.615477Z","shell.execute_reply":"2026-02-18T11:19:30.868291Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ประเมินผล\n# evaluate model\n_, acc = model.evaluate(test_it, steps=len(test_it), verbose=0)\nprint('> %.3f' % (acc * 100.0))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T11:55:39.290607Z","iopub.execute_input":"2026-02-18T11:55:39.291436Z","iopub.status.idle":"2026-02-18T11:55:49.322414Z","shell.execute_reply.started":"2026-02-18T11:55:39.291400Z","shell.execute_reply":"2026-02-18T11:55:49.321446Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 1. วาดกราฟ Loss\npyplot.subplot(211)\npyplot.title('Cross Entropy Loss')\npyplot.plot(history.history['loss'], color='blue', label='train')\npyplot.plot(history.history['val_loss'], color='orange', label='test')\npyplot.legend()\n\n# 2. วาดกราฟ Accuracy\npyplot.subplot(212)\npyplot.title('Classification Accuracy')\npyplot.plot(history.history['accuracy'], color='blue', label='train')\npyplot.plot(history.history['val_accuracy'], color='orange', label='test')\npyplot.legend()\n\n# 3. show\npyplot.tight_layout()\npyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T11:55:56.824238Z","iopub.execute_input":"2026-02-18T11:55:56.824583Z","iopub.status.idle":"2026-02-18T11:55:57.298063Z","shell.execute_reply.started":"2026-02-18T11:55:56.824557Z","shell.execute_reply":"2026-02-18T11:55:57.297107Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Explore Transfer Learning","metadata":{}},{"cell_type":"code","source":"import sys\nfrom matplotlib import pyplot\nfrom keras.utils import to_categorical\nfrom keras.applications.vgg16 import VGG16\nfrom keras.models import Model\nfrom keras.layers import Dense\nfrom keras.layers import Flatten\nfrom keras.optimizers import SGD\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.optimizers import Adam\n\n# load model\nbase_model = VGG16(include_top=False, input_shape=(224, 224, 3))\n# mark loaded layers as not trainable\nfor layer in base_model.layers:\n    layer.trainable = False\n    \n# add new classifier layers\nflat1 = Flatten()(base_model.layers[-1].output)\nclass1 = Dense(128, activation='relu', kernel_initializer='he_uniform')(flat1)\noutput = Dense(1, activation='sigmoid')(class1)\n\n# compile model\nopt = Adam(learning_rate=0.00001) \n\nmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T13:35:14.784423Z","iopub.execute_input":"2026-02-18T13:35:14.784772Z","iopub.status.idle":"2026-02-18T13:35:15.132268Z","shell.execute_reply.started":"2026-02-18T13:35:14.784745Z","shell.execute_reply":"2026-02-18T13:35:15.131515Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"datagen = ImageDataGenerator(rescale=1.0/255.0)\ntrain_it = datagen.flow_from_directory('dataset_dogs_vs_cats/train/',\n\tclass_mode='binary', batch_size=64, target_size=(224, 224))\ntest_it = datagen.flow_from_directory('dataset_dogs_vs_cats/test/',\n\tclass_mode='binary', batch_size=64, target_size=(224, 224))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T13:35:16.181893Z","iopub.execute_input":"2026-02-18T13:35:16.182250Z","iopub.status.idle":"2026-02-18T13:35:16.864265Z","shell.execute_reply.started":"2026-02-18T13:35:16.182223Z","shell.execute_reply":"2026-02-18T13:35:16.863579Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# fit model\nhistory = model.fit(train_it, \n                    validation_data=test_it, \n                    epochs=5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T13:35:18.973923Z","iopub.execute_input":"2026-02-18T13:35:18.974266Z","iopub.status.idle":"2026-02-18T13:40:34.395231Z","shell.execute_reply.started":"2026-02-18T13:35:18.974240Z","shell.execute_reply":"2026-02-18T13:40:34.394498Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# evaluate model\n_, acc = model.evaluate(test_it, steps=len(test_it), verbose=0)\nprint('> %.3f' % (acc * 100.0))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T13:40:37.751410Z","iopub.execute_input":"2026-02-18T13:40:37.752149Z","iopub.status.idle":"2026-02-18T13:40:54.526898Z","shell.execute_reply.started":"2026-02-18T13:40:37.752117Z","shell.execute_reply":"2026-02-18T13:40:54.526066Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# plot loss\npyplot.subplot(211)\npyplot.title('Cross Entropy Loss')\npyplot.plot(history.history['loss'], color='blue', label='train')\npyplot.plot(history.history['val_loss'], color='orange', label='test')\n\n# plot accuracy\npyplot.subplot(212)\npyplot.title('Classification Accuracy')\npyplot.plot(history.history['accuracy'], color='blue', label='train')\npyplot.plot(history.history['val_accuracy'], color='orange', label='test')\n\n# save plot to file\nfilename = sys.argv[0].split('/')[-1]\npyplot.savefig(filename + '_plot.png')\npyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T13:40:56.298795Z","iopub.execute_input":"2026-02-18T13:40:56.299568Z","iopub.status.idle":"2026-02-18T13:40:56.693643Z","shell.execute_reply.started":"2026-02-18T13:40:56.299536Z","shell.execute_reply":"2026-02-18T13:40:56.692767Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.applications import VGG16\nfrom tensorflow.keras.layers import Dense, Flatten, Dropout, Input\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.optimizers import Adam\n\ntrain_datagen = ImageDataGenerator(\n    rescale=1./255,\n    rotation_range=30,      # หมุนภาพ\n    width_shift_range=0.2,  # ขยับซ้ายขวา\n    height_shift_range=0.2, # ขยับขึ้นลง\n    shear_range=0.2,        # บิดภาพ\n    zoom_range=0.3,         # ซูมเข้าออก (สำคัญมาก)\n    horizontal_flip=True,   # กลับด้าน\n    fill_mode='nearest'\n)\n\ntest_datagen = ImageDataGenerator(rescale=1./255)\n\ntrain_it = train_datagen.flow_from_directory('dataset_dogs_vs_cats/train/',\n                                             class_mode='binary', \n                                             batch_size=64, \n                                             target_size=(224, 224))\n\ntest_it = test_datagen.flow_from_directory('dataset_dogs_vs_cats/test/',\n                                           class_mode='binary', \n                                           batch_size=64, \n                                           target_size=(224, 224))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T13:41:04.872777Z","iopub.execute_input":"2026-02-18T13:41:04.873132Z","iopub.status.idle":"2026-02-18T13:41:05.582488Z","shell.execute_reply.started":"2026-02-18T13:41:04.873106Z","shell.execute_reply":"2026-02-18T13:41:05.581568Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_model = VGG16(include_top=False, input_shape=(224, 224, 3))\n\n# แช่แข็งฐาน VGG ไว้ก่อน\nfor layer in base_model.layers:\n    layer.trainable = False\n\n# สร้างหัวใหม่แบบมี Dropout\nx = base_model.output\nx = Flatten()(x)\nx = Dense(256, activation='relu')(x) # ลดจำนวน neuron ลงหน่อย (จาก 4096 เหลือ 256 พอ)\nx = Dropout(0.5)(x)                  # <--- ใส่ Dropout 50% (สุ่มปิดสมองครึ่งนึงทุกรอบ)\noutput = Dense(1, activation='sigmoid')(x)\n\nmodel = Model(inputs=base_model.input, outputs=output)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T13:41:19.283397Z","iopub.execute_input":"2026-02-18T13:41:19.283761Z","iopub.status.idle":"2026-02-18T13:41:19.630836Z","shell.execute_reply.started":"2026-02-18T13:41:19.283732Z","shell.execute_reply":"2026-02-18T13:41:19.630010Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(optimizer=Adam(learning_rate=0.0001), \n              loss='binary_crossentropy', \n              metrics=['accuracy'])\n\nhistory = model.fit(train_it, \n                    validation_data=test_it, \n                    epochs=10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T13:41:27.387918Z","iopub.execute_input":"2026-02-18T13:41:27.388276Z","iopub.status.idle":"2026-02-18T14:19:20.865170Z","shell.execute_reply.started":"2026-02-18T13:41:27.388248Z","shell.execute_reply":"2026-02-18T14:19:20.864246Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# evaluate model\n_, acc = model.evaluate(test_it, steps=len(test_it), verbose=0)\nprint('> %.3f' % (acc * 100.0))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T14:23:48.313587Z","iopub.execute_input":"2026-02-18T14:23:48.314007Z","iopub.status.idle":"2026-02-18T14:24:05.375261Z","shell.execute_reply.started":"2026-02-18T14:23:48.313976Z","shell.execute_reply":"2026-02-18T14:24:05.374417Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# plot loss\npyplot.subplot(211)\npyplot.title('Cross Entropy Loss')\npyplot.plot(history.history['loss'], color='blue', label='train')\npyplot.plot(history.history['val_loss'], color='orange', label='test')\n\n# plot accuracy\npyplot.subplot(212)\npyplot.title('Classification Accuracy')\npyplot.plot(history.history['accuracy'], color='blue', label='train')\npyplot.plot(history.history['val_accuracy'], color='orange', label='test')\n\n# save plot to file\nfilename = sys.argv[0].split('/')[-1]\npyplot.savefig(filename + '_plot.png')\npyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T14:24:54.471525Z","iopub.execute_input":"2026-02-18T14:24:54.472393Z","iopub.status.idle":"2026-02-18T14:24:54.899882Z","shell.execute_reply.started":"2026-02-18T14:24:54.472360Z","shell.execute_reply":"2026-02-18T14:24:54.898959Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport random\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\n\n# 1. กำหนดโฟลเดอร์และคลาส\ntest_dir = 'dataset_dogs_vs_cats/test/'\nclasses = ['cats', 'dogs'] # ต้องตรงกับชื่อโฟลเดอร์\n\nplt.figure(figsize=(15, 7)) # กำหนดขนาดรูปใหญ่หน่อยจะได้เห็นชัด\nplot_index = 1\n\n# 2. วนลูปทีละคลาส (เริ่มจาก cats -> dogs)\nfor category in classes:\n    path = os.path.join(test_dir, category)\n    # สุ่มชื่อไฟล์มา 5 ชื่อ\n    random_files = random.sample(os.listdir(path), 5)\n    \n    for filename in random_files:\n        # เตรียมรูปภาพ\n        img_path = os.path.join(path, filename)\n        img = load_img(img_path, target_size=(224, 224)) # 1. โหลดและย่อ\n        x = img_to_array(img)                            # 2. แปลงเป็นตัวเลข\n        x = x / 255.0                                    # 3. หาร 255 (สำคัญมาก!)\n        x = np.expand_dims(x, axis=0)                    # 4. เพิ่มมิติให้เป็น (1, 224, 224, 3)\n        \n        # ให้ AI ทำนาย\n        pred = model.predict(x, verbose=0)\n        \n        # แปลผล (ถ้าค่า > 0.5 คือหมา, น้อยกว่าคือแมว)\n        if pred[0][0] > 0.5:\n            result = 'dogs'\n        else:\n            result = 'cats'\n            \n        # แสดงผล\n        plt.subplot(2, 5, plot_index) # จัดวางตำแหน่ง (2 แถว, 5 คอลัมน์)\n        plt.imshow(img)\n        \n        # เช็คว่าทายถูกไหม (ถ้าถูกให้ตัวหนังสือสีเขียว ผิดสีแดง)\n        if result == category:\n            color = 'green'\n        else:\n            color = 'red'\n            \n        plt.title(f\"True: {category}\\nPred: {result}\", color=color)\n        plt.axis('off') # ปิดแกน x, y ให้ดูสะอาดตา\n        plot_index += 1\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-18T14:58:39.557189Z","iopub.execute_input":"2026-02-18T14:58:39.557848Z","iopub.status.idle":"2026-02-18T14:58:41.389051Z","shell.execute_reply.started":"2026-02-18T14:58:39.557817Z","shell.execute_reply":"2026-02-18T14:58:41.388194Z"}},"outputs":[],"execution_count":null}]}