{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"colab":{"provenance":[],"mount_file_id":"1EfU-WEKdXjfProogV_F1P3-xv7auqpd7","authorship_tag":"ABX9TyPryZ6Ys1PytlRiVISmuzJs"},"accelerator":"TPU","kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":7327,"databundleVersionId":861871,"sourceType":"competition"}],"dockerImageVersionId":31154,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install keras-tuner --upgrade","metadata":{"id":"Lq_XQX4hTw3Q","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:29:48.311919Z","iopub.execute_input":"2025-11-01T14:29:48.312174Z","iopub.status.idle":"2025-11-01T14:29:52.533256Z","shell.execute_reply.started":"2025-11-01T14:29:48.312155Z","shell.execute_reply":"2025-11-01T14:29:52.532308Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import libs\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport tensorflow as tf\nfrom keras.layers import Dense, Conv2D, Flatten\nfrom tensorflow.keras import datasets, layers, models\nfrom tensorflow.math import confusion_matrix\nfrom sklearn.model_selection import train_test_split\nfrom tensorflow.keras.callbacks import ModelCheckpoint\nimport os\nimport cv2\nimport warnings\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom kerastuner.tuners import RandomSearch\nimport matplotlib.pyplot as plt\nwarnings.filterwarnings('ignore')","metadata":{"id":"HviWwh1BNaR0","executionInfo":{"status":"ok","timestamp":1701852446982,"user_tz":-420,"elapsed":547,"user":{"displayName":"Hoa Doan","userId":"10314358589020174905"}},"outputId":"c683b220-b18e-493e-9472-098aeaf821cc","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:29:52.534815Z","iopub.execute_input":"2025-11-01T14:29:52.535097Z","iopub.status.idle":"2025-11-01T14:30:06.414002Z","shell.execute_reply.started":"2025-11-01T14:29:52.535069Z","shell.execute_reply":"2025-11-01T14:30:06.413125Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.read_csv(\"/kaggle/input/dog-breed-identification/labels.csv\")\ntrain_dir = \"/kaggle/input/dog-breed-identification/train\"\ntest_dir = \"/kaggle/input/dog-breed-identification/test\"","metadata":{"id":"xj8KFfqfNcSv","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:30:06.414891Z","iopub.execute_input":"2025-11-01T14:30:06.415750Z","iopub.status.idle":"2025-11-01T14:30:06.442796Z","shell.execute_reply.started":"2025-11-01T14:30:06.415728Z","shell.execute_reply":"2025-11-01T14:30:06.442114Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_features(model_name, data_preprocessor, input_size, data):\n    input_layer = Input(input_size)\n    preprocessor = Lambda(data_preprocessor)(input_layer)\n    base_model = model_name(weights='imagenet', include_top=False,\n                            input_shape=input_size)(preprocessor)\n    avg = GlobalAveragePooling2D()(base_model)\n    feature_extractor = Model(inputs = input_layer, outputs = avg)\n    feature_maps = feature_extractor.predict(data, batch_size=64, verbose=1)\n    print('Feature maps shape: ', feature_maps.shape)\n    return feature_maps","metadata":{"id":"l-zXLStKNcY-","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:30:06.444383Z","iopub.execute_input":"2025-11-01T14:30:06.444625Z","iopub.status.idle":"2025-11-01T14:30:06.451220Z","shell.execute_reply.started":"2025-11-01T14:30:06.444607Z","shell.execute_reply":"2025-11-01T14:30:06.450503Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dog_breeds = sorted(list(set(train['breed'])))\nn_classes = len(dog_breeds)\nprint(n_classes)\ndog_breeds[:5]","metadata":{"id":"hty5QOpnN9cm","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:30:06.451827Z","iopub.execute_input":"2025-11-01T14:30:06.452021Z","iopub.status.idle":"2025-11-01T14:30:06.471140Z","shell.execute_reply.started":"2025-11-01T14:30:06.452006Z","shell.execute_reply":"2025-11-01T14:30:06.470513Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class_to_num = dict(zip(dog_breeds, range(n_classes)))\n","metadata":{"id":"COV8SNDoN9go","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:30:06.471886Z","iopub.execute_input":"2025-11-01T14:30:06.472495Z","iopub.status.idle":"2025-11-01T14:30:06.482339Z","shell.execute_reply.started":"2025-11-01T14:30:06.472456Z","shell.execute_reply":"2025-11-01T14:30:06.481681Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def images_to_array(data_dir, labels_dataframe, img_size = (224,224,3)):\n    images_names = labels_dataframe['id']\n    images_labels = labels_dataframe['breed']\n    data_size = len(images_names)\n    X = np.zeros([data_size, img_size[0], img_size[1], img_size[2]], dtype=np.uint8)\n    y = np.zeros([data_size,1], dtype=np.uint8)\n\n    for i in tqdm(range(data_size)):\n        image_name = images_names[i]\n        img_dir = os.path.join(data_dir, image_name+'.jpg')\n        img_pixels = load_img(img_dir, target_size=img_size)\n        X[i] = img_pixels\n\n        image_breed = images_labels[i]\n        y[i] = class_to_num[image_breed]\n\n    y = to_categorical(y)\n\n    ind = np.random.permutation(data_size)\n    X = X[ind]\n    y = y[ind]\n    print('Output Data Size: ', X.shape)\n    print('Output Label Size: ', y.shape)\n    return X, y","metadata":{"id":"Zl3WGrbtOVYu","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:30:06.483027Z","iopub.execute_input":"2025-11-01T14:30:06.483258Z","iopub.status.idle":"2025-11-01T14:30:06.495799Z","shell.execute_reply.started":"2025-11-01T14:30:06.483238Z","shell.execute_reply":"2025-11-01T14:30:06.495031Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import load_img\nfrom tqdm import tqdm\nfrom keras.utils import to_categorical\n\n\nimg_size = (224,224, 3)\nX, y = images_to_array(train_dir, train, img_size)","metadata":{"id":"yFgbBiNdOVde","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:30:06.496339Z","iopub.execute_input":"2025-11-01T14:30:06.496558Z","iopub.status.idle":"2025-11-01T14:31:23.215486Z","shell.execute_reply.started":"2025-11-01T14:30:06.496541Z","shell.execute_reply":"2025-11-01T14:31:23.214722Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from keras.models import Model\nfrom keras.layers import BatchNormalization, Dense, GlobalAveragePooling2D, Lambda, Dropout, InputLayer, Input\nfrom keras.applications.inception_v3 import InceptionV3, preprocess_input\n\ninception_preprocessor = preprocess_input\ninception_features = get_features(InceptionV3,\n                                  inception_preprocessor,\n                                  img_size, X)\n","metadata":{"id":"hm7Ck3lzNTcq","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:31:23.216425Z","iopub.execute_input":"2025-11-01T14:31:23.216718Z","iopub.status.idle":"2025-11-01T14:32:05.534670Z","shell.execute_reply.started":"2025-11-01T14:31:23.216693Z","shell.execute_reply":"2025-11-01T14:32:05.533841Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from keras.applications.xception import Xception, preprocess_input\nxception_preprocessor = preprocess_input\nxception_features = get_features(Xception,\n                                 xception_preprocessor,\n                                 img_size, X)","metadata":{"id":"rA-Vqo45THo1","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:32:05.537037Z","iopub.execute_input":"2025-11-01T14:32:05.537269Z","iopub.status.idle":"2025-11-01T14:32:47.568181Z","shell.execute_reply.started":"2025-11-01T14:32:05.537251Z","shell.execute_reply":"2025-11-01T14:32:47.567499Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from keras.applications.mobilenet_v2 import MobileNetV2, preprocess_input\nmobilenet_v2_preprocessor = preprocess_input\nmobilenet_v2_features = get_features(MobileNetV2,\n                                   mobilenet_v2_preprocessor,\n                                   img_size, X)","metadata":{"id":"ECmSSvxkTHs7","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:32:47.569508Z","iopub.execute_input":"2025-11-01T14:32:47.569783Z","iopub.status.idle":"2025-11-01T14:33:08.621632Z","shell.execute_reply.started":"2025-11-01T14:32:47.569764Z","shell.execute_reply":"2025-11-01T14:33:08.620817Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"del X\nfinal_features = np.concatenate([inception_features,\n                                 xception_features,\n                                 mobilenet_v2_features], axis=-1)\nprint('Final feature maps shape', final_features.shape)","metadata":{"id":"zgpCwmDqTNn6","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:33:08.623329Z","iopub.execute_input":"2025-11-01T14:33:08.623589Z","iopub.status.idle":"2025-11-01T14:33:08.708123Z","shell.execute_reply.started":"2025-11-01T14:33:08.623570Z","shell.execute_reply":"2025-11-01T14:33:08.707275Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX_train, X_temp, y_train, y_temp = train_test_split(final_features, y, test_size=0.2, random_state=42)\nX_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)\n","metadata":{"id":"077k7n-2TNsJ","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:33:08.708997Z","iopub.execute_input":"2025-11-01T14:33:08.709410Z","iopub.status.idle":"2025-11-01T14:33:08.800485Z","shell.execute_reply.started":"2025-11-01T14:33:08.709383Z","shell.execute_reply":"2025-11-01T14:33:08.799838Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from keras.callbacks import EarlyStopping\nEarlyStop_callback = EarlyStopping(monitor='val_loss', patience=15, restore_best_weights=True)\nmy_callback=[EarlyStop_callback]\nimport tensorflow as tf\nfrom tensorflow.keras import layers, models\nimport matplotlib.pyplot as plt\n\n\nmodel = models.Sequential([\n    InputLayer(X_train.shape[1:]),\n    layers.Flatten(),\n    layers.Dense(128, activation='relu'),\n    layers.Dropout(0.4),\n    layers.Dense(n_classes, activation='softmax')\n])\n\n\nmodel.compile(optimizer='adam',\n              loss='categorical_crossentropy',\n              metrics=['accuracy'])\n\nmodel.summary()\n","metadata":{"id":"LW_DSKkQTN2B","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:33:08.801239Z","iopub.execute_input":"2025-11-01T14:33:08.801479Z","iopub.status.idle":"2025-11-01T14:33:08.848940Z","shell.execute_reply.started":"2025-11-01T14:33:08.801448Z","shell.execute_reply":"2025-11-01T14:33:08.848385Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = model.fit(X_train, y_train, epochs=20, validation_data=(X_val, y_val), callbacks=my_callback, batch_size=128)\n","metadata":{"id":"qgdE85kWTWXS","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:33:08.849766Z","iopub.execute_input":"2025-11-01T14:33:08.850312Z","iopub.status.idle":"2025-11-01T14:33:18.950115Z","shell.execute_reply.started":"2025-11-01T14:33:08.850289Z","shell.execute_reply":"2025-11-01T14:33:18.949509Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_loss, test_accuracy = model.evaluate(X_test, y_test)\nprint(f'Test Accuracy: {test_accuracy*100:.2f}%')\nprint(f'Test Loss: {test_loss:.4f}')","metadata":{"id":"PJ-71LXWTWfJ","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:33:54.999837Z","iopub.execute_input":"2025-11-01T14:33:55.000445Z","iopub.status.idle":"2025-11-01T14:33:55.188673Z","shell.execute_reply.started":"2025-11-01T14:33:55.000422Z","shell.execute_reply":"2025-11-01T14:33:55.187998Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.plot(history.history['accuracy'], label='accuracy')\nplt.plot(history.history['val_accuracy'], label='val_accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.legend(loc='lower right')\nplt.show()","metadata":{"id":"Gp8TZgX4Tbh5","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:34:08.050595Z","iopub.execute_input":"2025-11-01T14:34:08.051266Z","iopub.status.idle":"2025-11-01T14:34:08.217368Z","shell.execute_reply.started":"2025-11-01T14:34:08.051244Z","shell.execute_reply":"2025-11-01T14:34:08.216655Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.plot(history.history['loss'], label='loss')\nplt.plot(history.history['val_loss'], label='val_loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend(loc='upper right')\nplt.show()","metadata":{"id":"73R8DvoPTgCK","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T14:34:10.462980Z","iopub.execute_input":"2025-11-01T14:34:10.463357Z","iopub.status.idle":"2025-11-01T14:34:10.606287Z","shell.execute_reply.started":"2025-11-01T14:34:10.463331Z","shell.execute_reply":"2025-11-01T14:34:10.605487Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}