{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"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":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":3649,"databundleVersionId":46718,"isSourceIdPinned":false},{"sourceType":"datasetVersion","sourceId":16308705,"datasetId":10455011,"databundleVersionId":17296263}],"dockerImageVersionId":31328,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"00c8ed9c","cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision.models as models\nimport torchvision.transforms as transforms\nfrom PIL import Image\nimport numpy as np\nimport pandas as pd\nimport os\nimport cv2\nfrom tqdm import tqdm\n# Kiểm tra GPU\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"✅ Using device: {device}\")\n\nmlp_hidden_sizes = [32, 32, 16]","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"fb039aed","cell_type":"code","source":"# Cell 2: Load CSV files\n\n# Load the train.csv file\ntrain_df = pd.read_csv('/kaggle/input/datasets/dannypigthomas/chonkyboi2/cifar/trainLabels.csv')\nprint(f\"Train CSV shape: {train_df.shape}\")\nprint(train_df.head())\n\n# Load the submission.csv file\nsubmission_df = pd.read_csv('/kaggle/input/datasets/dannypigthomas/chonkyboi2/cifar/sampleSubmission.csv')\nprint(f\"/nSubmission CSV shape: {submission_df.shape}\")\nprint(submission_df.head())","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"0566ffd8","cell_type":"code","source":"class PretrainedFeatureExtractor(nn.Module):\n    \"\"\"Sử dụng EfficientNet-B1 pre-trained để trích xuất đặc trưng\"\"\"\n    def __init__(self):\n        super(PretrainedFeatureExtractor, self).__init__()\n        # Tải EfficientNet-B1 với pre-trained weights\n        self.efficientnet = models.efficientnet_b0(weights=models.EfficientNet_B0_Weights.DEFAULT)\n        \n        # Đóng băng toàn bộ weights (không train lại)\n        for param in self.efficientnet.parameters():\n            value = False # Sửa nhẹ cú pháp để tránh format lỗi\n            param.requires_grad = False\n        \n        # Loại bỏ layer classification cuối cùng\n        self.feature_dim = self.efficientnet.classifier[1].in_features\n        self.efficientnet.classifier = nn.Identity()\n        \n    def forward(self, x):\n        # x: [batch, 3, 224, 224]\n        features = self.efficientnet(x)\n        return features\n\n# Khởi tạo và chuyển sang GPU\nfeature_extractor = PretrainedFeatureExtractor().to(device)\nfeature_extractor.eval() # BẮT BUỘC: Đưa mô hình về chế độ eval khi inference\nprint(f\"✅ Loaded EfficientNet-B1 pre-trained on ImageNet\")\nprint(f\"   Feature dimension: {feature_extractor.feature_dim}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"c39a2e78","cell_type":"code","source":"# Transform cho ảnh đầu vào (chuẩn hóa theo ImageNet)\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),  # Resize về 224x224\n    transforms.ToTensor(),           # Chuyển sang tensor\n    transforms.Normalize(\n        mean=[0.485, 0.456, 0.406],  # ImageNet mean\n        std=[0.229, 0.224, 0.225]    # ImageNet std\n    )\n])\n\nprint(\"✅ Transform pipeline defined\")\nprint(\"   - Resize: 224x224\")\nprint(\"   - Normalize: ImageNet stats\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"952efdf5","cell_type":"code","source":"def extract_single_image_feature(image_path):\n    \"\"\"\n    Trích xuất feature vector từ một ảnh duy nhất sử dụng torch.amp\n    \n    Args:\n        image_path: đường dẫn đến file ảnh\n        \n    Returns:\n        numpy array - feature vector (float32)\n    \"\"\"\n    # Đọc ảnh\n    img = cv2.imread(image_path)\n    if img is None:\n        raise ValueError(f\"Không thể đọc ảnh: {image_path}\")\n    \n    # Chuyển từ BGR (OpenCV) sang RGB và sang PIL Image\n    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    pil_img = Image.fromarray(img_rgb)\n    \n    # Áp dụng transform và đưa lên GPU\n    img_tensor = transform(pil_img).unsqueeze(0)  # [1, 3, 224, 224]\n    img_tensor = img_tensor.to(device)\n    \n    # Xác định loại thiết bị cho amp (cuda, cpu, xpu, v.v.)\n    device_type = device.type\n    \n    # Trích xuất feature với AMP và no_grad\n    with torch.no_grad():\n        # torch.amp.autocast tự động chọn kiểu dữ liệu tối ưu (ví dụ: float16 trên CUDA)\n        with torch.amp.autocast(device_type=device_type, enabled=(device_type == 'cuda')):\n            feature = feature_extractor(img_tensor)\n            \n        # AMP có thể trả về kiểu float16. Nên chuyển về float32 trước khi sang numpy \n        # để tránh lỗi tương thích hoặc mất độ chính xác khi tính toán sau này.\n        feature = feature.float()\n    \n    # Chuyển về numpy array\n    feature_numpy = feature.cpu().numpy().flatten()\n    \n    return feature_numpy","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"65e241ee","cell_type":"code","source":"train_features_array , train_labels = [] , []\ntrain_path = \"/kaggle/input/datasets/dannypigthomas/chonkyboi2/cifar/train\"\n\n# Wrap the iterator with tqdm and add a nice description\nfor idx, row in tqdm(train_df.iterrows(), total=len(train_df), desc=\"Processing Train Images\"):\n    img_name = f\"{row['id']}.png\"\n    img_path = f\"{train_path}/{img_name}\"\n    \n    # Removed the verbose print statement so the progress bar stays on one line\n    feature = extract_single_image_feature(img_path)\n    train_features_array.append(feature)\n    train_labels.append(row['label'])\n\ntrain_features_array = np.array(train_features_array)\ntrain_labels = np.array(train_labels)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"f66dbba4","cell_type":"code","source":"test_features_array , testing_ids = [] , []\ntest_path = \"/kaggle/input/datasets/dannypigthomas/chonkyboi2/cifar/test\"\n\n# Do the same for the test/submission loop\nfor idx, row in tqdm(submission_df.iterrows(), total=len(submission_df), desc=\"Processing Test Images\"):\n    img_name = f\"{row['id']}.png\"\n    img_path = f\"{test_path}/{img_name}\"    \n    \n    feature = extract_single_image_feature(img_path)\n    test_features_array.append(feature)\n    testing_ids.append(idx + 1)\n\ntest_features_array = np.array(test_features_array)\ntesting_ids = np.array(testing_ids)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"59578583","cell_type":"code","source":"from sklearn.neural_network import MLPClassifier\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import cross_val_score\n\n# Encode labels\nlabel_encoder = LabelEncoder()\nencoded_labels = label_encoder.fit_transform(train_labels)\n\n# Khởi tạo MLP\nmlp = MLPClassifier(\n    hidden_layer_sizes=(32, 32, 16),\n    activation='relu',\n    solver='adam',\n    max_iter=200,\n    random_state=42,\n    verbose=True\n)\n\n#Cross validation score\nscores = cross_val_score(\n    estimator=mlp,           # ← sửa từ 'models' thành 'estimator'\n    X=train_features_array,\n    y=encoded_labels,\n    cv=5,                    # 5-fold cross-validation\n    scoring='accuracy'       # metric đánh giá\n)\n\nprint(f\"{scores.mean():.4f}\")\n\n# Huấn luyện\nprint(\"\\n🚀 Training MLP on extracted features...\")\nmlp.fit(train_features_array, encoded_labels)\n\n# Dự đoán\npredictions_encoded = mlp.predict(test_features_array)\npredictions = label_encoder.inverse_transform(predictions_encoded)\n\n# Lưu kết quả\noutput_df = pd.DataFrame({\n    'id': testing_ids,\n    'label': predictions\n})\noutput_df.to_csv('chonky.csv', index=False)\n\nprint(\"\\n✅ Predictions saved to 'chonky.csv'\")\nprint(f\"\\n📋 Sample predictions:\")\nprint(output_df.head(10))","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}