{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceType":"competition","sourceId":5441,"databundleVersionId":38425}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\nimport os\nimport tensorflow as tf","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:07:37.583928Z","iopub.execute_input":"2026-04-09T00:07:37.584229Z","iopub.status.idle":"2026-04-09T00:08:02.369649Z","shell.execute_reply.started":"2026-04-09T00:07:37.584205Z","shell.execute_reply":"2026-04-09T00:08:02.369003Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import zipfile","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:02.371088Z","iopub.execute_input":"2026-04-09T00:08:02.371623Z","iopub.status.idle":"2026-04-09T00:08:02.375039Z","shell.execute_reply.started":"2026-04-09T00:08:02.371595Z","shell.execute_reply":"2026-04-09T00:08:02.374373Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with zipfile.ZipFile('/kaggle/input/competitions/dogs-vs-cats-redux-kernels-edition/train.zip', 'r') as z:\n    z.extractall('.')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:02.376185Z","iopub.execute_input":"2026-04-09T00:08:02.37648Z","iopub.status.idle":"2026-04-09T00:08:11.58343Z","shell.execute_reply.started":"2026-04-09T00:08:02.376449Z","shell.execute_reply":"2026-04-09T00:08:11.582842Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with zipfile.ZipFile('/kaggle/input/competitions/dogs-vs-cats-redux-kernels-edition/test.zip', 'r') as z:\n    z.extractall('.')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:11.584248Z","iopub.execute_input":"2026-04-09T00:08:11.584457Z","iopub.status.idle":"2026-04-09T00:08:14.766317Z","shell.execute_reply.started":"2026-04-09T00:08:11.584437Z","shell.execute_reply":"2026-04-09T00:08:14.765292Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import shutil","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:14.768525Z","iopub.execute_input":"2026-04-09T00:08:14.769174Z","iopub.status.idle":"2026-04-09T00:08:14.772531Z","shell.execute_reply.started":"2026-04-09T00:08:14.769147Z","shell.execute_reply":"2026-04-09T00:08:14.771817Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dir = '/kaggle/working/train/'\nfor filename in os.listdir(train_dir):\n    if filename.endswith('.jpg'):\n        label = filename.split('.')[0]\n        label_dir = os.path.join(train_dir, label)\n        os.makedirs(label_dir, exist_ok=True)\n        shutil.move(os.path.join(train_dir, filename), os.path.join(label_dir, filename))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:14.773444Z","iopub.execute_input":"2026-04-09T00:08:14.773695Z","iopub.status.idle":"2026-04-09T00:08:15.764229Z","shell.execute_reply.started":"2026-04-09T00:08:14.773673Z","shell.execute_reply":"2026-04-09T00:08:15.763635Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BATCH_SIZE = 64\nIMG_SIZE = (224, 224)\nRANDOM_STATE = 36\n\ntrain = tf.keras.utils.image_dataset_from_directory(\n    train_dir, shuffle = True,\n    batch_size = BATCH_SIZE,\n    image_size = IMG_SIZE,\n    validation_split = 0.3,\n    subset = 'training',\n    seed = RANDOM_STATE\n)\n\nval = tf.keras.utils.image_dataset_from_directory(\n    train_dir, shuffle = True,\n    batch_size = BATCH_SIZE,\n    image_size = IMG_SIZE,\n    validation_split = 0.3,\n    subset = 'validation',\n    seed = RANDOM_STATE\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:15.765147Z","iopub.execute_input":"2026-04-09T00:08:15.765491Z","iopub.status.idle":"2026-04-09T00:08:19.551737Z","shell.execute_reply.started":"2026-04-09T00:08:15.765467Z","shell.execute_reply":"2026-04-09T00:08:19.551013Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class_names = train.class_names\nprint(class_names)\n\nplt.figure(figsize=(10, 10))\nfor images, labels in train.take(1): #chỉ lấy 1 batch\n    for i in range (15):\n        ax = plt.subplot(4, 4, i+1)\n        plt.imshow(images[i].numpy().astype(\"uint8\"))\n        #chuyển từ tensor sang nparray, ép kiểu int\n        plt.title(class_names[labels[i]])\n        plt.axis(\"off\") #Tat grid","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:19.552613Z","iopub.execute_input":"2026-04-09T00:08:19.552909Z","iopub.status.idle":"2026-04-09T00:08:20.957821Z","shell.execute_reply.started":"2026-04-09T00:08:19.552873Z","shell.execute_reply":"2026-04-09T00:08:20.956563Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_dir = '/kaggle/working/test/'\ntest = tf.keras.utils.image_dataset_from_directory(\n    test_dir, \n    labels = None,\n    label_mode = None,\n    image_size = IMG_SIZE,\n    batch_size = BATCH_SIZE,\n    shuffle = False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:20.960135Z","iopub.execute_input":"2026-04-09T00:08:20.960497Z","iopub.status.idle":"2026-04-09T00:08:21.204078Z","shell.execute_reply.started":"2026-04-09T00:08:20.960459Z","shell.execute_reply":"2026-04-09T00:08:21.203269Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# prepare de giup chuong trinh chay nhanh hon\n# parralel cac thu\nAUTOTUNE = tf.data.AUTOTUNE\ntrain = train.prefetch(buffer_size = AUTOTUNE)\nval = val.prefetch(buffer_size = AUTOTUNE)\ntest = test.prefetch(buffer_size = AUTOTUNE)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:21.205271Z","iopub.execute_input":"2026-04-09T00:08:21.205943Z","iopub.status.idle":"2026-04-09T00:08:21.213025Z","shell.execute_reply.started":"2026-04-09T00:08:21.205917Z","shell.execute_reply":"2026-04-09T00:08:21.212127Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_augmentation = tf.keras.Sequential([\n    tf.keras.layers.RandomFlip('horizontal'),\n    tf.keras.layers.RandomRotation(0.2)\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:21.213902Z","iopub.execute_input":"2026-04-09T00:08:21.214172Z","iopub.status.idle":"2026-04-09T00:08:21.23053Z","shell.execute_reply.started":"2026-04-09T00:08:21.214141Z","shell.execute_reply":"2026-04-09T00:08:21.23Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for image, label in train.take(1):\n    plt.figure(figsize=(10, 10))\n    first_image = image[0]\n    for i in range(9):\n        ax = plt.subplot (3, 3, i+1)\n        augmented_image = data_augmentation (tf.expand_dims(first_image, 0))\n        plt.imshow(augmented_image[0]/255) #Neu la int thi [0,255], float thi [0,1]\n        plt.axis ('off')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:21.231405Z","iopub.execute_input":"2026-04-09T00:08:21.232113Z","iopub.status.idle":"2026-04-09T00:08:23.460707Z","shell.execute_reply.started":"2026-04-09T00:08:21.232078Z","shell.execute_reply":"2026-04-09T00:08:23.459791Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"rescale = tf.keras.layers.Rescaling(1./127.5, offset=-1)\n#Anh trong mobilenetv2 [-1, -1] chu khong phai [0, 255]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:23.461781Z","iopub.execute_input":"2026-04-09T00:08:23.462088Z","iopub.status.idle":"2026-04-09T00:08:23.466769Z","shell.execute_reply.started":"2026-04-09T00:08:23.462065Z","shell.execute_reply":"2026-04-09T00:08:23.465894Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMG_SHAPE = IMG_SIZE + (3,)\nbase_model = tf.keras.applications.MobileNetV2 (\n    input_shape = IMG_SHAPE,\n    include_top = False,\n    weights = 'imagenet'\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:23.469443Z","iopub.execute_input":"2026-04-09T00:08:23.469736Z","iopub.status.idle":"2026-04-09T00:08:24.682328Z","shell.execute_reply.started":"2026-04-09T00:08:23.469714Z","shell.execute_reply":"2026-04-09T00:08:24.68149Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_batch, label_batch = next(iter(train))\nfeature_batch = base_model(image_batch)\nprint(feature_batch.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:24.683241Z","iopub.execute_input":"2026-04-09T00:08:24.68356Z","iopub.status.idle":"2026-04-09T00:08:26.196557Z","shell.execute_reply.started":"2026-04-09T00:08:24.683536Z","shell.execute_reply":"2026-04-09T00:08:26.195754Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_model.trainable = False","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:26.197458Z","iopub.execute_input":"2026-04-09T00:08:26.197841Z","iopub.status.idle":"2026-04-09T00:08:26.204368Z","shell.execute_reply.started":"2026-04-09T00:08:26.197817Z","shell.execute_reply":"2026-04-09T00:08:26.203209Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:26.205389Z","iopub.execute_input":"2026-04-09T00:08:26.205726Z","iopub.status.idle":"2026-04-09T00:08:26.869714Z","shell.execute_reply.started":"2026-04-09T00:08:26.205691Z","shell.execute_reply":"2026-04-09T00:08:26.869122Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"global_average_layer = tf.keras.layers.GlobalAveragePooling2D()\nfeature_batch_average = global_average_layer(feature_batch)\nprint(feature_batch_average.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:26.870662Z","iopub.execute_input":"2026-04-09T00:08:26.870964Z","iopub.status.idle":"2026-04-09T00:08:26.886935Z","shell.execute_reply.started":"2026-04-09T00:08:26.870941Z","shell.execute_reply":"2026-04-09T00:08:26.886349Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"prediction_layer = tf.keras.layers.Dense(1, activation='sigmoid')\nprediction_batch = prediction_layer(feature_batch_average)\nprint(prediction_batch.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:26.887668Z","iopub.execute_input":"2026-04-09T00:08:26.887941Z","iopub.status.idle":"2026-04-09T00:08:26.993099Z","shell.execute_reply.started":"2026-04-09T00:08:26.887909Z","shell.execute_reply":"2026-04-09T00:08:26.992431Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = tf.keras.Sequential([\n    tf.keras.Input(shape=(224,224, 3)),\n    data_augmentation,\n    rescale,\n    base_model,\n    global_average_layer,\n    tf.keras.layers.Dropout(0.2),\n    prediction_layer\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:26.993965Z","iopub.execute_input":"2026-04-09T00:08:26.994265Z","iopub.status.idle":"2026-04-09T00:08:27.008903Z","shell.execute_reply.started":"2026-04-09T00:08:26.994241Z","shell.execute_reply":"2026-04-09T00:08:27.008325Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:27.009661Z","iopub.execute_input":"2026-04-09T00:08:27.00993Z","iopub.status.idle":"2026-04-09T00:08:27.028347Z","shell.execute_reply.started":"2026-04-09T00:08:27.009907Z","shell.execute_reply":"2026-04-09T00:08:27.027452Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(model.trainable_variables)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:27.029321Z","iopub.execute_input":"2026-04-09T00:08:27.029636Z","iopub.status.idle":"2026-04-09T00:08:27.035275Z","shell.execute_reply.started":"2026-04-09T00:08:27.029603Z","shell.execute_reply":"2026-04-09T00:08:27.034689Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"tf.keras.utils.plot_model(model, show_shapes=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:27.036095Z","iopub.execute_input":"2026-04-09T00:08:27.036343Z","iopub.status.idle":"2026-04-09T00:08:27.298734Z","shell.execute_reply.started":"2026-04-09T00:08:27.036322Z","shell.execute_reply":"2026-04-09T00:08:27.297998Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_learning_rate = 0.0001\nmodel.compile(\n    optimizer = tf.keras.optimizers.Adam(\n        learning_rate = base_learning_rate\n    ),\n    loss = tf.keras.losses.BinaryCrossentropy(),\n    metrics = [tf.keras.metrics.BinaryAccuracy(\n        threshold=0.5, name = 'accuracy')]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:27.299602Z","iopub.execute_input":"2026-04-09T00:08:27.299899Z","iopub.status.idle":"2026-04-09T00:08:27.317674Z","shell.execute_reply.started":"2026-04-09T00:08:27.299868Z","shell.execute_reply":"2026-04-09T00:08:27.316876Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"EPOCH = 25\nhistory = model.fit(train, epochs = EPOCH,\n                   validation_data = val)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:08:27.31868Z","iopub.execute_input":"2026-04-09T00:08:27.318981Z","iopub.status.idle":"2026-04-09T00:17:27.383845Z","shell.execute_reply.started":"2026-04-09T00:08:27.318958Z","shell.execute_reply":"2026-04-09T00:17:27.383104Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"acc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\n\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nplt.figure(figsize=(8, 8))\nplt.subplot(2, 1, 1)\nplt.plot(acc, label='Training Accuracy')\nplt.plot(val_acc, label='Validation Accuracy')\nplt.legend(loc='lower right')\nplt.ylabel('Accuracy')\nplt.ylim([min(plt.ylim()),1])\nplt.title('Training and Validation Accuracy')\n\nplt.subplot(2, 1, 2)\nplt.plot(loss, label='Training Loss')\nplt.plot(val_loss, label='Validation Loss')\nplt.legend(loc='upper right')\nplt.ylabel('Cross Entropy')\nplt.ylim([0,1.0])\nplt.title('Training and Validation Loss')\nplt.xlabel('epoch')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:17:27.384931Z","iopub.execute_input":"2026-04-09T00:17:27.385146Z","iopub.status.idle":"2026-04-09T00:17:27.632523Z","shell.execute_reply.started":"2026-04-09T00:17:27.385125Z","shell.execute_reply":"2026-04-09T00:17:27.631936Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions = model.predict(test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:17:27.633332Z","iopub.execute_input":"2026-04-09T00:17:27.633676Z","iopub.status.idle":"2026-04-09T00:17:42.951021Z","shell.execute_reply.started":"2026-04-09T00:17:27.63363Z","shell.execute_reply":"2026-04-09T00:17:42.950361Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:17:42.951942Z","iopub.execute_input":"2026-04-09T00:17:42.952455Z","iopub.status.idle":"2026-04-09T00:17:42.956272Z","shell.execute_reply.started":"2026-04-09T00:17:42.952427Z","shell.execute_reply":"2026-04-09T00:17:42.955628Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions[:5]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:17:42.957049Z","iopub.execute_input":"2026-04-09T00:17:42.957383Z","iopub.status.idle":"2026-04-09T00:17:42.971218Z","shell.execute_reply.started":"2026-04-09T00:17:42.95736Z","shell.execute_reply":"2026-04-09T00:17:42.970518Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"index = []\nguess = []\nfor i in predictions:\n    guess.append(i[0])\n# Lấy danh sách đường dẫn file từ dataset gốc (trước khi prefetch)\n# Nếu bạn đã lỡ prefetch biến 'test', hãy dùng lại biến lúc khởi tạo\nfile_paths = test._input_dataset.file_paths \n#Lưu ý: tensor flow đọc file theo thứ tự từ điển -> chết chí mạng\n\nfor path in file_paths:\n    # path có dạng: '/kaggle/working/test/123.jpg'\n    filename = os.path.basename(path) # Lấy '123.jpg'\n    file_id = filename.split('.')[0]  # Lấy '123'\n    index.append(file_id)\n\nsubmission = pd.DataFrame({'id': index, 'label': guess})\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:17:42.972082Z","iopub.execute_input":"2026-04-09T00:17:42.972298Z","iopub.status.idle":"2026-04-09T00:17:43.019014Z","shell.execute_reply.started":"2026-04-09T00:17:42.972276Z","shell.execute_reply":"2026-04-09T00:17:43.018469Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission.to_csv(\"submission2.csv\", index = False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:17:43.01977Z","iopub.execute_input":"2026-04-09T00:17:43.020044Z","iopub.status.idle":"2026-04-09T00:17:43.047789Z","shell.execute_reply.started":"2026-04-09T00:17:43.020013Z","shell.execute_reply":"2026-04-09T00:17:43.047012Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.save('model_mobilenet.keras')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-09T00:18:06.928972Z","iopub.execute_input":"2026-04-09T00:18:06.929394Z","iopub.status.idle":"2026-04-09T00:18:07.34764Z","shell.execute_reply.started":"2026-04-09T00:18:06.929364Z","shell.execute_reply":"2026-04-09T00:18:07.346775Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}