{"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,"isSourceIdPinned":false,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nimport torchvision\nimport torchvision.transforms as transforms\nfrom torch.utils.data import DataLoader, Dataset\nfrom torchvision.models import resnet18, ResNet18_Weights\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nimport pandas as pd","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:33:57.329727Z","iopub.execute_input":"2025-06-17T09:33:57.329907Z","iopub.status.idle":"2025-06-17T09:34:07.014269Z","shell.execute_reply.started":"2025-06-17T09:33:57.329881Z","shell.execute_reply":"2025-06-17T09:34:07.013729Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 设置随机种子\nseed=42\nnp.random.seed(seed)\ntorch.manual_seed(seed)\ntorch.cuda.manual_seed(seed)\ntorch.backends.cudnn.deterministic = True\ntorch.backends.cudnn.benchmark = False\n\n# 检查是否有可用的GPU\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"使用设备: {device}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:34:07.014892Z","iopub.execute_input":"2025-06-17T09:34:07.015155Z","iopub.status.idle":"2025-06-17T09:34:07.077776Z","shell.execute_reply.started":"2025-06-17T09:34:07.015140Z","shell.execute_reply":"2025-06-17T09:34:07.077055Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 数据预处理和增强\ntransform_train = transforms.Compose([\n    transforms.RandomCrop(32, padding=4),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(15),\n    transforms.ColorJitter(brightness=0.2, contrast=0.2),\n    transforms.ToTensor(),\n    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),\n])\n\ntransform_test = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:34:07.079205Z","iopub.execute_input":"2025-06-17T09:34:07.079491Z","iopub.status.idle":"2025-06-17T09:34:07.084139Z","shell.execute_reply.started":"2025-06-17T09:34:07.079471Z","shell.execute_reply":"2025-06-17T09:34:07.083421Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 加载CIFAR-10数据集\nprint(\"加载数据集...\")\ntrainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_train)\ntrainloader = DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2)\n\ntestset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)\ntestloader = DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:34:07.084906Z","iopub.execute_input":"2025-06-17T09:34:07.085429Z","iopub.status.idle":"2025-06-17T09:34:23.496935Z","shell.execute_reply.started":"2025-06-17T09:34:07.085404Z","shell.execute_reply":"2025-06-17T09:34:23.496399Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_size = len(trainset)\ntest_size = len(testset)\nprint(f\"训练集样本数量：{train_size}\")\nprint(f\"测试集样本数量：{test_size}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:34:23.497555Z","iopub.execute_input":"2025-06-17T09:34:23.497733Z","iopub.status.idle":"2025-06-17T09:34:23.501761Z","shell.execute_reply.started":"2025-06-17T09:34:23.497717Z","shell.execute_reply":"2025-06-17T09:34:23.500976Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class_names = trainset.classes\nprint(f\"类别名称：{class_names}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:34:23.502497Z","iopub.execute_input":"2025-06-17T09:34:23.502668Z","iopub.status.idle":"2025-06-17T09:34:23.536758Z","shell.execute_reply.started":"2025-06-17T09:34:23.502654Z","shell.execute_reply":"2025-06-17T09:34:23.536013Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 定义类别\nclasses = ('airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')\n# 定义一个改进的ResNet模型\nclass ModifiedResNet18(nn.Module):\n    def __init__(self, num_classes=10):\n        super(ModifiedResNet18, self).__init__()\n        # 使用预训练的ResNet18，但修改第一个卷积层以适应32x32的图像\n        self.model = resnet18(weights=ResNet18_Weights.DEFAULT)\n        \n        # 修改第一层卷积以适应CIFAR-10的32x32图像\n        self.model.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)\n        \n        # 修改最后的全连接层以适应10个类别\n        self.model.fc = nn.Sequential(\n            nn.Dropout(0.3),\n            nn.Linear(self.model.fc.in_features, num_classes)\n        )\n        \n    def forward(self, x):\n        return self.model(x)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:34:23.537561Z","iopub.execute_input":"2025-06-17T09:34:23.538150Z","iopub.status.idle":"2025-06-17T09:34:23.548146Z","shell.execute_reply.started":"2025-06-17T09:34:23.538126Z","shell.execute_reply":"2025-06-17T09:34:23.547488Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 初始化模型\nprint(\"初始化模型...\")\nmodel = ModifiedResNet18(num_classes=10)\nmodel = model.to(device)\n\n# 定义损失函数和优化器\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=5e-4)\nscheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=200)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:34:23.548818Z","iopub.execute_input":"2025-06-17T09:34:23.549043Z","iopub.status.idle":"2025-06-17T09:34:24.174655Z","shell.execute_reply.started":"2025-06-17T09:34:23.549020Z","shell.execute_reply":"2025-06-17T09:34:24.174063Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 训练模型\ndef train_model(model, trainloader, criterion, optimizer, scheduler, num_epochs=100):\n    model.train()\n    train_losses = []\n    train_accs = []\n    \n    for epoch in range(num_epochs):\n        running_loss = 0.0\n        correct = 0\n        total = 0\n        \n        progress_bar = tqdm(trainloader)\n        for i, (inputs, targets) in enumerate(progress_bar):\n            inputs, targets = inputs.to(device), targets.to(device)\n            \n            optimizer.zero_grad()\n            outputs = model(inputs)\n            loss = criterion(outputs, targets)\n            loss.backward()\n            optimizer.step()\n            \n            running_loss += loss.item()\n            _, predicted = outputs.max(1)\n            total += targets.size(0)\n            correct += predicted.eq(targets).sum().item()\n            \n            progress_bar.set_description(f'Epoch: {epoch+1}/{num_epochs} | Loss: {running_loss/(i+1):.3f} | Acc: {100.*correct/total:.3f}%')\n        \n        epoch_loss = running_loss / len(trainloader)\n        epoch_acc = 100. * correct / total\n        \n        train_losses.append(epoch_loss)\n        train_accs.append(epoch_acc)\n        \n        scheduler.step()\n        \n        # 每10个epoch保存一次模型\n        if (epoch+1) % 10 == 0:\n            torch.save(model.state_dict(), f'cifar10_model_epoch_{epoch+1}.pth')\n    \n    return train_losses, train_accs\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:34:24.176830Z","iopub.execute_input":"2025-06-17T09:34:24.177011Z","iopub.status.idle":"2025-06-17T09:34:24.183469Z","shell.execute_reply.started":"2025-06-17T09:34:24.176997Z","shell.execute_reply":"2025-06-17T09:34:24.182848Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 评估模型\ndef evaluate_model(model, testloader):\n    model.eval()\n    correct = 0\n    total = 0\n    all_preds = []\n    all_targets = []\n    \n    with torch.no_grad():\n        for inputs, targets in tqdm(testloader):\n            inputs, targets = inputs.to(device), targets.to(device)\n            outputs = model(inputs)\n            _, predicted = outputs.max(1)\n            \n            total += targets.size(0)\n            correct += predicted.eq(targets).sum().item()\n            \n            all_preds.extend(predicted.cpu().numpy())\n            all_targets.extend(targets.cpu().numpy())\n    \n    accuracy = 100. * correct / total\n    print(f'测试准确率: {accuracy:.2f}%')\n    \n    return accuracy, all_preds, all_targets\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:34:24.184212Z","iopub.execute_input":"2025-06-17T09:34:24.184471Z","iopub.status.idle":"2025-06-17T09:34:24.199233Z","shell.execute_reply.started":"2025-06-17T09:34:24.184444Z","shell.execute_reply":"2025-06-17T09:34:24.198632Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 训练模型\nprint(\"开始训练模型...\")\ntrain_losses, train_accs = train_model(model, \n                                       trainloader, \n                                       criterion, \n                                       optimizer, \n                                       scheduler, \n                                       num_epochs=20)\n\n# 评估模型\nprint(\"评估模型...\")\naccuracy, predictions, targets = evaluate_model(model, testloader)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:34:24.199925Z","iopub.execute_input":"2025-06-17T09:34:24.200125Z","iopub.status.idle":"2025-06-17T09:41:25.404849Z","shell.execute_reply.started":"2025-06-17T09:34:24.200110Z","shell.execute_reply":"2025-06-17T09:41:25.404066Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 绘制训练过程\nplt.figure(figsize=(12, 4))\nplt.subplot(1, 2, 1)\nplt.plot(train_losses)\nplt.title('Epoch-Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\n\nplt.subplot(1, 2, 2)\nplt.plot(train_accs)\nplt.title('Epoch-Acc')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy (%)')\nplt.savefig('training_history.png')\nplt.show()\n\n# 保存最终模型\ntorch.save(model.state_dict(), 'cifar10_final_model.pth')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:41:25.405856Z","iopub.execute_input":"2025-06-17T09:41:25.406091Z","iopub.status.idle":"2025-06-17T09:41:25.931824Z","shell.execute_reply.started":"2025-06-17T09:41:25.406067Z","shell.execute_reply":"2025-06-17T09:41:25.931191Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 创建提交文件\ndef create_submission(model, testloader, filename='submission.csv'):\n    model.eval()\n    all_preds = []\n    \n    with torch.no_grad():\n        for inputs, _ in tqdm(testloader):\n            inputs = inputs.to(device)\n            outputs = model(inputs)\n            _, predicted = outputs.max(1)\n            all_preds.extend(predicted.cpu().numpy())\n    \n    # 创建提交文件\n    submission = pd.DataFrame({\n        'id': range(len(all_preds)),\n        'label': all_preds\n    })\n    submission.to_csv(filename, index=False)\n    print(f\"提交文件已保存为 {filename}\")\n\n# 创建提交文件\ncreate_submission(model, testloader)\n\nprint(\"完成!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T09:41:25.932637Z","iopub.execute_input":"2025-06-17T09:41:25.932876Z","iopub.status.idle":"2025-06-17T09:41:28.017086Z","shell.execute_reply.started":"2025-06-17T09:41:25.932853Z","shell.execute_reply":"2025-06-17T09:41:28.016135Z"}},"outputs":[],"execution_count":null}]}