{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":14774,"databundleVersionId":875431,"sourceType":"competition"}],"dockerImageVersionId":30919,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nfrom PIL import Image\nimport torch\nfrom torchvision import transforms\nfrom sklearn.model_selection import train_test_split\nfrom torch.utils.data import Dataset, DataLoader\n\n# 确保路径正确\ntrain_csv_path = '../input/aptos2019-blindness-detection/train.csv'\nimage_dir = '../input/aptos2019-blindness-detection/train_images'\n\n# 检查文件是否存在\nif not os.path.exists(train_csv_path):\n    raise FileNotFoundError(f\"文件未找到，请检查路径：{train_csv_path}\")\nif not os.path.exists(image_dir):\n    raise FileNotFoundError(f\"文件夹未找到，请检查路径：{image_dir}\")\n\n# 加载原始数据集\ntrain_df = pd.read_csv(train_csv_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-04T03:43:09.395116Z","iopub.execute_input":"2025-03-04T03:43:09.395363Z","iopub.status.idle":"2025-03-04T03:43:18.565291Z","shell.execute_reply.started":"2025-03-04T03:43:09.395342Z","shell.execute_reply":"2025-03-04T03:43:18.564622Z"}},"outputs":[],"execution_count":1},{"cell_type":"code","source":"# 定义数据增强操作\ntransforms_list = {\n    \"Resize\": transforms.Compose([transforms.Resize((224, 224)), transforms.ToTensor()]),\n    \"HorizontalFlip\": transforms.Compose([transforms.RandomHorizontalFlip(p=1), transforms.Resize((224, 224)), transforms.ToTensor()]),\n    \"Rotation\": transforms.Compose([transforms.RandomRotation(degrees=10), transforms.Resize((224, 224)), transforms.ToTensor()]),\n    \"RandomResizedCrop\": transforms.Compose([transforms.RandomResizedCrop(224, scale=(0.8, 1.0), ratio=(0.75, 1.33)), transforms.ToTensor()]),\n    \"VerticalFlip\": transforms.Compose([transforms.RandomVerticalFlip(p=1), transforms.Resize((224, 224)), transforms.ToTensor()]),\n    \"Normalize\": transforms.Compose([transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])\n}\n\n# 创建增强后的数据列表\naugmented_data = []\n\n# 初始化类别计数器\nclass_counts = {i: 0 for i in range(5)}  # 假设类别为 0-4\n\n# 遍历数据集中的每张图像\nfor idx, row in train_df.iterrows():\n    image_id = row['id_code']  # 图像 ID\n    diagnosis = row['diagnosis']  # 图像对应的类别\n    image_path = os.path.join(image_dir, f\"{image_id}.png\")\n    \n    if not os.path.exists(image_path):\n        print(f\"警告：图像文件未找到，跳过 {image_path}\")\n        continue\n    \n    original_image = Image.open(image_path).convert('RGB')\n    \n    # 应用每种数据增强操作\n    for transform_name, transform in transforms_list.items():\n        augmented_image = transform(original_image)\n        \n        # 提取绿色通道\n        if isinstance(augmented_image, torch.Tensor):\n            green_channel = augmented_image[1, :, :]  # 提取绿色通道 (C, H, W)\n        else:\n            green_channel = np.array(augmented_image)[:, :, 1]  # 如果是 NumPy 数组\n            green_channel = torch.tensor(green_channel, dtype=torch.float32)  # 转换为 Tensor\n        \n        # 将增强后的图像和标签添加到数据列表中\n        augmented_data.append({\n            \"image\": green_channel.unsqueeze(0),  # 添加通道维度 (1, H, W)\n            \"label\": diagnosis,                  # 图像对应的类别\n            \"id_code\": f\"{image_id}_{transform_name}\"  # 增强后的图像 ID\n        })\n        \n        # 更新类别计数器\n        class_counts[diagnosis] += 1\n\n# 将增强后的数据转换为 DataFrame\naugmented_df = pd.DataFrame(augmented_data)\n\n# 打印增强后每类的数量\nprint(\"增强后每类的数量：\")\nfor class_label, count in class_counts.items():\n    print(f\"类别 {class_label}: {count} 张图像\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-04T03:43:18.566165Z","iopub.execute_input":"2025-03-04T03:43:18.566473Z","iopub.status.idle":"2025-03-04T03:58:10.847033Z","shell.execute_reply.started":"2025-03-04T03:43:18.566444Z","shell.execute_reply":"2025-03-04T03:58:10.846105Z"}},"outputs":[{"name":"stdout","text":"增强后每类的数量：\n类别 0: 10830 张图像\n类别 1: 2220 张图像\n类别 2: 5994 张图像\n类别 3: 1158 张图像\n类别 4: 1770 张图像\n","output_type":"stream"}],"execution_count":2},{"cell_type":"code","source":"# 自定义数据集类\nclass RetinalDataset(Dataset):\n    def __init__(self, dataframe, transform=None):\n        self.dataframe = dataframe\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.dataframe)\n\n    def __getitem__(self, idx):\n        row = self.dataframe.iloc[idx]\n        image = row['image']  # 图像数据 (1, H, W)\n        label = row['label']  # 标签\n        if self.transform:\n            image = self.transform(image)\n        return image, label\n\n# 划分数据集\ntrain_df, val_df = train_test_split(augmented_df, test_size=0.2, random_state=42, stratify=augmented_df['label'])\n\n# 创建数据集实例\ntrain_dataset = RetinalDataset(train_df)\nval_dataset = RetinalDataset(val_df)\n\n# 创建数据加载器\nbatch_size = 32\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\n\nprint(f\"训练集大小: {len(train_df)}\")\nprint(f\"验证集大小: {len(val_df)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-04T03:58:10.848018Z","iopub.execute_input":"2025-03-04T03:58:10.848347Z","iopub.status.idle":"2025-03-04T03:58:10.876344Z","shell.execute_reply.started":"2025-03-04T03:58:10.848315Z","shell.execute_reply":"2025-03-04T03:58:10.87572Z"}},"outputs":[{"name":"stdout","text":"训练集大小: 17577\n验证集大小: 4395\n","output_type":"stream"}],"execution_count":3},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim  # 导入优化器模块\nimport torchvision.models as models  # 导入 torchvision 的 models 模块","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-04T03:58:10.877055Z","iopub.execute_input":"2025-03-04T03:58:10.877278Z","iopub.status.idle":"2025-03-04T03:58:10.88082Z","shell.execute_reply.started":"2025-03-04T03:58:10.877253Z","shell.execute_reply":"2025-03-04T03:58:10.879996Z"}},"outputs":[],"execution_count":4},{"cell_type":"code","source":"# 加载预训练的 DenseNet 模型\ndensenet = models.densenet121(weights=models.DenseNet121_Weights.IMAGENET1K_V1)  # 使用预训练权重\ndensenet.features.conv0 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)  # 修改输入通道为 1\ndensenet.classifier = nn.Linear(densenet.classifier.in_features, 5)  # 修改输出类别数为 5\n\n# 将模型移动到 GPU\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ndensenet = densenet.to(device)\n\n# 定义损失函数和优化器\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(densenet.parameters(), lr=0.001)\n\n# 训练模型\nnum_epochs = 20\ntrain_losses = []\ntrain_accuracies = []\nval_losses = []\nval_accuracies = []","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-04T03:58:10.881744Z","iopub.execute_input":"2025-03-04T03:58:10.881998Z","iopub.status.idle":"2025-03-04T03:58:11.863763Z","shell.execute_reply.started":"2025-03-04T03:58:10.881979Z","shell.execute_reply":"2025-03-04T03:58:11.863077Z"}},"outputs":[{"name":"stderr","text":"Downloading: \"https://download.pytorch.org/models/densenet121-a639ec97.pth\" to /root/.cache/torch/hub/checkpoints/densenet121-a639ec97.pth\n100%|██████████| 30.8M/30.8M [00:00<00:00, 78.5MB/s]\n","output_type":"stream"}],"execution_count":5},{"cell_type":"code","source":"for epoch in range(num_epochs):\n    densenet.train()\n    running_loss = 0.0\n    running_corrects = 0\n\n    for inputs, labels in train_loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n        outputs = densenet(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item() * inputs.size(0)\n        _, preds = torch.max(outputs, 1)\n        running_corrects += torch.sum(preds == labels.data)\n\n    epoch_loss = running_loss / len(train_dataset)\n    epoch_acc = running_corrects.double() / len(train_dataset)\n    train_losses.append(epoch_loss)\n    train_accuracies.append(epoch_acc.item())\n\n    print(f'Epoch {epoch+1}/{num_epochs} Train Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')\n\n    # 验证阶段\n    densenet.eval()\n    running_loss = 0.0\n    running_corrects = 0\n    with torch.no_grad():\n        for inputs, labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n\n            outputs = densenet(inputs)\n            loss = criterion(outputs, labels)\n\n            running_loss += loss.item() * inputs.size(0)\n            _, preds = torch.max(outputs, 1)\n            running_corrects += torch.sum(preds == labels.data)\n\n        epoch_loss = running_loss / len(val_dataset)\n        epoch_acc = running_corrects.double() / len(val_dataset)\n        val_losses.append(epoch_loss)\n        val_accuracies.append(epoch_acc.item())\n\n        print(f'Epoch {epoch+1}/{num_epochs} Val Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-04T03:58:11.865853Z","iopub.execute_input":"2025-03-04T03:58:11.866079Z","execution_failed":"2025-03-04T05:09:18.174Z"}},"outputs":[{"name":"stdout","text":"Epoch 1/20 Train Loss: 0.6771 Acc: 0.7457\nEpoch 1/20 Val Loss: 0.6845 Acc: 0.7356\nEpoch 2/20 Train Loss: 0.5376 Acc: 0.7958\nEpoch 2/20 Val Loss: 0.5103 Acc: 0.8127\nEpoch 3/20 Train Loss: 0.4825 Acc: 0.8160\nEpoch 3/20 Val Loss: 0.5767 Acc: 0.7681\nEpoch 4/20 Train Loss: 0.4433 Acc: 0.8311\n","output_type":"stream"}],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score\n# 在验证集上进行预测\ndensenet.eval()\nall_preds = []\nall_labels = []\n\nwith torch.no_grad():\n    for inputs, labels in val_loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n        outputs = densenet(inputs)\n        _, preds = torch.max(outputs, 1)\n        all_preds.extend(preds.cpu().numpy())\n        all_labels.extend(labels.cpu().numpy())\n\n# 计算指标\naccuracy = accuracy_score(all_labels, all_preds)\nprecision = precision_score(all_labels, all_preds, average='weighted')\nrecall = recall_score(all_labels, all_preds, average='weighted')\nf1 = f1_score(all_labels, all_preds, average='weighted')\n\nprint(f\"准确率 (Accuracy): {accuracy:.4f}\")\nprint(f\"精确率 (Precision): {precision:.4f}\")\nprint(f\"召回率 (Recall): {recall:.4f}\")\nprint(f\"F1值 (F1 Score): {f1:.4f}\")","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-04T05:09:18.175Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 加载预训练的 ResNet50 模型\nresnet50 = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)  # 使用预训练权重\nresnet50.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)  # 修改输入通道为 1\nresnet50.fc = nn.Linear(resnet50.fc.in_features, 5)  # 修改输出类别数为 5\n\n# 将模型移动到 GPU\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nresnet50 = resnet50.to(device)\n\n# 定义损失函数和优化器\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(resnet50.parameters(), lr=0.001)\n\n# 训练模型\nnum_epochs = 20\ntrain_losses = []\ntrain_accuracies = []\nval_losses = []\nval_accuracies = []","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-04T05:09:18.175Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for epoch in range(num_epochs):\n    resnet50.train()\n    running_loss = 0.0\n    running_corrects = 0\n\n    for inputs, labels in train_loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n        outputs = resnet50(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item() * inputs.size(0)\n        _, preds = torch.max(outputs, 1)\n        running_corrects += torch.sum(preds == labels.data)\n\n    epoch_loss = running_loss / len(train_dataset)\n    epoch_acc = running_corrects.double() / len(train_dataset)\n    train_losses.append(epoch_loss)\n    train_accuracies.append(epoch_acc.item())\n\n    print(f'Epoch {epoch+1}/{num_epochs} Train Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')\n\n    # 验证阶段\n    resnet50.eval()\n    running_loss = 0.0\n    running_corrects = 0\n    with torch.no_grad():\n        for inputs, labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n\n            outputs = resnet50(inputs)\n            loss = criterion(outputs, labels)\n\n            running_loss += loss.item() * inputs.size(0)\n            _, preds = torch.max(outputs, 1)\n            running_corrects += torch.sum(preds == labels.data)\n\n        epoch_loss = running_loss / len(val_dataset)\n        epoch_acc = running_corrects.double() / len(val_dataset)\n        val_losses.append(epoch_loss)\n        val_accuracies.append(epoch_acc.item())\n\n        print(f'Epoch {epoch+1}/{num_epochs} Val Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')\n","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-04T05:09:18.175Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 在验证集上进行预测\nresnet50.eval()\nall_preds = []\nall_labels = []\n\nwith torch.no_grad():\n    for inputs, labels in val_loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n        outputs = resnet50(inputs)\n        _, preds = torch.max(outputs, 1)\n        all_preds.extend(preds.cpu().numpy())\n        all_labels.extend(labels.cpu().numpy())\n\n# 计算指标\naccuracy = accuracy_score(all_labels, all_preds)\nprecision = precision_score(all_labels, all_preds, average='weighted')\nrecall = recall_score(all_labels, all_preds, average='weighted')\nf1 = f1_score(all_labels, all_preds, average='weighted')\n\nprint(f\"准确率 (Accuracy): {accuracy:.4f}\")\nprint(f\"精确率 (Precision): {precision:.4f}\")\nprint(f\"召回率 (Recall): {recall:.4f}\")\nprint(f\"F1值 (F1 Score): {f1:.4f}\")","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-04T05:09:18.175Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 加载预训练的 AlexNet 模型\nalexnet = models.alexnet(weights=models.AlexNet_Weights.IMAGENET1K_V1)  # 使用预训练权重\nalexnet.features[0] = nn.Conv2d(1, 64, kernel_size=11, stride=4, padding=2)  # 修改输入通道为 1\nalexnet.classifier[6] = nn.Linear(alexnet.classifier[6].in_features, 5)  # 修改输出类别数为 5\n\n# 将模型移动到 GPU\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nalexnet = alexnet.to(device)\n\n# 定义损失函数和优化器\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(alexnet.parameters(), lr=0.001)\n\n# 训练模型\nnum_epochs = 20\ntrain_losses = []\ntrain_accuracies = []\nval_losses = []\nval_accuracies = []","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-04T05:09:18.175Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for epoch in range(num_epochs):\n    alexnet.train()\n    running_loss = 0.0\n    running_corrects = 0\n\n    for inputs, labels in train_loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n        outputs = alexnet(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item() * inputs.size(0)\n        _, preds = torch.max(outputs, 1)\n        running_corrects += torch.sum(preds == labels.data)\n\n    epoch_loss = running_loss / len(train_dataset)\n    epoch_acc = running_corrects.double() / len(train_dataset)\n    train_losses.append(epoch_loss)\n    train_accuracies.append(epoch_acc.item())\n\n    print(f'Epoch {epoch+1}/{num_epochs} Train Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')\n\n    # 验证阶段\n    alexnet.eval()\n    running_loss = 0.0\n    running_corrects = 0\n    with torch.no_grad():\n        for inputs, labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n\n            outputs = alexnet(inputs)\n            loss = criterion(outputs, labels)\n\n            running_loss += loss.item() * inputs.size(0)\n            _, preds = torch.max(outputs, 1)\n            running_corrects += torch.sum(preds == labels.data)\n\n        epoch_loss = running_loss / len(val_dataset)\n        epoch_acc = running_corrects.double() / len(val_dataset)\n        val_losses.append(epoch_loss)\n        val_accuracies.append(epoch_acc.item())\n\n        print(f'Epoch {epoch+1}/{num_epochs} Val Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-04T05:09:18.176Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}