{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":29193,"databundleVersionId":2318453,"sourceType":"competition"}],"dockerImageVersionId":30787,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torchvision import datasets, transforms\nfrom torchvision.models import efficientnet_b0, EfficientNet_B0_Weights\nfrom torch.utils import data\n#from torch.utils.data import Dataset\nimport pandas as pd\nfrom sklearn.model_selection import KFold\nimport numpy as np\nfrom torch.utils.data import Dataset\nimport os\nfrom torchvision.io import read_image\nimport numpy as np","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-06T04:05:06.069780Z","iopub.execute_input":"2024-11-06T04:05:06.070073Z","iopub.status.idle":"2024-11-06T04:05:11.730509Z","shell.execute_reply.started":"2024-11-06T04:05:06.070040Z","shell.execute_reply":"2024-11-06T04:05:11.729720Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 图像文件夹路径\nimg_dir = '/kaggle/input/classify-leaves'\n# 标签文件路径\ntrain_csv_file = '/kaggle/input/classify-leaves/train.csv'\ntest_csv_file = '/kaggle/input/classify-leaves/test.csv'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-06T04:05:11.732453Z","iopub.execute_input":"2024-11-06T04:05:11.733045Z","iopub.status.idle":"2024-11-06T04:05:11.737535Z","shell.execute_reply.started":"2024-11-06T04:05:11.732996Z","shell.execute_reply":"2024-11-06T04:05:11.736616Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_data = pd.read_csv(train_csv_file)\ntrain_data['label'], unique_labels = pd.factorize(train_data['label'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-06T04:05:11.738600Z","iopub.execute_input":"2024-11-06T04:05:11.738956Z","iopub.status.idle":"2024-11-06T04:05:11.802531Z","shell.execute_reply.started":"2024-11-06T04:05:11.738923Z","shell.execute_reply":"2024-11-06T04:05:11.801445Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 图像变换\nprocess = EfficientNet_B0_Weights.IMAGENET1K_V1.transforms()\ntransform = transforms.Compose([\n    # 随机水平翻转\n    transforms.RandomHorizontalFlip(),\n\n    # 随机旋转\n    transforms.RandomRotation(30),  # 随机旋转 30 度以内\n\n    # 随机调整图像的亮度、对比度、饱和度和色调\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2),\n])\ntransform = transforms.Compose([transform, process])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-06T04:05:11.805443Z","iopub.execute_input":"2024-11-06T04:05:11.805817Z","iopub.status.idle":"2024-11-06T04:05:11.812521Z","shell.execute_reply.started":"2024-11-06T04:05:11.805780Z","shell.execute_reply":"2024-11-06T04:05:11.811450Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 定义自定义数据集\nclass CustomDataset(Dataset):\n    def __init__(self, train_data, img_dir, transform=None):\n        self.data = train_data\n        self.img_dir = img_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.data)  # 返回样本数量\n\n    def __getitem__(self, idx):\n        img_file = self.data.iloc[idx, 0]  # 假设第一列是文件名\n        label = self.data.iloc[idx, 1]     # 假设第二列是标签\n        img_path = os.path.join(self.img_dir, img_file)\n        image = read_image(img_path)  # 读取图像\n\n        if self.transform:\n            image = self.transform(image)  # 应用变换\n            return image, label  # 返回图像和标签\n\n\nclass CustomTestDataset(Dataset):\n    def __init__(self, test_data, img_dir, transform=None):\n        self.data = test_data\n        self.img_dir = img_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.data)  # 返回样本数量\n\n    def __getitem__(self, idx):\n        img_file = self.data.iloc[idx, 0]  # 假设第一列是文件名\n        img_path = os.path.join(self.img_dir, img_file)\n        image = read_image(img_path)  # 读取图像\n\n        if self.transform:\n            image = self.transform(image)  # 应用变换\n            return image  # 返回图像","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-06T04:05:11.813934Z","iopub.execute_input":"2024-11-06T04:05:11.814264Z","iopub.status.idle":"2024-11-06T04:05:11.826122Z","shell.execute_reply.started":"2024-11-06T04:05:11.814228Z","shell.execute_reply":"2024-11-06T04:05:11.825161Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 三要素\n\ndataset_aug = CustomDataset(train_data, img_dir=img_dir, transform=transform)\ndataset_noaug = CustomDataset(train_data, img_dir=img_dir, transform=process)\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(device)\n\nmodel = efficientnet_b0(weights='DEFAULT')\n# 修改最后一层\nmodel.classifier = nn.Sequential(\n    nn.Dropout(p=0.2, inplace=True),\n    nn.Linear(in_features=1280, out_features=176, bias=True)\n)\n\nnet = model.to(device)\nloss = nn.CrossEntropyLoss()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-06T04:05:11.827459Z","iopub.execute_input":"2024-11-06T04:05:11.828291Z","iopub.status.idle":"2024-11-06T04:05:12.697782Z","shell.execute_reply.started":"2024-11-06T04:05:11.828241Z","shell.execute_reply":"2024-11-06T04:05:12.696873Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 定义精度测试\n\ndef accuracy(y_hat, y):\n    \"\"\"计算预测正确的数量\"\"\"\n    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:\n        y_hat = y_hat.argmax(axis=1)\n    cmp = y_hat.type(y.dtype) == y\n    return float(cmp.type(y.dtype).sum())\n\n\nclass Accumulator:\n    \"\"\"在n个变量上累加\"\"\"\n\n    def __init__(self, n):\n        self.data = [0.0] * n\n\n    def add(self, *args):\n        self.data = [a + float(b) for a, b in zip(self.data, args)]\n\n    def reset(self):\n        self.data = [0.0] * len(self.data)\n\n    def __getitem__(self, idx):\n        return self.data[idx]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-06T04:05:12.699026Z","iopub.execute_input":"2024-11-06T04:05:12.699339Z","iopub.status.idle":"2024-11-06T04:05:12.707166Z","shell.execute_reply.started":"2024-11-06T04:05:12.699305Z","shell.execute_reply":"2024-11-06T04:05:12.706049Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 5 折交叉验证\nkf = KFold(n_splits=5, shuffle=True, random_state=42) ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-06T04:05:12.708459Z","iopub.execute_input":"2024-11-06T04:05:12.708791Z","iopub.status.idle":"2024-11-06T04:05:12.719931Z","shell.execute_reply.started":"2024-11-06T04:05:12.708759Z","shell.execute_reply":"2024-11-06T04:05:12.719144Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train(net, dataset_aug, dataset_noaug, batch_size, num_epochs, learning_rate, weight_decay):\n\n    # 使用Adam优化算法\n    optimizer = torch.optim.Adam([\n        {'params': model.features.parameters(), 'lr': learning_rate, 'weight_decay': weight_decay},\n        {'params': model.classifier.parameters(), 'lr': learning_rate * 10, 'weight_decay': weight_decay}\n    ])\n    # 定义学习率调度器\n    scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=20)\n\n    # 定义k折交叉子集\n    train_index, val_index = next(kf.split(dataset_aug))\n    train_subset = torch.utils.data.Subset(dataset_aug, train_index)\n    val_subset = torch.utils.data.Subset(dataset_noaug, val_index)\n    # 定义小批量生成器f\n    train_loader = data.DataLoader(dataset_aug, batch_size, shuffle=True, num_workers=4)\n    val_loader = data.DataLoader(val_subset, batch_size, shuffle=False, num_workers=4)\n\n    for epoch in range(num_epochs):\n        net.train()\n        metric = Accumulator(2)\n        current_lr = optimizer.param_groups[0]['lr']\n        for X, y in train_loader:\n            #  GPU\n            X, y = X.to(device), y.to(device)\n            optimizer.zero_grad()\n            batch_loss = loss(net(X), y)\n            batch_loss.backward()\n            optimizer.step()\n        # 更新学习率\n        scheduler.step()\n        train_loss = 0.0\n        val_loss = 0.0\n        # 每个epoch计算损失\n        with torch.no_grad():\n            net.eval()\n            for X, y in train_loader:\n                #  GPU\n                X, y = X.to(device), y.to(device)\n                batch_loss = loss(net(X), y)\n                train_loss += batch_loss.item() * X.size(0)\n            train_loss = train_loss / len(train_subset)\n            for X, y in val_loader:\n                #  GPU\n                X, y = X.to(device), y.to(device)\n                batch_loss = loss(net(X), y)\n                val_loss += batch_loss.item() * X.size(0)\n                metric.add(accuracy(net(X), y), y.numel())\n            val_loss = val_loss / len(val_subset)\n            val_accuracy = metric[0] / metric[1]\n\n        print(f'epoch {epoch + 1}, train_loss {train_loss:f}, val_loss {val_loss:f}, val_accuracy {val_accuracy:f}, Learning Rate: {current_lr:.6f}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-06T04:05:12.721169Z","iopub.execute_input":"2024-11-06T04:05:12.721475Z","iopub.status.idle":"2024-11-06T04:05:12.735787Z","shell.execute_reply.started":"2024-11-06T04:05:12.721440Z","shell.execute_reply":"2024-11-06T04:05:12.734829Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 运行训练函数\ntrain(net, dataset_aug, dataset_noaug, batch_size=64, num_epochs=20, learning_rate=0.00005, weight_decay=0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-06T04:05:12.738303Z","iopub.execute_input":"2024-11-06T04:05:12.738651Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(net.state_dict(), 'model_weights.pth')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_data = pd.read_csv(test_csv_file)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_dataset = dataset = CustomTestDataset(test_data, img_dir=img_dir, transform=transform)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"net = net.eval()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_loader = data.DataLoader(test_dataset, batch_size=128, shuffle=False, num_workers=4)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with torch.no_grad():\n    result = np.array([])\n    for X in test_loader:\n        X = X.to(device)\n        batch_output = net(X).cpu().argmax(axis=1).numpy()\n        result = np.concatenate((result, batch_output))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"result = pd.Series(result, name='label')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"result = result.apply(lambda x: unique_labels[int(x)])","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.concat([test_data, result], axis=1)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission.to_csv('leaves_aug.csv', index=False)","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}