{"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":"none","dataSources":[{"sourceType":"competition","sourceId":143086,"databundleVersionId":17278409}],"dockerImageVersionId":31328,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torch.utils.data import TensorDataset, DataLoader, random_split\nimport pandas as pd\n\n# 讀取數據集，'train-images.pt' 和 'train-labels.csv'\nimages_raw = torch.load('/kaggle/input/competitions/moai-practice/train_images.pt', weights_only=False)\nlabels_raw = pd.read_csv('/kaggle/input/competitions/moai-practice/train_labels.csv')\n\n# 歸一化數據集並轉換為 torch.Tensor\nimages = (images_raw.float() - images_raw.float().mean()) / images_raw.float().std()\nlabels = torch.tensor(labels_raw['label'].values)\n\n# 創建數據集\ndataset = TensorDataset(images, labels)\n\n# 按照 8:2 劃分成訓練集和驗證集\ntrain_size = int(0.8 * len(dataset))\nval_size = len(dataset) - train_size\ntrain_dataset, val_dataset = random_split(dataset, [train_size, val_size])\n\ntrain_loader = DataLoader(train_dataset, batch_size=512, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=512)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\n\ndef visualize_samples(loader, title):\n    images, labels = next(iter(loader))\n    images = images[:5]\n    labels = labels[:5]\n    \n    plt.figure(figsize=(15, 3))\n    plt.suptitle(title, fontsize=16)\n    \n    for i in range(5):\n        plt.subplot(1, 5, i+1)\n        img = images[i].squeeze()\n        plt.imshow(img.numpy(), cmap='gray' if img.dim() == 2 else None)\n        plt.title(f\"Label: {labels[i].item()}\")\n        plt.axis('off')\n    \n    plt.tight_layout()\n    plt.show()\n\n# 可視化訓練集樣本\nvisualize_samples(train_loader, \"Training set\")\n\n# 可視化驗證集樣本\nvisualize_samples(val_loader, \"Validation set\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CNN(nn.Module):\n    def __init__(self):\n        super(CNN, self).__init__()\n        self.conv = nn.Conv2d(1, 8, kernel_size=3)\n        self.pool = nn.MaxPool2d(2)\n        self.relu = nn.ReLU()\n        self.fc = nn.Linear(13 * 13 * 8, 10)\n        \n    def forward(self, x):\n        x = x.view(-1, 1, 28, 28)\n        x = self.relu(self.conv(x))\n        x = self.pool(x)\n        x = torch.flatten(x, 1)\n        x = self.fc(x)\n        return x\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = CNN().to(device)\n\nprint(model)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import accuracy_score\n\n# 選擇損失函數\ncriterion = nn.CrossEntropyLoss()\n\n# 選擇優化器\noptimizer = torch.optim.Adam(model.parameters(), lr=0.0001)\n\n# 訓練循環\nfor epoch in range(1):\n    model.train()\n    for batch_idx, (images, labels) in enumerate(train_loader):\n        optimizer.zero_grad()\n        images = images.to(device)\n        labels = labels.to(device)\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        \n        preds = outputs.argmax(dim=1)\n        train_loss = loss.item()\n        train_acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())\n\n        if batch_idx % 100 == 0:\n            print(f\"Epoch {epoch+1}, Batch {batch_idx}, Train Loss: {train_loss:.4f}, Train Accuracy: {train_acc * 100:.2f}%\")\n        \n    model.eval()\n\n    val_preds, val_true = [], []\n    with torch.no_grad():\n        for images, labels in val_loader:\n            images = images.to(device)\n            outputs = model(images)\n            \n            val_preds.extend(outputs.argmax(dim=1).cpu().numpy())\n            val_true.extend(labels.numpy())\n\n    val_loss = criterion(outputs.cpu(), labels).item()\n    val_acc = accuracy_score(val_true, val_preds)\n    \n    print(f\"Epoch {epoch+1}, Val Loss: {val_loss:.4f}, Val Accuracy: {val_acc * 100:.2f}%\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport pandas as pd\n\ntest_images = torch.load('/kaggle/input/competitions/moai-practice/test_images.pt', weights_only=True)\ntest_images = (test_images.float() - test_images.float().mean()) /test_images.float().std()\n\nmodel.eval()\nwith torch.no_grad():\n    device = next(model.parameters()).device\n    outputs = model(test_images.to(device))\n    predictions = outputs.argmax(dim=1)\n\ndf_test = pd.DataFrame({\"label\": predictions.cpu().numpy()})\ndf_test.to_csv(\"submission.csv\", index_label=\"id\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}