{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":3649,"databundleVersionId":46718,"sourceType":"competition"}],"dockerImageVersionId":31041,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"图像kaggle竞赛：图像分类（CIFAR-10）","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19"}},{"cell_type":"code","source":"pip install d2l","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-21T13:14:24.154334Z","iopub.execute_input":"2025-06-21T13:14:24.154600Z","iopub.status.idle":"2025-06-21T13:14:27.536565Z","shell.execute_reply.started":"2025-06-21T13:14:24.154583Z","shell.execute_reply":"2025-06-21T13:14:27.535540Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader\nfrom torchvision import datasets, transforms, models\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# 设备配置\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Using device: {device}\")\n\n# 超参数设置\nbatch_size = 128\nnum_epochs = 20\nlearning_rate = 0.001\nnum_classes = 10\ndata_dir = \"./data/cifar10\"  # 数据集存储路径","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-21T13:14:27.538612Z","iopub.execute_input":"2025-06-21T13:14:27.538856Z","iopub.status.idle":"2025-06-21T13:14:27.545787Z","shell.execute_reply.started":"2025-06-21T13:14:27.538834Z","shell.execute_reply":"2025-06-21T13:14:27.545021Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 定义训练集数据增强\ntrain_transform = transforms.Compose([\n    transforms.RandomCrop(32, padding=4),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))\n])\n\n# 定义测试集数据增强（仅标准化）\ntest_transform = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))\n])\n\n# 加载CIFAR-10数据集\ntrain_dataset = datasets.CIFAR10(\n    root=data_dir, train=True, download=True, transform=train_transform)\ntrain_loader = DataLoader(\n    train_dataset, batch_size=batch_size, shuffle=True, num_workers=4)\n\ntest_dataset = datasets.CIFAR10(\n    root=data_dir, train=False, download=True, transform=test_transform)\ntest_loader = DataLoader(\n    test_dataset, batch_size=batch_size, shuffle=False, num_workers=4)\n\n# 类别名称\nclasses = ('plane', 'car', 'bird', 'cat', 'deer', \n           'dog', 'frog', 'horse', 'ship', 'truck')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-21T13:14:27.546590Z","iopub.execute_input":"2025-06-21T13:14:27.546764Z","iopub.status.idle":"2025-06-21T13:14:36.976520Z","shell.execute_reply.started":"2025-06-21T13:14:27.546749Z","shell.execute_reply":"2025-06-21T13:14:36.975939Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 定义ResNet-18模型\ndef get_resnet_model(num_classes=10):\n    # 加载预训练的ResNet-18\n    model = models.resnet18(pretrained=True)\n    # 修改最后一层全连接层以适应CIFAR-10的10个类别\n    model.fc = nn.Linear(model.fc.in_features, num_classes)\n    return model.to(device)\n\n# 也可以使用CNN模型作为基线\nclass SimpleCNN(nn.Module):\n    def __init__(self, num_classes=10):\n        super(SimpleCNN, self).__init__()\n        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)\n        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)\n        self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1)\n        self.pool = nn.MaxPool2d(2, 2)\n        self.fc1 = nn.Linear(128 * 4 * 4, 512)\n        self.fc2 = nn.Linear(512, num_classes)\n        self.relu = nn.ReLU()\n        self.dropout = nn.Dropout(0.25)\n        \n    def forward(self, x):\n        x = self.pool(self.relu(self.conv1(x)))\n        x = self.pool(self.relu(self.conv2(x)))\n        x = self.pool(self.relu(self.conv3(x)))\n        x = x.view(-1, 128 * 4 * 4)\n        x = self.dropout(x)\n        x = self.relu(self.fc1(x))\n        x = self.dropout(x)\n        x = self.fc2(x)\n        return x\n\n# 初始化模型\n# model = SimpleCNN(num_classes).to(device)  # 简单CNN模型\nmodel = get_resnet_model(num_classes).to(device)  # ResNet-18模型","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-21T13:14:36.978013Z","iopub.execute_input":"2025-06-21T13:14:36.978246Z","iopub.status.idle":"2025-06-21T13:14:37.454412Z","shell.execute_reply.started":"2025-06-21T13:14:36.978229Z","shell.execute_reply":"2025-06-21T13:14:37.453475Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 定义ResNet-18模型\ndef get_resnet_model(num_classes=10):\n    # 加载预训练的ResNet-18\n    model = models.resnet18(pretrained=True)\n    # 修改最后一层全连接层以适应CIFAR-10的10个类别\n    model.fc = nn.Linear(model.fc.in_features, num_classes)\n    return model.to(device)\n\n# 也可以使用CNN模型作为基线\nclass SimpleCNN(nn.Module):\n    def __init__(self, num_classes=10):\n        super(SimpleCNN, self).__init__()\n        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)\n        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)\n        self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1)\n        self.pool = nn.MaxPool2d(2, 2)\n        self.fc1 = nn.Linear(128 * 4 * 4, 512)\n        self.fc2 = nn.Linear(512, num_classes)\n        self.relu = nn.ReLU()\n        self.dropout = nn.Dropout(0.25)\n        \n    def forward(self, x):\n        x = self.pool(self.relu(self.conv1(x)))\n        x = self.pool(self.relu(self.conv2(x)))\n        x = self.pool(self.relu(self.conv3(x)))\n        x = x.view(-1, 128 * 4 * 4)\n        x = self.dropout(x)\n        x = self.relu(self.fc1(x))\n        x = self.dropout(x)\n        x = self.fc2(x)\n        return x\n\n# 初始化模型\n# model = SimpleCNN(num_classes).to(device)  # 简单CNN模型\nmodel = get_resnet_model(num_classes).to(device)  # ResNet-18模型","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-21T13:14:37.455502Z","iopub.execute_input":"2025-06-21T13:14:37.456058Z","iopub.status.idle":"2025-06-21T13:14:37.659523Z","shell.execute_reply.started":"2025-06-21T13:14:37.456025Z","shell.execute_reply":"2025-06-21T13:14:37.658950Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 定义损失函数和优化器\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=learning_rate)\nscheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=num_epochs)\n\n# 训练函数\ndef train(model, train_loader, criterion, optimizer, epoch):\n    model.train()\n    train_loss = 0\n    correct = 0\n    total = 0\n    \n    with tqdm(total=len(train_loader)) as pbar:\n        for batch_idx, (data, target) in enumerate(train_loader):\n            data, target = data.to(device), target.to(device)\n            optimizer.zero_grad()\n            output = model(data)\n            loss = criterion(output, target)\n            loss.backward()\n            optimizer.step()\n            \n            train_loss += loss.item()\n            _, predicted = output.max(1)\n            total += target.size(0)\n            correct += predicted.eq(target).sum().item()\n            \n            pbar.set_description(f'Epoch: {epoch} Loss: {train_loss/(batch_idx+1):.3f} Acc: {100.*correct/total:.3f}%')\n            pbar.update(1)\n    \n    return train_loss / len(train_loader), 100. * correct / total\n\n# 评估函数\ndef test(model, test_loader, criterion):\n    model.eval()\n    test_loss = 0\n    correct = 0\n    total = 0\n    \n    with torch.no_grad():\n        with tqdm(total=len(test_loader)) as pbar:\n            for data, target in test_loader:\n                data, target = data.to(device), target.to(device)\n                output = model(data)\n                loss = criterion(output, target)\n                \n                test_loss += loss.item()\n                _, predicted = output.max(1)\n                total += target.size(0)\n                correct += predicted.eq(target).sum().item()\n                \n                pbar.set_description(f'Test Loss: {test_loss/(len(test_loader)):.3f} Acc: {100.*correct/total:.3f}%')\n                pbar.update(1)\n    \n    return test_loss / len(test_loader), 100. * correct / total\n\n# 训练过程\ntrain_losses, train_accs = [], []\ntest_losses, test_accs = [], []\n\nbest_acc = 0.0\nbest_model_path = \"cifar10_best_model.pth\"\n\nfor epoch in range(1, num_epochs + 1):\n    train_loss, train_acc = train(model, train_loader, criterion, optimizer, epoch)\n    test_loss, test_acc = test(model, test_loader, criterion)\n    \n    train_losses.append(train_loss)\n    train_accs.append(train_acc)\n    test_losses.append(test_loss)\n    test_accs.append(test_acc)\n    \n    # 保存最佳模型\n    if test_acc > best_acc:\n        best_acc = test_acc\n        torch.save(model.state_dict(), best_model_path)\n        print(f\"Best model saved at epoch {epoch}, accuracy: {best_acc:.2f}%\")\n    \n    scheduler.step()\n\n# 绘制训练过程\nplt.figure(figsize=(12, 4))\nplt.subplot(1, 2, 1)\nplt.plot(train_losses, label='Train Loss')\nplt.plot(test_losses, label='Test Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend()\n\nplt.subplot(1, 2, 2)\nplt.plot(train_accs, label='Train Accuracy')\nplt.plot(test_accs, label='Test Accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy (%)')\nplt.legend()\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-21T13:14:37.660312Z","iopub.execute_input":"2025-06-21T13:14:37.660495Z","iopub.status.idle":"2025-06-21T13:23:42.183398Z","shell.execute_reply.started":"2025-06-21T13:14:37.660480Z","shell.execute_reply":"2025-06-21T13:23:42.182487Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 加载最佳模型\nmodel.load_state_dict(torch.load(best_model_path))\nmodel.eval()\n\n# 对测试集进行预测\nall_predictions = []\nall_ids = list(range(len(test_dataset)))\n\nwith torch.no_grad():\n    for data, _ in tqdm(test_loader):\n        data = data.to(device)\n        output = model(data)\n        _, pred = torch.max(output, 1)\n        all_predictions.extend(pred.cpu().numpy())\n\n# 准备提交文件\nimport pandas as pd\n\n# 创建提交数据框\nsubmission = pd.DataFrame({\n    'id': all_ids,\n    'label': all_predictions\n})\n\n# 保存为CSV文件\nsubmission.to_csv('cifar10_submission.csv', index=False)\nprint(\"Submission file created: cifar10_submission.csv\")\n\n# 可视化一些预测结果\ndef visualize_predictions(model, test_loader, classes, num_samples=9):\n    model.eval()\n    dataiter = iter(test_loader)\n    images, labels = next(dataiter)\n    \n    with torch.no_grad():\n        outputs = model(images.to(device))\n        _, predicted = torch.max(outputs, 1)\n    \n    fig, axes = plt.subplots(3, 3, figsize=(10, 10))\n    axes = axes.flatten()\n    \n    for i in range(num_samples):\n        img = images[i].cpu().numpy()\n        img = np.transpose(img, (1, 2, 0))\n        # 反标准化\n        mean = np.array([0.4914, 0.4822, 0.4465])\n        std = np.array([0.2023, 0.1994, 0.2010])\n        img = std * img + mean\n        img = np.clip(img, 0, 1)\n        \n        axes[i].imshow(img)\n        axes[i].set_title(f\"True: {classes[labels[i]]}\\nPred: {classes[predicted[i].cpu()]}\")\n        axes[i].axis('off')\n    \n    plt.tight_layout()\n    plt.show()\n\n# 可视化预测结果\nvisualize_predictions(model, test_loader, classes)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-21T13:23:42.184328Z","iopub.execute_input":"2025-06-21T13:23:42.184612Z","iopub.status.idle":"2025-06-21T13:23:44.632813Z","shell.execute_reply.started":"2025-06-21T13:23:42.184584Z","shell.execute_reply":"2025-06-21T13:23:44.631945Z"}},"outputs":[],"execution_count":null}]}