{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":114675,"databundleVersionId":13685133,"sourceType":"competition"}],"dockerImageVersionId":31193,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"#导入库函数\nimport math\nimport os\nimport random\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nfrom torchvision import transforms\nfrom PIL import Image\n\n#随机种子\ndef set_seed(seed):\n    seed = int(seed)\n    if seed < 0 or seed > (2**32 - 1):\n        raise ValueError(\"Seed must be between 0 and 2**32 - 1\")\n    else:\n        random.seed(seed)\n        np.random.seed(seed)\n        torch.manual_seed(seed)\n        torch.cuda.manual_seed(seed)\n        torch.backends.cudnn.deterministic = True\nset_seed(16)\n\n#当前设备\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\nprint(f'使用{device}训练')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:24:53.093886Z","iopub.execute_input":"2025-12-13T12:24:53.094107Z","iopub.status.idle":"2025-12-13T12:25:05.430162Z","shell.execute_reply.started":"2025-12-13T12:24:53.094088Z","shell.execute_reply":"2025-12-13T12:25:05.429452Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#数据预处理\n\nimport torch.optim as optim\nimport torchvision\nimport torchvision.transforms as transforms\nfrom torch.optim.lr_scheduler import CosineAnnealingLR\nfrom torch.utils.data import DataLoader, Subset\nfrom sklearn.model_selection import train_test_split\n\n#定义tranform\ntransform_train = transforms.Compose([\n    transforms.RandomCrop(32, padding=4),  # 随机裁剪\n    transforms.RandomHorizontalFlip(p=0.5),      # 随机水平翻转\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2),  # 颜色抖动\n    transforms.RandomRotation(degrees=20), # 随机旋转\n    transforms.ToTensor(),\n    transforms.Normalize([125 / 255, 124 / 255, 115 / 255],\n                         [60 / 255, 59 / 255, 64 / 255])\n])\n\ntransform_test = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2470, 0.2435, 0.2616)),\n])\n\n#训练集：trainset \ntrainset = torchvision.datasets.CIFAR10(\n    root='/kaggle/input/cnn-cifar-10',  # 数据所在目录（包含cifar-10-batches-py文件夹）\n    train=True,\n    download=False, \n    transform=transform_train\n)\n\n# 测试集：test_batch \ntestset = torchvision.datasets.CIFAR10(\n    root='/kaggle/input/cnn-cifar-10',\n    train=False,\n    download=False,\n    transform=transform_test\n)\n\n#数据加载器\ntrain_loader = DataLoader(trainset,batch_size=128,shuffle=True,num_workers=2)\ntest_loader = DataLoader(testset,batch_size=128,shuffle=False,num_workers=2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:25:05.431233Z","iopub.execute_input":"2025-12-13T12:25:05.431664Z","iopub.status.idle":"2025-12-13T12:25:09.083455Z","shell.execute_reply.started":"2025-12-13T12:25:05.431643Z","shell.execute_reply":"2025-12-13T12:25:09.082803Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def ResNet(weights):\n    #加载模型,使用 ResNet-18\n    model = torchvision.models.resnet18(weights=weights)\n    \n    #修改第一层卷积\n    model.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)\n    #移除池化层\n    model.maxpool = nn.Identity()\n    \n    #替换输出层\n    model.fc = nn.Linear(model.fc.in_features, 10)\n    \n    #冻结\n    if weights:\n        for param in model.parameters():\n            param.requires_grad = False\n        for param in model.fc.parameters():\n            param.requires_grad = True\n            \n    return model.to(device)\n    \nmodel = ResNet(None)\n#print(model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:25:09.084201Z","iopub.execute_input":"2025-12-13T12:25:09.084559Z","iopub.status.idle":"2025-12-13T12:25:09.456166Z","shell.execute_reply.started":"2025-12-13T12:25:09.084533Z","shell.execute_reply":"2025-12-13T12:25:09.455570Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#训练方法和测试方法\nfrom torch.amp import autocast, GradScaler \nif device == 'cuda':    #GPU下使用混合精度\n    scaler = GradScaler('cuda') #梯度缩放\n    use_amp = True    #使用混合精度\n    print(\"启用混合精度训练\")\n\n#训练方法: train\ndef train():\n    model.train()\n    total_loss = 0.0 #损失值\n    correct = 0 #正确数\n    total = 0 #总数\n    \n    for batch,(X,y) in enumerate(train_loader):\n        X,y = X.to(device),y.to(device)\n\n        optimizer.zero_grad()#梯度清零\n        #混合精度\n        if device == 'cude':\n            with autocast('cuda'):#自动转换\n                pred = model(X)\n                loss = criterion(pred,y)\n            scaler.scale(loss).backward() \n            scaler.step(optimizer)\n            scaler.update()\n        else:\n            pred = model(X)\n            loss = criterion(pred,y)\n            loss.backward()\n            optimizer.step()\n            \n        total_loss += loss.item()  #损失值\n        total += y.size(0)  #总数\n        pred_index = torch.argmax(pred,dim=1) #最大值索引\n        correct += pred_index.eq(y).sum().item() #正确数\n    acc = 100. * correct / total #正确率\n    loss_ave = total_loss / len(train_loader) #训练损失值取平均\n    return loss_ave, acc\n\n#测试方法 test\ndef test():\n    model.eval()\n    total_loss = 0.0\n    correct = 0\n    total = 0\n    with torch.no_grad():\n        for batch,(X,y) in enumerate(test_loader):\n            X,y = X.to(device),y.to(device)\n            pred = model(X)\n            loss = criterion(pred,y)\n            \n            total_loss += loss.item()  #损失值\n            total += y.size(0)  #总数\n            pred_index = torch.argmax(pred,dim=1) #最大值索引\n            correct += pred_index.eq(y).sum().item() #正确数\n            \n    acc = 100. * correct / total #正确率\n    loss_ave = total_loss / len(test_loader) #训练损失值取平均\n    return loss_ave, acc\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:25:09.457547Z","iopub.execute_input":"2025-12-13T12:25:09.457748Z","iopub.status.idle":"2025-12-13T12:25:09.466841Z","shell.execute_reply.started":"2025-12-13T12:25:09.457733Z","shell.execute_reply":"2025-12-13T12:25:09.466262Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#主训练流程\nfrom torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR\nfrom torch.optim.lr_scheduler import SequentialLR\n\ncriterion = nn.CrossEntropyLoss(label_smoothing=0.1) #损失函数\noptimizer = optim.SGD(model.parameters(),\n                      lr=0.05,               # 初始学习率（关键！）\n                      momentum=0.9,\n                      weight_decay=5e-4)\nepoch = 120\n#学习率预热\nwarmup_step= int(epoch * 0.2)  #预热步数\nwarmup = LinearLR(optimizer,\n                  start_factor=0.01,\n                  total_iters=warmup_step)\n#余弦退火\ncosin = CosineAnnealingLR(optimizer,\n                          T_max=epoch - warmup_step)\n#调度器\nscheduler = SequentialLR(optimizer, \n                         schedulers=[warmup,cosin],#预热然后余弦退火\n                         milestones=[warmup_step])#切换\n\n#迭代\ntrain_loss_list=[]\ntrain_acc_list=[]\ntest_loss_list=[]\ntest_acc_list=[]\nlr_list=[]\nbest_acc = 90.0 #最高正确率\nfor i in range(epoch):\n    train_loss,train_acc = train()\n    test_loss,test_acc = test()\n    scheduler.step()  # 更新学习率\n\n    #保存最优模型\n    if test_acc > best_acc:\n        best_acc = test_acc\n        torch.save(model.state_dict(), 'resnet18_cifar10_best.pth')\n\n    train_loss_list.append(train_loss)\n    train_acc_list.append(train_acc)\n    test_loss_list.append(test_loss)\n    test_acc_list.append(test_acc)\n    lr_list.append(scheduler.get_last_lr()[0])\n    print(\"----------------------------------------------\")\n    print(f'| epoch：{i+1}/{epoch} |\\n训练损失值: {train_loss:.3f} | 训练正确率: {train_acc:.2f}% | 测试损失值{test_loss:.3f} | 测试正确率: {test_acc:.2f}% | 学习率: {scheduler.get_last_lr()[0]}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:27:00.358127Z","iopub.execute_input":"2025-12-13T12:27:00.359010Z","iopub.status.idle":"2025-12-13T12:28:55.089640Z","shell.execute_reply.started":"2025-12-13T12:27:00.358982Z","shell.execute_reply":"2025-12-13T12:28:55.088520Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#可视化\nprint(f'最高学习率: {best_acc}')\nx=[i for i in range(epoch)]\n\nplt.figure(figsize=(20,15))\n\nplt.subplot(3,2,1)\nplt.plot(x,train_loss_list,color='red',label='train_loss')\nplt.plot(x,test_loss_list,color='green',label='test_loss')\nplt.title(\"loss\")\n\nplt.subplot(3,2,2)\nplt.plot(x[-50:],train_loss_list[-50:],color='red',label='train_loss')\nplt.plot(x[-50:],test_loss_list[-50:],color='green',label='test_loss')\nplt.title(\"tail_loss\")\n\nplt.subplot(3,2,3)\nplt.plot(x,train_acc_list,color='red',label='train_loss')\nplt.plot(x,test_acc_list,color='green',label='test_loss')\nplt.title(\"Accuracy\")\n\nplt.subplot(3,2,4)\nplt.plot(x[-50:],train_acc_list[-50:],color='red',label='train_loss')\nplt.plot(x[-50:],test_acc_list[-50:],color='green',label='test_loss')\nplt.title(\"tail_Accuracy\")\n\nplt.subplot(3,2,5)\nplt.plot(lr_list)\nplt.title(\"lr\")\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:30:42.241166Z","iopub.execute_input":"2025-12-13T12:30:42.241908Z","iopub.status.idle":"2025-12-13T12:30:42.961323Z","shell.execute_reply.started":"2025-12-13T12:30:42.241882Z","shell.execute_reply":"2025-12-13T12:30:42.960552Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#使用最优模型输出结果\nimport pandas as pd\n#读取模型参数\nmodel.load_state_dict(torch.load(\"/kaggle/working/resnet18_cifar10_best.pth\"))\nmodel.eval()\nres=[]\nwith torch.no_grad():        \n    for inputs,targets in test_loader:\n        inputs, targets = inputs.to(device), targets.to(device)\n        outputs = model(inputs)\n\n        #拼接结果\n        if res == []:\n            res = outputs.argmax(1)\n        else:res = torch.cat((res,outputs.argmax(1)),dim=0)\n\nID=[i for i in range(0,10000)]\nres=res.to('cpu').numpy()\nresult=pd.DataFrame({\n    'Id':ID,\n    'label':res\n    })\n#输出结果\nresult.to_csv('result.csv',index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:30:50.498079Z","iopub.execute_input":"2025-12-13T12:30:50.498631Z","iopub.status.idle":"2025-12-13T12:30:53.404425Z","shell.execute_reply.started":"2025-12-13T12:30:50.498609Z","shell.execute_reply":"2025-12-13T12:30:53.403412Z"}},"outputs":[],"execution_count":null}]}