{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"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\n\n# Use the kagglehub client library to attach Kaggle resources like competitions, datasets, and models to your session\n# Learn more about kagglehub: https://github.com/Kaggle/kagglehub/blob/main/README.md\n\nimport kagglehub\n# kagglehub.dataset_download('<owner>/<dataset-slug>')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-07-14T03:14:05.172792Z","iopub.execute_input":"2026-07-14T03:14:05.173004Z","iopub.status.idle":"2026-07-14T03:14:07.653176Z","shell.execute_reply.started":"2026-07-14T03:14:05.172975Z","shell.execute_reply":"2026-07-14T03:14:07.652250Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cài đặt công cụ giải nén 7z (trong trường hợp máy chủ Kaggle chưa cài sẵn)\n!apt-get install p7zip-full -y\n\n# Giải nén train.7z và test.7z vào thư mục làm việc hiện tại (/kaggle/working/)\n!7za x /kaggle/input/competitions/cifar-10/train.7z -o/kaggle/working/ -y","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-14T03:50:45.926408Z","iopub.execute_input":"2026-07-14T03:50:45.927341Z","iopub.status.idle":"2026-07-14T03:51:17.264342Z","shell.execute_reply.started":"2026-07-14T03:50:45.927303Z","shell.execute_reply":"2026-07-14T03:51:17.263605Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# 1. Đọc file CSV chứa nhãn\ndf = pd.read_csv('/kaggle/input/competitions/cifar-10/trainLabels.csv')\n\n# Chuyển đổi cột 'id' từ dạng số nguyên (ví dụ: 1) sang định dạng tên file ảnh (ví dụ: '1.png')\ndf['id'] = df['id'].astype(str) + '.png'\n\n# 2. Thiết lập ImageDataGenerator\n# Lệnh này thực hiện 2 việc: Chuẩn hóa pixel về khoảng [0, 1] và tự động trích ra 20% dữ liệu để làm tập kiểm thử (validation)\ndatagen = ImageDataGenerator(\n    rescale=1./255,\n    validation_split=0.2 \n)\n\n# Đường dẫn tới thư mục ảnh huấn luyện vừa được giải nén\ntrain_dir = '/kaggle/working/train/'\n\n# 3. Tạo luồng dữ liệu cho tập Train (Huấn luyện)\ntrain_generator = datagen.flow_from_dataframe(\n    dataframe=df,\n    directory=train_dir,\n    x_col='id',         # Cột chứa tên tệp ảnh\n    y_col='label',      # Cột chứa nhãn phân loại\n    subset='training',  # Lấy 80% dữ liệu\n    batch_size=32,\n    seed=42,\n    shuffle=True,\n    class_mode='categorical', # Mã hóa nhãn dạng chữ sang dạng one-hot\n    target_size=(32, 32)\n)\n\n# 4. Tạo luồng dữ liệu cho tập Validation (Kiểm định)\nval_generator = datagen.flow_from_dataframe(\n    dataframe=df,\n    directory=train_dir,\n    x_col='id',\n    y_col='label',\n    subset='validation', # Lấy 20% dữ liệu còn lại\n    batch_size=32,\n    seed=42,\n    shuffle=True,\n    class_mode='categorical',\n    target_size=(32, 32)\n)\n\n# 1. Khởi tạo lại luồng dữ liệu kiểm định KHÔNG xáo trộn (shuffle=False)\nval_generator_eval = datagen.flow_from_dataframe(\n    dataframe=df,\n    directory=train_dir, \n    x_col='id',\n    y_col='label',\n    subset='validation',\n    batch_size=32,\n    seed=42,\n    shuffle=False,       # <--- Không xáo trộn để đối chiếu chính xác\n    class_mode='categorical',\n    target_size=(32, 32)\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-14T03:51:50.617780Z","iopub.execute_input":"2026-07-14T03:51:50.618280Z","iopub.status.idle":"2026-07-14T03:51:51.318538Z","shell.execute_reply.started":"2026-07-14T03:51:50.618254Z","shell.execute_reply":"2026-07-14T03:51:51.317838Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras import models, layers\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint\n\nmodel = models.Sequential([\n    layers.Input(shape=(32, 32, 3)),\n    \n    # --- Khối Tích chập 1 (Học các chi tiết cơ bản) ---\n    # Thêm padding='same' để không bị mất viền của bức ảnh\n    layers.Conv2D(32, (3, 3), padding='same', activation='relu'),\n    layers.BatchNormalization(), # Chuẩn hóa dữ liệu\n    layers.Conv2D(32, (3, 3), padding='same', activation='relu'),\n    layers.BatchNormalization(),\n    layers.MaxPooling2D((2, 2)),\n    layers.Dropout(0.25), # Ngẫu nhiên \"tắt\" 25% nơ-ron để chống học vẹt\n\n    # --- Khối Tích chập 2 (Học các đặc trưng phức tạp hơn) ---\n    layers.Conv2D(64, (3, 3), padding='same', activation='relu'),\n    layers.BatchNormalization(),\n    layers.Conv2D(64, (3, 3), padding='same', activation='relu'),\n    layers.BatchNormalization(),\n    layers.MaxPooling2D((2, 2)),\n    layers.Dropout(0.25),\n\n    # --- Khối Tích chập 3 (Nâng cao sức mạnh - Tùy chọn nhưng khuyên dùng) ---\n    layers.Conv2D(128, (3, 3), padding='same', activation='relu'),\n    layers.BatchNormalization(),\n    layers.Conv2D(128, (3, 3), padding='same', activation='relu'),\n    layers.BatchNormalization(),\n    layers.MaxPooling2D((2, 2)),\n    layers.Dropout(0.25),\n\n    # --- Khối Phân loại (Đưa ra kết luận) ---\n    layers.Flatten(),\n    layers.Dense(128, activation='relu'), # Tăng lên 128 nơ-ron vì khối tích chập đã phức tạp hơn\n    layers.BatchNormalization(),\n    layers.Dropout(0.5), # Ở lớp Fully Connected, Dropout mạnh tay hơn (50%)\n    layers.Dense(10, activation='softmax') \n])\n\n# Biên dịch mô hình\nmodel.compile(optimizer='adam',\n              loss='categorical_crossentropy', # <-- Đổi từ SparseCategoricalCrossentropy sang CategoricalCrossentropy\n              metrics=['accuracy'])\n\n# 1. Cài đặt Early Stopping (Dừng sớm nếu không cải thiện)\nearly_stop = EarlyStopping(\n    monitor='val_loss', \n    patience=20, \n    restore_best_weights=True\n)\n\n# 2. Cài đặt Checkpoint (Chỉ lưu model có điểm Validation Accuracy cao nhất)\ncheckpoint = ModelCheckpoint(\n    filepath='/kaggle/working/best_cifar10_model.keras', # Tên file sẽ lưu\n    monitor='val_accuracy', \n    save_best_only=True,    # Chỉ lưu nếu kết quả tốt hơn lần trước\n    mode='max',\n    verbose=1               # In ra thông báo mỗi lần lưu\n)\n\n# 3. Gắn cả 2 công cụ này vào hàm fit\nhistory = model.fit(\n    train_generator,\n    validation_data=val_generator_eval, # Đảm bảo generator validation không shuffle\n    epochs=100,\n    callbacks=[early_stop, checkpoint]  # <--- Khai báo tại đây\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-14T03:56:47.495031Z","iopub.execute_input":"2026-07-14T03:56:47.495709Z","iopub.status.idle":"2026-07-14T03:59:34.416715Z","shell.execute_reply.started":"2026-07-14T03:56:47.495679Z","shell.execute_reply":"2026-07-14T03:59:34.416010Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Trích xuất dữ liệu từ lịch sử huấn luyện\nacc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs = range(1, len(acc) + 1)\n\n# Vẽ biểu đồ Độ chính xác (Accuracy)\nplt.figure(figsize=(12, 5))\nplt.subplot(1, 2, 1)\nplt.plot(epochs, acc, 'b-', label='Độ chính xác (Train)')\nplt.plot(epochs, val_acc, 'r-', label='Độ chính xác (Validation)')\nplt.title('Biểu đồ Độ chính xác')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.legend()\n\n# Vẽ biểu đồ Độ mất mát (Loss)\nplt.subplot(1, 2, 2)\nplt.plot(epochs, loss, 'b-', label='Sai số (Train)')\nplt.plot(epochs, val_loss, 'r-', label='Sai số (Validation)')\nplt.title('Biểu đồ Sai số (Loss)')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend()\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-14T03:59:45.633044Z","iopub.execute_input":"2026-07-14T03:59:45.633676Z","iopub.status.idle":"2026-07-14T03:59:45.890700Z","shell.execute_reply.started":"2026-07-14T03:59:45.633646Z","shell.execute_reply":"2026-07-14T03:59:45.889993Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom sklearn.metrics import classification_report, confusion_matrix\n\n# --- CELL MỚI: DÀNH RIÊNG CHO ĐÁNH GIÁ (EVALUATION) ---\n\n# 2. Lấy nhãn thực tế và dự đoán\nprint(\"\\nĐang tiến hành dự đoán trên tập Validation...\")\ny_true = val_generator_eval.classes\npredictions = model.predict(val_generator_eval)\ny_pred = np.argmax(predictions, axis=1)\nclass_names = list(val_generator_eval.class_indices.keys())\n\n# 3. In Báo cáo phân loại (Classification Report)\nprint(\"\\n\" + \"=\"*50)\nprint(\"BÁO CÁO PHÂN LOẠI CHI TIẾT (CLASSIFICATION REPORT)\")\nprint(\"=\"*50)\nprint(classification_report(y_true, y_pred, target_names=class_names))\n\n# 4. Vẽ Ma trận nhầm lẫn (Confusion Matrix)\ncm = confusion_matrix(y_true, y_pred)\nplt.figure(figsize=(10, 8))\n\n# Cấu hình biểu đồ heatmap\nsns.heatmap(cm, annot=True, fmt='d', cmap='Blues', \n            xticklabels=class_names,\n            yticklabels=class_names)\n\nplt.title('Ma trận Nhầm lẫn (Confusion Matrix)', fontsize=14)\nplt.ylabel('Nhãn thực tế (True Label)', fontsize=12)\nplt.xlabel('Nhãn dự đoán (Predicted Label)', fontsize=12)\nplt.xticks(rotation=45) # Xoay nhãn trục X một chút để chữ không bị đè lên nhau\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-14T08:24:59.060121Z","iopub.execute_input":"2026-07-14T08:24:59.060371Z","iopub.status.idle":"2026-07-14T08:25:03.926798Z","shell.execute_reply.started":"2026-07-14T08:24:59.060348Z","shell.execute_reply":"2026-07-14T08:25:03.925622Z"}},"outputs":[],"execution_count":null}]}